[+] 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.
This commit is contained in:
parent
75f911dbc9
commit
973631c335
15 changed files with 126 additions and 48 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue