Enhanced hero system

Maian

Warlord
Joined
Jan 16, 2003
Messages
210
NOTE: This is a proof of concept, not meant to be played in real games. Many of the features, namely the equipment/item/inventory system, are not fully implemented (in fact, the equipment system has no impact on gameplay currently). There may also be odd behavior and possibly even crashes.

Download ffh2-015k-mods-inventory.zip

To install: Make sure you have the latest version of Fall from Heaven 0.15k. Extract to the Civilization 4 folder (by default, it's C:\Program Files\Sid Meier's Civilization 4\). The archive also includes diff files that include the exact changes in the source code from the official version.

NOTE: I just found out that the above patch extracts to the wrong Fall from Heaven 2 directory. The FfH2 0.15k patch extracts to "Mods\Fall from Heaven 2 015k" instead of "Mods\Fall from Heaven 2 015". So all folders and files extracted to "Mods\Fall from Heaven 2 015" from my patch must be moved to "Mods\Fall from Heaven 2 015k". In addition, the CvModName.py file needs to be edited: change "Fall from Heaven 2 015" to "Fall from Heaven 2 015k".

Alternatively, rename the "Mods\Fall from Heaven 2 015k" directory to "Mods\Fall from Heaven 2 015". The shortcut to the mod will also have to be edited so that it starts 015 rather than 015k.

I'll post a new patch later that will fix this issue (along with other changes).


To uninstall: Reinstall the 0.15k patch. If you're updating to a new version of this mod, you should reinstall the 0.15k patch before installing the new version.

This patch is NOT compatible with 0.15 save games.

The features:

Items and inventory system:
  • Inventory GUI (screen) that can be opened by clicking a button in a hero's action button list (the bottom part of the screen).
  • Two display modes: one for resolutions with less than 1280, and the other for 1280+ width.
  • Each hero has 10 equipment slots: head, body, feet, hands, weapon, shield, mount, misc1, misc2, misc3
  • Each hero also has a backpack that has 18 slots.
  • Each player has a 36 slot vault. Any item can be stored in the vault.
  • Each player has an 18 slot market. Tech-based items are introduced to the market whenever the tech for those items are researched. A tech-based item is infinite in supply in the market if you have the tech for that item.
  • Several items. However, none of them do anything and are preset in this POC.
  • Proficiency system where heroes with a certain proficiency gets bonuses with items related to that proficiency. System in place, but currently has no effect in this POC.
  • Items can be dragged and dropped in the inventory GUI.
  • Items can be transferred from hero to hero, hero to vault/market, and vice versa.
  • Items are retained thru game loads/saves.
  • New sheet added to FfH editor named Items. Promotions still need to be added for each item, but it's a step toward seperating items and promotions.
  • Indefinitely removed: Combat odds hint is adjusted to factor in the new combat mechanics. System in place, but since the new combat mechanics aren't in, this does nothing in this POC.
  • Known issue: Blank entries appear in Civilopedia under Promotions.

Indefinitely removed: Retreating, a.k.a. defensive withdrawals:
  • First some terminology. "Withdrawal" means the unit is attacking and withdraws. "Retreat" means the unit is attacked and withdraws. "Hero" is a bit of a misnomer - this system works for all unique units, including dragons.
  • Note that these retreat rules below now apply to ALL units that have withdrawal, in addition to heroes. The only difference is the hero's 100% withdrawal bonus.
  • If a unit is defeated it tries to win a withdrawal roll (using its withdrawal probability). If it wins the roll, it tries to find a safe plot to retreat to. If it can't find one, it dies. Otherwise, it will retreat to that safe plot with barely any health left. The attacker's group then advances into the defender's old plot.
  • A hero starts off with a 100% withdrawal bonus. Every turn, the hero regains 50% of the bonus up to the 100% maximum.
  • Every attack the hero makes reduces that bonus by 50%. Once the bonus is depleted, the hero only has his "normal" withdrawal chance left (the hero's base withdrawal + bonuses from promotions like Flanking). The net withdrawal chance will never go below this normal withdrawal chance.
  • Every time a unit retreats, its withdrawal chance is reduced by 50% and MPs are wasted depending on where the unit moves (1 MP for plains, 2 MP for forest and hills, etc.).
  • If a unit has no MPs left, it can't retreat.
  • The MPs lost to retreating remain lost the next turn. This now hopefully works for multiplayer games and AI heroes who have engaged the human player in combat.
  • Withdraw failure message is displayed if the hero fails to retreat (and dies).

Some additional ideas I've been considering:
  • Fortify, sleep, and sentry would result in different withdrawal behavior. Heroes on fortify mode will fight to the last moment before withdrawing (as it is now). Heroes on sleep mode will try to retreat when they lose half their original HP. Heroes on sentry mode will try to retreat immediately.
  • A rock-paper-scissors counter system: assassins vs. heroes vs. guards. Assassins would preferably target heroes and reduce their withdrawal chance. Guards would try to block assassins from attacking heroes. And heroes are just plain powerful. Some combat-oriented heroes can act as assassins too.

This is only a test. It's completely written in Python with some XML changes. The code is hacky (but not as much as my first implementation). Much of the code should go in the SDK, but since I don't have access to FfH's SDK source, I had to come up with hacky workarounds. Specifically, the retreat code should go in CvUnit::updateCombat, or rather CvUnit::updateCombat needs better Python hooks.

There are a couple limitations that I can't think up workarounds for at the moment:
  • It's inefficient, but there's little I can do about that without using the SDK.
  • Doesn't apply right now: Game may stutter if you force a barbarian hero to retreat. A unit has a chance of winning automatically against a barbarian, depending on the game difficulty level, and so the game stubbornly refuses to let the attacker withdraw to allow the barbarian to retreat (the attacker needs to withdraw to let the defender live, then the retreat code kicks in) for a while until it finally gives up, which can happen tens or even hundreds of combat rounds later.
  • Doesn't apply right now: Although the combat odds for heroes with armor are correctly displayed in the help text area, the calculation of the best defender in a plot or best attacker in a group doesn't take armor into account. Also, there's a very rare chance of the combat odds being listed for the wrong hero in the same plot.
  • AI will be completely clueless on how to use these new features.

New files:
Spoiler :

  • <FfH path>\Assets\python\FFHInventory.py
  • <FfH path>\Assets\python\screens\CvInventoryScreen.py
  • <FfH path>\Assets\python\CvModName (for CvPath)
  • <FfH path>\Assets\python\Utils\CyUID.py
  • <FfH path>\Assets\python\Utils\DragDrop.py
  • <FfH path>\Assets\xml\units\CIV4ItemInfos.xml
  • <FfH path>\Assets\art\interface\buttons\Promotions\transparent.dds
  • <Civ4 path>\Assets\python\system\xml\* (Python XML libraries)
  • <Civ4 path>\Assets\python\system\pyexpat.pyd (Python expat XML parser)


Changed files:
Spoiler :

  • <FfH path>\Assets\python\CustomFunctions.py
  • <FfH path>\Assets\python\CvEventManager.py
  • <FfH path>\Assets\python\CvFFHSpellsEventManager.py
  • <FfH path>\Assets\python\FFHSpells.py
  • <FfH path>\Assets\python\entrypoints\CvGameInterface.py
  • <FfH path>\Assets\python\entrypoints\CvScreensInterface.py
  • <FfH path>\Assets\python\screens\CvMainInterface.py
  • <FfH path>\Assets\python\screens\CvScreenEnums.py
  • <FfH path>\Assets\python\UnitStatisticsUtils\CvUnitStatisticsEventManager.py
  • <FfH path>\Assets\python\Utils\sdToolKitAdvanced.py
  • <FfH path>\Assets\xml\GlobalDefinesAlt.xml
  • <FfH path>\Assets\xml\text\CIV4GameText_FFH2.xml
  • <FfH path>\Assets\xml\units\CIV4PromotionInfos.xml
  • <FfH path>\Assets\xml\units\CIV4SpellInfos.xml
  • <FfH path>\Assets\xml\units\CIV4UnitInfos.xml
  • <FfH path>\Assets\xml\units\CIV4UnitSchema.xml
  • <FfH path>\FfH Editor.xls


Changelog:
Spoiler :

0.15k (09/18/06):
  • Merged with FfH 0.15k.
  • Market is nearly fully functional now. Tech-based items are introduced to the market whenever the tech for those items are researched. A tech-based item is infinite in supply in the market if you have the tech for that item.
  • Forgot to add CvUnitStatisticsEventManager.py in previous patch.
  • Added prices for each item.
  • Misc. internal changes.

0.15j (09/17/06):
  • Merged with FfH 0.15j. Removed a bunch of old fixes that no longer apply.
  • Factored out the drag&drop code from CvInventoryScreen into a new library called DragDrop.
  • Merged my old ScriptDataCache library into sdToolKitAdvanced: Sped up the object variable functions in sdToolKitAdvanced (from O(n) to O(1) amortized). Downsides: sdToolKitAdvanced now depends on CvCustomEventManager (or rather CvFFHSpellsEventManager), and if sdToolKitAdvanced is reloaded, all changes to object variables since the last load are lost (only makes debugging more difficult; no impact on real games).
  • Merged my old event handler/listener library into CvCustomEventManager/CvFFHSpellsEventManager. Features: event handler priority (this can also be used to determine whether a handler fires before or after the default event handler), removeEventHandler(), hasEventHandler(), generic way to prevent subsequent handlers from firing, a way to get a handler to unregister itself, a way to specify extra arguments for a handler, Cv* objects can be passed safely via those extra arguments (accessing it in any other way is dangerous).
  • Added CyUID library. Has two functions that are inverses of each other: getCyUID and getCyObject. getCyUID accepts a Cy* object and returns a tuple that contains the information needed to get the object. getCyObjects accepts such as "unique ID" and returns a Cy* object. Useful in situations where the Cy* object cannot be stored/passed since it would be invalid.
  • Split FFHFindSafePlot into FFHFindSafestPlot and FFHFindSafePlot, where FFHFindSafestPlot intelligently finds a safe plot and FFHFindSafePlot simply finds an arbitrary safe plot.
  • Indefinitely removed the retreat code.
  • Indefinitely removed the ability to customize combat result messages.
  • Indefinitely removed the unit conversion code and the related classes it depends on.
  • A bunch of other refactoring to make the code easier to maintain, merge, and reuse.
 
I appreciate the disclaimer and I certainly dont mind (heck I even encourage) people to play with what we have made.

I suggest that if you put together a new patch set that you run a thread here so it doesn't get lost in other posts.

And I can't garuntee that we wont break your patch sets with each revision. In fact I pretty much garuntee that we will. But outside of that, I love to see this kind of work.
 
Other changes...

Changes:
  • When units are converted to the enemy side and can't stay in the same plot, or when Loki runs away, the plot the unit goes to is chosen more intelligently. The unit can also go onto friendly boats. Made more intelligent by using a multi-pass algorithm that takes into account unit strengths, "areas of control", and can look at a larger range of plots (square radius 5 instead of 3). (Also implemented a brute force algorithm that calculates which enemies can go to which plots and compare strengths of enemy and friendly units, but it was took too much time to calculate so I commented it out.)

Bug fixes:
  • A unit spawning in a plot that isn't controlled by the unit's owner won't get the Homeland promotion. (This is a really minor bug that rarely happens.)
  • Fixed vampire feeding bug. (checked into 0.16)
  • If Fireballs, Meteors, and Floating Eyes are summoned on ships, they are immediately unloaded. (0.16 also fixes this)
  • Indefinitely removed: When Loki runs away, the game won't display the message that the attacker withdrew. This fix also removes the Fear withdrawal message (and any other events in the cannotAttack function).
  • Indefinitely removed: When any enemy unit is converted into a friendly unit in an attack, there is a rare case that the converted unit doesn't stay in the same plot if its safe. This has been fixed (very complicated fix).
  • Indefinitely removed: When a Boarding Party attacks and captures a ship, the captured ship loads the Boarding Party.
  • Indefinitely removed: When successfully attacking a non-ship unit such as the Kraken or Drown, Boarding Party stays on the ship it attacked from.
  • Indefinitely removed: An attacking Werewolf that upgrades to a higher Werewolf can advance into the plot it is attacking into.
  • Loki's attacker moves into the plot Loki was just at, using the correct amount of movement points and retaining the selection group.

Internal changes:
  • Added a DragDrop library that abstracts out the CvInventoryScreen's drag&drop feature.
  • Sped up the object variable functions in sdToolKitAdvanced (from O(n) to O(1) amortized). Downsides: sdToolKitAdvanced now depends on CvCustomEventManager (or rather CvFFHSpellsEventManager), and if sdToolKitAdvanced is reloaded, all changes to object variables since the last load are lost (only makes debugging more difficult; no impact on real games).
  • Added new features to CvFFHSpellsEventManager (CvCustomEventManager)'s event handler system: Event handler priority - this can also be used to determine whether a handler fires before or after the default event handler). removeEventHandler(). hasEventHandler(). Generic way to prevent subsequent handlers from firing. A way to get a handler to unregister itself. A way to specify extra arguments for a handler. Cv* objects can be passed safely via those extra arguments (accessing a Cv* object in any other way is dangerous).
  • Added CyUID library. Has two functions that are inverses of each other: getCyUID and getCyObject. getCyUID accepts a Cy* object and returns a tuple that contains the information needed to get the object. getCyObjects accepts such as "unique ID" and returns a Cy* object. Useful in situations where the Cy* object cannot be stored/passed since it would be invalid.
  • Added the missing Python xml libraries and expat XML parser to <civ4 assets>\Python\System.
  • Make sure CvGameInterface.cannotAttack() isn't called twice in combat when quick combat is disabled (actually, cannotAttack is still called twice; it just returns early the second time).
  • Added a FFHMoveGroup function that moves a group or the selection group to the specified adjacent plot. Movement cost is considered (MPs are subtracted), and the selection group is retained if it's the group being moved.
  • Indefinitely removed: Added an AfterPlayerTurns event that occurs after all onEndPlayerTurn events for the turn and, more importantly, after all the units are updated for the turn. This means that this event happens after units heal up, have their MPs reset, etc. Implementated in CvGameInterface.isVictoryTest().
  • Indefinitely removed: Withdraw and combat result messages "moved out" of the SDK (by adding blank entries for them in CIV4GameText_FFH2.xml) and are now manually displayed in CvEventManager. This allows CvEventManager to control when, if, and how to show the messages.
  • Made onBeginPlayerTurn's iPlayer and onBeginGameTurn's iGameTurn CvEventManager attributes so they can be accessed outside the module.
  • Indefinitely removed: Heavily modified FFHConvert and factored in the previous conversion changes. Namely: Captured units can stay in their original plots if it's safe (i.e. the attacker moves into the plot after combat). FFHConvert has been split into FFHConvertWinner, FFHConvertLoser, and FFHConvert: the former two for use in onCombatResult, and latter one for generic conversions. See FFHConvertLoser for details. Update to the conversion code: only use listeners when the unit to be converted will stay in its original plot.
  • Indefinitely removed: New class called PyHelpers.PyUnit that acts as wrapper around CyUnit and can store the unit's state even when the wrapped CyUnit instance becomes invalid (but the data isn't retained between saves/loads). This class can be used to converts units to enemy units (which is its original purpose). Supports some default arguments for certain CyUnit methods. Can be used to serialize a unit's state into a string. Can act as an extension point for more convenience methods. Look at the source docstring for more info.
  • Branched FFHFindClearPlot into FFHFindSafestPlot, FFHFindSafePlot, and FFHFindClearPlot and changed the function signature of both. Loki code and several other places now call FFHFindSafestPlot instead of FFHFindClearPlot. FFHFindSafestPlot calculates the best plot around a specified unit to move to (this is the most "intelligent" function). FFHFindSafePlot gets an arbitrary plot around a specified unit that is safe. FFHFindClearPlot gets a random clear plot around a specified plot.
  • Added FFHIsSafePlot function. Has the ability to ignore specified units. Called by FFHFindSafestPlot and FFHFindSafePlot.
 
