merge lp:stratagus

This commit is contained in:
Tim Felgentreff 2013-05-21 21:05:22 +02:00
commit a7e147a480
92 changed files with 805 additions and 345 deletions
CMakeLists.txt
src
action
ai
animation
include
map
particle
sound
spell
tolua
ui
unit
video
tests/network

View file

@ -90,6 +90,7 @@ set(animation_SRCS
src/animation/animation_goto.cpp
src/animation/animation_ifvar.cpp
src/animation/animation_label.cpp
src/animation/animation_luacallback.cpp
src/animation/animation_move.cpp
src/animation/animation_randomgoto.cpp
src/animation/animation_randomrotate.cpp
@ -475,6 +476,7 @@ set(stratagus_animation_HDRS
src/include/animation/animation_goto.h
src/include/animation/animation_ifvar.h
src/include/animation/animation_label.h
src/include/animation/animation_luacallback.h
src/include/animation/animation_move.h
src/include/animation/animation_randomgoto.h
src/include/animation/animation_randomrotate.h

View file

@ -346,7 +346,7 @@ void COrder_Built::Progress(CUnit &unit, int amount)
Boost(unit, amount, HP_INDEX);
Boost(unit, amount, SHIELD_INDEX);
this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
this->ProgressCounter += std::max(1, amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR);
UpdateConstructionFrame(unit);
}
@ -354,7 +354,7 @@ void COrder_Built::ProgressHp(CUnit &unit, int amount)
{
Boost(unit, amount, HP_INDEX);
this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
this->ProgressCounter += std::max(1, amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR);
UpdateConstructionFrame(unit);
}
@ -365,7 +365,7 @@ void COrder_Built::Boost(CUnit &building, int amount, int varIndex) const
const int costs = building.Stats->Costs[TimeCost] * 600;
const int progress = this->ProgressCounter;
const int newProgress = progress + amount * building.Player->SpeedBuild / SPEEDUP_FACTOR;
const int newProgress = progress + std::max(1, amount * building.Player->SpeedBuild / SPEEDUP_FACTOR);
const int maxValue = building.Variable[varIndex].Max;
int &currentValue = building.Variable[varIndex].Value;

View file

@ -38,6 +38,7 @@
#include "action/action_follow.h"
#include "iolib.h"
#include "missile.h"
#include "pathfinder.h"
#include "script.h"
#include "ui.h"
@ -168,6 +169,12 @@ enum {
return ;
}
// Don't follow after immobile units
if (goal && goal->CanMove() == false) {
this->Finished = true;
return;
}
if (goal->tilePos == this->goalPos) {
// Move to the next order
if (unit.Orders.size() > 1) {
@ -204,42 +211,51 @@ enum {
// Handle Teleporter Units
// FIXME: BAD HACK
// goal shouldn't be busy and portal should be alive
if (goal->Type->Teleporter && goal->IsIdle() && goal->Goal
&& goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) {
// Teleport the unit
unit.Remove(NULL);
unit.tilePos = goal->Goal->tilePos;
DropOutOnSide(unit, unit.Direction, NULL);
#if 0
// FIXME: SoundForName() should be called once
PlayGameSound(SoundForName("invisibility"), MaxSampleVolume);
// FIXME: MissileTypeByIdent() should be called once
MakeMissile(MissileTypeByIdent("missile-normal-spell"),
unit.GetMapPixelPosCenter(),
unit.GetMapPixelPosCenter());
#endif
// FIXME: we must check if the units supports the new order.
CUnit &dest = *goal->Goal;
if (goal->Type->Teleporter && goal->Goal && goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) {
if (!goal->IsIdle()) { // wait
unit.Wait = 10;
return;
}
// Check if we have enough mana
if (goal->Goal->Type->TeleportCost > goal->Variable[MANA_INDEX].Value) {
this->Finished = true;
return;
} else {
goal->Variable[MANA_INDEX].Value -= goal->Goal->Type->TeleportCost;
}
// Everything is OK, now teleport the unit
unit.Remove(NULL);
if (goal->Type->TeleportEffect.Missile) {
MakeMissile(*goal->Type->TeleportEffect.Missile, unit.GetMapPixelPosCenter(), unit.GetMapPixelPosCenter());
}
unit.tilePos = goal->Goal->tilePos;
DropOutOnSide(unit, unit.Direction, NULL);
if (dest.NewOrder == NULL
|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->Harvester)
|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
this->Finished = true;
return ;
} else {
if (dest.NewOrder->HasGoal()) {
if (dest.NewOrder->GetGoal()->Destroyed) {
delete dest.NewOrder;
dest.NewOrder = NULL;
this->Finished = true;
return ;
}
// FIXME: we must check if the units supports the new order.
CUnit &dest = *goal->Goal;
if (dest.Type->TeleportEffect.Missile) {
MakeMissile(*dest.Type->TeleportEffect.Missile, unit.GetMapPixelPosCenter(), unit.GetMapPixelPosCenter());
}
if (dest.NewOrder == NULL
|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->Harvester)
|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
this->Finished = true;
return ;
} else {
if (dest.NewOrder->HasGoal()) {
if (dest.NewOrder->GetGoal()->Destroyed) {
delete dest.NewOrder;
dest.NewOrder = NULL;
this->Finished = true;
return ;
}
unit.Orders.insert(unit.Orders.begin() + 1, dest.NewOrder->Clone());
this->Finished = true;
return ;
}
}
}
this->goalPos = goal->tilePos;
this->State = State_TargetReached;

View file

@ -131,7 +131,7 @@
}
#endif
CPlayer &player = *unit.Player;
player.UpgradeTimers.Upgrades[upgrade.ID] += player.SpeedResearch / SPEEDUP_FACTOR;
player.UpgradeTimers.Upgrades[upgrade.ID] += std::max(1, player.SpeedResearch / SPEEDUP_FACTOR);
if (player.UpgradeTimers.Upgrades[upgrade.ID] >= upgrade.Costs[TimeCost]) {
player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), type.Name.c_str());
if (&player == ThisPlayer) {

View file

@ -470,7 +470,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
#endif
UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
if (resinfo.WaitAtResource) {
this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] * SPEEDUP_FACTOR;
this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
} else {
this->TimeToHarvest = 1;
}
@ -538,7 +538,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
goal->Resource.Active++;
if (resinfo.WaitAtResource) {
this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] * SPEEDUP_FACTOR;
this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
} else {
this->TimeToHarvest = 1;
}
@ -671,7 +671,7 @@ int COrder_Resource::GatherResource(CUnit &unit)
while (!this->DoneHarvesting && this->TimeToHarvest < 0) {
//FIXME: rb - how should it look for WaitAtResource == 0
if (resinfo.WaitAtResource) {
this->TimeToHarvest += resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId];
this->TimeToHarvest += std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]);
} else {
this->TimeToHarvest += 1;
}
@ -954,7 +954,7 @@ int COrder_Resource::MoveToDepot(CUnit &unit)
unit.CurrentResource = 0;
if (unit.Wait) {
unit.Wait /= unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR;
unit.Wait /= std::max(1, unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR);
if (unit.Wait) {
unit.Wait--;
}
@ -1103,6 +1103,9 @@ bool COrder_Resource::ActionResourceInit(CUnit &unit)
unit.DeAssignWorkerFromMine(*mine);
this->Resource.Mine = NULL;
}
if (goal && goal->IsAlive() == false) {
return false;
}
if (goal && goal->CurrentAction() != UnitActionBuilt) {
unit.AssignWorkerToMine(*goal);
this->Resource.Mine = goal;
@ -1133,6 +1136,7 @@ void COrder_Resource::Execute(CUnit &unit)
// Let's start mining.
if (this->State == SUB_START_RESOURCE) {
if (ActionResourceInit(unit) == false) {
ResourceGiveUp(unit);
return;
}
}

View file

@ -333,7 +333,7 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
}
// FALL THROUGH
case 2: // Cast spell on the target.
if (!spell.IsCasterOnly()) {
if (!spell.IsCasterOnly() || spell.ForceUseAnimation) {
AnimateActionSpellCast(unit, *this);
if (unit.Anim.Unbreakable) {
return ;

View file

@ -183,7 +183,7 @@ static void AnimateActionTrain(CUnit &unit)
CPlayer &player = *unit.Player;
const CUnitType &nType = *this->Type;
const int cost = nType.Stats[player.Index].Costs[TimeCost];
this->Ticks += player.SpeedTrain / SPEEDUP_FACTOR;
this->Ticks += std::max(1, player.SpeedTrain / SPEEDUP_FACTOR);
if (this->Ticks < cost) {
unit.Wait = CYCLES_PER_SECOND / 6;

View file

@ -260,7 +260,7 @@ static void AnimateActionUpgradeTo(CUnit &unit)
const CUnitType &newtype = *this->Type;
const CUnitStats &newstats = newtype.Stats[player.Index];
this->Ticks += player.SpeedUpgrade / SPEEDUP_FACTOR;
this->Ticks += std::max(1, player.SpeedUpgrade / SPEEDUP_FACTOR);
if (this->Ticks < newstats.Costs[TimeCost]) {
unit.Wait = CYCLES_PER_SECOND / 6;
return ;

View file

@ -36,7 +36,10 @@
#include "stratagus.h"
#include "actions.h"
#include "action/action_built.h"
#include "action/action_research.h"
#include "action/action_train.h"
#include "action/action_upgradeto.h"
#include "commands.h"
#include "map.h"
#include "pathfinder.h"
@ -63,8 +66,19 @@ static void ReleaseOrders(CUnit &unit)
Assert(unit.Orders.empty() == false);
// Order 0 must be stopped in the action loop.
for (size_t i = 1; i != unit.Orders.size(); ++i) {
delete unit.Orders[i];
for (size_t i = 0; i != unit.Orders.size(); ++i) {
if (unit.Orders[i]->Action == UnitActionBuilt) {
(dynamic_cast<COrder_Built *>(unit.Orders[i]))->Cancel(unit);
} else if (unit.Orders[i]->Action == UnitActionResearch) {
(dynamic_cast<COrder_Research *>(unit.Orders[i]))->Cancel(unit);
} else if (unit.Orders[i]->Action == UnitActionTrain) {
(dynamic_cast<COrder_Train *>(unit.Orders[i]))->Cancel(unit);
} else if (unit.Orders[i]->Action == UnitActionUpgradeTo) {
(dynamic_cast<COrder_UpgradeTo *>(unit.Orders[i]))->Cancel(unit);
}
if (i > 0) {
delete unit.Orders[i];
}
}
unit.Orders.resize(1);
unit.Orders[0]->Finished = true;

View file

@ -670,7 +670,7 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender)
return;
}
// Summoned unit, don't help
if (defender.GroupId == -1) {
if (defender.Summoned) {
return;
}

View file

@ -448,14 +448,14 @@ void AiForce::ReturnToHome()
AiForceManager::AiForceManager()
{
forces.resize(3);
forces.resize(AI_MAX_FORCES);
memset(script, -1, AI_MAX_FORCES * sizeof(char));
}
unsigned int AiForceManager::FindFreeForce(AiForceRole role)
unsigned int AiForceManager::FindFreeForce(AiForceRole role, int begin)
{
/* find free force */
unsigned int f = 0;
unsigned int f = begin;
while (f < forces.size() && (forces[f].State > AiForceAttackingState_Free)) {
++f;
};
@ -467,6 +467,30 @@ unsigned int AiForceManager::FindFreeForce(AiForceRole role)
return f;
}
/**
** Find unit in force
**
** @param unit Unit to search for.
**
** @return Force number, or -1 if not found
*/
int AiForceManager::GetForce(const CUnit &unit)
{
for (unsigned int i = 0; i < forces.size(); ++i) {
AiForce &force = forces[i];
for (unsigned int j = 0; j < force.Units.size(); ++j) {
CUnit &aiunit = *force.Units[j];
if (UnitNumber(unit) == UnitNumber(aiunit)) {
return i;
}
}
}
return -1;
}
/**
** Cleanup units in forces.
*/
@ -591,7 +615,7 @@ void AiAttackWithForceAt(unsigned int force, int x, int y)
{
const Vec2i pos(x, y);
if (!(force < AI_MAX_FORCES)) {
if (!(force < AI_MAX_FORCE_INTERNAL)) {
DebugPrint("Force out of range: %d" _C_ force);
return ;
}
@ -611,7 +635,7 @@ void AiAttackWithForceAt(unsigned int force, int x, int y)
*/
void AiAttackWithForce(unsigned int force)
{
if (!(force < AI_MAX_FORCES)) {
if (!(force < AI_MAX_FORCE_INTERNAL)) {
DebugPrint("Force out of range: %d" _C_ force);
return ;
}
@ -620,7 +644,7 @@ void AiAttackWithForce(unsigned int force)
// the first force, so we can reuse it
if (!AiPlayer->Force[force].Defending) {
unsigned int top;
unsigned int f = AiPlayer->Force.FindFreeForce();
unsigned int f = AiPlayer->Force.FindFreeForce(AiForceRoleDefault, AI_MAX_FORCE_INTERNAL);
AiPlayer->Force[f].Reset();
AiPlayer->Force[f].Role = AiPlayer->Force[force].Role;
@ -658,7 +682,7 @@ void AiAttackWithForces(int *forces)
const Vec2i invalidPos(-1, -1);
bool found = false;
unsigned int top;
unsigned int f = AiPlayer->Force.FindFreeForce();
unsigned int f = AiPlayer->Force.FindFreeForce(AiForceRoleDefault, AI_MAX_FORCE_INTERNAL);
AiPlayer->Force[f].Reset();

View file

@ -159,12 +159,12 @@ public:
void ReturnToHome();
bool NewRallyPoint(const Vec2i &startPos, Vec2i *resultPos);
void Insert(CUnit &unit);
private:
void CountTypes(unsigned int *counter, const size_t len);
bool IsBelongsTo(const CUnitType &type);
void Insert(CUnit &unit);
void Update();
static void InternalRemoveUnit(CUnit *unit);
@ -186,7 +186,8 @@ public:
};
// forces
#define AI_MAX_FORCES 50 /// How many forces are supported
#define AI_MAX_FORCES 50 /// How many forces are supported
#define AI_MAX_FORCE_INTERNAL (AI_MAX_FORCES / 2) /// The forces after AI_MAX_FORCE_INTERNAL are for internal use
/**
** AI force manager.
@ -219,10 +220,11 @@ public:
return script[index];
}
int GetForce(const CUnit &unit);
void RemoveDeadUnit();
bool Assign(CUnit &unit);
void Update();
unsigned int FindFreeForce(AiForceRole role = AiForceRoleDefault);
unsigned int FindFreeForce(AiForceRole role = AiForceRoleDefault, int begin = 0);
void CheckUnits(int *counter);
private:
std::vector<AiForce> forces;

View file

@ -116,14 +116,14 @@ class WallFinder
{
public:
WallFinder(const CUnit &unit, int maxDist, Vec2i *resultPos) :
unit(unit),
// unit(unit),
maxDist(maxDist),
movemask(unit.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)),
resultPos(resultPos)
{}
VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
private:
const CUnit &unit;
// const CUnit &unit;
int maxDist;
int movemask;
Vec2i *resultPos;
@ -213,12 +213,12 @@ class ReachableTerrainMarker
{
public:
ReachableTerrainMarker(const CUnit &unit) :
unit(unit),
// unit(unit),
movemask(unit.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit))
{}
VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
private:
const CUnit &unit;
// const CUnit &unit;
int movemask;
};

View file

@ -692,7 +692,7 @@ static int CclAiForce(lua_State *l)
resetForce = LuaToBoolean(l, 3);
}
int force = LuaToNumber(l, 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
LuaError(l, "Force out of range: %d" _C_ force);
}
AiForce &aiforce = AiPlayer->Force[AiPlayer->Force.getScriptForce(force)];
@ -762,7 +762,7 @@ static int CclAiForceRole(lua_State *l)
{
LuaCheckArgs(l, 2);
int force = LuaToNumber(l, 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
LuaError(l, "Force %i out of range" _C_ force);
}
@ -789,7 +789,7 @@ static int CclAiCheckForce(lua_State *l)
{
LuaCheckArgs(l, 1);
int force = LuaToNumber(l, 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
lua_pushfstring(l, "Force out of range: %d", force);
}
if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@ -809,7 +809,7 @@ static int CclAiWaitForce(lua_State *l)
{
LuaCheckArgs(l, 1);
int force = LuaToNumber(l, 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
lua_pushfstring(l, "Force out of range: %d", force);
}
if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@ -834,7 +834,7 @@ static int CclAiAttackWithForce(lua_State *l)
{
LuaCheckArgs(l, 1);
int force = LuaToNumber(l, 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
LuaError(l, "Force out of range: %d" _C_ force);
}
AiAttackWithForce(AiPlayer->Force.getScriptForce(force));
@ -857,7 +857,7 @@ static int CclAiWaitForces(lua_State *l)
for (int i = 0; i < args; ++i) {
const int force = LuaToNumber(l, 1, i + 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
lua_pushfstring(l, "Force out of range: %d", force);
}
if (!AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
@ -876,7 +876,7 @@ static int CclAiWaitForces(lua_State *l)
*/
static int CclAiAttackWithForces(lua_State *l)
{
int Forces[AI_MAX_FORCES + 1];
int Forces[AI_MAX_FORCE_INTERNAL + 1];
LuaCheckArgs(l, 1);
if (!lua_istable(l, 1)) {
@ -886,7 +886,7 @@ static int CclAiAttackWithForces(lua_State *l)
for (int i = 0; i < args; ++i) {
const int force = LuaToNumber(l, 1, i + 1);
if (force < 0 || force >= AI_MAX_FORCES) {
if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
lua_pushfstring(l, "Force out of range: %d", force);
}
Forces[i] = AiPlayer->Force.getScriptForce(force);

View file

@ -46,6 +46,7 @@
#include "animation/animation_goto.h"
#include "animation/animation_ifvar.h"
#include "animation/animation_label.h"
#include "animation/animation_luacallback.h"
#include "animation/animation_move.h"
#include "animation/animation_randomgoto.h"
#include "animation/animation_randomrotate.h"
@ -133,17 +134,17 @@ static int ParseAnimPlayer(const CUnit &unit, const char *parseint)
** @return The parsed value.
*/
int ParseAnimInt(const CUnit *unit, const char *parseint)
int ParseAnimInt(const CUnit &unit, const char *parseint)
{
char s[100];
const CUnit *goal = unit;
const CUnit *goal = &unit;
strcpy(s, parseint);
char *cur = &s[2];
if ((s[0] == 'v' || s[0] == 't') && unit != NULL) { //unit variable detected
if (s[0] == 'v' || s[0] == 't') { //unit variable detected
if (s[0] == 't') {
if (unit->CurrentOrder()->HasGoal()) {
goal = unit->CurrentOrder()->GetGoal();
if (unit.CurrentOrder()->HasGoal()) {
goal = unit.CurrentOrder()->GetGoal();
} else {
return 0;
}
@ -151,7 +152,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
char *next = strchr(cur, '.');
if (next == NULL) {
fprintf(stderr, "Need also specify the variable '%s' tag \n", cur);
Exit(1);
ExitFatal(1);
} else {
*next = '\0';
}
@ -163,7 +164,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return goal->Resource.Active;
}
fprintf(stderr, "Bad variable name '%s'\n", cur);
Exit(1);
ExitFatal(1);
}
if (!strcmp(next + 1, "Value")) {
return goal->Variable[index].Value;
@ -177,10 +178,10 @@ 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' || s[0] == 'g') && unit != NULL) { //unit bool flag detected
} else if (s[0] == 'b' || s[0] == 'g') { //unit bool flag detected
if (s[0] == 'g') {
if (unit->CurrentOrder()->HasGoal()) {
goal = unit->CurrentOrder()->GetGoal();
if (unit.CurrentOrder()->HasGoal()) {
goal = unit.CurrentOrder()->GetGoal();
} else {
return 0;
}
@ -188,11 +189,10 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
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;
ExitFatal(1);
}
return goal->Type->BoolFlag[index].value;
} else if ((s[0] == 's') && unit != NULL) { //spell type detected
} else if (s[0] == 's') { //spell type detected
Assert(goal->CurrentAction() == UnitActionSpellCast);
const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
const SpellType &spell = order.GetSpell();
@ -200,11 +200,11 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return 1;
}
return 0;
} else if (s[0] == 'p' && unit != NULL) { //player variable detected
} else if (s[0] == 'p') { //player variable detected
char *next = strchr(cur, '.');
if (next == NULL) {
fprintf(stderr, "Need also specify the %s player's property\n", cur);
Exit(1);
ExitFatal(1);
} else {
*next = '\0';
}
@ -212,7 +212,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
if (arg != NULL) {
*arg = '\0';
}
return GetPlayerData(ParseAnimPlayer(*unit, cur), next + 1, arg + 1);
return GetPlayerData(ParseAnimPlayer(unit, cur), next + 1, arg + 1);
} else if (s[0] == 'r') { //random value
char *next = strchr(cur, '.');
if (next == NULL) {
@ -223,12 +223,72 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return min + SyncRand(atoi(next + 1) - min + 1);
}
} else if (s[0] == 'l') { //player number
return ParseAnimPlayer(*unit, cur);
return ParseAnimPlayer(unit, cur);
}
return atoi(parseint);
}
/**
** Parse flags list in animation frame.
**
** @param unit Unit of the animation.
** @param parseflag Flag list to parse.
**
** @return The parsed value.
*/
int ParseAnimFlags(const CUnit &unit, const char *parseflag)
{
char s[100];
int flags = 0;
strcpy(s, parseflag);
char *cur = s;
char *next = s;
while (next && *next) {
next = strchr(cur, '.');
if (next) {
*next = '\0';
++next;
}
if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
if (!strcmp(cur, "none")) {
flags = SM_None;
return flags;
} else if (!strcmp(cur, "damage")) {
flags |= SM_Damage;
} else if (!strcmp(cur, "totarget")) {
flags |= SM_ToTarget;
} else if (!strcmp(cur, "pixel")) {
flags |= SM_Pixel;
} else if (!strcmp(cur, "reltarget")) {
flags |= SM_RelTarget;
} else if (!strcmp(cur, "ranged")) {
flags |= SM_Ranged;
} else if (!strcmp(cur, "setdirection")) {
flags |= SM_SetDirection;
} else {
fprintf(stderr, "Unknown animation flag: %s\n", cur);
ExitFatal(1);
}
} else if (unit.Anim.Anim->Type == AnimationSpawnUnit) {
if (!strcmp(cur, "none")) {
flags = SU_None;
return flags;
} else if (!strcmp(cur, "summoned")) {
flags |= SU_Summoned;
} else if (!strcmp(cur, "jointoai")) {
flags |= SU_JoinToAIForce;
} else {
fprintf(stderr, "Unknown animation flag: %s\n", cur);
ExitFatal(1);
}
}
cur = next;
}
return flags;
}
/**
** Show unit animation.
@ -479,10 +539,12 @@ static CAnimation *ParseAnimationFrame(lua_State *l, const char *str)
anim = new CAnimation_Goto;
} else if (op1 == "random-goto") {
anim = new CAnimation_RandomGoto;
} else if (op1 == "lua-callback") {
anim = new CAnimation_LuaCallback;
} else {
LuaError(l, "Unknown animation: %s" _C_ op1.c_str());
}
anim->Init(extraArg.c_str());
anim->Init(extraArg.c_str(), l);
return anim;
}

View file

@ -47,7 +47,7 @@
}
/* virtual */ void CAnimation_Attack::Init(const char *s)
/* virtual */ void CAnimation_Attack::Init(const char *s, lua_State *)
{
}

View file

@ -54,7 +54,7 @@
throw AnimationDie_Exception();
}
/* virtual */ void CAnimation_Die::Init(const char *s)
/* virtual */ void CAnimation_Die::Init(const char *s, lua_State *)
{
this->DeathType = s;
}

View file

@ -45,14 +45,18 @@
unit.Frame = ParseAnimInt(&unit);
}
/* virtual */ void CAnimation_ExactFrame::Init(const char *s)
/* virtual */ void CAnimation_ExactFrame::Init(const char *s, lua_State *)
{
this->frame = s;
}
int CAnimation_ExactFrame::ParseAnimInt(const CUnit *unit) const
{
return ::ParseAnimInt(unit, this->frame.c_str());
if (unit == NULL) {
return atoi(this->frame.c_str());
} else {
return ::ParseAnimInt(*unit, this->frame.c_str());
}
}
//@}

View file

@ -46,14 +46,18 @@
UnitUpdateHeading(unit);
}
/* virtual */ void CAnimation_Frame::Init(const char *s)
/* virtual */ void CAnimation_Frame::Init(const char *s, lua_State *)
{
this->frame = s;
}
int CAnimation_Frame::ParseAnimInt(const CUnit *unit) const
{
return ::ParseAnimInt(unit, this->frame.c_str());
if (unit == NULL) {
return atoi(this->frame.c_str());
} else {
return ::ParseAnimInt(*unit, this->frame.c_str());
}
}
//@}

View file

@ -46,7 +46,7 @@
unit.Anim.Anim = this->gotoLabel;
}
/* virtual */ void CAnimation_Goto::Init(const char *s)
/* virtual */ void CAnimation_Goto::Init(const char *s, lua_State *)
{
FindLabelLater(&this->gotoLabel, s);
}

View file

@ -61,8 +61,8 @@ static bool returnFalse(int, int) { return false; }
{
Assert(unit.Anim.Anim == this);
const int lop = ParseAnimInt(&unit, this->leftVar.c_str());
const int rop = ParseAnimInt(&unit, this->rightVar.c_str());
const int lop = ParseAnimInt(unit, this->leftVar.c_str());
const int rop = ParseAnimInt(unit, this->rightVar.c_str());
const bool cond = this->binOpFunc(lop, rop);
if (cond) {
@ -73,7 +73,7 @@ static bool returnFalse(int, int) { return false; }
/*
** s = "leftOp Op rigthOp gotoLabel"
*/
/* virtual */ void CAnimation_IfVar::Init(const char *s)
/* virtual */ void CAnimation_IfVar::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();

View file

@ -44,7 +44,7 @@
Assert(unit.Anim.Anim == this);
}
/* virtual */ void CAnimation_Label::Init(const char *s)
/* virtual */ void CAnimation_Label::Init(const char *s, lua_State *)
{
}

View file

@ -0,0 +1,84 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name animation_luacallback.cpp - The animation LuaCallback. */
//
// (c) Copyright 2013 by cybermind
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "stratagus.h"
#include "animation/animation_luacallback.h"
#include "script.h"
#include "unit.h"
/* virtual */ void CAnimation_LuaCallback::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
Assert(unit.Anim.Anim == this);
Assert(cb);
cb->pushPreamble();
for (std::vector<std::string>::const_iterator it = cbArgs.begin(); it != cbArgs.end(); ++it) {
const std::string str = *it;
const int arg = ParseAnimInt(unit, str.c_str());
cb->pushInteger(arg);
}
cb->run();
}
/*
** s = "cbName cbArg1 [cbArgN ...]"
*/
/* virtual */ void CAnimation_LuaCallback::Init(const char *s, lua_State *l)
{
const std::string str(s);
const size_t len = str.size();
size_t begin = 0;
size_t end = str.find(' ', begin);
this->cbName.assign(str, begin, end - begin);
lua_getglobal(l, cbName.c_str());
cb = new LuaCallback(l, -1);
lua_pop(l, 1);
for (size_t begin = std::min(len, str.find_first_not_of(' ', end));
begin != std::string::npos;) {
end = std::min(len, str.find(' ', begin));
this->cbArgs.push_back(str.substr(begin, end - begin));
begin = str.find_first_not_of(' ', end);
}
}
//@}

View file

@ -44,10 +44,10 @@
Assert(unit.Anim.Anim == this);
Assert(!move);
move = ParseAnimInt(&unit, this->moveStr.c_str());
move = ParseAnimInt(unit, this->moveStr.c_str());
}
/* virtual */ void CAnimation_Move::Init(const char *s)
/* virtual */ void CAnimation_Move::Init(const char *s, lua_State *)
{
this->moveStr = s;
}

View file

@ -43,7 +43,7 @@
{
Assert(unit.Anim.Anim == this);
if (SyncRand() % 100 < ParseAnimInt(&unit, this->randomStr.c_str())) {
if (SyncRand() % 100 < ParseAnimInt(unit, this->randomStr.c_str())) {
unit.Anim.Anim = this->gotoLabel;
}
}
@ -51,7 +51,7 @@
/*
** s : "percent label"
*/
/* virtual */ void CAnimation_RandomGoto::Init(const char *s)
/* virtual */ void CAnimation_RandomGoto::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();

View file

@ -45,13 +45,13 @@
Assert(unit.Anim.Anim == this);
if ((SyncRand() >> 8) & 1) {
UnitRotate(unit, -ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, -ParseAnimInt(unit, this->rotateStr.c_str()));
} else {
UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
}
}
/* virtual */ void CAnimation_RandomRotate::Init(const char *s)
/* virtual */ void CAnimation_RandomRotate::Init(const char *s, lua_State *)
{
this->rotateStr = s;
}

View file

@ -54,7 +54,7 @@
/*
** s = "Sound1 [SoundN ...]"
*/
/* virtual */ void CAnimation_RandomSound::Init(const char *s)
/* virtual */ void CAnimation_RandomSound::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();

View file

@ -43,8 +43,8 @@
{
Assert(unit.Anim.Anim == this);
const int arg1 = ParseAnimInt(&unit, this->minWait.c_str());
const int arg2 = ParseAnimInt(&unit, this->maxWait.c_str());
const int arg1 = ParseAnimInt(unit, this->minWait.c_str());
const int arg2 = ParseAnimInt(unit, this->maxWait.c_str());
unit.Anim.Wait = arg1 + SyncRand() % (arg2 - arg1 + 1);
}
@ -52,7 +52,7 @@
/*
** s = "minWait MaxWait"
*/
/* virtual */ void CAnimation_RandomWait::Init(const char *s)
/* virtual */ void CAnimation_RandomWait::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();

View file

@ -66,11 +66,11 @@ void UnitRotate(CUnit &unit, int rotate)
const Vec2i pos = target.tilePos + target.Type->GetHalfTileSize() - unit.tilePos;
UnitHeadingFromDeltaXY(unit, pos);
} else {
UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
}
}
/* virtual */ void CAnimation_Rotate::Init(const char *s)
/* virtual */ void CAnimation_Rotate::Init(const char *s, lua_State *)
{
this->rotateStr = s;
}

View file

@ -42,13 +42,6 @@
#include <stdio.h>
//Modify types
#define MOD_ADD 1
#define MOD_SUB 2
#define MOD_MUL 3
#define MOD_DIV 4
#define MOD_MOD 5
/**
** Gets the player data.
**
@ -185,34 +178,46 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
const char *var = this->varStr.c_str();
const char *arg = this->argStr.c_str();
const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
int rop = ParseAnimInt(&unit, this->valueStr.c_str());
const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
int rop = ParseAnimInt(unit, this->valueStr.c_str());
int data = GetPlayerData(playerId, var, arg);
switch (this->mod) {
case MOD_ADD:
case modAdd:
data += rop;
break;
case MOD_SUB:
case modSub:
data -= rop;
break;
case MOD_MUL:
case modMul:
data *= rop;
break;
case MOD_DIV:
case modDiv:
if (!rop) {
fprintf(stderr, "Division by zero in AnimationSetPlayerVar\n");
Exit(1);
}
data /= rop;
break;
case MOD_MOD:
case modMod:
if (!rop) {
fprintf(stderr, "Division by zero in AnimationSetPlayerVar\n");
Exit(1);
}
data %= rop;
break;
case modAnd:
data &= rop;
break;
case modOr:
data |= rop;
break;
case modXor:
data ^= rop;
break;
case modNot:
data = !data;
break;
default:
data = rop;
}
@ -223,7 +228,7 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
/*
** s = "player var mod value [arg2]"
*/
/* virtual */ void CAnimation_SetPlayerVar::Init(const char *s)
/* virtual */ void CAnimation_SetPlayerVar::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();
@ -239,7 +244,29 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
const std::string modStr(str, begin, end - begin);
this->mod = atoi(modStr.c_str());
if (modStr == "=") {
this->mod = modSet;
} else if (modStr == "+=") {
this->mod = modAdd;
} else if (modStr == "-=") {
this->mod = modSub;
} else if (modStr == "*=") {
this->mod = modMul;
} else if (modStr == "/=") {
this->mod = modDiv;
} else if (modStr == "%=") {
this->mod = modMod;
} else if (modStr == "&=") {
this->mod = modAnd;
} else if (modStr == "|=") {
this->mod = modOr;
} else if (modStr == "^=") {
this->mod = modXor;
} else if (modStr == "!") {
this->mod = modNot;
} else {
this->mod = (SetVar_ModifyTypes)(atoi(modStr.c_str()));
}
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));

View file

@ -43,13 +43,6 @@
#include <stdio.h>
//Modify types
#define MOD_ADD 1
#define MOD_SUB 2
#define MOD_MUL 3
#define MOD_DIV 4
#define MOD_MOD 5
/* virtual */ void CAnimation_SetVar::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
@ -102,7 +95,7 @@
return;
}
const int rop = ParseAnimInt(&unit, this->valueStr.c_str());
const int rop = ParseAnimInt(unit, this->valueStr.c_str());
int value = 0;
if (!strcmp(next + 1, "Value")) {
value = goal->Variable[index].Value;
@ -116,16 +109,16 @@
value = goal->Variable[index].Value * 100 / goal->Variable[index].Max;
}
switch (this->mod) {
case MOD_ADD:
case modAdd:
value += rop;
break;
case MOD_SUB:
case modSub:
value -= rop;
break;
case MOD_MUL:
case modMul:
value *= rop;
break;
case MOD_DIV:
case modDiv:
if (!rop) {
fprintf(stderr, "Division by zero in AnimationSetVar\n");
Exit(1);
@ -133,7 +126,7 @@
}
value /= rop;
break;
case MOD_MOD:
case modMod:
if (!rop) {
fprintf(stderr, "Division by zero in AnimationSetVar\n");
Exit(1);
@ -141,6 +134,18 @@
}
value %= rop;
break;
case modAnd:
value &= rop;
break;
case modOr:
value |= rop;
break;
case modXor:
value ^= rop;
break;
case modNot:
value = !value;
break;
default:
value = rop;
}
@ -161,7 +166,7 @@
/*
** s = "var mod value [unitSlot]"
*/
/* virtual */ void CAnimation_SetVar::Init(const char *s)
/* virtual */ void CAnimation_SetVar::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();
@ -173,7 +178,30 @@
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
const std::string modStr(str, begin, end - begin);
this->mod = atoi(modStr.c_str());
if (modStr == "=") {
this->mod = modSet;
} else if (modStr == "+=") {
this->mod = modAdd;
} else if (modStr == "-=") {
this->mod = modSub;
} else if (modStr == "*=") {
this->mod = modMul;
} else if (modStr == "/=") {
this->mod = modDiv;
} else if (modStr == "%=") {
this->mod = modMod;
} else if (modStr == "&=") {
this->mod = modAnd;
} else if (modStr == "|=") {
this->mod = modOr;
} else if (modStr == "^=") {
this->mod = modXor;
} else if (modStr == "!") {
this->mod = modNot;
} else {
this->mod = (SetVar_ModifyTypes)(atoi(modStr.c_str()));
}
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));

View file

@ -49,7 +49,7 @@
}
}
/* virtual */ void CAnimation_Sound::Init(const char *s)
/* virtual */ void CAnimation_Sound::Init(const char *s, lua_State *)
{
this->sound.Name = s;
}

