-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[WIP] doc: Nyan types #640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
doc/nyan/base types.md
Outdated
| Gold(Resource) | ||
| Food | ||
| ... | ||
| ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, they're defined by the base data pack (aka the original game conversion) :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/SFTtech/nyan/blob/master/doc/nyan.md says: "Defined in the game engine"
Maybe I'll change that there.
edit: changed that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx
TheJJ
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really happy to see that somebody else actually understood how nyan works, good job :)
The only thing I can recommend you is to understand that nyan only provides data, never logic. All logic is implemented in the engine. Once you internalized this, nyan makes much more sense and you can offload everything to the engine.
Which is quite intuitive actually, because the implementation of whatever game logic must be done in the engine. Nyan is only the tool to manipulate the numbers (and filenames).
doc/nyan/base types.md
Outdated
| # WIP4: how do we reference Animations? | ||
| # animation : file # one picture that contains all frames or, if a directory, | ||
| # contains all frames. # WIP5: naming scheme? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The engine has to support animations, it therefore defines Animation and we have to instance VillagerWalking(Animation): image : ... and reference it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Ability() should get a member `animation : Animation'.
CooldownAbility does not need an Animation, but since every actual Ability will need an Animation, CooldownAbility can stay abstract. Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. For example, castles don't have an attack animation. And if training units/researching techs/attack stances etc. also become abilities, neither do they.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if for example buildings have an ability without animation, they could reference to their static picture. Maybe that's a dirty workaround. The only alternative I see is to include an AnimatedAbility class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say the animation is a mixin, mainly used in abilities like Walking(Ability, Animation). If that ability becomes active, we can check in the engine if the ability also inherited from Animation, then activate and display the data specified there. That way, we can add custom animations for nearly everything we want but do not enforce it and can fall back to the standard walk animation etc.
doc/nyan/base types.md
Outdated
| # Everything you can see in the game # (WIP: but not assets, which is basically everything you see. Maybe better:) | ||
| # Everything that has some 'Ability' inherits from this. | ||
| ability : set(Ability) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything that has a (possibly varying) location ingame. Probably has a hp : float member.
Can't tell yet if we should add buildings as units as well or introduce another parent object for that.
We also have to think about if we wanna have a MoveAbility or simply create a engine-defined MovingUnit. The result is of course the same and i'm not sure if movement shall be done by some member value (the ability set) or by another base object. For nyan itselt it doesn't matter, depends how we wanna design the engine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything that has a position has a look. So add an Animation or Sprite member?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, yes. Each Unit needs its idle look.
doc/nyan/base types.md
Outdated
| Open nyan implementation questions: | ||
|
|
||
| 1. How do we say in Nyan, that a Towncenter attack depends on how many people are inside the building? | ||
| 2. What about the building 'Ability' to carry units? will this lead to recursive references? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
References can be recursive of course, they can point to each other. But the carry ability would also be implemented in the engine i think, in a way that if the unit has the CarryAbility, nyan doesn't know about what the unit actually carries, but nyan only tells us it can carry 20 weight units, and that one unit type elephant will consume 5 weight units. That means each unit must define its weight :).
The engine then checks for each unit to board if current_weight + weight_of_new_unit_to_board >= max_weight and decides by that if it can board.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have to tell somehow, what units can go inside: many units can garrison the castle, but not the towncenter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can define types of units: infantry, cavalry, ships, siege. this could help with the allowed_targets member in attackability and with the upgrades from research.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, the original game has those unit types available for us, we can represent it simply in the inheritance hierarchy. (Huskarl(Cavalry) e.g.)
doc/nyan/base types.md
Outdated
|
|
||
| Open nyan implementation questions: | ||
|
|
||
| 1. How do we say in Nyan, that a Towncenter attack depends on how many people are inside the building? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The possibility of attacking buildings must also be implemented in the engine. Nyan provides the information n units (of size x?) can garrison in the building. Then those people can either regularly attack from there or the engine multiplies the attack damage for the building.
doc/nyan/base types.md
Outdated
|
|
||
| -> If the {Towncenter,Castle} has certain damage, contained units need to leave. | ||
|
|
||
| -> A relict in a Church leads to increasing gold. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The damage info is a combination of nyan and the engine. The building itself must define a collapse threshold (in percent maybe) which the engine respects to send units out.
The relic gold is purely implemented in the engine which provides a "ResourceGenerator" object, which the relic inherits (Relic(ResourceGenerator)) and adds to the set(resource_type) += {Gold} and rate = 10. Nyan is not aware of the game mechanics, this is always the job of the engine (that was by the way the key enlightment i finally had to get a sufficient nyan design).
doc/nyan/base types.md
Outdated
| Resource(): | ||
| name : text | ||
| icon : file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jup, the resource is part of the engine and the data pack can then create arbitrary resources.
doc/nyan/base types.md
Outdated
| name : text | ||
| description : text | ||
| icon: text | ||
| Tech(Update, HUDElement): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be a very good idea. I've never really thought about the ui integration, but having another mixin for that may be the way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we still need a way to keep all the elements in order and allow 'pages'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say the order and paging is done by categories first and addition order. If mods remove elements the layout won't get fucked up and we can also easily add new elements. If we use numbers for positioning things will always conflict. Tough thing, but just storing it via orderedsets is the easiest way i think.
doc/nyan/base types.md
Outdated
|
|
||
| -> We need a unified way/member-name to add a new animation to an 'Ability' | ||
|
|
||
| -> animations are stored in one big picture (or allow one file per frame?). How do we tell where in the picture is which frame? How can you tell to mirror a frame? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the original game, the relic thing is actually a new unit: "monk with relic". This is kinda stupid because it assumes only monks can carry relics, which is fine in age2 but very unsuitable for us.
So we can prepare the combination of a Carryable and some Unit in the sense that the carryable has to define its size and position, and we can then render the carryable in front of the unit. We can even define workaround replacement graphics that way in the sense that if it's a "known combination", the combination image is used (aka the monk with relic animation). How we model this in nyan I cannot tell right now (and haven't thought about it yet, so very good catch here).
The image metainformation should still be done in the good old .docx files as they're currently describing where a subimage is in one image. Things like animation speed, looping etc is defined in nyan though.
The engine will provide a nyan object Sprite which has a file member and others like the speed, etc. When this sprite is then required to be shown (e.g. because a unit uses it as its image) the engine will handle everything else internally, like parsing the subtexture information from the .docx, drawing it etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I rename the Animation class to Sprite?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think animation is fine, we can extend it to a 3d model animation in a few years then hehehe.
doc/nyan/base types.md
Outdated
| -> We need a unified way/member-name to add a new animation to an 'Ability' | ||
|
|
||
| -> animations are stored in one big picture (or allow one file per frame?). How do we tell where in the picture is which frame? How can you tell to mirror a frame? | ||
| 5. Of what type are the ingame objects, that don't move and give ressources? goldmine, fish, dead deer? How are deer and dead deer connected? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd name them ResourceSpot, also defined by the engine (as it has to support giving out resources at that point).
Deer is a Animal which is a Unit i guess (so you can kill it), and if it's dead, like with all units it has to reference its dead form (to have the animations etc). So there is a DeadDeer(Animal, ResourceSpot) with hp = 0 and a resource type and amount. The gathering itself, the amount decay etcetc is done in the engine, just the decay rate is specified by nyan again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why DeadDeer needs to inherit from from Animal. It needs:
- A dying animation.
- A rotting animation. After
RessourceSpot.amountdropped to zero, play this and hold the last frame for like a minute, then remove this Unit completely.
Between 0 and 1 we need to decide if we want to hold the last frame from 0 or the first from 1. To me it looks like they're the same in the original assets.
My idea: We could add dying : animation to Unit. This is played when our unit dies. After that, create the referenced Deadunit(Unit). If it is a RessourceSpot, wait until RessourceSpot.amount dropped to zero.
Then play deadunit.dying (or deadunit.idle), which is the rotting animation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, could also work. I think you're right that all units have a dying animation but many won't have one. also we somehow need to model that the living deer is not a resource spot.
Basically we have multiple possibilities to model this:
- store everything relevant for the dead deer in the living one already, aka
rotting_animationandresource_decayandresource_typeetcetc, this is the "bad" approach i'd say - have a separate
DeadDeerthat inherits from(original deer, resource spot)and updates graphics etc. the original deer then references to that object ason_death_become : Unit = DeadDeer. this requires a forward declaration which will be allowed in the next revision of the nyan design. - use abilities to test if the deer can even die. that ability then performs the death animation, another ability performs the resource collection, another one the decay.
I think the best approach is having an ability "being hunted" because it's different if a villager or a tribok killed it for the collectible food. That ability is implemented to change the unit type to DeadDeer once it is killed. The ability is included in the Deer abilities set, and also requires a forward declaration. It's the most overkill but also most extensible and awesome approach i'd say.
doc/nyan/base types.md
Outdated
|
|
||
| Mod questions: | ||
|
|
||
| 1. Adding new units/buildungs: There are only blue units in the original assets. How does the engine now, what part of a frame needs new color? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh. Tricky thing this. Basically in the original data there is a "magical color" which is then recolored. Our approach is to paint that magical color as blue with an alpha value of 254. The fragment shader checks if the alpha value is 254 at some point, then looks up the blue tone, then replaces it with the matching yellow or whatever tone, and draws it.
In the original game this was done in assembly, but we process it in opengl with the teamcolor shader.
|
Can you rename the file to |
doc/nyan/engine types.md
Outdated
| resource : Resource | ||
| amount : int # initial amount | ||
| droprate : float # in units per second. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is called "decay" in the original, which i think is better.
|
We don't wanna have a file name separated with spaces in the repo please :) |
|
is it possible to model something like: if the building(or all of the same type) is destroyed where something was researched, than the tech is lost and must be researched again? |
|
Yes, but nyan would (if ever) just store the boolean and more information to enable that feature. The revert of the patch (aka undoing the tech) would require inversing patches, which we would have to add to nyan indeed. But the main work for this feature must be done in the engine (namely the "what happends when this building is destroyed). |
|
How will this Stuff be implemented in the Engine? In my opinion, this should be implemented as Triggers: Trigger: condition:
action:
example: player klicks tech Y research new trigger 1: new trigger 2: |
|
For non-general behavior modifications the trigger approach is awesome and we should definitively add those for building scenarios and map interactions. But if we're talking about the general behavior of the game ("researches get lost when building is destroyed") then we should not have to add a trigger for each building x as you wrote, but instead for all buildings that do research. Nevertheless, it has to be implemented in the engine, and what amount of configuration data is stored in nyan for that is up to us. |
doc/nyan/engine_types.md
Outdated
| idleLook : animation | ||
| death : Unit # What is the dead form of this Unit? | ||
| # Proposal: | ||
| # dying : animation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as noted in the Deer-discussion above, not every unit has the ability to die. then we'd have to insert a placeholder or an empty value for dying, which we wanna avoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, remove dying and death, right?
doc/nyan/engine_types.md
Outdated
| Building(Unit): # WIP: make another parent Object for Building? | ||
| # WIP2: Some buildings consist of a static frame and an animation on top. How do we reference that? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably an AnimatedBuilding, also the building annexes like the towncenter need to be modeled out of parts.
They have an ordered set of sprites (which may be animated) so the draw order is fixed.
doc/nyan/engine_types.md
Outdated
| # 3. remove `renameMe': | ||
| # possibilities: 1. `metainfo' is a regular file: description of `animation' (syntax?) | ||
| # 2. replace `metainfo' by more fields that describe `animation' (ugly imo, but maybe the best way) | ||
| # 3. remove `metainfo': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can either keep the current docx format or add a new one to just contain the frame positions and ids. i wouln't store information about the texture itself in nyan, the implicit reference to filename.anim or something might be better. the current docx approach is very simple and works well, we should load it on demand though and not on launch.
Renamed member droprate -> decay in ResourceSpot.
MaanooAk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is still active...
doc/nyan/engine_types.md
Outdated
| damage : float # rename to baseDamage ? | ||
| HealingAbility(Ability): #WIP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably must be split. Healing, Repairing and Healing_inside_a_building must be separate because its have different logic behind it (eg. repair has cost).
Healing_inside_a_building could also be megred with Garison.
doc/nyan/engine_types.md
Outdated
| HealingAbility(Ability): #WIP | ||
| # Workers can repair buildings, ships and siege weapons. Buildings heal contained Units, Priests can heal moving units (including siege weapons?) | ||
| # WIP: priests and workers need an animation for this, buildings not. | ||
| # Should we write that as an attack with negative |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will always have the same sign, so better positive which can be stored in a unsigned int
| maxUnitsize : int # maximum size of each unit. If we want this, every movable unit should have a size member declared by a base class. | ||
| collapsingRate : float # percentage of health at which no units can be contained any longer. | ||
| AttackAbility(Ability): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Friendly fire
- Min range
- Area of effect
- Consider projectiles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean with "consider projectiles" and "area of effect"?
|
|
||
| 4. How do we add new animations? | ||
|
|
||
| -> How would a mod add a new relict-like object that can be carried (the animation)? can we describe composition of frames? How is it done by the original game? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Original game: Two different units: monk and monk with relic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd do it with the ability to carry things, and a relic is a Carryable (and ResourceProvider when garrisoned in the monastry). To solve the asset combination the thing to be carried could be able to provide a overall carrying graphic, so the monk-with-relic graphic is activated as soon as it is picked up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ResourceProviderwhen garrisoned in the monastry
@TheJJ Now that you mention it, I'd even go further than that and regard the relic as some kind of BonusItem or BonusProvider. While it's true that AoE2 see relics only as another source for gold income, AoM's relics also provide boni like cheaper unit creation cost, faster research time. RoN has something similar, where rare resources on the map provide a bonus to the player who places a merchant on it (and rare resources can be controlled by multiple people). I think modders would also get very creative with this construct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would BonusProvider look like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be similar to a ResourceProvider, but instead of giving a Resource, it provides a Bonus to the player who controls the BonusProvider. Boni could give stats upgrades (like 5% faster unit creation), area of effect buffs (like the generals in RoN), constant flow of resources (e.g. relics and feitoria in AoE2) or give a new ability to a hero who equips the Mighty Staff of Midgets, for example. Boni could also be temporary, permanent or tied to an item/unit/building.
In nyan a Bonus would probably be utilized as a nyan patch. Similar to the Tech() patch. BonusProvider on the other hand would be like a ResourceSpot:
Item():
name : text
Bonus():
timeout : float
updates : set(NyanPatch)
ResourceBonus(Bonus):
resources : Resource
rate : float
BonusProvider():
condition : Condition
is_temporary : bool
boni : set(Bonus)
# Content
Relic(Item, BonusProvider):
name = "relic"
condition = garrisoned
is_temporary = false
boni = {RelicBonus}
RelicBonus(ResourceBonus):
resource = {Gold}
timeout = -1.0
rate = 1.0
GoldBoost<resource>():
amount += 2.0
patches = {GoldBoost}
Or something like that. I hope i got the nyan syntax right.
| Tech(Update, HUDElement): | ||
| Unit(): # WIP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Cost
- Have limit (The max number of units of this type that a player can have at an instance)
- Had limit (The max number of units of this type that a player can create)
| name : text | ||
| patches : set(NyanPatch) # Add your mod's patches to this member. | ||
| Tech(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Cost
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what type should cost be?
orderedset(int) (what order?) or the unimplemented dict(Ressource, int) ?
|
Maybe Unit should have a population field. AoE1 and the last AoE2 extensions have infantries with 0.5 population usage. |
|
More in draft: https://pad.stusta.de/p/openage-mod-api |
|
Superseeded and continued by #1021 :) |
I started a list of all base types that need to be implemented in the engine. Add your thoughts and make changes.