Hi Maian,

You wrote that some hero could be upgraded. Who are they ? How will we recognize upgraded and non-upgraded ones (new picutures, texts...) ?

Last thing. OMI, when a hero retreats he would have to lose some xps. For exemple, (100- remaining HPs)/10. Logical: a hero never retreat (or he is not a hero, but a coward chicken !)

The Frog.
 
Actually it's still easy to kill heroes right now. You usually just have to attack them twice in the same turn. The first time the hero is attacked and retreats, its HP is reduced to near 0. It's not like it just runs away - it fights til it's about to lose. The second time the hero is attacked, its HP is so low that if the attacker is strong enough, the attacker will deal enough damage in one round to get the one-hit kill.
 
Hian the Frog said:
Hi Maian,

You wrote that some hero could be upgraded. Who are they ? How will we recognize upgraded and non-upgraded ones (new picutures, texts...) ?

Last thing. OMI, when a hero retreats he would have to lose some xps. For exemple, (100- remaining HPs)/10. Logical: a hero never retreat (or he is not a hero, but a coward chicken !)

The Frog.

I'm leaning toward not reducing any exp, since retreating is a normal aspect of warfare. If anything, it should still reward the hero a bit of exp. For normal units, it's simulated by the mass amounts of them that you have - when an enemy attacks a stack of units, it can kill a couple, allowing you to retreat with the rest of the stack the next turn. However, that can't happen with heroes since they're unexpendable, so they deserve special treatment in this regard. However, if you can provide some rationale for why they should lose exp, I'll consider changing it.