View file

@ -46,68 +46,17 @@
#include "pathfinder.h"
#include "unit.h"
//SpawnMissile flags
#define ANIM_SM_DAMAGE 1
#define ANIM_SM_TOTARGET 2
#define ANIM_SM_PIXEL 4
#define ANIM_SM_RELTARGET 8
#define ANIM_SM_RANGED 16
#define ANIM_SM_SETDIRECTION 32
/**
** Parse flags list in animation frame.
**
** @param unit Unit of the animation.
** @param parseflag Flag list to parse.
**
** @return The parsed value.
*/
static int ParseAnimFlags(CUnit &unit, const char *parseflag)
{
char s[100];
int flags = 0;
strcpy(s, parseflag);
char *cur = s;
char *next = s;
while (next) {
next = strchr(cur, '.');
if (next) {
*next = '\0';
++next;
}
if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
if (!strcmp(cur, "damage")) {
flags |= ANIM_SM_DAMAGE;
} else if (!strcmp(cur, "totarget")) {
flags |= ANIM_SM_TOTARGET;
} else if (!strcmp(cur, "pixel")) {
flags |= ANIM_SM_PIXEL;
} else if (!strcmp(cur, "reltarget")) {
flags |= ANIM_SM_RELTARGET;
} else if (!strcmp(cur, "ranged")) {
flags |= ANIM_SM_RANGED;
} else if (!strcmp(cur, "setdirection")) {
flags |= ANIM_SM_SETDIRECTION;
}
}
cur = next;
}
return flags;
}
/* virtual */ void CAnimation_SpawnMissile::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
Assert(unit.Anim.Anim == this);
const int startx = ParseAnimInt(&unit, this->startXStr.c_str());
const int starty = ParseAnimInt(&unit, this->startYStr.c_str());
const int destx = ParseAnimInt(&unit, this->destXStr.c_str());
const int desty = ParseAnimInt(&unit, this->destYStr.c_str());
const int flags = ParseAnimFlags(unit, this->flagsStr.c_str());
const int offsetnum = ParseAnimInt(&unit, this->offsetNumStr.c_str());
const CUnit *goal = flags & ANIM_SM_RELTARGET ? unit.CurrentOrder()->GetGoal() : &unit;
const int startx = ParseAnimInt(unit, this->startXStr.c_str());
const int starty = ParseAnimInt(unit, this->startYStr.c_str());
const int destx = ParseAnimInt(unit, this->destXStr.c_str());
const int desty = ParseAnimInt(unit, this->destYStr.c_str());
const SpawnMissile_Flags flags = (SpawnMissile_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
const int offsetnum = ParseAnimInt(unit, this->offsetNumStr.c_str());
const CUnit *goal = flags & SM_RelTarget ? unit.CurrentOrder()->GetGoal() : &unit;
const int dir = ((goal->Direction + NextDirection / 2) & 0xFF) / NextDirection;
const PixelPos moff = goal->Type->MissileOffsets[dir][!offsetnum ? 0 : offsetnum - 1];
PixelPos start;
@ -120,14 +69,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
if (!goal || goal->Destroyed) {
return;
}
if ((flags & ANIM_SM_PIXEL)) {
if ((flags & SM_Pixel)) {
start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + moff.x + startx;
start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + moff.y + starty;
} else {
start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2 + moff.x;
start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2 + moff.y;
}
if ((flags & ANIM_SM_TOTARGET)) {
if ((flags & SM_ToTarget)) {
CUnit *target = goal->CurrentOrder()->GetGoal();
if (!target || target->Destroyed) {
Assert(!mtype->AlwaysFire || mtype->Range);
@ -143,14 +92,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
dest = Map.TilePosToMapPixelPos_Center(order.GetGoalPos());
}
if (flags & ANIM_SM_PIXEL) {
if (flags & SM_Pixel) {
dest.x += destx;
dest.y += desty;
} else {
dest.x += destx * PixelTileSize.x;
dest.y += desty * PixelTileSize.y;
}
} else if (flags & ANIM_SM_PIXEL) {
} else if (flags & SM_Pixel) {
dest.x = target->GetMapPixelPosCenter().x + destx;
dest.y = target->GetMapPixelPosCenter().y + desty;
} else {
@ -159,7 +108,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
dest += target->Type->GetPixelSize() / 2;
}
} else {
if ((flags & ANIM_SM_PIXEL)) {
if ((flags & SM_Pixel)) {
dest.x = goal->GetMapPixelPosCenter().x + destx;
dest.y = goal->GetMapPixelPosCenter().y + desty;
} else {
@ -170,22 +119,22 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
}
Vec2i destTilePos = Map.MapPixelPosToTilePos(dest);
const int dist = goal->MapDistanceTo(destTilePos);
if ((flags & ANIM_SM_RANGED) && !(flags & ANIM_SM_PIXEL)
if ((flags & SM_Ranged) && !(flags & SM_Pixel)
&& dist > goal->Stats->Variables[ATTACKRANGE_INDEX].Max
&& dist < goal->Type->MinAttackRange) {
} else {
Missile *missile = MakeMissile(*mtype, start, dest);
if (flags & ANIM_SM_SETDIRECTION) {
if (flags & SM_SetDirection) {
PixelPos posd;
posd.x = Heading2X[goal->Direction / NextDirection];
posd.y = Heading2Y[goal->Direction / NextDirection];
missile->MissileNewHeadingFromXY(posd);
}
if (flags & ANIM_SM_DAMAGE) {
if (flags & SM_Damage) {
missile->SourceUnit = &unit;
}
CUnit *target = goal->CurrentOrder()->GetGoal();
if (flags & ANIM_SM_TOTARGET && target && target->IsAlive()) {
if (flags & SM_ToTarget && target && target->IsAlive()) {
missile->TargetUnit = target;
}
}
@ -194,7 +143,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
/*
** s = "missileType startX startY destX destY [flag1[.flagN]] [missileoffset]"
*/
/* virtual */ void CAnimation_SpawnMissile::Init(const char *s)
/* virtual */ void CAnimation_SpawnMissile::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();

View file

@ -37,6 +37,9 @@
#include "animation/animation_spawnunit.h"
#include "../ai/ai_local.h"
#include "commands.h"
#include "map.h"
#include "unit.h"
@ -104,10 +107,12 @@ found:
{
Assert(unit.Anim.Anim == this);
const int offX = ParseAnimInt(&unit, this->offXStr.c_str());
const int offY = ParseAnimInt(&unit, this->offYStr.c_str());
const int range = ParseAnimInt(&unit, this->rangeStr.c_str());
const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
const int offX = ParseAnimInt(unit, this->offXStr.c_str());
const int offY = ParseAnimInt(unit, this->offYStr.c_str());
const int range = ParseAnimInt(unit, this->rangeStr.c_str());
const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
CPlayer &player = Players[playerId];
const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY);
CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str());
@ -120,6 +125,17 @@ found:
if (target != NULL) {
target->tilePos = resPos;
target->Place(resPos);
if (flags & SU_Summoned) {
target->Summoned = 1;
}
if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) {
int force = unit.Player->Ai->Force.GetForce(unit);
if (force != -1) {
unit.Player->Ai->Force[force].Insert(*target);
target->GroupId = unit.GroupId;
CommandDefend(*target, unit, FlushCommands);
}
}
//DropOutOnSide(*target, LookingW, NULL);
} else {
DebugPrint("Unable to allocate Unit");
@ -128,9 +144,9 @@ found:
}
/*
** s = "unitType offX offY range player"
** s = "unitType offX offY range player [flags]"
*/
/* virtual */ void CAnimation_SpawnUnit::Init(const char *s)
/* virtual */ void CAnimation_SpawnUnit::Init(const char *s, lua_State *)
{
const std::string str(s);
const size_t len = str.size();
@ -154,6 +170,12 @@ found:
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
this->playerStr.assign(str, begin, end - begin);
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
if (begin != end) {
this->flagsStr.assign(str, begin, end - begin);
}
}
//@}

View file

@ -47,7 +47,7 @@
unit.Anim.Unbreakable = this->state;
}
/* virtual */ void CAnimation_Unbreakable::Init(const char *s)
/* virtual */ void CAnimation_Unbreakable::Init(const char *s, lua_State *)
{
if (!strcmp(s, "begin")) {
this->state = 1;

View file

@ -42,7 +42,7 @@
/* virtual */ void CAnimation_Wait::Action(CUnit &unit, int &/*move*/, int scale) const
{
Assert(unit.Anim.Anim == this);
unit.Anim.Wait = ParseAnimInt(&unit, this->wait.c_str()) << scale >> 8;
unit.Anim.Wait = ParseAnimInt(unit, this->wait.c_str()) << scale >> 8;
if (unit.Variable[SLOW_INDEX].Value) { // unit is slowed down
unit.Anim.Wait <<= 1;
}
@ -54,7 +54,7 @@
}
}
/* virtual */ void CAnimation_Wait::Init(const char *s)
/* virtual */ void CAnimation_Wait::Init(const char *s, lua_State *)
{
this->wait = s;
}

View file

@ -72,7 +72,22 @@ enum AnimationType {
AnimationIfVar,
AnimationSetVar,
AnimationSetPlayerVar,
AnimationDie
AnimationDie,
AnimationLuaCallback
};
//Modify types
enum SetVar_ModifyTypes {
modSet = 0, /// Set value to this
modAdd, /// Addition
modSub, /// Subtraction
modMul, /// Multiplication
modDiv, /// Division
modMod, /// Modulo
modAnd, /// Bitwise AND
modOr, /// Bitwise OR
modXor, /// Bitwise XOR
modNot, /// Bitwise NOT
};
class CAnimation
@ -83,7 +98,7 @@ public:
virtual ~CAnimation() {}
virtual void Action(CUnit &unit, int &move, int scale) const = 0;
virtual void Init(const char *s) {}
virtual void Init(const char *s, lua_State *l = NULL) {}
const AnimationType Type;
CAnimation *Next;
@ -152,7 +167,8 @@ extern int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scal
extern int UnitShowAnimation(CUnit &unit, const CAnimation *anim);
extern int ParseAnimInt(const CUnit *unit, const char *parseint);
extern int ParseAnimInt(const CUnit &unit, const char *parseint);
extern int ParseAnimFlags(const CUnit &unit, const char *parseflag);
extern void FindLabelLater(CAnimation **anim, const std::string &name);

View file

@ -41,7 +41,7 @@ public:
CAnimation_Attack() : CAnimation(AnimationAttack) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
};

View file

@ -41,7 +41,7 @@ public:
CAnimation_Die() : CAnimation(AnimationDie) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string DeathType;

View file

@ -41,7 +41,7 @@ public:
CAnimation_ExactFrame() : CAnimation(AnimationExactFrame) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
int ParseAnimInt(const CUnit *unit) const;

View file

@ -41,7 +41,7 @@ public:
CAnimation_Frame() : CAnimation(AnimationFrame) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
int ParseAnimInt(const CUnit *unit) const;
private:

View file

@ -41,7 +41,7 @@ public:
CAnimation_Goto() : CAnimation(AnimationGoto), gotoLabel(NULL) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
CAnimation *gotoLabel;

View file

@ -41,7 +41,7 @@ public:
CAnimation_IfVar() : CAnimation(AnimationIfVar), binOpFunc(NULL), gotoLabel(NULL) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
typedef bool BinOpFunc(int lhs, int rhs);

View file

@ -40,7 +40,7 @@ public:
CAnimation_Label() : CAnimation(AnimationLabel) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
};
//@}

View file

@ -0,0 +1,57 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name animation_luacallback.h - The animation LuaCallback headerfile. */
//
// (c) Copyright 2013 by cybermind
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; only version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
#ifndef ANIMATION_LUACALLBACK_H
#define ANIMATION_LUACALLBACK_H
//@{
#include <string>
#include "animation.h"
#include "luacallback.h"
class CAnimation_LuaCallback : public CAnimation
{
public:
CAnimation_LuaCallback() : CAnimation(AnimationLuaCallback), cb(NULL) {}
~CAnimation_LuaCallback() { delete cb; }
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s, lua_State *l);
private:
LuaCallback *cb;
std::string cbName;
std::vector<std::string> cbArgs;
};
//@}
#endif // ANIMATION_LUACALLBACK_H

View file

@ -41,7 +41,7 @@ public:
CAnimation_Move() : CAnimation(AnimationMove) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string moveStr;

View file

@ -41,7 +41,7 @@ public:
CAnimation_RandomGoto() : CAnimation(AnimationRandomGoto), gotoLabel(NULL) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string randomStr;

View file

@ -41,7 +41,7 @@ public:
CAnimation_RandomRotate() : CAnimation(AnimationRandomRotate) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string rotateStr;

View file

@ -43,7 +43,7 @@ public:
CAnimation_RandomSound() : CAnimation(AnimationRandomSound) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
void MapSound();
private:

View file

@ -41,7 +41,7 @@ public:
CAnimation_RandomWait() : CAnimation(AnimationRandomWait) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string minWait;

View file

@ -41,7 +41,7 @@ public:
CAnimation_Rotate() : CAnimation(AnimationRotate) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string rotateStr;

View file

@ -41,10 +41,10 @@ public:
CAnimation_SetPlayerVar() : CAnimation(AnimationSetPlayerVar) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
int mod;
SetVar_ModifyTypes mod;
std::string playerStr;
std::string varStr;
std::string argStr;

View file

@ -41,10 +41,10 @@ public:
CAnimation_SetVar() : CAnimation(AnimationSetVar) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
int mod;
SetVar_ModifyTypes mod;
std::string varStr;
std::string valueStr;
std::string unitSlotStr;

View file

@ -42,7 +42,7 @@ public:
CAnimation_Sound() : CAnimation(AnimationSound) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
void MapSound();

View file

@ -35,13 +35,25 @@
#include <string>
#include "animation.h"
//SpawnMissile flags
enum SpawnMissile_Flags {
SM_None = 0, /// Clears all flags
SM_Damage = 1, /// Missile deals damage to units
SM_ToTarget = 2, /// Missile is directed to unit's target
SM_Pixel = 4, /// Missile's offsets are calculated in pixels rather than tiles
SM_RelTarget = 8, /// All calculations are relative to unit's target
SM_Ranged = 16, /// Missile can't be shot if current range between unit and it's target
/// is bigger than unit's attack range
SM_SetDirection = 32 /// Missile takes the same direction as spawner
};
class CAnimation_SpawnMissile : public CAnimation
{
public:
CAnimation_SpawnMissile() : CAnimation(AnimationSpawnMissile) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string missileTypeStr;

View file

@ -35,13 +35,20 @@
#include <string>
#include "animation.h"
//SpawnUnit flags
enum SpawnUnit_Flags {
SU_None = 0, /// Clears all flags
SU_Summoned = 1, /// Unit is marked as "summoned"
SU_JoinToAIForce = 2 /// Unit is included into spawner's AI force, if available
};
class CAnimation_SpawnUnit : public CAnimation
{
public:
CAnimation_SpawnUnit() : CAnimation(AnimationSpawnUnit) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string unitTypeStr;
@ -49,6 +56,7 @@ private:
std::string offYStr;
std::string rangeStr;
std::string playerStr;
std::string flagsStr;
};
//@}

View file

@ -41,7 +41,7 @@ public:
CAnimation_Unbreakable() : CAnimation(AnimationUnbreakable), state(0) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
int state;

View file

@ -41,7 +41,7 @@ public:
CAnimation_Wait() : CAnimation(AnimationWait) {}
virtual void Action(CUnit &unit, int &move, int scale) const;
virtual void Init(const char *s);
virtual void Init(const char *s, lua_State *l);
private:
std::string wait;

View file

@ -77,8 +77,8 @@ public:
class CParticle
{
public:
CParticle(CPosition position) :
pos(position), destroyed(false)
CParticle(CPosition position, int drawlevel = 0) :
pos(position), destroyed(false), drawLevel(drawlevel)
{}
virtual ~CParticle() {}
@ -91,16 +91,20 @@ public:
virtual CParticle *clone() = 0;
int getDrawLevel() const { return drawLevel; }
void setDrawLevel(int value) { drawLevel = value; }
protected:
CPosition pos;
bool destroyed;
int drawLevel;
};
class StaticParticle : public CParticle
{
public:
StaticParticle(CPosition position, GraphicAnimation *flame);
StaticParticle(CPosition position, GraphicAnimation *flame, int drawlevel = 0);
virtual ~StaticParticle();
virtual bool isVisible(const CViewport &vp) const;
@ -120,13 +124,17 @@ public:
CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation,
GraphicAnimation *destroyAnimation,
int minVelocity = 0, int maxVelocity = 400,
int minTrajectoryAngle = 77, int maxTTL = 0);
int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
virtual ~CChunkParticle();
virtual bool isVisible(const CViewport &vp) const;
virtual void draw();
virtual void update(int ticks);
virtual CParticle *clone();
int getSmokeDrawLevel() const { return smokeDrawLevel; }
int getDestroyDrawLevel() const { return destroyDrawLevel; }
void setSmokeDrawLevel(int value) { smokeDrawLevel = value; }
void setDestroyDrawLevel(int value) { destroyDrawLevel = value; }
protected:
CPosition initialPos;
@ -140,6 +148,8 @@ protected:
int maxVelocity;
int minTrajectoryAngle;
float height;
int smokeDrawLevel;
int destroyDrawLevel;
GraphicAnimation *debrisAnimation;
GraphicAnimation *smokeAnimation;
GraphicAnimation *destroyAnimation;
@ -155,7 +165,7 @@ protected:
class CSmokeParticle : public CParticle
{
public:
CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f);
CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f, int drawlevel = 0);
virtual ~CSmokeParticle();
virtual bool isVisible(const CViewport &vp) const;
@ -174,7 +184,7 @@ protected:
class CRadialParticle : public CParticle
{
public:
CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed);
CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel = 0);
virtual ~CRadialParticle();
virtual bool isVisible(const CViewport &vp) const;
@ -199,7 +209,9 @@ public:
static void init();
static void exit();
void draw(const CViewport &vp);
void prepareToDraw(const CViewport &vp, std::vector<CParticle *> &table);
void endDraw();
void update();
void add(CParticle *particle);

View file

@ -41,13 +41,14 @@
class Spell_Capture : public SpellActionType
{
public:
Spell_Capture() : SacrificeEnable(0), Damage(0), DamagePercent(0) {};
Spell_Capture() : SacrificeEnable(false), JoinToAIForce(false), Damage(0), DamagePercent(0) {};
virtual int Cast(CUnit &caster, const SpellType &spell,
CUnit *target, const Vec2i &goalPos);
virtual void Parse(lua_State *l, int startIndex, int endIndex);
private:
char SacrificeEnable; /// true if the caster dies after casting.
bool SacrificeEnable; /// true if the caster dies after casting.
bool JoinToAIForce; /// if true, captured unit is joined into caster's AI force, if available
int Damage; /// damage the spell does if unable to caputre
int DamagePercent; /// percent the target must be damaged for a
/// capture to suceed.

View file

@ -41,7 +41,8 @@
class Spell_Summon : public SpellActionType
{
public:
Spell_Summon() : SpellActionType(1), UnitType(NULL), TTL(0), RequireCorpse(0) {};
Spell_Summon() : SpellActionType(1), UnitType(NULL), TTL(0),
RequireCorpse(false), JoinToAiForce(false) {};
virtual int Cast(CUnit &caster, const SpellType &spell,
CUnit *target, const Vec2i &goalPos);
virtual void Parse(lua_State *l, int startIndex, int endIndex);
@ -50,6 +51,7 @@ private:
CUnitType *UnitType; /// Type of unit to be summoned.
int TTL; /// Time to live for summoned unit. 0 means infinite
int RequireCorpse; /// Corpse consumed while summoning.
bool JoinToAiForce; /// if true, captured unit is joined into caster's AI force, if available
};

View file

@ -40,15 +40,10 @@
class Spell_Teleport : public SpellActionType
{
public:
Spell_Teleport() : SpellActionType(1), UnitType(NULL), TTL(0), RequireCorpse(0) {};
Spell_Teleport() : SpellActionType(0) {}
virtual int Cast(CUnit &caster, const SpellType &spell,
CUnit *target, const Vec2i &goalPos);
virtual void Parse(lua_State *l, int startIndex, int endIndex);
private:
CUnitType *UnitType; /// Type of unit to be summoned.
int TTL; /// Time to live for summoned unit. 0 means infinite
int RequireCorpse; /// Corpse consumed while summoning.
};

View file

@ -224,6 +224,7 @@ public:
bool IsCasterOnly() const {
return !Range && Target == TargetSelf;
}
bool ForceUseAnimation;
};

View file

@ -339,21 +339,23 @@ public:
int ResourcesHeld; /// Resources Held by a unit
unsigned char DamagedType; /// Index of damage type of unit which damaged this unit
unsigned long Attacked; /// gamecycle unit was last attacked
unsigned Blink : 3; /// Let selection rectangle blink
unsigned Moving : 1; /// The unit is moving
unsigned ReCast : 1; /// Recast again next cycle
unsigned AutoRepair : 1; /// True if unit tries to repair on still action.
unsigned long Attacked; /// gamecycle unit was last attacked
unsigned Blink : 3; /// Let selection rectangle blink
unsigned Moving : 1; /// The unit is moving
unsigned ReCast : 1; /// Recast again next cycle
unsigned AutoRepair : 1; /// True if unit tries to repair on still action.
unsigned Burning : 1; /// unit is burning
unsigned Destroyed : 1; /// unit is destroyed pending reference
unsigned Removed : 1; /// unit is removed (not on map)
unsigned Selected : 1; /// unit is selected
unsigned Burning : 1; /// unit is burning
unsigned Destroyed : 1; /// unit is destroyed pending reference
unsigned Removed : 1; /// unit is removed (not on map)
unsigned Selected : 1; /// unit is selected
unsigned Constructed : 1; /// Unit is in construction
unsigned Active : 1; /// Unit is active for AI
unsigned Boarded : 1; /// Unit is on board a transporter.
unsigned CacheLock : 1; /// Unit is on lock by unitcache operations.
unsigned CacheLock : 1; /// Unit is on lock by unitcache operations.
unsigned Summoned : 1; /// Unit is summoned using spells.
unsigned TeamSelected; /// unit is selected by a team member.
CPlayer *RescuedFrom; /// The original owner of a rescued unit.
@ -417,13 +419,15 @@ class CPreference
public:
CPreference() : ShowSightRange(false), ShowReactionRange(false),
ShowAttackRange(false), ShowMessages(true),
BigScreen(false), ShowOrders(0), ShowNameDelay(0), ShowNameTime(0) {};
BigScreen(false), PauseOnLeave(true), ShowOrders(0), ShowNameDelay(0),
ShowNameTime(0) {};
bool ShowSightRange; /// Show sight range.
bool ShowReactionRange; /// Show reaction range.
bool ShowAttackRange; /// Show attack range.
bool ShowMessages; /// Show messages.
bool BigScreen; /// If true, shows the big screen(without panels)
bool PauseOnLeave; /// If true, game pauses when cursor is gone
int ShowOrders; /// How many second show orders of unit on map.
int ShowNameDelay; /// How many cycles need to wait until unit's name popup will appear.

View file

@ -281,7 +281,7 @@ extern CUnit *FindIdleWorker(const CPlayer &player, const CUnit *last);
extern bool FindTerrainType(int movemask, int resmask, int range,
const CPlayer &player, const Vec2i &startPos, Vec2i *pos);
extern void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units);
extern void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units, bool everybody = false);
/// Find all units of this type of the player
extern void FindPlayerUnitsByType(const CPlayer &player, const CUnitType &type, std::vector<CUnit *> &units);

View file

@ -467,6 +467,10 @@ public:
LuaCallback *OnHit; /// lua function called when unit is hit
LuaCallback *OnEachCycle; /// lua function called every cycle
LuaCallback *OnEachSecond; /// lua function called every second
LuaCallback *OnInit; /// lua function called on unit init
int TeleportCost; /// mana used for teleportation
MissileConfig TeleportEffect; /// missile created when teleported
mutable std::string DamageType; /// DamageType (used for extra death animations and impacts)

View file

@ -294,8 +294,6 @@ public:
int getPercent() const;
private:
int width; /// width of the widget.
int height; /// height of the widget.
std::string caption; /// caption of the widget.
unsigned int percent; /// percent value of the widget.
};

