Animosity

Ploeperpengel

academic precarity
Joined
Feb 2, 2006
Messages
4,748
Location
Berlin
To not further spam the pythonthread please dicuss Animosity here.



It would be cool to have animosity as a boolean tag in the promotions xml. With another tag there to set the percentage chance for it to take effect. And a third to define single units(unit_goblinarcher and unit_goblinspearman etc.) that could provoke animosity for the unit which has that promotion.

Promotions info because: I can define a lot of changes on unit combats, firststrikes there etc.
The game should check each turn onunitmove if one of the units defined are in an adjacted square. If yes the percentage chance should be checked and if the result is true the promotion should get active(only there all of the boni/mali defined in the promtionxml should apply) and the unit affected by animosity does the following by chance:

1.)1-80% stand immobile this turn(a message in the log about the internal squabble should pop up)
2.)81-90% the unit attacks the friendly unit that caused animosity.(Get'em!)
3.)91-100% the unit immediatly attacks the nearest enemy unit(or just rushed towards it if cannot reach) receiving an additional +1Movement during this process.(We'll show 'em!)

This chances could be modified to:
1.)1-80%(Squabbling)
2.)81-100%(Get'em!)
if the civ is at peace with everyone.

Results so far: I've got Squabbling working fine. Get'em works OK, but I've got a couple of issues when 2 stacks of 2 units or more are near each other, as after the First Get'Em, another unit trys to attack where the old unit was. Doesn't crash but in a debug popup you get an unknown C++ exception. Show'Em hasn't been started because I wanted some more info. All animosity actions force a finishmoves() on a unit

Questions:
Show'em - Should there be a limit of how far away a unit is for Animosity unit to charge it? Say, max moves + animosity bonus move + 1?
If that unit is in a neutral territory, do we attack and declare war against the neutral?

Notes:
I set the Animosity trigger to be based off Promotion rather than unit class, or else an Orc would only be affected by that exact same type of orc (Axemen would ignore non Axmen)
Also, I don't trigger Animosity for units in the same plot as attacking the square you are in is a problem at the moment
I'm triggering the animosity check for everyunit on every turn (made a custom event on CvUnit::doTurn), as a unit that is not moving should still have to "roll" for animosity no? Also trigggering at onUnitMove (unless someone can tell me) gives me problems finding out where the unit came from to send back on a Squabble action.

This took a bit longer than I wanted (wanted to finish it today) but I'm trying to get most of it in Python and I ran into quite a few beginer errors in my First Every Python Script. Especially finding out onBeginPlayerTurn is in fact at the end of the last turn

Anyway, any feedback will be highly appreciated. I'll post an upload once I have the kinks out of the Get'em Effect if everyones happy. The Show'em can come later.
E.L.M. I think you're doing nice no critics for how you code here. About the diplo thing I didn't think yet since we only have one orc civ yet but as soon we also have gobbos as civ that seriously is a problem. I think units that get affected by animosity shouldn't start a war even if they attack units of another civ(which they in fact should do!) since orc and goblin civ should be able to cooperate but this shouldn't disable animosity at all.
We'll show 'em charge attack should be limited to 2 tiles distance imo.

A promotion that quells animosity would be a good idea. I'm thinking here this should be a promotion that quells animosity for all units in the same tile simulating strong fearstriking Leaders that can make the squabbling stop by their mere presence. (For Black Orcs and Heros- I vote against prereqs and giving this promotion to other ordinary orcs as well)

I support the idea of having a building in a city that reduces the chance for animosity to take effect.
 
EDIT: UPDATE POST CURRENT ANIMOSITY STATUS

EDIT: ISSUES POST BUG POST

ANIMOSITY is now complete at version 2, please see the above posts for information (EDIT: Whoops - links now go to the right posts!)

Do we want to totally restrict animosity from cities at the moment. I have found the unfortunate circumstance that a unit will charge out of the city square to attack a friendly unit and if it is the only unit the city is left defensless. Or are we just considering this as a risk of animosity?

Do we want a replace to "Show'em" during peace time or just make "Get'em" twice as likely?

Also, as a note all the Get'em attacks occur at once - that's why I get the Attack plot == NULL exception in the Python debug, so you will get a message for every animosity Get'em and will see maybe more than one orc group running around and attacking. I might turn zoom on next time just to see what will happen.

I'll put a check in the Python to look for a promotion on the same square that prevents animosity (but comment it out for now until the promotion exists). Do we want a hardcoded promotion, or a new entry on the promotion options? Also, same square, or adjacent and same square?

A show'em attack of units that are max 2 plots away will mean the unit will always get the target. This is because of the +1 movement from a Show'em charge. It's listed in the Python as a global so we can set it to zero if we want a chance of the unit charging but not making it.

Expect a lot of test results and uploads in the next couple of days, work has calmed down and I also had to study from an exam I had today (not a real one, the super "life in the UK" citizenship test - I'm a Kiwi in the UK) so once again I have not finished everything I wanted.... Will be back on it tomorrow...... promise!
 
El Loco Mono said:
Do we want to totally restrict animosity from cities at the moment. I have found the unfortunate circumstance that a unit will charge out of the city square to attack a friendly unit and if it is the only unit the city is left defensless. Or are we just considering this as a risk of animosity?
:lol: funny! I'd say that'll teach players not to relie on a single goblinarcher-keep it risky!
El Loco Mono said:
Do we want a replace to "Show'em" during peace time or just make "Get'em" twice as likely?
twice as likly should suffice or got a good idea for replacement?
El Loco Mono said:
Also, as a note all the Get'em attacks occur at once - that's why I get the Attack plot == NULL exception in the Python debug, so you will get a message for every animosity Get'em and will see maybe more than one orc group running around and attacking. I might turn zoom on next time just to see what will happen.
At once?! Sounds like trouble. Way of having them one after the other?
El Loco Mono said:
I'll put a check in the Python to look for a promotion on the same square that prevents animosity (but comment it out for now until the promotion exists). Do we want a hardcoded promotion, or a new entry on the promotion options? Also, same square, or adjacent and same square?
the less hardcoded there is the better. Same square only!
El Loco Mono said:
A show'em attack of units that are max 2 plots away will mean the unit will always get the target. This is because of the +1 movement from a Show'em charge. It's listed in the Python as a global so we can set it to zero if we want a chance of the unit charging but not making it.
Make it so that the orcs allways try to reach the next enemyunit up to 3, 4 or 5 tiles away. No problem with the 2 tiles that it reaches the enemy.
El Loco Mono said:
Expect a lot of test results and uploads in the next couple of days, work has calmed down and I also had to study from an exam I had today (not a real one, the super "life in the UK" citizenship test - I'm a Kiwi in the UK) so once again I have not finished everything I wanted.... Will be back on it tomorrow...... promise!
Wonderful! Keep up the good work!:thumbsup:
 
At once?! Sounds like trouble. Way of having them one after the other?

Well, they're are not actually at once, but it's like the civil disorders in the cities. Each city is done in turn at the start of the turn but the player does not have control until after all the animosity checks. So according to the player, it all happens at once. Not sure yet, but I think the code triggers the fight animation, but does not check it is finished before moving to the next units turn. In this case the unit is still in plot X, but once the previous fight is completed, it triggers the new fight, but the previous unit may have moved after winning the earlier fight. I'll try and get the first stage animosity (Squabble and Get'em and Show'em without the check on same plot) finished tonight or tomorrow so I'll look into it a bit deeper soon
 
EDIT: Version 2 complete, current status of v1 will no longer be updated

OK, I've got a basic animosity working but I thought I would post what it does first before I upload the files. Just incase anyone has objections or ideas for last minute adjustments I can make. I've only done Worldbuilder tests so far, but I am going to spend some time tomorrow testing it in a game environment before uploading also.

WHAT IT DOES:
Spoiler :

Using 3 XML promotion flags (animosity Y/N : Animosity% chance : Promotion that triggers Animosity), animosity is checked for all units.

If a unit has a promotion with animosity AND a unit in an adjacent square with the Animosity Trigger promotion AND a "die roll" out of 100 is greater than animosity% chance, one of the 3 animosity events occur

1: Squabble - all movement points removed for the next turn
2: Get'EM - launchs an attack at the plot with the unit that triggered the animosity
3: Show'EM - If an enemy in withing MaxCharge plots, attempts to attack that unit (if no valid unit, Get'Em performed)

All events use all the units moves for the next turn

This happens at the begining of a Players turn, so the events appear to happen at the same time as the code cycles through the units.

EDIT: Send messages to the screen that a unit has triggered an Animosity Action

EDIT: A unit will not attack a unit currently in a fight. This prevents the attacker == NULL issue but also means a single unit will not be hit twice in one turn from animosity


WHAT IT DOES NOT DO (yet):
Spoiler :
Check the same plot for a unit that triggers animosity. I need to make sure a unit can attack it's own square first. Do to the defense rules at the moment, a unit could, in theory, attack itself. EDIT: A unit can attack it's own square but more than one attack on one square hangs Civ4. Investigating. FIXED IN V2


Checked what happens when the enemy is in a neutral units borders done in V2

Does not attack the specific unit on a plot that triggered the animosity. At the moment the BestDefender() function is used as normal, so the unit attacked might not even be a type of unit to cause animosity, but happens to be in the same square as one that does. done in V2

Does not check for an anit-animosity promotion / unit - this is because I has seen discussion on botha promotion to prevent animoisty and a unit to prevent so was not sure what to build the exception for. Need concensus on this before i can do anything done in V2

No bonus given for a Show'Em charge yet. Will only charge as far as a the unit can normally move. done in V2

Need to prevent a Show'em charge if a unit is within the MaxCharge but not visable (from Fog of War or the unit is invisible) using isVisibleEnemyUnit but everything is returning TRUE at the moment, might need some C++ code done in V2

Need to retrieve the "Quick Combat" flag from the settings and apply to updatecombat() (EDIT: currently hardcoded to false as a global in the Python) Hehe the Civ 4 core code hard codes this to False if the attack is not a stack. Therefore leaving as a hardcoded FALSE

Show'Em charge at nearest unit. At the moment, it is the first unit found that is not busy attacking another unit. done in V2


THINGS THAT SHOULD BE DONE:
Spoiler :
Need to rewrite the code to be more efficent. Far too many nested for loops at the moment.work in progress

Steal/aquire a cool sound to signal at lest one animosity action has occured(?)

Need a button to display when animosity occurs



NOTES:
MaxCharge, Squabble% and Get'EM% are globals in the python script. Everything above the Get'Em% is considered Show'em. If there is no unit the player is at war with nearby, this becomes a Get'Em action also.



Hope this all makes sense.


Version 2 (to be uploaded):
Spoiler :

Attacks the specific unit that triggered animosity

Attacks only valid plots - will not declare war on a neutral unit by charging into their territory

Animosity Checks the same square - DO WE WANT TO LIMIT ANIMOSITY TO THE STACK ONLY?

Attack nearest unit in a Show'em charge (using a radial patteren resrtiction on a recursive for loop, inside out, maybe need to rewrite in future to something more efficent)

Extra movement for a Show'Em charge. This is done by adding and removing a promotion SHOWEM that grants mobility. The XML controls movement bonus (example XML with be attached to upload)

Check for a new XML tag on a promotion - QuellAnimosity = TRUE. If a unit is in the same square or adjacent, no animosity is performed - DO WE WANT TO LIMIT QUELL ANIMOSITY TO THE STACK ONLY?

Only Charge units that can be seen at the start of that units turn

 
Added the code to the DLL thread. A document attached there shows example entries in the promotions and unit xml as how to use animosity.
 
looks very interesting. Is this all done in c++ or is the SDK just used to redirect to python? I would download it but I cant atm.

I managed to get most of it in Python (trying to make it as adjustable as possible without needed to recompile the mod). I needed to create a new generic event call and a new function to force friendly attacks, plus the new XML reads. but bar that, it's just a horrible amount of nested loops with some basic calls - which I hope to rewrite much more tidy when I've finished getting the scope finished.

I think it took a week, when it should have only taken a few days, but I'm new to the python world so I had a few basic hic-ups along the way. I probably won't get round to expanding it further until Friday, so for now it's the standard working version.
 
Just for info, had no time this week but hopefully this weekend I can plough through and tidy this up to a better finished product.
 
Only 2 tweaks to make before i can upload the finished animosity (minus buttons and sound of course)
 
Wahoo! Animosity is complete. I will spend a few hours doing in game tests, but hopefully today I will be uploading the complete version
 
Animosity is now complete! Check the DLL thread for the code
EDIT Current Version 2.1 now integrated

Basic Rules of Animosity according to code
If a unit is adjacent to or in the same square as a unit that has the Promotion that triggers animosity for this unit, an animosity check will occur

Die Rolls
Animosity Percent = The % chance that animosity will cause the unit to perform an uncontrolled action. This is checked against EACH unit in the adjacent squares. That means , the bigger the stack or number of surrounding units, the more likely you will have animosity.

Action: (controlled by Python globals)
1 - 80% Squabble - The unit cannot move next turn
81 - 90% Get'Em - The unit will attack the unit that caused the animosity
91 - 100% Show'em - The nearest valid enemy unit that is with a specific distance and in a valid plot to attack, will be attacked by this unit. If there is none, a Get'Em action is performed.

Controls
Spoiler :

XML Tag Promotion - bAnimosity: Does this unit suffer from animosity 0/1 FALSE/TRUE
XML Tag Promotion - iAnimosityPercent: The % chance that animosity will cause the unit to perform an uncontrolled action 0 - 100
XML Tag Promotion - AnimosityProtagonist: Promotion that will trigger animosity
EDIT XML Tag Promotion - AnimosityProtagonist2: Promotion that will trigger animosity
XML Tag Promotion - AnimosityProtagonist3: Promotion that will trigger animosity

XML Tag Promotion - bQuellAnimosity: Does this unit prevent Animosity 0/1 FALSE/TRUE
PYTHON Global - g_bAnimosityActive: Activate the Animosity module True/False
PYTHON Global - g_iSquabblingPercent: percent/int, from 1 - X% Squabble will occur (max = 100)
PYTHON Global - g_iGetEmPercent: percent/int, from Squabble% - X% Get'Em will occur (max = 100)
PYTHON Global - g_iMaxCharge: The number of plots outside the units maximum charge range (including Show'Em bonus) that an enemy unit is considered valid


Effects
Spoiler :


All Animosity events removes any moves for the next turn.

A unit in an adjacent or same square with a Promotion that has the XML tag bQuellAnimosity = 1, will prevent animosity checks Changed in v2.1, same stack only

Only if a unit is in the same Area, an animosity, quell animosity or Show'Em charge is the unit considered valid.

A message will be displayed if a unit suffers animosity - I need a button for the events!

Units will still gain XP from friendly attacks

If a unit is in a neutral territory without an Open Boarders - even if it is an enemy unit - a Show'em charge will not consider this a valid unit

Only Visible units will be charged by a Show'Em event

A Show'em charge will increase the units movement by the amount defined in a new promtion called "PROMOTION_SHOWEM" (I copied the musician promotion in testing and renamed it)

Invisible units will not be charged - even if they can see them. What's the point of a Show'em charge if the unit you are trying to impress cannot see your attack?




Code Effects
Spoiler :

AnimosityAttack in the CvUnit, calls updateCombat but with a forced declare war, a new Animosity Boolean, and the target unit. All default so all other calls to updateCombat are not affected.

If AnimosityAttack is called with a ShowEm = TRUE, a path will be generated first and the "path at end of turn", used in the updateCombat call.

There are a few scattered "print" statements in the animosity Python I haven't removed yet. This is to help me debug if any problems are found in the near future.

A Show'Em charge will use more time/memory than any other effect. This is because the rules first search for a Quell Animosity, then a Animosity Cause, then a valid unit. Several for loops ,if anyone knows a better way, I am all ears.

The Show'Em search uses a radial pattern, inside out, so any units in the nearest circle of plots is selected first.

I could only implement the Show'em charge extra movement using a promotion give/strip. It was a bit difficult to pass through an integer to AnimosityAttack and manipulate the generatePath.



Notes
Spoiler :

After doing some basic unit and gameplay testing, I think it would be more enjoyable is we make Show'em more likely than Get'Em - especially since an invalid is a Get'Em anyway.

Even at animosity at 15% chance, my well planned armies had a habit of becomming disorganised as units had to be left behind due to animosity. And nothing is more frustrating than seeing your high XP unit that is injured attack a city in a Show'Em charge and through away his life :D

Cities become very interesting in defense, it maybe an idea to either have a building or a defensive unit that stops or lowers the animosity chance.


Need
I still need some buttons to display during the animosity event and maybe a sound as well
 
As Bugs arrive, I will list them here and the progress on the fixes.

Also I attached an example Promotion XML as how the animosity flags were used, and the example PROMOTION_SHOWEM in my testing.

Bugs v2

PRIORITY HIGH

PRIORITY MED

PRIORITY LOW

camera zoom on the Get'Em / Show'Em will only display once, so you may not see the battle with camera zoom one. Cosmetic.
 

Attachments

@Elm
I'm currently integrating animosity to the game.
thing I'd like to have changed:
-the promtion to quell animosity should only affect units in the same tile. Blackorcs leading a stack should quell all squabbling in their stack but shouldn't prevent being attacked by neighbor stacks.


other than that feel free to make changes to animositychances according to your playtesting. It's your baby and I trust you fully about that;)

Edit:
Err can you please also post some example lines of unitinfos. I'm not sure where exactly I have to put the lines and what kind of content I can give:mischief:

Edit2:
Ah forget it I think I found what I was looking for. But a question. Is it possible to give not one but 3 animosityprotagonists? We will need this for daemonanimosity for the chaos civ.
 
Ploeperpengel said:
the boolean tag for quell animosity seems not added yet. I encountered a tag in the prominfo under regenerate and got an xml error.

Yeah I noticed that when I didn't put it in the right place. Not being a guru in XML I didn't understand why, but I actually put it in the same promotion, but at the point below:

<FeatureDoubleMoves/>
<bQuellAnimosity>1</bQuellAnimosity>
<UnitCombats>

When I put it elsewhere it threw an error. Thought you would understand that error better than me. Also, do you have the schema change for the new tag? It was in a new copy of the unit shema XML.

Ah forget it I think I found what I was looking for. But a question. Is it possible to give not one but 3 animosityprotagonists? We will need this for daemonanimosity for the chaos civ.

No problem, but I will have to change the code to deal with up to 3 returns though. Give me a day or two

I'm currently integrating animosity to the game.
thing I'd like to have changed:
-the promtion to quell animosity should only affect units in the same tile. Blackorcs leading a stack should quell all squabbling in their stack but shouldn't prevent being attacked by neighbor stacks.

I was thinking this also, but it's easier to change back to single plot, than expand the code to adjacent plots. Will only take an hour or 2 to do and test, but I'll probably upload with the triple protaganist.
 
El Loco Mono said:
Yeah I noticed that when I didn't put it in the right place. Not being a guru in XML I didn't understand why, but I actually put it in the same promotion, but at the point below:

<FeatureDoubleMoves/>
<bQuellAnimosity>1</bQuellAnimosity>
<UnitCombats>

When I put it elsewhere it through an error. Thought you would understand that error better than me
No I'm sorry just an editor of xml. I don't understand its structure. I'll try at that position again;)
 
Ploeperpengel said:
No, still get that error. I think you must define that tag in the unitschema but I don't know how.

Man your quick on the reply! ;) here's the schema change

EDIT: Forgot the second part of the schema change

Spoiler :

<ElementType name="FeatureDoubleMove" content="eltOnly">
<element type="FeatureType"/>
<element type="bFeatureDoubleMove"/>
</ElementType>
<!-- ELM - Warhammer Mod - 10th August 2006 -->
<!-- Animosity -->
<ElementType name="bAnimosity" content="textOnly" dt:type="boolean"/>
<ElementType name="iAnimosityPercent" content="textOnly" dt:type="int"/>
<ElementType name="AnimosityProtagonist" content="textOnly"/>
<ElementType name="bQuellAnimosity" content="textOnly" dt:type="boolean"/>
<!-- Animosity - End -->
<ElementType name="FeatureDoubleMoves" content="eltOnly">
<element type="FeatureDoubleMove" minOccurs="0" maxOccurs="*"/>
</ElementType>
</ElementType>
<ElementType name="PromotionInfo" content="eltOnly">

...
<element type="TerrainDoubleMoves"/>
<element type="FeatureDoubleMoves"/>
<!-- ELM - Warhammer Mod - 10th August 2006 -->
<!-- Animosity -->
<element type="bAnimosity" minOccurs="0"/>
<element type="iAnimosityPercent" minOccurs="0"/>
<element type="AnimosityProtagonist" minOccurs="0"/>
<element type="bQuellAnimosity" minOccurs="0"/>
<!-- Animosity - End -->
<element type="UnitCombats"/>
 
Back
Top Bottom