The heroes that can be upgraded are the ones that can hold items. I haven't fully fleshed out the inventory system. There will be a couple item types: melee weapons, ranged weapons, light armor, heavy armor, misc items. Each hero can only equip certain items. Most items will be introduced with new tech, while some come from enemies, e.g. Orthus Axe.

I'm not an artist so I can't introduce new graphics (unless you want stick figures :D). At first, I thought about adding a suffix to the name of heroes that inclues the equipment they are using e.g. "Gilden Silveric (Shortbow)" but I realized that that wouldn't work if they had more than one item in their inventory. The inventory items can appear as promotions, but adding new promotions types seems to crash existing games, so each time I add new items (and thus promotions), you'd have to start new games. Trying to think of a workaround for that...
 
How about fortified in cities? Perhaps you should add a second fortify ability, hold ground, where they won't retreat no matter what.
Also, if a hero is in a stack, could he retreat to his current tile? in other words, the battle ends, but the hero is still in the same square hiding behind his troops.
 
There doesn't need to be a second fortify ability. The hero already fights until it's about to lose before retreating. That is, if the attacker is going to deal a lethal blow in the current combat round, the defending hero will try to retreat. It's basically a last resort thing, not a "run away at first sight of enemy" thing.

You do have a good point with the hero retreat in stacks. I'll need to make it so that it only retreats if it's still the strongest unit in the stack.
 