View file

@ -332,25 +332,68 @@ void CViewport::Draw() const
CurrentViewport = this;
{
// Now we need to sort units, missiles, particles by draw level and draw them
std::vector<CUnit *> unittable;
std::vector<Missile *> missiletable;
std::vector<CParticle *> particletable;
// We find and sort units after draw level.
FindAndSortUnits(*this, unittable);
const size_t nunits = unittable.size();
FindAndSortMissiles(*this, missiletable);
const size_t nmissiles = missiletable.size();
ParticleManager.prepareToDraw(*this, particletable);
const size_t nparticles = particletable.size();
size_t i = 0;
size_t j = 0;
size_t k = 0;
while (i < nunits && j < nmissiles) {
if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) {
unittable[i]->Draw(*this);
++i;
} else {
missiletable[j]->DrawMissile(*this);
++j;
}
while ((i < nunits && j < nmissiles) || (i < nunits && k < nparticles)
|| (j < nmissiles && k < nparticles)) {
if (i == nunits) {
if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
missiletable[j]->DrawMissile(*this);
++j;
} else {
particletable[k]->draw();
++k;
}
} else if (j == nmissiles) {
if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
unittable[i]->Draw(*this);
++i;
} else {
particletable[k]->draw();
++k;
}
} else if (k == nparticles) {
if (unittable[i]->Type->DrawLevel < missiletable[j]->Type->DrawLevel) {
unittable[i]->Draw(*this);
++i;
} else {
missiletable[j]->DrawMissile(*this);
++j;
}
} else {
if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) {
if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
unittable[i]->Draw(*this);
++i;
} else {
particletable[k]->draw();
++k;
}
} else {
if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) {
missiletable[j]->DrawMissile(*this);
++j;
} else {
particletable[k]->draw();
++k;
}
}
}
}
for (; i < nunits; ++i) {
unittable[i]->Draw(*this);
@ -358,10 +401,12 @@ void CViewport::Draw() const
for (; j < nmissiles; ++j) {
missiletable[j]->DrawMissile(*this);
}
for (; k < nparticles; ++k) {
particletable[k]->draw();
}
ParticleManager.endDraw();
}
ParticleManager.draw(*this);
this->DrawMapFogOfWar();
//

