Some FfH SDK requests

Maian

Warlord
Joined
Jan 16, 2003
Messages
210
If you've seen my code for hero retreats, you can tell it's one very big hack. If you haven't seen it, don't bother - it's ugly and outdated :) I've rewritten it to make it much cleaner, but there are a couple SDK things that could really make it easier. I've implemented the following events, changes, and features and I'd like them to be implemented in the SDK:

onCombatInit: Called right after cannotAttack() but before onCombatLogCalc.

onCombatWithdraw: Called when a unit withdraws (or retreats).

onCombatDone: Called after onCombatResult or onCombatWithdraw.

onCombatLogCalc, onCombatLogHit: Attacker and defender added to arguments list.

onCombatResult: Attacker and defender also added to the arguments list. This wouldn't be necessary if CvUnit::isAttacking() and CvUnit::isDefending() worked. Please either fix this or add the attacker and defender arguments.

onAfterPlayerTurns: Supposedly called after moves are reset for a turn. I say supposedly since this actually happens at the very end of CvGame::doTurn(). For its purpose (changing moves before the turn starts) and with simultaneous moves enabled, this event seems to work just fine. But ideally, there should be an event right after CvPlayer::doTurnUnits() is called in the CvPlayer::setTurnActive() function.

cannotAttack: Should only be called once during a fight. Right now, if combat animations are enabled, cannotAttack is called again at the end of the animation but before onCombatResult fires.

Some way to toggle the display of combat messages. I have this implemented by overriding the default combat text strings with blank entries in XML, then manually display them with Python (and new text strings).

onCombatLogCalc, onCombatLogHit: This is something I couldn't find a workaround for. I can mess around with the mechanics of combat in onCombatLogHit, but these fire only during battles involving human players. They should also fire for battles between AI players. Although the SDK should be solely responsible for the combat mechanics, since Python is so much more customizable, I'd argue that at the very least, there should be reliable Python hooks to modify combat mechanics.

CvGameInterface.canWithdraw: This function is called when a unit is about to be dealt a lethal blow in combat. The unit can be either the attacker or the defender. This allows customization of withdrawal chances and behavior.

Custom data: I've been tinkering around with the *ScriptData functions to add custom data to objects. What I've done is simulate a dictionary on objects that custom data can be added to. This allows multiple custom values to be stored instead of just one string. I've finally gotten to a point where storing and modifying custom data is pretty efficient, but it would still be better for this to be implemented in the SDK. This is a low priority request.

CvSelectionGroup::generatePath, CvUnit::generatePath, (possibly more generatePath functions): This function just doesn't work since an int pointer can't be passed. Please fix this.

Combat odds: I will need to change the combat odds message. I know how to do it - port CvGameCoreUtils::getCombatOdds() to Python and modify it, then intercept the CyInterface().getHelpString() call in CvMainInterface.updateHelpStrings and modify the message. But I haven't done it yet, since it would be very time consuming. So I'm not sure what the best way a Python hook can be implemented for getCombatOdds(). Here's one possible approach: Allow the 4 calls to currCombatStr() and currFirepower() to be replaced by a call to a Python function that can return the 4 values by reference. Not sure if that's possible, but if Cy* objects can be modified in Python functions (which can be viewed as a type of return by reference), it should be possible here.

That's all the requests I can think of off the top of my head. I'll post more later whenever I encounter another obstacle.
 
Maian said:
If you've seen my code for hero retreats, you can tell it's one very big hack. If you haven't seen it, don't bother - it's ugly and outdated :) I've rewritten it to make it much cleaner, but there are a couple SDK things that could really make it easier. I've implemented the following events, changes, and features and I'd like them to be implemented in the SDK:

Its very simple. As we want Heros to be trappable and do not want them to flee (that Lokis domain) we won't invest work into SDK changes that are purely for that functionality.

Nevertheless we might add some of those hooks when they are needed for other functionalities we want to enable.

Some things that are on the list are:

onCombatLogCalc, onCombatLogHit: Not exactly that way but we want a python hook that is simply onCombatHit (needed for the Stoneskin spell)

onCombatResult: Attacker and defender also added to the arguments list. This wouldn't be necessary if CvUnit::isAttacking() and CvUnit::isDefending() worked. Please either fix this or add the attacker and defender arguments.
This fix sounds absoluteley resonable. Lets see how we get it to work properly.

onAfterPlayerTurns: The old problem with the turn sequence. There might be some work done with that, too.

cannotAttack: Double call needs to be fixed for sure. Most probably it simply has to be moved around a bit.
 
Remembered another event that would be useful:

onBombard: This could be used to kill fireballs and meteors after they bombard.


The new combat events would be very simple to implement:

onCombatInit would be fired right after cannotAttack. Alternatively make onCombatLogCalc fire for non-human players as well.

onCombatWithdraw and canWithdraw would go here:
Code:
				if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Combat") <= iDefenderOdds)
				{
					if (getCombatFirstStrikes() == 0)
					{
						iDamage = max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (iDefenderFirepower + iStrengthFactor)) / (iAttackerFirepower + iStrengthFactor)));

						[color="blue"]if ((getDamage() + iDamage) >= maxHitPoints())
						{
							int lResult = -1;
							// <-- call to canWithdraw goes here
							if (lResult == -1)
								lResult = (int) (GC.getGameINLINE().getSorenRandNum(100, "Withdrawal") < withdrawalProbability());
							if (lResult == 1)
							{
								changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue());
								// <-- onCombatWithdraw event goes here
								break;
							}
						}[/color]

onCombatDone is more of a sugar event. Not really necessary, but it's nice to add combat cleanup code to.

EDIT: changed code thingy, forgot semicolons
 
Oh and one more thing. This isn't related to the SDK. Can you increase the number of FreePromotions entries for units in the editor spreadsheet? I've increased it to 15.
 
Maian said:
Oh and one more thing. This isn't related to the SDK. Can you increase the number of FreePromotions entries for units in the editor spreadsheet? I've increased it to 15.

Yeap, will do.
 
Okay, the onAfterPlayerTurns pseudo-event definitely is not a substitute for an doTurnUnits() event. It's purpose is to provide an event after units' moves are reset, so I can modify moves there. It only works for the human player, and since I've only been able to test it single-player, it may only work for player 0. Furthermore, I really doubt it would work for other modes besides simultaneous turns. So it doesn't work for AIs and possibly doesn't work in multiplayer.

Right now, I have a hack that modifies moves for AIs in CvGameInterface's AI_unitUpdate function. That seems to work. And I think onAfterPlayerTurns works for all human players in simultaneous turns mode.

So what I really need is an event that's called right after the doTurnUnits() function call in CvPlayer::setTurnActive().
 
Back
Top Bottom