One thing with heroes that would be nice, is if they weren't chosen to fight when they are attacked in a stack and already heavily damaged.

Like, I can have Gilden in a stack of archers, and the enemy will attack with say 6 units, all the units will target the hero even when he's down to 1.0 health/strength because even with 1.0 health he's still stronger than the archers due to his promotions... but the combat odds are not in his favor.
Basically it'd be nice if a hero was not chosen to fight in defense when his odds are terrible if there's someone else in their stack who could fight instead. This would give them a little extra survivability.

Also, when a hero is in a stack and fighting barbs and already maxed out on XP (100XP), it'd be nice if either other units in the stack fight if they have good odds, or if the hero winning gave a random other unit in the stack XP (like they're watching and learning).
 
Sureshot said:
One thing with heroes that would be nice, is if they weren't chosen to fight when they are attacked in a stack and already heavily damaged.

Like, I can have Gilden in a stack of archers, and the enemy will attack with say 6 units, all the units will target the hero even when he's down to 1.0 health/strength because even with 1.0 health he's still stronger than the archers due to his promotions... but the combat odds are not in his favor.
Basically it'd be nice if a hero was not chosen to fight in defense when his odds are terrible if there's someone else in their stack who could fight instead. This would give them a little extra survivability.

Also, when a hero is in a stack and fighting barbs and already maxed out on XP (100XP), it'd be nice if either other units in the stack fight if they have good odds, or if the hero winning gave a random other unit in the stack XP (like they're watching and learning).