View file

@ -46,8 +46,8 @@ static inline float deg2rad(int degrees)
CChunkParticle::CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation,
GraphicAnimation *destroyAnimation,
int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL) :
CParticle(position), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0),
int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL, int drawlevel) :
CParticle(position, drawlevel), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0),
age(0), height(0.f)
{
float radians = deg2rad(MyRand() % 360);
@ -112,7 +112,7 @@ void CChunkParticle::update(int ticks)
if (destroyAnimation) {
CPosition p(pos.x, calculateScreenPos(pos.y, height));
GraphicAnimation *destroyanimation = destroyAnimation->clone();
StaticParticle *destroy = new StaticParticle(p, destroyanimation);
StaticParticle *destroy = new StaticParticle(p, destroyanimation, destroyDrawLevel);
ParticleManager.add(destroy);
}
@ -126,7 +126,7 @@ void CChunkParticle::update(int ticks)
if (age > nextSmokeTicks) {
CPosition p(pos.x, calculateScreenPos(pos.y, height));
GraphicAnimation *smokeanimation = smokeAnimation->clone();
CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation);
CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation, 0, -22.0f, smokeDrawLevel);
ParticleManager.add(smoke);
nextSmokeTicks += MyRand() % randSmokeTicks + minSmokeTicks;
@ -151,7 +151,10 @@ void CChunkParticle::update(int ticks)
CParticle *CChunkParticle::clone()
{
return new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL);
CChunkParticle *particle = new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL, drawLevel);
particle->smokeDrawLevel = smokeDrawLevel;
particle->destroyDrawLevel = destroyDrawLevel;
return particle;
}
//@}

