From 759fe7e7608b96820e623c9c17dbbc9daba28aea Mon Sep 17 00:00:00 2001
From: jarod42 <>
Date: Sat, 20 Mar 2004 20:59:17 +0000
Subject: [PATCH] correct bug, cleaning and doc

---
 src/stratagus/spells.cpp | 296 +++++++++++++++++----------------------
 1 file changed, 126 insertions(+), 170 deletions(-)

diff --git a/src/stratagus/spells.cpp b/src/stratagus/spells.cpp
index b62d5dbfd..af1473860 100644
--- a/src/stratagus/spells.cpp
+++ b/src/stratagus/spells.cpp
@@ -90,6 +90,7 @@ global int SpellTypeCount;
 ** 		Cast demolish
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -172,6 +173,7 @@ global int CastDemolish(Unit* caster, const SpellType* spell __attribute__((unus
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -202,9 +204,6 @@ global int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((u
 	} else {
 		portal = MakeUnitAndPlace(x, y, ptype, &Players[PlayerNumNeutral]);
 	}
-/*	MakeMissile(spell->Missile,
-		x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2,
-		x * TileSizeX + TileSizeX / 2, y * TileSizeY + TileSizeY / 2);*/
 	//  Goal is used to link to destination circle of power
 	caster->Goal = portal;
 	RefsIncrease(portal);
@@ -217,6 +216,7 @@ global int CastSpawnPortal(Unit* caster, const SpellType* spell __attribute__((u
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -269,21 +269,19 @@ global int CastAreaAdjustVitals(Unit* caster, const SpellType* spell,
 	return 0;
 }
 
-
-//		AreaBombardment
-//   NOTE: vladi: blizzard differs than original in this way:
-//   original: launches 50 shards at 5 random spots x 10 for 25 mana.
-
 /**
 **		Cast area bombardment.
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
 **
 **		@return				=!0 if spell should be repeated, 0 if not
+**      @internal: vladi: blizzard differs than original in this way:
+**       original: launches 50 shards at 5 random spots x 10 for 25 mana.
 */
 global int CastAreaBombardment(Unit* caster, const SpellType* spell,
 	const SpellActionType* action, Unit* target __attribute__((unused)), int x, int y)
@@ -346,18 +344,18 @@ global int CastAreaBombardment(Unit* caster, const SpellType* spell,
 /**
 **		Evaluate missile location description.
 **
+**      @param location     Parameters for location.
 **		@param caster		Unit that casts the spell
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
-**
 **		@param resx		pointer to X coord of the result
 **		@param resy		pointer to Y coord of the result
 */
 local void EvaluateMissileLocation(const SpellActionMissileLocation* location,
 	Unit* caster, Unit* target, int x, int y, int* resx, int* resy)
 {
-	if (location->Base==LocBaseCaster) {
+	if (location->Base == LocBaseCaster) {
 		*resx = caster->X * TileSizeX + TileSizeX / 2;
 		*resy = caster->Y * TileSizeY + TileSizeY / 2;
 	} else {
@@ -384,6 +382,7 @@ local void EvaluateMissileLocation(const SpellActionMissileLocation* location,
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -404,8 +403,6 @@ global int CastSpawnMissile(Unit* caster, const SpellType* spell,
 	DebugCheck(!action);
 	DebugCheck(!action->Data.SpawnMissile.Missile);
 
-	missile = NULL;
-
 	EvaluateMissileLocation(&action->Data.SpawnMissile.StartPoint,
 		caster, target, x, y, &sx, &sy);
 	EvaluateMissileLocation(&action->Data.SpawnMissile.EndPoint,
@@ -430,6 +427,7 @@ global int CastSpawnMissile(Unit* caster, const SpellType* spell,
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -468,6 +466,7 @@ global int CastAdjustBuffs(Unit* caster, const SpellType* spell,
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -525,7 +524,6 @@ global int CastAdjustVitals(Unit* caster, const SpellType* spell,
 	}
 
 	DebugCheck(castcount < 0);
-
 	DebugLevel3Fn("Used to have %d hp and %d mana.\n" _C_
 		target->HP _C_ target->Mana);
 
@@ -556,6 +554,7 @@ global int CastAdjustVitals(Unit* caster, const SpellType* spell,
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -565,7 +564,6 @@ global int CastAdjustVitals(Unit* caster, const SpellType* spell,
 global int CastPolymorph(Unit* caster, const SpellType* spell,
 	const SpellActionType* action, Unit* target, int x, int y)
 {
-	int canplace;
 	int i;
 	int j;
 	UnitType* type;
@@ -599,30 +597,24 @@ global int CastPolymorph(Unit* caster, const SpellType* spell,
 	// as said somewhere else -- no corpses :)
 	RemoveUnit(target, NULL);
 	UnitCacheRemove(target);
-	canplace = 1;
 	for (i = 0; i < type->TileWidth; ++i) {
 		for (j = 0; j < type->TileHeight; ++j) {
 			if (!UnitTypeCanMoveTo(x + i, y + j, type)) {
-				canplace = 0;
-				i = j = 10343243;
+				PlaceUnit(target, target->X, target->Y);
+				return 0;
 			}
 		}
 	}
-	if (canplace) {
-		caster->Mana -= spell->ManaCost;
-		if (action->Data.Polymorph.PlayerNeutral) {
-			MakeUnitAndPlace(x, y, type, Players + PlayerNumNeutral);
-		} else {
-			MakeUnitAndPlace(x, y, type, target->Player);
-		}
-		UnitLost(target);
-		UnitClearOrders(target);
-		ReleaseUnit(target);
-		return 1;
+	caster->Mana -= spell->ManaCost;
+	if (action->Data.Polymorph.PlayerNeutral) {
+		MakeUnitAndPlace(x, y, type, Players + PlayerNumNeutral);
 	} else {
-		PlaceUnit(target, target->X, target->Y);
-		return 0;
+		MakeUnitAndPlace(x, y, type, target->Player);
 	}
+	UnitLost(target);
+	UnitClearOrders(target);
+	ReleaseUnit(target);
+	return 1;
 }
 
 /**
@@ -630,6 +622,7 @@ global int CastPolymorph(Unit* caster, const SpellType* spell,
 **
 **		@param caster		Unit that casts the spell
 **		@param spell		Spell-type pointer
+**      @param action       Parameters of the spell.
 **		@param target		Target unit that spell is addressed to
 **		@param x		X coord of target spot when/if target does not exist
 **		@param y		Y coord of target spot when/if target does not exist
@@ -705,12 +698,9 @@ global int CastSummon(Unit* caster, const SpellType* spell,
 			DropOutOnSide(target, LookingW, 0, 0);
 			CheckUnitToBeDrawn(target);
 		}
-
 		caster->Mana -= spell->ManaCost;
-
 		return 1;
 	}
-
 	return 0;
 }
 
@@ -719,7 +709,13 @@ global int CastSummon(Unit* caster, const SpellType* spell,
 // ****************************************************************************
 
 /**
-**		FIXME: docu
+**      Target constructor.
+**
+**      @param t            Type of target (unit, position).
+**      @param unit         Unit target.
+**      @param x            x coord of the target.
+**      @param y            y coord of the target.
+**      @return the new target.
 */
 local Target* NewTarget(TargetType t, const Unit* unit, int x, int y)
 {
@@ -739,7 +735,11 @@ local Target* NewTarget(TargetType t, const Unit* unit, int x, int y)
 }
 
 /**
-**		FIXME: docu
+**      Target constructor for unit.
+**
+**      @param unit     Target unit.
+**
+**      @return the new target.
 */
 local Target* NewTargetUnit(const Unit* unit)
 {
@@ -748,7 +748,12 @@ local Target* NewTargetUnit(const Unit* unit)
 }
 
 /**
-**		FIXME: docu
+**      Target constructor for position.
+**
+**      @param x        x position.
+**      @param y        y position.
+**
+**      @return the new target.
 */
 local Target* NewTargetPosition(int x, int y)
 {
@@ -765,9 +770,9 @@ local Target* NewTargetPosition(int x, int y)
 /*
 **		Check the condition.
 **
-**		@param caster				Pointer to caster unit.
-**		@param spell 				Pointer to the spell to cast.
-**		@param target				Pointer to target unit, or 0 if it is a position spell.
+**		@param caster			Pointer to caster unit.
+**		@param spell 			Pointer to the spell to cast.
+**		@param target			Pointer to target unit, or 0 if it is a position spell.
 **		@param x				X position, or -1 if it is an unit spell.
 **		@param y				Y position, or -1 if it is an unit spell.
 **		@param condition		Pointer to condition info.
@@ -778,96 +783,84 @@ local int PassCondition(const Unit* caster, const SpellType* spell, const Unit*
 	int x, int y, const ConditionInfo* condition)
 {
 	int i;
-	//
-	//		Check caster mana. FIXME: move somewhere else?
-	//
-	if (caster->Mana < spell->ManaCost) {
+
+	if (caster->Mana < spell->ManaCost) { // Check caster mana.
 		return 0;
 	}
-
-	//
-	//		Casting an unit spell without a target.
-	//
-	if (spell->Target == TargetUnit) {
+	if (spell->Target == TargetUnit) { // Casting an unit spell without a target.
 		if ((!target) || target->Destroyed || target->Orders->Action == UnitActionDie) {
 			return 0;
 		}
 	}
-	if (!condition) {
-		// no condition, pass.
+	if (!condition) { // no condition, pass.
 		return 1;
 	}
-	// Check dead units.
+	if (!target) {
+		return 1;
+	}
+	if (condition->Building != CONDITION_TRUE) {
+		if ((condition->Building == CONDITION_ONLY) ^ (target->Type->Building)) {
+			return 0;
+		}
+	}
+	if (condition->Coward != CONDITION_TRUE) {
+		if ((condition->Coward == CONDITION_ONLY) ^ (target->Type->Coward)) {
+			return 0;
+		}
+	}
+	for (i = 0; i < NumberBoolFlag; i++) { // User defined flags
+		if (condition->BoolFlag[i] != CONDITION_TRUE) {
+			if ((condition->BoolFlag[i] == CONDITION_ONLY) ^ (target->Type->BoolFlag[i])) {
+				return 0;
+			}
+		}
+	}
+	if (condition->Alliance != CONDITION_TRUE) {
+		if ((condition->Alliance == CONDITION_ONLY) ^
+				(IsAllied(caster->Player,target) || target->Player == caster->Player)) {
+			return 0;
+		}
+	}
+	if (condition->TargetSelf != CONDITION_TRUE) {
+		if ((condition->TargetSelf == CONDITION_ONLY) ^ (caster == target)) {
+			return 0;
+		}
+	}
 	//
-	//		Now check conditions regarding the target unit.
+	//		Check vitals now.
 	//
-	if (target) {
-		if (condition->Building != CONDITION_TRUE) {
-			if ((condition->Building == CONDITION_ONLY) ^ (target->Type->Building)) {
-				return 0;
-			}
-		}
-		if (condition->Coward != CONDITION_TRUE) {
-			if ((condition->Coward == CONDITION_ONLY) ^ (target->Type->Coward)) {
-				return 0;
-			}
-		}
-		for (i = 0; i < NumberBoolFlag; i++) { // User defined flags
-			if (condition->BoolFlag[i] != CONDITION_TRUE) {
-				if ((condition->BoolFlag[i] == CONDITION_ONLY) ^ (target->Type->BoolFlag[i])) {
-					return 0;
-				}
-			}
-		}
-		if (condition->Alliance != CONDITION_TRUE) {
-			if ((condition->Alliance == CONDITION_ONLY) ^
-					(IsAllied(caster->Player,target) || target->Player == caster->Player)) {
-				return 0;
-			}
-		}
-		if (condition->TargetSelf != CONDITION_TRUE) {
-			if ((condition->TargetSelf == CONDITION_ONLY) ^ (caster == target)) {
-				return 0;
-			}
-		}
-		//
-		//		Check vitals now.
-		//
-		if (condition->MinHpPercent * target->Stats->HitPoints / 100 > target->HP) {
+	if (condition->MinHpPercent * target->Stats->HitPoints / 100 > target->HP) {
+		return 0;
+	}
+	if (condition->MaxHpPercent * target->Stats->HitPoints / 100 <= target->HP) {
+		return 0;
+	}
+	if (target->Type->CanCastSpell) {
+		if (condition->MinManaPercent * target->Type->_MaxMana / 100 > target->Mana) {
 			return 0;
 		}
-		if (condition->MaxHpPercent * target->Stats->HitPoints / 100 <= target->HP) {
-			return 0;
-		}
-		if (target->Type->CanCastSpell) {
-			if (condition->MinManaPercent * target->Type->_MaxMana / 100 > target->Mana) {
-				return 0;
-			}
-			if (condition->MaxManaPercent * target->Type->_MaxMana / 100 < target->Mana) {
-				return 0;
-			}
-		}
-		//
-		//		Check for slow/haste stuff
-		//		This should be used mostly for ai, if you want to keep casting
-		//		slow to no effect I can't see why should we stop you.
-		//
-		if (condition->MaxSlowTicks < target->Slow) {
-			return 0;
-		}
-		if (condition->MaxHasteTicks < target->Haste) {
-			return 0;
-		}
-		if (condition->MaxBloodlustTicks < target->Bloodlust) {
-			return 0;
-		}
-		if (condition->MaxInvisibilityTicks < target->Invisible) {
-			return 0;
-		}
-		if (condition->MaxInvincibilityTicks < target->UnholyArmor) {
+		if (condition->MaxManaPercent * target->Type->_MaxMana / 100 < target->Mana) {
 			return 0;
 		}
 	}
+	//		Check for slow/haste stuff
+	//		This should be used mostly for ai, if you want to keep casting
+	//		slow to no effect I can't see why should we stop you.
+	if (condition->MaxSlowTicks < target->Slow) {
+		return 0;
+	}
+	if (condition->MaxHasteTicks < target->Haste) {
+		return 0;
+	}
+	if (condition->MaxBloodlustTicks < target->Bloodlust) {
+		return 0;
+	}
+	if (condition->MaxInvisibilityTicks < target->Invisible) {
+		return 0;
+	}
+	if (condition->MaxInvincibilityTicks < target->UnholyArmor) {
+		return 0;
+	}
 	return 1;
 }
 
@@ -878,9 +871,9 @@ local int PassCondition(const Unit* caster, const SpellType* spell, const Unit*
 **		@param spell		Spell-type pointer.
 **
 **		@return Target*		choosen target or Null if spell can't be cast.
-**
+**      @fixme should be global (for AI) ???
+**      @fixme write for position target.
 */
-// FIXME: should be global (for AI) ???
 local Target* SelectTargetUnitsOfAutoCast(const Unit* caster, const SpellType* spell)
 {
 	Unit* table[UnitMax];
@@ -894,12 +887,9 @@ local Target* SelectTargetUnitsOfAutoCast(const Unit* caster, const SpellType* s
 	AutoCastInfo* autocast;
 
 	DebugCheck(!spell);
-	DebugCheck(!spell->AutoCast);
 	DebugCheck(!caster);
 
-	//
 	//		Ai cast should be a lot better. Use autocast if not found.
-	//
 	if (caster->Player->AiEnabled && spell->AICast) {
 		DebugLevel3Fn("The borg uses AI autocast XP.\n");
 		autocast = spell->AICast;
@@ -907,7 +897,7 @@ local Target* SelectTargetUnitsOfAutoCast(const Unit* caster, const SpellType* s
 		DebugLevel3Fn("You puny mortal, join the colective!\n");
 		autocast = spell->AutoCast;
 	}
-
+	DebugCheck(!autocast);
 	x = caster->X;
 	y = caster->Y;
 	range = spell->AutoCast->Range;
@@ -1027,7 +1017,7 @@ global SpellType* SpellTypeByIdent(const char* ident)
 			return SpellTypeTable[i];
 		}
 	}
-	return 0;
+	return NULL;
 }
 
 // ****************************************************************************
@@ -1037,7 +1027,9 @@ global SpellType* SpellTypeByIdent(const char* ident)
 /**
 **		Check if spell is research for player \p player.
 **		@param		player : player for who we want to know if he knows the spell.
-**		@param		id :
+**		@param		spellid : id of the spell to check.
+**
+**      @return 0 if spell is not available, else no null.
 */
 global int SpellIsAvailable(const Player* player, int spellid)
 {
@@ -1076,24 +1068,19 @@ global int CanAutoCastSpell(const SpellType* spell)
 **		@param y		Y coord of target spot when/if target does not exist
 **
 **		@return				=!0 if spell should/can casted, 0 if not
+**		@note caster must know the spell, and spell must be researched.
 */
 global int CanCastSpell(const Unit* caster, const SpellType* spell,
-	const Unit* target, // FIXME: Use a unique struture t_Target ?
-	int x, int y)
+	const Unit* target, int x, int y)
 {
 	DebugCheck(!caster);
 	DebugCheck(!spell);
-
-	// And caster must know the spell
-	// FIXME: spell->Ident < MaxSpell
+	DebugCheck(!SpellIsAvailable(caster->Player, spell->Slot));
 	DebugCheck(!(caster->Type->CanCastSpell && caster->Type->CanCastSpell[spell->Slot]));
 
-	if (!caster->Type->CanCastSpell ||
-			!caster->Type->CanCastSpell[spell->Slot] ||
-			(spell->Target == TargetUnit && target == NULL)) {
+	if (spell->Target == TargetUnit && target == NULL) {
 		return 0;
 	}
-
 	return PassCondition(caster, spell, target, x, y, spell->Condition);
 }
 
@@ -1115,10 +1102,9 @@ global int AutoCastSpell(Unit* caster, const SpellType* spell)
 	DebugCheck(!(caster->Type->CanCastSpell));
 	DebugCheck(!(caster->Type->CanCastSpell[spell->Slot]));
 
-	target = NULL;
-
 	//  Check for mana, trivial optimization.
-	if (caster->Mana < spell->ManaCost) {
+	if (!SpellIsAvailable(caster->Player, spell->Slot)
+		|| caster->Mana < spell->ManaCost) {
 		return 0;
 	}
 	target = SelectTargetUnitsOfAutoCast(caster, spell);
@@ -1152,6 +1138,7 @@ global int SpellCast(Unit* caster, const SpellType* spell, Unit* target,
 	SpellActionType* act;
 
 	DebugCheck(!spell);
+	DebugCheck(!spell->Action);
 	DebugCheck(!spell->Action->CastFunction);
 	DebugCheck(!caster);
 	DebugCheck(!SpellIsAvailable(caster->Player, spell->Slot));
@@ -1164,10 +1151,10 @@ global int SpellCast(Unit* caster, const SpellType* spell, Unit* target,
 	//
 	//		For TargetSelf, you target.... YOURSELF
 	//
-	if (spell->Target==TargetSelf) {
-		x=caster->X;
-		y=caster->Y;
-		target=caster;
+	if (spell->Target == TargetSelf) {
+		x = caster->X;
+		y = caster->Y;
+		target = caster;
 	}
 	DebugLevel0Fn("Spell cast: (%s), %s -> %s (%d,%d)\n" _C_ spell->Ident _C_
 		caster->Type->Name _C_ target ? target->Type->Name : "none" _C_ x _C_ y);
@@ -1252,9 +1239,7 @@ void CleanSpells(void)
 			}
 			free(spell->AICast);
 		}
-		if (spell->SoundWhenCast.Name) {
-			free(spell->SoundWhenCast.Name);
-		}
+		free(spell->SoundWhenCast.Name);
 		free(spell);
 		// FIXME: missile free somewhere else, right?
 	}
@@ -1263,33 +1248,4 @@ void CleanSpells(void)
 	SpellTypeCount = 0;
 }
 
-#if 0
-
-/*
-**		 TODO :
-**		- Modify missile.c for better configurable and clear the code.
-** ccl info
-
-
-// !!! Special deathcoil
-
-// if (!target->Type->Building
-		   && (target->Type->UnitType == UnitTypeLand || target->Type->UnitType == UnitTypeNaval)
-		&& target->FlameShield < spell->TTL) // FlameShield
-
-		= {
-
-  NOTE: vladi:
-
-  The point to have variable unsorted list of spell-types and
-  dynamic id's and in the same time -- SpellAction id's is that
-  spell actions are hardcoded and cannot be changed at all.
-  On the other hand we can have different spell-types as with
-  different range, cost and time to live (possibly and other
-  parameters as extensions)
-
-*/
-
-#endif
-
 //@}