The algorithym that chooses what unit defends is pretty complex. It definitly isnt just the the unit with the best odds and heroes do tend to be defended when the odds are close.
 
Alright, new patch up. Synced with 0.14b, includes some new hero enhancements, and lots of internal changes.

New changes:
  • Heroes can retreat. See 1st post for more details. Heroes right now have 100% withdrawal when attacking. This makes them really powerful. Later on, I'll make each attack the hero makes reduce the withdraw chance, and add promotions that oppose withdrawal.
  • When a vampire feeds, its MPs could go into the negatives (causing odd displays like 2 out of 1 moves) - this has been fixed so that a vampire correctly loses a MP when feeding.
  • When Loki runs away, the game won't display the message that the attacker withdrew.

New internal changes:
  • Added a FFHMoveGroup function that moves a group or the selection group to the specified adjacent plot. Movement cost is considered (MPs are subtracted), and the selection group is retained if it's the group being moved.
  • Added a onAfterPlayerTurns event that occurs after all onEndPlayerTurn events for the turn and, more importantly, after all the units are updated for the turn. This means that this event happens after units heal up, have their MPs reset, etc. Implementated via a hack in CvGameInterface.isVictoryTest().
  • Withdraw and combat result messages "moved out" of the SDK (by adding blank entries for them in CIV4GameText_FFH2.xml) and are now manually displayed in CvEventManager. This allows CvEventManager to control when, if, and how to show the messages.
  • Readded the FFH*CustomData functions from a previous version to PyUnit as getData/delData/setData. Fixed a bug with delData.
  • CvEventManager derives from Borg. This allows usage of CvEventManager in CustomFunctions and CvGameInterface, without having to import CvEventInterface or CvFFHSpellsEventManager and without worrying about import order.
  • CustomFunctions derives from Singleton. May save a bit of memory and time.
  • Added a Borg "abstract" class to CvUtil. A Borg subclass and any subclasses of that class will share the same data. Unlike Singletons, each instance is not equivalent to each other (pointer-wise); they just share the same data. The downside is that each Borg instance takes a bit more time to instantiate than Singletons. (Google "python borg" for more info.)
  • Added a Singleton "abstract" class to CvUtil. A Singleton subclass will have only a single instance no matter how many times its constructor is called, unless the module that class is in is reloaded.
  • Made onBeginPlayerTurn's iPlayer and onBeginGameTurn's iGameTurn global vars so they can be accessed outside the module.
  • Changed initialization of the global CvEventManager.iLastPlayer to just -1 (don't know why it was set to a one-element array), and added "global iLastPlayer" to onBeginPlayerTurn so that it really does reflect the last player.
  • Heavily modified FFHConvert and factored in the previous conversion changes. Namely: Captured units can stay in their original plots if it's safe (i.e. the attacker moves into the plot after combat). FFHConvert has been split into FFHConvertWinner, FFHConvertLoser, and FFHConvert: the former two for use in onCombatResult, and latter one for generic conversions. See FFHConvertLoser for details. Update to the conversion code: only use listeners when the unit to be converted will stay in its original plot.
  • Synced with version 0.14b :)
  • PyHelpers.PyUnit: Added update() method, which is modelled after dict.update(), and added a way to specify the removal and addition of promotions (rather than just replacing) in a PyUnit unit state dictionary. Added getNameNoDesc() and fixed a setName() bug.