View file

@ -34,6 +34,8 @@
#include "ui.h"
#include "video.h"
#include <algorithm>
CParticleManager ParticleManager;
@ -70,17 +72,27 @@ void CParticleManager::clear()
new_particles.clear();
}
void CParticleManager::draw(const CViewport &vp)
static inline bool DrawLevelCompare(const CParticle *lhs, const CParticle *rhs)
{
return lhs->getDrawLevel() < rhs->getDrawLevel();
}
void CParticleManager::prepareToDraw(const CViewport &vp, std::vector<CParticle *> &table)
{
this->vp = &vp;
std::vector<CParticle *>::iterator i;
for (i = particles.begin(); i != particles.end(); ++i) {
if ((*i)->isVisible(vp)) {
(*i)->draw();
for (std::vector<CParticle *>::iterator it = particles.begin(); it != particles.end(); ++it) {
CParticle &particle = **it;
if (particle.isVisible(vp)) {
table.push_back(&particle);
}
}
std::sort(table.begin(), table.end(), DrawLevelCompare);
}
void CParticleManager::endDraw()
{
this->vp = NULL;
}

View file

@ -34,8 +34,8 @@
#include "stratagus.h"
#include "particle.h"
CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed) :
CParticle(position)
CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel) :
CParticle(position, drawlevel)
{
Assert(animation);
this->animation = animation->clone();
@ -76,7 +76,7 @@ void CRadialParticle::update(int ticks)
CParticle *CRadialParticle::clone()
{
CParticle *p = new CRadialParticle(pos, animation, maxSpeed);
CParticle *p = new CRadialParticle(pos, animation, maxSpeed, drawLevel);
return p;
}

View file

@ -36,8 +36,8 @@
CSmokeParticle::CSmokeParticle(CPosition position, GraphicAnimation *smoke,
float speedx, float speedy) :
CParticle(position)
float speedx, float speedy, int drawlevel) :
CParticle(position, drawlevel)
{
Assert(smoke);
this->puff = smoke->clone();
@ -77,7 +77,7 @@ void CSmokeParticle::update(int ticks)
CParticle *CSmokeParticle::clone()
{
return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y);
return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y, drawLevel);
}
//@}

