From 973631c33515a68d6b5dfc6fd446fbe3d65ebd47 Mon Sep 17 00:00:00 2001 From: iddqd-mail <iddqd_mail@mail.ru> Date: Fri, 15 Jun 2012 11:24:08 +0600 Subject: [PATCH] [+] Ability to get info for unit's bool-flags and currently used spell in animations. [+] Ability to change some target's variable when missile hits it. Use (in DefineMissile) ChangeVariable for variable name, ChangeAmount for changing amount (may be negative) and bool ChangeMax to increase the Max field if Value will be greater than Max. [*] CclDefineUnitStats now supports more user defined variables (NOTE: saves compatibility will be lost) [*] AI units who uses repeat-cast magic won't stop on each cast. [-] Units no more attack revealers. [-] Some fixes to stored resources. [-] Don't clone attack action for dead units. --- src/action/action_attack.cpp | 2 +- src/action/action_upgradeto.cpp | 2 +- src/ai/ai_magic.cpp | 5 ++- src/animation/animation.cpp | 19 +++++++++ src/animation/animation_setplayervar.cpp | 4 +- src/include/missile.h | 3 ++ src/include/player.h | 10 ++++- src/include/unit.h | 10 ++++- src/missile/missile.cpp | 6 +-- src/missile/script_missile.cpp | 12 ++++++ src/stratagus/player.cpp | 29 +++++++++----- src/stratagus/script_player.cpp | 2 +- src/unit/script_unittype.cpp | 49 +++++++++++++----------- src/unit/unit.cpp | 15 +++++++- src/unit/unittype.cpp | 6 +-- 15 files changed, 126 insertions(+), 48 deletions(-) diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index a812eca12..89a2dd426 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -477,7 +477,7 @@ void COrder_Attack::AttackTarget(CUnit &unit) return; } // Save current command to come back. - COrder *savedOrder = this->Clone(); + COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp index b089eda5c..cab047d4f 100644 --- a/src/action/action_upgradeto.cpp +++ b/src/action/action_upgradeto.cpp @@ -116,7 +116,7 @@ static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype) for (int i = 0; i < MaxCosts; ++i) { if (player.MaxResources[i] != -1) { player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i]; - player.SetResource(i, player.StoredResources[i], true); + player.SetResource(i, player.StoredResources[i], STORE_BUILDING); } } diff --git a/src/ai/ai_magic.cpp b/src/ai/ai_magic.cpp index d3e40c3d4..4b906fcde 100644 --- a/src/ai/ai_magic.cpp +++ b/src/ai/ai_magic.cpp @@ -37,6 +37,7 @@ #include "unittype.h" #include "unit.h" #include "spells.h" +#include "actions.h" #include "ai_local.h" /*---------------------------------------------------------------------------- @@ -55,8 +56,8 @@ void AiCheckMagic() for (int i = 0; i < n; ++i) { CUnit &unit = player.GetUnit(i); - // Check only magic units - if (unit.Type->CanCastSpell) { + // Check only idle magic units + if (unit.Type->CanCastSpell && unit.CurrentAction() != UnitActionSpellCast) { for (unsigned int j = 0; j < SpellTypeTable.size(); ++j) { // Check if we can cast this spell. SpellIsAvailable checks for upgrades. if (unit.Type->CanCastSpell[j] && SpellIsAvailable(player, j) diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp index cad4a9242..7fb1f3ebe 100644 --- a/src/animation/animation.cpp +++ b/src/animation/animation.cpp @@ -39,6 +39,8 @@ #include "stratagus.h" +#include "action/action_spellcast.h" + #include "animation.h" #include "animation/animation_attack.h" @@ -66,6 +68,7 @@ #include "iolib.h" #include "player.h" #include "script.h" +#include "spells.h" #include "unit.h" #include "unittype.h" @@ -178,6 +181,22 @@ int ParseAnimInt(const CUnit *unit, const char *parseint) return goal->Variable[index].Value * 100 / goal->Variable[index].Max; } return 0; + } else if ((s[0] == 'b') && unit != NULL) { //unit bool flag detected + const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags + if (index == -1) { + fprintf(stderr, "Bad bool-flag name '%s'\n", cur); + Exit(1); + return 0; + } + return goal->Type->BoolFlag[index].value; + } else if ((s[0] == 's') && unit != NULL) { //spell type detected + Assert(goal->CurrentAction() == UnitActionSpellCast); + const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder()); + const SpellType &spell = order.GetSpell(); + if (!strcmp(spell.Ident.c_str(), cur)) { + return 1; + } + return 0; } else if (s[0] == 'p' && unit != NULL) { //player variable detected char *next = strchr(cur, '.'); if (next == NULL) { diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp index 013659236..dd665deb8 100644 --- a/src/animation/animation_setplayervar.cpp +++ b/src/animation/animation_setplayervar.cpp @@ -138,14 +138,14 @@ static void SetPlayerData(int player, const char *prop, const char *arg, int val fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } - Players[player].SetResource(resId, value); + Players[player].SetResource(resId, value, STORE_BOTH); } else if (!strcmp(prop, "StoredResources")) { const int resId = GetResourceIdByName(arg); if (resId == -1) { fprintf(stderr, "Invalid resource \"%s\"", arg); Exit(1); } - Players[player].SetResource(resId, value, true); + Players[player].SetResource(resId, value, STORE_BUILDING); } else if (!strcmp(prop, "UnitLimit")) { Players[player].UnitLimit = value; } else if (!strcmp(prop, "BuildingLimit")) { diff --git a/src/include/missile.h b/src/include/missile.h index 3a5df6216..edbede9de 100644 --- a/src/include/missile.h +++ b/src/include/missile.h @@ -360,6 +360,9 @@ public: int DrawLevel; /// Level to draw missile at int SpriteFrames; /// number of sprite frames in graphic int NumDirections; /// number of directions missile can face + int ChangeVariable; /// variable to change + int ChangeAmount; /// how many to change + bool ChangeMax; /// modify the max, if value will exceed it /// @todo FiredSound defined but not used! SoundConfig FiredSound; /// fired sound diff --git a/src/include/player.h b/src/include/player.h index a6eb25767..3159ff1ed 100644 --- a/src/include/player.h +++ b/src/include/player.h @@ -45,6 +45,14 @@ #endif #include "vec2i.h" +/*---------------------------------------------------------------------------- +-- Definitons +----------------------------------------------------------------------------*/ + +#define STORE_OVERALL 0 +#define STORE_BUILDING 1 +#define STORE_BOTH 2 + /*---------------------------------------------------------------------------- -- Declarations ----------------------------------------------------------------------------*/ @@ -135,7 +143,7 @@ public: /// Adds/subtracts some resources to/from the player store void ChangeResource(int resource, int value, bool store = false); /// Set a resource of the player - void SetResource(int resource, int value, bool store = false); + void SetResource(int resource, int value, int type = STORE_OVERALL); /// Check, if there enough resources for action. bool CheckResource(int resource, int value); diff --git a/src/include/unit.h b/src/include/unit.h index 3b574a4cb..48b4a8e52 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -339,6 +339,10 @@ #include "player.h" #endif +#ifndef __MISSILE_H__ +#include "missile.h" +#endif + #include "vec2i.h" /*---------------------------------------------------------------------------- @@ -676,6 +680,10 @@ unsigned ByPlayer : PlayerMax; /// Track unit seen by player if (IsInvisibile(player)) { return false; } + // Don't attack revealers + if (this->Type->Revealer) { + return false; + } if ((player.Type == PlayerComputer && !this->Type->PermanentCloak) || IsVisible(player) || IsVisibleOnRadar(player)) { return IsAliveOnMap(); @@ -960,7 +968,7 @@ extern void DestroyAllInside(CUnit &source); /// Calculate some value to measure the unit's priority for AI extern int ThreatCalculate(const CUnit &unit, const CUnit &dest); /// Hit unit with damage, if destroyed give attacker the points -extern void HitUnit(CUnit *attacker, CUnit &target, int damage); +extern void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile = NULL); /// Calculate the distance from current view point to coordinate extern int ViewPointDistance(const Vec2i &pos); diff --git a/src/missile/missile.cpp b/src/missile/missile.cpp index 63d2d1e26..945866224 100644 --- a/src/missile/missile.cpp +++ b/src/missile/missile.cpp @@ -682,7 +682,7 @@ static void MissileHitsGoal(const Missile &missile, CUnit &goal, int splash) } else { Assert(missile.SourceUnit != NULL); HitUnit(missile.SourceUnit, goal, - CalculateDamage(*missile.SourceUnit, goal) / splash); + CalculateDamage(*missile.SourceUnit, goal) / splash, &missile); } } } @@ -1091,8 +1091,8 @@ void InitMissileTypes() ** Constructor. */ MissileType::MissileType(const std::string &ident) : - Ident(ident), Transparency(0), - DrawLevel(0), SpriteFrames(0), NumDirections(0), + Ident(ident), Transparency(0), DrawLevel(0), + SpriteFrames(0), NumDirections(0), ChangeVariable(-1), ChangeAmount(0), ChangeMax(false), CorrectSphashDamage(false), Flip(false), CanHitOwner(false), FriendlyFire(false), AlwaysFire(false), Class(), NumBounces(0), StartDelay(0), Sleep(0), Speed(0), Range(0), SplashFactor(0), ImpactParticle(NULL), G(NULL) diff --git a/src/missile/script_missile.cpp b/src/missile/script_missile.cpp index 7f7a7602a..fd0e5b55e 100644 --- a/src/missile/script_missile.cpp +++ b/src/missile/script_missile.cpp @@ -116,6 +116,18 @@ void MissileType::Load(lua_State *l) this->FiredSound.Name = LuaToString(l, -1); } else if (!strcmp(value, "ImpactSound")) { this->ImpactSound.Name = LuaToString(l, -1); + } else if (!strcmp(value, "ChangeVariable")) { + const int index = UnitTypeVar.VariableNameLookup[LuaToString(l, -1)];// User variables + if (index == -1) { + fprintf(stderr, "Bad variable name '%s'\n", LuaToString(l, -1)); + Exit(1); + return; + } + this->ChangeVariable = index; + } else if (!strcmp(value, "ChangeAmount")) { + this->ChangeAmount = LuaToNumber(l, -1); + } else if (!strcmp(value, "ChangeMax")) { + this->ChangeMax = LuaToBoolean(l, -1); } else if (!strcmp(value, "Class")) { const char *className = LuaToString(l, -1); unsigned int i = 0; diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp index 7523e6131..abf36e3d9 100644 --- a/src/stratagus/player.cpp +++ b/src/stratagus/player.cpp @@ -812,18 +812,18 @@ int CPlayer::GetUnitCount() const ** Gets the player resource. ** ** @param resource Resource to get. -** @param store Resource type to get +** @param type Storing type ** -** @note Resource types: 0 - overall store, 1 - store buildings, 2 - both +** @note Storing types: 0 - overall store, 1 - store buildings, 2 - both */ int CPlayer::GetResource(int resource, int type) { switch (type) { - case 0: + case STORE_OVERALL: return this->Resources[resource]; - case 1: + case STORE_BUILDING: return this->StoredResources[resource]; - case 2: + case STORE_BOTH: return this->Resources[resource] + this->StoredResources[resource]; default: DebugPrint("Wrong resource type\n"); @@ -844,6 +844,9 @@ void CPlayer::ChangeResource(int resource, int value, bool store) int fromStore = std::min(this->StoredResources[resource], abs(value)); this->StoredResources[resource] -= fromStore; this->Resources[resource] -= abs(value) - fromStore; + if (this->Resources[resource] < 0) { + this->Resources[resource] = 0; + } } else { if (store && this->MaxResources[resource] != -1) { this->StoredResources[resource] += std::min(value, this->MaxResources[resource] - this->StoredResources[resource]); @@ -858,13 +861,21 @@ void CPlayer::ChangeResource(int resource, int value, bool store) ** ** @param resource Resource to change. ** @param value How many of this resource. -** @param store If true, sets the building store resources, else the overall resources. +** @param type Resource types: 0 - overall store, 1 - store buildings, 2 - both */ -void CPlayer::SetResource(int resource, int value, bool store) +void CPlayer::SetResource(int resource, int value, int type) { - if (store && this->MaxResources[resource] != -1) { + if (type == STORE_BOTH) { + if (this->MaxResources[resource] != -1) { + const int toStore = std::min(0, value - this->Resources[resource]); + this->StoredResources[resource] = std::min(toStore, this->MaxResources[resource]); + this->Resources[resource] = std::max(0, value - toStore); + } else { + this->Resources[resource] = value; + } + } else if (type == STORE_BUILDING && this->MaxResources[resource] != -1) { this->StoredResources[resource] = std::min(value, this->MaxResources[resource]); - } else { + } else if (type == STORE_OVERALL) { this->Resources[resource] = value; } } diff --git a/src/stratagus/script_player.cpp b/src/stratagus/script_player.cpp index 2b8b89a71..839c1e4f2 100644 --- a/src/stratagus/script_player.cpp +++ b/src/stratagus/script_player.cpp @@ -840,7 +840,7 @@ static int CclSetPlayerData(lua_State *l) const std::string res = LuaToString(l, 3); const int resId = GetResourceIdByName(l, res.c_str()); - p->SetResource(resId, LuaToNumber(l, 4), true); + p->SetResource(resId, LuaToNumber(l, 4), STORE_BUILDING); // } else if (!strcmp(data, "UnitTypesCount")) { // } else if (!strcmp(data, "AiEnabled")) { // } else if (!strcmp(data, "TotalNumUnits")) { diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp index c8eea988f..cb3099b62 100644 --- a/src/unit/script_unittype.cpp +++ b/src/unit/script_unittype.cpp @@ -1179,16 +1179,11 @@ static int CclDefineUnitType(lua_State *l) */ static int CclDefineUnitStats(lua_State *l) { - const int args = lua_gettop(l); - int j = 0; - - CUnitType *type = UnitTypeByIdent(LuaToString(l, j + 1)); + CUnitType *type = UnitTypeByIdent(LuaToString(l, 1)); + const int playerId = LuaToNumber(l, 2); + Assert(type); - ++j; - - int playerId = LuaToNumber(l, j + 1); Assert(playerId < PlayerMax); - ++j; CUnitStats *stats = &type->Stats[playerId]; if (!stats->Variables) { @@ -1196,51 +1191,61 @@ static int CclDefineUnitStats(lua_State *l) } // Parse the list: (still everything could be changed!) - for (; j < args; ++j) { - const char *value = LuaToString(l, j + 1); + const int args = lua_rawlen(l, 3); + for (int j = 0; j < args; ++j) { + lua_rawgeti(l, 3, j + 1); + const char *value = LuaToString(l, -1); + lua_pop(l, 1); ++j; if (!strcmp(value, "costs")) { - if (!lua_istable(l, j + 1)) { + lua_rawgeti(l, 3, j + 1); + if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } - const int subargs = lua_rawlen(l, j + 1); + const int subargs = lua_rawlen(l, -1); for (int k = 0; k < subargs; ++k) { - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, 3, j + 1); + lua_rawgeti(l, -1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); ++k; const int resId = GetResourceIdByName(l, value); - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, -1, k + 1); stats->Costs[resId] = LuaToNumber(l, -1); lua_pop(l, 1); + lua_pop(l, 1); } } else if (!strcmp(value, "storing")) { - if (!lua_istable(l, j + 1)) { + lua_rawgeti(l, 3, j + 1); + if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } - const int subargs = lua_rawlen(l, j + 1); + const int subargs = lua_rawlen(l, -1); for (int k = 0; k < subargs; ++k) { - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, 3, j + 1); + lua_rawgeti(l, -1, k + 1); value = LuaToString(l, -1); lua_pop(l, 1); ++k; const int resId = GetResourceIdByName(l, value); - lua_rawgeti(l, j + 1, k + 1); + lua_rawgeti(l, -1, k + 1); stats->Storing[resId] = LuaToNumber(l, -1); lua_pop(l, 1); + lua_pop(l, 1); } } else { int i = UnitTypeVar.VariableNameLookup[value];// User variables if (i != -1) { // valid index - if (lua_istable(l, j + 1)) { - DefineVariableField(l, stats->Variables + i, j + 1); + lua_rawgeti(l, 3, j + 1); + if (lua_istable(l, -1)) { + DefineVariableField(l, stats->Variables + i, -1); } else if (lua_isnumber(l, -1)) { stats->Variables[i].Enable = 1; - stats->Variables[i].Value = LuaToNumber(l, j + 1); - stats->Variables[i].Max = LuaToNumber(l, j + 1); + stats->Variables[i].Value = LuaToNumber(l, -1); + stats->Variables[i].Max = LuaToNumber(l, -1); } else { // Error LuaError(l, "incorrect argument for the variable in unittype"); } diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 02be6fb1e..c916e79cb 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -959,7 +959,7 @@ void UnitLost(CUnit &unit) const int newMaxValue = player.MaxResources[i] - type.Stats[player.Index].Storing[i]; player.MaxResources[i] = std::max(0, newMaxValue); - player.SetResource(i, player.StoredResources[i], true); + player.SetResource(i, player.StoredResources[i], STORE_BUILDING); } } // Handle income improvements, look if a player loses a building @@ -2695,8 +2695,9 @@ int ThreatCalculate(const CUnit &unit, const CUnit &dest) ** @param attacker Unit that attacks. ** @param target Unit that is hit. ** @param damage How many damage to take. +** @param missile Which missile took the damage. */ -void HitUnit(CUnit *attacker, CUnit &target, int damage) +void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile) { // Can now happen by splash damage // Multiple places send x/y as damage, which may be zero @@ -2836,6 +2837,16 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage) type->OnHit->run(); } + // Increase variables + if (missile && missile->Type->ChangeVariable != -1) { + const int var = missile->Type->ChangeVariable; + target.Variable[var].Enable = 1; + target.Variable[var].Value += missile->Type->ChangeAmount; + if (target.Variable[var].Value > target.Variable[var].Max && missile->Type->ChangeMax) { + target.Variable[var].Max = target.Variable[var].Value; + } + } + // Show impact missiles if (target.Variable[SHIELD_INDEX].Value > 0 && !target.Type->Impact[ANIMATIONS_DEATHTYPES + 1].Name.empty()) { // shield impact diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp index 652d1e8fa..0de9886cb 100644 --- a/src/unit/unittype.cpp +++ b/src/unit/unittype.cpp @@ -368,7 +368,7 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl if (stats == type.DefaultStat) { return false; } - file.printf("DefineUnitStats(\"%s\", %d,\n ", type.Ident.c_str(), plynr); + file.printf("DefineUnitStats(\"%s\", %d, {\n ", type.Ident.c_str(), plynr); for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) { file.printf("\"%s\", {Value = %d, Max = %d, Increase = %d%s},\n ", UnitTypeVar.VariableNameLookup[i], stats.Variables[i].Value, @@ -382,14 +382,14 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl } file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Costs[i]); } - file.printf("\"storing\", {"); + file.printf("},\n\"storing\", {"); for (unsigned int i = 0; i < MaxCosts; ++i) { if (i) { file.printf(" "); } file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Storing[i]); } - file.printf("})\n"); + file.printf("}})\n"); return true; }