EDIT: Forgot to mention that 0.14 save games probably won't work with this patch.
 
Maian said:
[*]An equipment system. I've already started a bit on this.
[*]Hero "upgrades" facilitated by the equipment system. For example, Gilden Silveric will start off with a shortbow and can later upgrade to a longbow once the tech becomes available.
[*]Heroes "levelling up" from normal units. Only applicable in some situations. For ex, Typhoid Mary isn't based off any unit.[/list]

I like these ideas a lot. Especially the heroes being able to upgrade into better versions as new tech units in a similar vein become available. It is sad and kind of ridiculous that a hero becomes obsolete because he won't take advantage of the latest weapons. The general, capturable equipment would be very neat as well. I've always wanted more items like Orthus's Axe.

- feydras
 
Gonna post a new version of the patch soon once Kael releases 0.14d. I've revamped the hero retreat code, fixing bugs, testing corner cases, and making it more consistent overall. Still one hell of a hack, so it's still ugly and there are probably some more bugs lurking there.

I changed the hero withdraw and retreat mechanics:
  • Each turn, the hero starts off with a 100% withdraw bonus.
  • Every attack the hero makes reduces that bonus by 50%. Once the bonus is depleted, the hero only has his "base" withdrawal chance left (the hero's base withdrawal + bonuses from promotions like Flanking). The net withdrawal chance will never go below this base withdrawal chance.
  • Every turn, the hero starts off with 100% chance to retreat.
  • Every time the hero retreats, that chance is reduced by 50% and MPs are wasted depending on where the hero moves (1 MP for plains, 2 MP for forest and hills, etc.).
  • If the hero has no MPs left, he can't retreat.
  • The MPs lost to retreating remain lost the next turn.
  • If the attacker deals damage greater than the hero's original HP (HP before the battle began), the hero dies and has no chance to retreat.
  • If the attacker deals damage greater than the hero's original HP (HP before the battle began), the hero dies and has no chance to retreat.
  • If the attacker isn't a hero and doesn't one-hit kill the defending hero, the hero gets a parting hit on the attacker unless the attacker withdraws. This can happen even after the hero forced to retreat (attacker defeats hero before hero gets a single hit off attacker). Thus, if the hero fails to retreat and the hero's hit on the attacker is fatal and the attacker fails to withdraw, both attacker and hero will die. This is a limitation that I found and can't work around, so I might as well call this a feature: the hero in his desperation tries to take his enemy down with him to the grave.

Todo: Calculate whether it's safe for the hero to retreat into its own plot if there are friendlies there. The tricky part about this is that the strength of a defender depends on the attacker. Also, even if it's safe to stay in the same plot, should a hero retreat to a plot with more troops or stay in the same plot?

Todo: Make assassin and its ilk reduce hero withdraw/retreat chance.

EDIT: Some more details...
EDIT: More details again...
 
Hmm, I'll have to think about that... The purpose of the MP cost is for there to be at least some benefit to forcing the hero to retreat (unlike Loki :p).
 
New patch up. Branched it into two versions: one with the hero enhancements and one without. I'll keep the old version up for now.
 
Wow I feel dumb. I just realized that I could obtain the attacker and defender objects from the cannotAttack function. With that information available, I can drastically simplify the code and even extend it to work with any unit, regardless of whether it's a hero. I can also get rid of some of the obscure corner cases, like the defending hero getting a parting hit if he's defeated.
 
There might be some OOS problems and a multiplayer crash issue with the patch. In my version (unreleased), I'm getting those problems, and they likely affect the previous patches as well.

Also, there might be problems when the quick attacks and/or quick defense options are disabled.
 
Back
Top Bottom