View file

@ -33,8 +33,8 @@
#include "particle.h"
StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation) :
CParticle(position)
StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel) :
CParticle(position, drawlevel)
{
Assert(animation);
this->animation = animation->clone();
@ -66,7 +66,7 @@ void StaticParticle::update(int ticks)
CParticle *StaticParticle::clone()
{
CParticle *p = new StaticParticle(pos, animation);
CParticle *p = new StaticParticle(pos, animation, drawLevel);
return p;
}

View file

@ -438,14 +438,7 @@ int SetChannelStereo(int channel, int stereo)
stereo = Channels[channel].Stereo;
} else {
SDL_LockAudio();
if (stereo > 127) {
stereo = 127;
} else if (stereo < -128) {
stereo = -128;
}
Channels[channel].Stereo = stereo;
SDL_UnlockAudio();
}
return stereo;

View file

@ -333,6 +333,9 @@ static int CclDefineSpell(lua_State *l)
} else if (!strcmp(value, "repeat-cast")) {
spell->RepeatCast = 1;
--i;
} else if (!strcmp(value, "force-use-animation")) {
spell->ForceUseAnimation = true;
--i;
} else if (!strcmp(value, "target")) {
value = LuaToString(l, i + 1);
if (!strcmp(value, "self")) {

View file

@ -34,6 +34,9 @@
#include "spell/spell_capture.h"
#include "../ai/ai_local.h"
#include "commands.h"
#include "game.h"
#include "script.h"
#include "unit.h"
@ -44,7 +47,9 @@
const char *value = LuaToString(l, -1, j + 1);
++j;
if (!strcmp(value, "sacrifice")) {
this->SacrificeEnable = 1;
this->SacrificeEnable = true;
} else if (!strcmp(value, "join-to-ai-force")) {
this->JoinToAIForce = true;
} else if (!strcmp(value, "damage")) {
this->Damage = LuaToNumber(l, -1, j + 1);
} else if (!strcmp(value, "percent")) {
@ -79,8 +84,7 @@
if (this->SacrificeEnable) {
// No corpse.
caster.Remove(NULL);
UnitLost(caster);
UnitClearOrders(caster);
caster.Release();
}
return 1;
}
@ -103,15 +107,24 @@
caster.Variable[KILL_INDEX].Enable = 1;
}
target->ChangeOwner(*caster.Player);
UnitClearOrders(*target);
if (this->JoinToAIForce && caster.Player->AiEnabled) {
int force = caster.Player->Ai->Force.GetForce(caster);
if (force != -1) {
caster.Player->Ai->Force[force].Insert(*target);
target->GroupId = caster.GroupId;
CommandDefend(*target, caster, FlushCommands);
}
}
if (this->SacrificeEnable) {
// No corpse.
caster.Remove(NULL);
UnitLost(caster);
UnitClearOrders(caster);
caster.Release();
} else {
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
}
UnitClearOrders(*target);
return 0;
}

View file

@ -85,6 +85,7 @@
} else {
portal = MakeUnitAndPlace(goalPos, *this->PortalType,
CurrentPlayer ? caster.Player : &Players[PlayerNumNeutral]);
portal->Summoned = 1;
}
portal->TTL = GameCycle + this->TTL;
// Goal is used to link to destination circle of power

View file

@ -36,6 +36,8 @@
#include "spell/spell_summon.h"
#include "../ai/ai_local.h"
#include "actions.h"
#include "commands.h"
#include "script.h"
@ -57,7 +59,10 @@
} else if (!strcmp(value, "time-to-live")) {
this->TTL = LuaToNumber(l, -1, j + 1);
} else if (!strcmp(value, "require-corpse")) {
this->RequireCorpse = 1;
this->RequireCorpse = true;
--j;
} else if (!strcmp(value, "join-to-ai-force")) {
this->JoinToAiForce = true;
--j;
} else {
LuaError(l, "Unsupported summon tag: %s" _C_ value);
@ -124,6 +129,8 @@ public:
if (target != NULL) {
target->tilePos = pos;
DropOutOnSide(*target, LookingW, NULL);
// To avoid defending summoned unit for AI
target->Summoned = 1;
//
// set life span. ttl=0 results in a permanent unit.
//
@ -131,13 +138,13 @@ public:
target->TTL = GameCycle + ttl;
}
// To avoid defending summoned unit for AI
if (caster.Player->AiEnabled) {
if (caster.GroupId) {
// Insert summoned unit to AI force so it will help them in battle
if (this->JoinToAiForce && caster.Player->AiEnabled) {
int force = caster.Player->Ai->Force.GetForce(caster);
if (force != -1) {
caster.Player->Ai->Force[force].Insert(*target);
target->GroupId = caster.GroupId;
CommandDefend(*target, caster, FlushCommands);
} else {
target->GroupId = -1;
}
}

View file

@ -485,7 +485,7 @@ SpellType::SpellType(int slot, const std::string &ident) :
Ident(ident), Slot(slot), Target(), Action(),
Range(0), ManaCost(0), RepeatCast(0),
DependencyId(-1), Condition(NULL),
AutoCast(NULL), AICast(NULL)
AutoCast(NULL), AICast(NULL), ForceUseAnimation(false)
{
memset(Costs, 0, sizeof(Costs));
}

View file

@ -16,30 +16,35 @@ class GraphicAnimation
class CParticle
{
virtual CParticle* clone();
void setDrawLevel(int value);
};
class StaticParticle : public CParticle
{
public:
StaticParticle(CPosition position, GraphicAnimation *animation);
StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel = 0);
};
class CChunkParticle : public CParticle
{
public:
CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0);
CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
int getSmokeDrawLevel() const;
int getDestroyDrawLevel() const;
void setSmokeDrawLevel(int value);
void setDestroyDrawLevel(int value);
};
class CSmokeParticle : public CParticle
{
public:
CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0);
CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0, int drawlevel = 0);
};
class CRadialParticle : public CParticle
{
public:
CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed);
CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed, int drawlevel = 0);
};
class CParticleManager

View file

@ -22,6 +22,7 @@ class CPreference
bool ShowAttackRange;
bool ShowMessages;
bool BigScreen;
bool PauseOnLeave;
unsigned int ShowOrders;
unsigned int ShowNameDelay;

View file

@ -847,14 +847,17 @@ void UpdateStatusLineForButton(const ButtonAction &button)
*/
bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction)
{
bool res = false;
if (buttonaction.Allowed) {
return buttonaction.Allowed(unit, buttonaction);
res = buttonaction.Allowed(unit, buttonaction);
if (!res) {
return false;
} else {
res = false;
}
}
bool res = false;
// FIXME: we have to check and if these unit buttons are available
// i.e. if button action is ButtonTrain for example check if
// required unit is not restricted etc...
// Check button-specific cases
switch (buttonaction.Action) {
case ButtonStop:
case ButtonStandGround:

View file

@ -153,7 +153,7 @@ static void UiDrawLifeBar(const CUnit &unit, int x, int y)
}
f = (f * (unit.Type->Icon.Icon->G->Width)) / 100;
Video.FillRectangleClip(color, x + 1, y + 1, f - 2, 5);
Video.FillRectangleClip(color, x + 1, y + 1, f > 1 ? f - 2 : 0, 5);
}
}

View file

@ -377,6 +377,9 @@ static int CclUnit(lua_State *l)
} else if (!strcmp(value, "selected")) {
unit->Selected = 1;
--j;
} else if (!strcmp(value, "summoned")) {
unit->Summoned = 1;
--j;
} else if (!strcmp(value, "rescued-from")) {
unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)];
} else if (!strcmp(value, "seen-by-player")) {

View file

@ -551,6 +551,11 @@ static int CclDefineUnitType(lua_State *l)
type->ExplodeWhenKilled = 1;
type->Explosion.Name = LuaToString(l, -1);
type->Explosion.Missile = NULL;
} else if (!strcmp(value, "TeleportCost")) {
type->TeleportCost = LuaToNumber(l, -1);
} else if (!strcmp(value, "TeleportEffect")) {
type->TeleportEffect.Name = LuaToString(l, -1);
type->TeleportEffect.Missile = NULL;
} else if (!strcmp(value, "DeathExplosion")) {
type->DeathExplosion = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnHit")) {
@ -559,6 +564,8 @@ static int CclDefineUnitType(lua_State *l)
type->OnEachCycle = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnEachSecond")) {
type->OnEachSecond = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnInit")) {
type->OnInit = new LuaCallback(l, -1);
} else if (!strcmp(value, "Type")) {
value = LuaToString(l, -1);
if (!strcmp(value, "land")) {

View file

@ -453,6 +453,7 @@ void CUnit::Init()
Moving = 0;
ReCast = 0;
CacheLock = 0;
Summoned = 0;
memset(&Anim, 0, sizeof(Anim));
CurrentResource = 0;
Orders.clear();
@ -738,6 +739,12 @@ CUnit *MakeUnit(const CUnitType &type, CPlayer *player)
unit->AssignToPlayer(*player);
}
if (unit->Type->OnInit) {
unit->Type->OnInit->pushPreamble();
unit->Type->OnInit->pushInteger(UnitNumber(*unit));
unit->Type->OnInit->run();
}
// fancy buildings: mirror buildings (but shadows not correct)
if (type.Building && FancyBuildings
&& unit->Type->NoRandomPlacing == false && (MyRand() & 1) != 0) {

View file

@ -310,7 +310,6 @@ public:
resinfo(*worker.Type->ResInfo[resource]),
deposit(deposit),
movemask(worker.Type->MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)),
resource(resource),
maxRange(maxRange),
check_usage(check_usage),
res_finder(resource, 1),
@ -348,7 +347,6 @@ private:
const ResourceInfo &resinfo;
const CUnit *deposit;
unsigned int movemask;
int resource;
int maxRange;
bool check_usage;
CResourceFinder res_finder;
@ -511,15 +509,16 @@ CUnit *FindIdleWorker(const CPlayer &player, const CUnit *last)
/**
** Find all units of type.
**
** @param type type of unit requested
** @param units array in which we have to store the units
** @param type type of unit requested
** @param units array in which we have to store the units
** @param everybody if true, include all units
*/
void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units)
void FindUnitsByType(const CUnitType &type, std::vector<CUnit *> &units, bool everybody)
{
for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it) {
CUnit &unit = **it;
if (unit.Type == &type && !unit.IsUnusable()) {
if (unit.Type == &type && !unit.IsUnusable(everybody)) {
units.push_back(&unit);
}
}
@ -1008,9 +1007,7 @@ private:
}
// don't consider small damages...
if (sgood < 20) {
sgood = 20;
}
sgood = std::max(sgood, 20);
int cost = sbad / sgood;
if (cost > best_cost) {

View file

@ -177,6 +177,9 @@ void SaveUnit(const CUnit &unit, CFile &file)
if (unit.Selected) {
file.printf(" \"selected\",");
}
if (unit.Summoned) {
file.printf(" \"summoned\",");
}
if (unit.RescuedFrom) {
file.printf(" \"rescued-from\", %d,", unit.RescuedFrom->Index);
}

View file

@ -611,7 +611,8 @@ CUnitType::CUnitType() :
Slot(0), Width(0), Height(0), OffsetX(0), OffsetY(0), DrawLevel(0),
ShadowWidth(0), ShadowHeight(0), ShadowOffsetX(0), ShadowOffsetY(0),
Animations(NULL), StillFrame(0),
DeathExplosion(NULL), OnHit(NULL), OnEachCycle(NULL), OnEachSecond(NULL),
DeathExplosion(NULL), OnHit(NULL), OnEachCycle(NULL), OnEachSecond(NULL), OnInit(NULL),
TeleportCost(0),
CorpseType(NULL), Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
BoxWidth(0), BoxHeight(0), BoxOffsetX(0), BoxOffsetY(0), NumDirections(0),
MinAttackRange(0), ReactRangeComputer(0), ReactRangePerson(0), Priority(0),
@ -649,6 +650,7 @@ CUnitType::~CUnitType()
delete OnHit;
delete OnEachCycle;
delete OnEachSecond;
delete OnInit;
BoolFlag.clear();
@ -1123,6 +1125,7 @@ void LoadUnitTypes()
// Lookup missiles.
type.Missile.MapMissile();
type.Explosion.MapMissile();
type.TeleportEffect.MapMissile();
// Lookup impacts
for (int i = 0; i < ANIMATIONS_DEATHTYPES + 2; ++i) {

View file

@ -597,7 +597,7 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
if (varModified) {
std::vector<CUnit *> unitupgrade;
FindUnitsByType(*UnitTypes[z], unitupgrade);
FindUnitsByType(*UnitTypes[z], unitupgrade, true);
for (size_t j = 0; j != unitupgrade.size(); ++j) {
CUnit &unit = *unitupgrade[j];

View file

@ -94,6 +94,7 @@
#include "sound_server.h"
#include "translate.h"
#include "ui.h"
#include "unit.h"
#include "video.h"
#include "widgets.h"
@ -860,7 +861,7 @@ static void SdlDoEvent(const EventCallback &callbacks, SDL_Event &event)
}
InMainWindow = (event.active.gain != 0);
}
if (event.active.state & SDL_APPACTIVE || SDL_GetAppState() & SDL_APPACTIVE) {
if (Preference.PauseOnLeave && (event.active.state & SDL_APPACTIVE || SDL_GetAppState() & SDL_APPACTIVE)) {
static bool DoTogglePause = false;
if (IsSDLWindowVisible && !event.active.gain) {

View file

@ -53,6 +53,7 @@ void FillCustomValue(CServerSetup *obj)
obj->GameTypeOption = 52;
obj->Difficulty = 54;
obj->MapRichness = 56;
obj->Opponents = 58;
for (int i = 0; i != PlayerMax; ++i) {
obj->CompOpt[i] = i + 1;
}