[+] Added OnEachCycle and OnEachSecond lua callbacks in unittype to make some action on each cycle or on each second
[*] Cleanup: - check if we can save the order before clonning it - removed unused unit.State [-] More correct spell checking for AI magic [-] Fixed UnitOnScreen for shared vision
This commit is contained in:
parent
812f065687
commit
ca8d2ea568
29 changed files with 190 additions and 137 deletions
|
@ -327,9 +327,11 @@ bool COrder_Attack::CheckForTargetInRange(CUnit &unit)
|
|||
if (goal) {
|
||||
COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos);
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
if (unit.CanStoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
} else {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
this->SetGoal(goal);
|
||||
this->MinRange = unit.Type->MinAttackRange;
|
||||
|
@ -344,11 +346,12 @@ bool COrder_Attack::CheckForTargetInRange(CUnit &unit)
|
|||
|
||||
if (newTarget && newTarget->IsAgressive()
|
||||
&& ThreatCalculate(unit, *newTarget) < ThreatCalculate(unit, *goal)) {
|
||||
COrder *savedOrder = this->Clone();
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
COrder *savedOrder = NULL;
|
||||
if (unit.CanStoreOrder(this)) {
|
||||
savedOrder = this->Clone();
|
||||
}
|
||||
if (savedOrder != NULL) {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
this->SetGoal(newTarget);
|
||||
this->goalPos = newTarget->tilePos;
|
||||
|
@ -396,7 +399,6 @@ void COrder_Attack::MoveToTarget(CUnit &unit)
|
|||
if (goal
|
||||
&& unit.MapDistanceTo(*goal) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
|
||||
// Reached another unit, now attacking it
|
||||
unit.State = 0;
|
||||
const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
|
||||
UnitHeadingFromDeltaXY(unit, dir);
|
||||
this->State++;
|
||||
|
@ -407,7 +409,6 @@ void COrder_Attack::MoveToTarget(CUnit &unit)
|
|||
|| (!goal && (Map.WallOnMap(this->goalPos) || this->Action == UnitActionAttackGround)))
|
||||
&& unit.MapDistanceTo(this->goalPos) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
|
||||
// Reached wall or ground, now attacking it
|
||||
unit.State = 0;
|
||||
UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
|
||||
this->State &= WEAK_TARGET;
|
||||
this->State |= ATTACK_TARGET;
|
||||
|
@ -417,7 +418,6 @@ void COrder_Attack::MoveToTarget(CUnit &unit)
|
|||
// Unreachable.
|
||||
|
||||
if (err == PF_UNREACHABLE) {
|
||||
unit.State = 0;
|
||||
if (!this->HasGoal()) {
|
||||
// When attack-moving we have to allow a bigger range
|
||||
this->Range++;
|
||||
|
@ -431,7 +431,6 @@ void COrder_Attack::MoveToTarget(CUnit &unit)
|
|||
// Return to old task?
|
||||
if (!unit.RestoreOrder()) {
|
||||
this->Finished = true;
|
||||
unit.State = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,7 +460,6 @@ void COrder_Attack::AttackTarget(CUnit &unit)
|
|||
|
||||
// No target choose one.
|
||||
if (!goal) {
|
||||
unit.State = 0;
|
||||
goal = AttackUnitsInReactRange(unit);
|
||||
|
||||
// No new goal, continue way to destination.
|
||||
|
@ -476,9 +474,11 @@ void COrder_Attack::AttackTarget(CUnit &unit)
|
|||
// Save current command to come back.
|
||||
COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos);
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
if (unit.CanStoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
} else {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
this->SetGoal(goal);
|
||||
this->goalPos = goal->tilePos;
|
||||
|
@ -493,11 +493,12 @@ void COrder_Attack::AttackTarget(CUnit &unit)
|
|||
CUnit *newTarget = AttackUnitsInReactRange(unit);
|
||||
if (newTarget && newTarget->IsAgressive()
|
||||
&& ThreatCalculate(unit, *newTarget) < ThreatCalculate(unit, *goal)) {
|
||||
COrder *savedOrder = this->Clone();
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
COrder *savedOrder = NULL;
|
||||
if (unit.CanStoreOrder(this)) {
|
||||
savedOrder = this->Clone();
|
||||
}
|
||||
if (savedOrder != NULL) {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
goal = newTarget;
|
||||
this->SetGoal(newTarget);
|
||||
|
@ -513,14 +514,15 @@ void COrder_Attack::AttackTarget(CUnit &unit)
|
|||
if (dist > unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
|
||||
// towers don't chase after goal
|
||||
if (unit.CanMove()) {
|
||||
COrder *savedOrder = this->Clone();
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos);
|
||||
if (unit.CanStoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
} else {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
}
|
||||
unit.Frame = 0;
|
||||
unit.State = 0;
|
||||
this->State &= WEAK_TARGET;
|
||||
this->State |= MOVE_TO_TARGET;
|
||||
}
|
||||
|
@ -579,14 +581,12 @@ void COrder_Attack::AttackTarget(CUnit &unit)
|
|||
}
|
||||
this->State = MOVE_TO_TARGET;
|
||||
// FIXME: should use a reachable place to reduce pathfinder time.
|
||||
Assert(unit.State == 0);
|
||||
}
|
||||
// FALL THROUGH
|
||||
case MOVE_TO_TARGET:
|
||||
case MOVE_TO_TARGET + WEAK_TARGET:
|
||||
if (!unit.CanMove()) {
|
||||
this->Finished = true;
|
||||
unit.State = 0;
|
||||
return;
|
||||
}
|
||||
MoveToTarget(unit);
|
||||
|
|
|
@ -269,14 +269,16 @@ enum {
|
|||
CUnit *target = AttackUnitsInReactRange(unit);
|
||||
if (target) {
|
||||
// Save current command to come back.
|
||||
COrder *savedOrder = this->Clone();
|
||||
COrder *savedOrder = NULL;
|
||||
if (unit.CanStoreOrder(unit.CurrentOrder())) {
|
||||
savedOrder = this->Clone();
|
||||
}
|
||||
|
||||
this->Finished = true;
|
||||
unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos));
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
if (savedOrder != NULL) {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -269,7 +269,6 @@ static void AnimateActionRepair(CUnit &unit)
|
|||
// Have reached target? FIXME: could use return value
|
||||
if (goal && unit.MapDistanceTo(*goal) <= unit.Type->RepairRange
|
||||
&& goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
|
||||
unit.State = 0;
|
||||
this->State = 2;
|
||||
this->RepairCycle = 0;
|
||||
const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
|
||||
|
@ -307,7 +306,6 @@ static void AnimateActionRepair(CUnit &unit)
|
|||
}
|
||||
} else if (dist > unit.Type->RepairRange) {
|
||||
// If goal has move, chase after it
|
||||
unit.State = 0;
|
||||
this->State = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,10 +205,11 @@ COrder_Resource::~COrder_Resource()
|
|||
if (mine && mine->IsAlive()) {
|
||||
worker->DeAssignWorkerFromMine(*mine);
|
||||
}
|
||||
if (this->HasGoal() && this->GetGoal()->IsAlive()) {
|
||||
|
||||
CUnit *goal = this->GetGoal();
|
||||
if (goal) {
|
||||
// If mining decrease the active count on the resource.
|
||||
if (this->State == SUB_GATHER_RESOURCE) {
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
goal->Resource.Active--;
|
||||
Assert(goal->Resource.Active >= 0);
|
||||
|
@ -443,7 +444,6 @@ void COrder_Resource::UnitGotoGoal(CUnit &unit, CUnit *const goal, int state)
|
|||
}
|
||||
}
|
||||
this->State = state;
|
||||
unit.State = 0;
|
||||
if (state == SUB_MOVE_TO_DEPOT || state == SUB_MOVE_TO_RESOURCE) {
|
||||
unit.pathFinderData->output.Cycles = 0; //moving counter
|
||||
}
|
||||
|
@ -488,7 +488,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
|
|||
goal = this->GetGoal();
|
||||
|
||||
// Target is dead, stop getting resources.
|
||||
if (!goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
if (!goal || goal->IsVisibleAsGoal(*unit.Player) == false) {
|
||||
// Find an alternative, but don't look too far.
|
||||
this->goalPos.x = -1;
|
||||
this->goalPos.y = -1;
|
||||
|
@ -586,17 +586,10 @@ void COrder_Resource::LoseResource(CUnit &unit, const CUnit &source)
|
|||
CUnit *goal = UnitFindResource(unit, unit, 15, this->CurrentResource, 1);
|
||||
|
||||
if (goal) {
|
||||
CUnit *mine = this->Resource.Mine;
|
||||
|
||||
if (mine) {
|
||||
unit.DeAssignWorkerFromMine(*mine);
|
||||
}
|
||||
unit.AssignWorkerToMine(*goal);
|
||||
this->goalPos.x = -1;
|
||||
this->goalPos.y = -1;
|
||||
this->State = SUB_START_RESOURCE;
|
||||
this->SetGoal(goal);
|
||||
this->Resource.Mine = goal;
|
||||
this->goalPos = goal->tilePos;
|
||||
this->State = SUB_MOVE_TO_RESOURCE;
|
||||
unit.State = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -630,13 +623,11 @@ void COrder_Resource::LoseResource(CUnit &unit, const CUnit &source)
|
|||
DebugPrint("%d: Worker %d report: Resource is exhausted, Found another resource.\n"
|
||||
_C_ unit.Player->Index _C_ unit.Slot);
|
||||
this->State = SUB_START_RESOURCE;
|
||||
unit.State = 0;
|
||||
this->SetGoal(depot);
|
||||
} else {
|
||||
DebugPrint("%d: Worker %d report: Resource is exhausted, Just sits around confused.\n"
|
||||
_C_ unit.Player->Index _C_ unit.Slot);
|
||||
this->Finished = true;
|
||||
unit.State = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,7 +724,7 @@ int COrder_Resource::GatherResource(CUnit &unit)
|
|||
return 0;
|
||||
}
|
||||
DebugPrint("%d: Worker %d report: Resource is destroyed\n" _C_ unit.Player->Index _C_ unit.Slot);
|
||||
bool dead = source->Destroyed || source->CurrentAction() == UnitActionDie;
|
||||
bool dead = source->IsAlive() == false;
|
||||
|
||||
// Improved version of DropOutAll that makes workers go to the depot.
|
||||
LoseResource(unit, *source);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
#include "animation.h"
|
||||
#include "iolib.h"
|
||||
#include "map.h"
|
||||
#include "missile.h"
|
||||
#include "pathfinder.h"
|
||||
#include "player.h"
|
||||
|
@ -133,7 +134,12 @@
|
|||
|
||||
/* virtual */ bool COrder_SpellCast::IsValid() const
|
||||
{
|
||||
return true;
|
||||
Assert(Action == UnitActionSpellCast);
|
||||
if (this->HasGoal()) {
|
||||
return this->GetGoal()->IsAliveOnMap();
|
||||
} else {
|
||||
return Map.Info.IsPointOnMap(this->goalPos);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ PixelPos COrder_SpellCast::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
|
||||
|
@ -206,6 +212,40 @@ static void AnimateActionSpellCast(CUnit &unit, COrder_SpellCast &order)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Check for dead goal.
|
||||
**
|
||||
** @warning The caller must check, if he likes the restored SavedOrder!
|
||||
**
|
||||
** @todo If a unit enters an building, than the attack choose an
|
||||
** other goal, perhaps it is better to wait for the goal?
|
||||
**
|
||||
** @param unit Unit using the goal.
|
||||
**
|
||||
** @return true if order have changed, false else.
|
||||
*/
|
||||
bool COrder_SpellCast::CheckForDeadGoal(CUnit &unit)
|
||||
{
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
// Position or valid target, it is ok.
|
||||
if (!goal || goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Goal could be destroyed or unseen
|
||||
// So, cannot use type.
|
||||
this->goalPos = goal->tilePos;
|
||||
this->Range = 0;
|
||||
this->ClearGoal();
|
||||
|
||||
// If we have a saved order continue this saved order.
|
||||
if (unit.RestoreOrder()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle moving to the target.
|
||||
**
|
||||
|
@ -228,7 +268,6 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
|
|||
|
||||
if (goal && unit.MapDistanceTo(*goal) <= this->Range) {
|
||||
// there is goal and it is in range
|
||||
unit.State = 0;
|
||||
UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
|
||||
this->State++; // cast the spell
|
||||
return false;
|
||||
|
@ -239,7 +278,6 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
|
|||
return false;
|
||||
} else if (err == PF_UNREACHABLE || !unit.CanMove()) {
|
||||
// goal/spot unreachable and out of range -- give up
|
||||
unit.State = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -276,6 +314,9 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
|
|||
this->Finished = true;
|
||||
return ;
|
||||
}
|
||||
if (CheckForDeadGoal(unit)) {
|
||||
return;
|
||||
}
|
||||
// FIXME FIXME FIXME: Check if already in range and skip straight to 2(casting)
|
||||
unit.ReCast = 0; // repeat spell on next pass? (defaults to `no')
|
||||
this->State = 1;
|
||||
|
@ -306,6 +347,12 @@ bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
|
|||
unit.ReCast = SpellCast(unit, &spell, goal, order.goalPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Target is dead ? Change order ?
|
||||
if (CheckForDeadGoal(unit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check, if goal has moved (for ReCast)
|
||||
if (unit.ReCast && order.GetGoal() && unit.MapDistanceTo(*order.GetGoal()) > this->Range) {
|
||||
this->State = 0;
|
||||
|
|
|
@ -273,13 +273,15 @@ bool AutoRepair(CUnit &unit)
|
|||
return false;
|
||||
}
|
||||
const Vec2i invalidPos = { -1, -1};
|
||||
COrder *savedOrder = unit.CurrentOrder()->Clone();
|
||||
COrder *savedOrder = NULL;
|
||||
if (unit.CanStoreOrder(unit.CurrentOrder())) {
|
||||
savedOrder = unit.CurrentOrder()->Clone();
|
||||
}
|
||||
|
||||
//Command* will clear unit.SavedOrder
|
||||
CommandRepair(unit, invalidPos, repairedUnit, FlushCommands);
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
if (savedOrder != NULL) {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -292,11 +294,10 @@ bool COrder_Still::AutoAttackStand(CUnit &unit)
|
|||
// Removed units can only attack in AttackRange, from bunker
|
||||
this->AutoTarget = AttackUnitsInRange(unit);
|
||||
|
||||
if (this->AutoTarget == NULL) {
|
||||
if (this->AutoTarget == NoUnitP) {
|
||||
return false;
|
||||
}
|
||||
this->State = SUB_STILL_ATTACK; // Mark attacking.
|
||||
this->SetGoal(this->AutoTarget);
|
||||
UnitHeadingFromDeltaXY(unit, this->AutoTarget->tilePos + this->AutoTarget->Type->GetHalfTileSize() - unit.tilePos);
|
||||
return true;
|
||||
}
|
||||
|
@ -330,20 +331,18 @@ bool AutoAttack(CUnit &unit)
|
|||
if (goal == NULL) {
|
||||
return false;
|
||||
}
|
||||
COrder *savedOrder;
|
||||
COrder *savedOrder = NULL;
|
||||
|
||||
if (unit.SavedOrder != NULL) {
|
||||
savedOrder = unit.SavedOrder->Clone();
|
||||
} else if (unit.CurrentAction() == UnitActionStill) {
|
||||
if (unit.CurrentAction() == UnitActionStill) {
|
||||
savedOrder = COrder::NewActionAttack(unit, unit.tilePos);
|
||||
} else {
|
||||
} else if (unit.CanStoreOrder(unit.CurrentOrder())) {
|
||||
savedOrder = unit.CurrentOrder()->Clone();
|
||||
}
|
||||
// Weak goal, can choose other unit, come back after attack
|
||||
CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
|
||||
|
||||
if (unit.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
if (savedOrder != NULL) {
|
||||
unit.SavedOrder = savedOrder;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
#include "animation/animation_die.h"
|
||||
#include "commands.h"
|
||||
#include "luacallback.h"
|
||||
#include "map.h"
|
||||
#include "missile.h"
|
||||
#include "pathfinder.h"
|
||||
|
@ -331,7 +332,6 @@ static void HandleUnitAction(CUnit &unit)
|
|||
|
||||
delete unit.Orders[0];
|
||||
unit.Orders[0] = COrder::NewActionStill();
|
||||
unit.State = 0;
|
||||
if (IsOnlySelected(unit)) { // update display for new action
|
||||
SelectedUnitChanged();
|
||||
}
|
||||
|
@ -347,17 +347,9 @@ static void HandleUnitAction(CUnit &unit)
|
|||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
delete unit.Orders[0];
|
||||
unit.Orders.erase(unit.Orders.begin());
|
||||
} while (unit.Orders[0]->IsValid() == false && unit.Orders.size() > 1);
|
||||
delete unit.Orders[0];
|
||||
unit.Orders.erase(unit.Orders.begin());
|
||||
|
||||
if (unit.Orders[0]->IsValid() == false && unit.Orders.size() == 1) {
|
||||
delete unit.Orders[0];
|
||||
unit.Orders[0] = COrder::NewActionStill();
|
||||
}
|
||||
|
||||
unit.State = 0;
|
||||
unit.Wait = 0;
|
||||
if (IsOnlySelected(unit)) { // update display for new action
|
||||
SelectedUnitChanged();
|
||||
|
@ -377,6 +369,13 @@ static void UnitActionsEachSecond(UNITP_ITERATOR begin, UNITP_ITERATOR end)
|
|||
continue;
|
||||
}
|
||||
|
||||
// OnEachSecond callback
|
||||
if (unit.Type->OnEachSecond) {
|
||||
unit.Type->OnEachSecond->pushPreamble();
|
||||
unit.Type->OnEachSecond->pushInteger(unit.Slot);
|
||||
unit.Type->OnEachSecond->run();
|
||||
}
|
||||
|
||||
// 1) Blink flag.
|
||||
if (unit.Blink) {
|
||||
--unit.Blink;
|
||||
|
@ -411,13 +410,13 @@ static void DumpUnitInfo(CUnit &unit)
|
|||
fprintf(logf, ";\tMap: %s\n\n", Map.Info.Description.c_str());
|
||||
}
|
||||
|
||||
fprintf(logf, "%lu: ", GameCycle);
|
||||
fprintf(logf, "%d %s S%d-%d P%d Refs %d: %X %d,%d %d,%d\n",
|
||||
UnitNumber(unit), unit.Type ? unit.Type->Ident.c_str() : "unit-killed",
|
||||
unit.State,
|
||||
!unit.Orders.empty() ? unit.CurrentAction() : -1,
|
||||
unit.Player ? unit.Player->Index : -1, unit.Refs, SyncRandSeed,
|
||||
unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY);
|
||||
fprintf(logf, "%lu: ", GameCycle);
|
||||
fprintf(logf, "%d %s S%d-%d P%d Refs %d: %X %d,%d %d,%d\n",
|
||||
UnitNumber(unit), unit.Type ? unit.Type->Ident.c_str() : "unit-killed",
|
||||
unit.State,
|
||||
!unit.Orders.empty() ? unit.CurrentAction() : -1,
|
||||
unit.Player ? unit.Player->Index : -1, unit.Refs, SyncRandSeed,
|
||||
unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY);
|
||||
#if 0
|
||||
SaveUnit(unit, logf);
|
||||
#endif
|
||||
|
@ -436,6 +435,14 @@ static void UnitActionsEachCycle(UNITP_ITERATOR begin, UNITP_ITERATOR end)
|
|||
if (unit.Destroyed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// OnEachCycle callback
|
||||
if (unit.Type->OnEachCycle) {
|
||||
unit.Type->OnEachCycle->pushPreamble();
|
||||
unit.Type->OnEachCycle->pushInteger(unit.Slot);
|
||||
unit.Type->OnEachCycle->run();
|
||||
}
|
||||
|
||||
try {
|
||||
HandleUnitAction(unit);
|
||||
} catch (AnimationDie_Exception &) {
|
||||
|
@ -447,7 +454,6 @@ static void UnitActionsEachCycle(UNITP_ITERATOR begin, UNITP_ITERATOR end)
|
|||
// Calculate some hash.
|
||||
SyncHash = (SyncHash << 5) | (SyncHash >> 27);
|
||||
SyncHash ^= unit.Orders.empty() == false ? unit.CurrentAction() << 18 : 0;
|
||||
SyncHash ^= unit.State << 12;
|
||||
SyncHash ^= unit.Refs << 3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -713,9 +713,11 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender)
|
|||
CommandAttack(aiunit, attacker->tilePos, const_cast<CUnit *>(attacker), FlushCommands);
|
||||
COrder *savedOrder = COrder::NewActionAttack(aiunit, attacker->tilePos);
|
||||
|
||||
if (aiunit.StoreOrder(savedOrder) == false) {
|
||||
if (aiunit.CanStoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
} else {
|
||||
aiunit.SavedOrder = savedOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,8 +56,13 @@ void AiCheckMagic()
|
|||
for (int i = 0; i < n; ++i) {
|
||||
CUnit &unit = player.GetUnit(i);
|
||||
|
||||
// Check only idle magic units
|
||||
if (unit.Type->CanCastSpell && unit.CurrentAction() != UnitActionSpellCast) {
|
||||
if (unit.Type->CanCastSpell) {
|
||||
// Check only idle magic units
|
||||
for (size_t i = 0; i != unit.Orders.size(); ++i) {
|
||||
if (unit.Orders[i]->Action == UnitActionSpellCast) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
|
||||
void AnimationDie_OnCatch(CUnit &unit)
|
||||
{
|
||||
unit.State = 0;
|
||||
LetUnitDie(unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
|
|||
PixelPos start;
|
||||
PixelPos dest;
|
||||
|
||||
if (!goal || goal->Destroyed || goal->Removed) {
|
||||
if (!goal || goal->IsAliveOnMap() == false) {
|
||||
return;
|
||||
}
|
||||
if ((flags & ANIM_SM_PIXEL)) {
|
||||
|
@ -115,7 +115,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
|
|||
}
|
||||
if ((flags & ANIM_SM_TOTARGET)) {
|
||||
CUnit *target = goal->CurrentOrder()->GetGoal();
|
||||
if (!target || target->Destroyed || target->Removed) {
|
||||
if (!target || goal->IsAliveOnMap() == false) {
|
||||
Assert(!unit.Type->Missile.Missile->AlwaysFire || unit.Type->Missile.Missile->Range);
|
||||
if (!target || !unit.Type->Missile.Missile->AlwaysFire) {
|
||||
return;
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
const SpellType &GetSpell() const { return *Spell; }
|
||||
void SetSpell(SpellType &spell) { Spell = &spell; }
|
||||
private:
|
||||
bool CheckForDeadGoal(CUnit &unit);
|
||||
bool SpellMoveToTarget(CUnit &unit);
|
||||
private:
|
||||
SpellType *Spell;
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
const CUnitType &GetUnitType() const { return *Type; }
|
||||
private:
|
||||
CUnitType *Type; /// upgrate to this unit-type
|
||||
CUnitType *Type; /// upgrade to this unit-type
|
||||
int Ticks; /// Ticks to complete
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
//@{
|
||||
|
||||
#include "unit.h"
|
||||
#include "unitptr.h"
|
||||
#include "vec2i.h"
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ public:
|
|||
void Init();
|
||||
// @note int is faster than shorts
|
||||
unsigned int Refs; /// Reference counter
|
||||
unsigned int ReleaseCycle; /// When this unit could be recycled
|
||||
int Slot; /// Assigned slot number
|
||||
CUnit **UnitSlot; /// Slot pointer of Units
|
||||
size_t PlayerSlot; /// index in Player->Units
|
||||
|
@ -225,7 +226,6 @@ public:
|
|||
|
||||
unsigned char DamagedType; /// Index of damage type of unit which damaged this unit
|
||||
unsigned long Attacked; /// gamecycle unit was last attacked
|
||||
unsigned State : 8; /// action state
|
||||
unsigned Blink : 3; /// Let selection rectangle blink
|
||||
unsigned Moving : 1; /// The unit is moving
|
||||
unsigned ReCast : 1; /// Recast again next cycle
|
||||
|
@ -335,7 +335,7 @@ unsigned ByPlayer : PlayerMax; /// Track unit seen by player
|
|||
void Release(bool final = false);
|
||||
|
||||
bool RestoreOrder();
|
||||
bool StoreOrder(COrder *order);
|
||||
bool CanStoreOrder(COrder *order);
|
||||
|
||||
// Cowards and invisible units don't attack unless ordered.
|
||||
bool IsAgressive() const {
|
||||
|
|
|
@ -939,7 +939,9 @@ public:
|
|||
MissileConfig Impact[ANIMATIONS_DEATHTYPES + 2]; /// Missiles spawned if unit is hit(+shield)
|
||||
|
||||
LuaCallback *DeathExplosion;
|
||||
LuaCallback *OnHit; /// lua function called whel unit is hit
|
||||
LuaCallback *OnHit; /// lua function called when unit is hit
|
||||
LuaCallback *OnEachCycle; /// lua function called every cycle
|
||||
LuaCallback *OnEachSecond; /// lua function called every second
|
||||
|
||||
std::string DamageType; /// DamageType (used for extra death animations and impacts)
|
||||
|
||||
|
|
|
@ -166,8 +166,7 @@ void MapUnmarkTileSight(const CPlayer &player, const unsigned int index)
|
|||
switch (*v) {
|
||||
case 0: // Unexplored
|
||||
case 1:
|
||||
// We are at minimum, don't do anything shouldn't happen.
|
||||
Assert(0);
|
||||
// This happens when we unmark everything in CommandSharedVision
|
||||
break;
|
||||
case 2:
|
||||
// When there is NoFogOfWar units never get unmarked.
|
||||
|
|
|
@ -48,7 +48,7 @@ void MissileFire::Action()
|
|||
CUnit &unit = *this->SourceUnit;
|
||||
|
||||
this->Wait = this->Type->Sleep;
|
||||
if (unit.Destroyed || unit.CurrentAction() == UnitActionDie) {
|
||||
if (unit.IsAlive() == false) {
|
||||
this->TTL = 0;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -683,7 +683,7 @@ static bool PassCondition(const CUnit &caster, const SpellType *spell, const CUn
|
|||
return false;
|
||||
}
|
||||
if (spell->Target == TargetUnit) { // Casting a unit spell without a target.
|
||||
if ((!target) || target->Destroyed || target->CurrentAction() == UnitActionDie) {
|
||||
if ((!target) || target->IsAlive() == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ extern int GetGameSpeed();
|
|||
extern tolua_property__s int GameSpeed;
|
||||
extern bool GameObserve;
|
||||
|
||||
extern tolua_readonly unsigned long GameCycle;
|
||||
extern unsigned long GameCycle;
|
||||
|
||||
|
||||
$#include "settings.h"
|
||||
|
|
|
@ -858,7 +858,18 @@ void UIHandleMouseMove(const PixelPos &cursorPos)
|
|||
ShowNameTime = GameCycle + Preference.ShowNameDelay + Preference.ShowNameTime;
|
||||
}
|
||||
|
||||
if (Map.IsFieldExplored(*ThisPlayer, tilePos) || ReplayRevealMap) {
|
||||
bool show = ReplayRevealMap ? true : false;
|
||||
if (show == false) {
|
||||
for (int i = 0; i < PlayerMax; ++i) {
|
||||
if (Map.IsFieldExplored(Players[i], tilePos)
|
||||
&& (i == ThisPlayer->Index || Players[i].IsBothSharedVision(*ThisPlayer))) {
|
||||
show = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (show) {
|
||||
const PixelPos mapPixelPos = vp.ScreenToMapPixelPos(cursorPos);
|
||||
UnitUnderCursor = UnitOnScreen(NULL, mapPixelPos.x, mapPixelPos.y);
|
||||
}
|
||||
|
|
|
@ -508,10 +508,6 @@ static int CclUnit(lua_State *l)
|
|||
lua_rawgeti(l, 2, j + 1);
|
||||
unit->Wait = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "state")) {
|
||||
lua_rawgeti(l, 2, j + 1);
|
||||
unit->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "anim-data")) {
|
||||
lua_rawgeti(l, 2, j + 1);
|
||||
CAnimations::LoadUnitAnim(l, *unit, -1);
|
||||
|
@ -1098,7 +1094,7 @@ static int CclSlotUsage(lua_State *l)
|
|||
}
|
||||
Assert(unit_index != -1 && cycle != static_cast<unsigned long>(-1));
|
||||
UnitManager.ReleaseUnit(UnitSlots[unit_index]);
|
||||
UnitSlots[unit_index]->Refs = cycle;
|
||||
UnitSlots[unit_index]->ReleaseCycle = cycle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -624,6 +624,10 @@ static int CclDefineUnitType(lua_State *l)
|
|||
type->DeathExplosion = new LuaCallback(l, -1);
|
||||
} else if (!strcmp(value, "OnHit")) {
|
||||
type->OnHit = new LuaCallback(l, -1);
|
||||
} else if (!strcmp(value, "OnEachCycle")) {
|
||||
type->OnEachCycle = new LuaCallback(l, -1);
|
||||
} else if (!strcmp(value, "OnEachSecond")) {
|
||||
type->OnEachSecond = new LuaCallback(l, -1);
|
||||
} else if (!strcmp(value, "Type")) {
|
||||
value = LuaToString(l, -1);
|
||||
if (!strcmp(value, "land")) {
|
||||
|
|
|
@ -411,6 +411,7 @@ void CUnit::RefsDecrease()
|
|||
void CUnit::Init()
|
||||
{
|
||||
Refs = 0;
|
||||
ReleaseCycle = 0;
|
||||
Slot = 0;
|
||||
UnitSlot = NULL;
|
||||
PlayerSlot = static_cast<size_t>(-1);
|
||||
|
@ -463,7 +464,6 @@ void CUnit::Init()
|
|||
LastGroup = 0;
|
||||
ResourcesHeld = 0;
|
||||
Wait = 0;
|
||||
State = 0;
|
||||
Blink = 0;
|
||||
Moving = 0;
|
||||
ReCast = 0;
|
||||
|
@ -653,14 +653,11 @@ bool CUnit::RestoreOrder()
|
|||
}
|
||||
|
||||
if (savedOrder->IsValid() == false) {
|
||||
delete this->SavedOrder;
|
||||
delete savedOrder;
|
||||
this->SavedOrder = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restart order state.
|
||||
this->State = 0;
|
||||
|
||||
// Cannot delete this->Orders[0] since it is generally that order
|
||||
// which call this method.
|
||||
this->Orders[0]->Finished = true;
|
||||
|
@ -673,11 +670,11 @@ bool CUnit::RestoreOrder()
|
|||
}
|
||||
|
||||
/**
|
||||
** Store the Current order
|
||||
** Check if we can store this order
|
||||
**
|
||||
** @return True if the current order was saved
|
||||
** @return True if the order could be saved
|
||||
*/
|
||||
bool CUnit::StoreOrder(COrder *order)
|
||||
bool CUnit::CanStoreOrder(COrder *order)
|
||||
{
|
||||
Assert(order);
|
||||
|
||||
|
@ -685,14 +682,8 @@ bool CUnit::StoreOrder(COrder *order)
|
|||
return false;
|
||||
}
|
||||
if (this->SavedOrder != NULL) {
|
||||
if (this->SavedOrder->IsValid() == true) {
|
||||
return false;
|
||||
}
|
||||
delete this->SavedOrder;
|
||||
this->SavedOrder = NULL;
|
||||
return false;
|
||||
}
|
||||
// Save current order to come back or to continue it.
|
||||
this->SavedOrder = order;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1297,7 +1288,6 @@ void UnitClearOrders(CUnit &unit)
|
|||
}
|
||||
unit.Orders.clear();
|
||||
unit.Orders.push_back(COrder::NewActionStill());
|
||||
unit.State = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2838,7 +2828,6 @@ void LetUnitDie(CUnit &unit)
|
|||
// Unit has death animation.
|
||||
|
||||
// Not good: UnitUpdateHeading(unit);
|
||||
unit.State = 0;
|
||||
delete unit.Orders[0];
|
||||
unit.Orders[0] = COrder::NewActionDie();
|
||||
if (type->CorpseType) {
|
||||
|
@ -3160,8 +3149,11 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile)
|
|||
|
||||
// Attack units in range (which or the attacker?)
|
||||
// Don't bother unit if it casting repeatable spell
|
||||
if (target.IsAgressive() && target.CanMove() && target.CurrentAction() != UnitActionSpellCast) {
|
||||
COrder *savedOrder = target.CurrentOrder()->Clone();
|
||||
if (target.IsAgressive() && target.CanMove() && !target.ReCast) {
|
||||
COrder *savedOrder = NULL;
|
||||
if (target.CanStoreOrder(target.CurrentOrder())) {
|
||||
savedOrder = target.CurrentOrder()->Clone();
|
||||
}
|
||||
CUnit *oldgoal = target.CurrentOrder()->GetGoal();
|
||||
CUnit *goal, *best = oldgoal;
|
||||
|
||||
|
@ -3188,7 +3180,7 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile)
|
|||
|| (ThreatCalculate(target, *attacker) < ThreatCalculate(target, *best)))))) {
|
||||
best = attacker;
|
||||
}
|
||||
if (best) {
|
||||
if (best && best != oldgoal) {
|
||||
if (target.MapDistanceTo(*best) <= target.Stats->Variables[ATTACKRANGE_INDEX].Max) {
|
||||
CommandAttack(target, best->tilePos, best, FlushCommands);
|
||||
} else {
|
||||
|
@ -3198,9 +3190,8 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage, const Missile *missile)
|
|||
if (best->IsAgressive()) {
|
||||
target.Threshold = threshold;
|
||||
}
|
||||
if (target.StoreOrder(savedOrder) == false) {
|
||||
delete savedOrder;
|
||||
savedOrder = NULL;
|
||||
if (savedOrder != NULL) {
|
||||
target.SavedOrder = savedOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ CUnit *CUnitManager::AllocUnit()
|
|||
//
|
||||
// Can use released unit?
|
||||
//
|
||||
if (!ReleasedUnits.empty() && ReleasedUnits.front()->Refs < GameCycle) {
|
||||
if (!ReleasedUnits.empty() && ReleasedUnits.front()->ReleaseCycle < GameCycle) {
|
||||
unit = ReleasedUnits.front();
|
||||
ReleasedUnits.pop_front();
|
||||
int slot = unit->Slot;
|
||||
|
@ -111,7 +111,7 @@ CUnit *CUnitManager::AllocUnit()
|
|||
void CUnitManager::ReleaseUnit(CUnit *unit)
|
||||
{
|
||||
ReleasedUnits.push_back(unit);
|
||||
unit->Refs = GameCycle + 500; // can be reused after this time
|
||||
unit->ReleaseCycle = GameCycle + 500; // can be reused after this time
|
||||
//Refs = GameCycle + (NetworkMaxLag << 1); // could be reuse after this time
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ void CUnitManager::Save(CFile &file) const
|
|||
|
||||
std::list<CUnit *>::const_iterator it = ReleasedUnits.begin();
|
||||
for (; it != ReleasedUnits.end(); ++it) {
|
||||
file.printf(", {Slot = %d, FreeCycle = %u}", (*it)->Slot, (*it)->Refs);
|
||||
file.printf(", {Slot = %d, FreeCycle = %u}", (*it)->Slot, (*it)->ReleaseCycle);
|
||||
}
|
||||
file.printf(")\n");
|
||||
}
|
||||
|
|
|
@ -237,7 +237,6 @@ void SaveUnit(const CUnit &unit, CFile &file)
|
|||
unit.pathFinderData->output.Save(file);
|
||||
|
||||
file.printf("\"wait\", %d, ", unit.Wait);
|
||||
file.printf("\"state\", %d,", unit.State);
|
||||
CAnimations::SaveUnitAnim(file, unit);
|
||||
file.printf(",\n \"blink\", %d,", unit.Blink);
|
||||
if (unit.Moving) {
|
||||
|
|
|
@ -41,11 +41,11 @@ CUnitPtr::CUnitPtr(CUnit *u) : unit(u)
|
|||
}
|
||||
}
|
||||
|
||||
CUnitPtr::CUnitPtr(const CUnitPtr &u) : unit(u.unit)
|
||||
{
|
||||
if (unit) {
|
||||
unit->RefsIncrease();
|
||||
}
|
||||
CUnitPtr::CUnitPtr(const CUnitPtr &u) : unit(u.unit)
|
||||
{
|
||||
if (unit) {
|
||||
unit->RefsIncrease();
|
||||
}
|
||||
}
|
||||
|
||||
void CUnitPtr::Reset()
|
||||
|
|
|
@ -134,7 +134,7 @@ extern int ParseAnimInt(CUnit *unit, const char *parseint);
|
|||
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),
|
||||
Animations(NULL), StillFrame(0), OnEachCycle(NULL), OnEachSecond(NULL),
|
||||
DeathExplosion(NULL), OnHit(NULL), CorpseType(NULL),
|
||||
Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
|
||||
BoxWidth(0), BoxHeight(0), NumDirections(0), MinAttackRange(0),
|
||||
|
@ -171,6 +171,8 @@ CUnitType::~CUnitType()
|
|||
{
|
||||
delete DeathExplosion;
|
||||
delete OnHit;
|
||||
delete OnEachCycle;
|
||||
delete OnEachSecond;
|
||||
|
||||
BoolFlag.clear();
|
||||
|
||||
|
|
|
@ -568,9 +568,7 @@ int CFont::Width(const int number) const
|
|||
|
||||
if (isReverse == false && fc != backup) {
|
||||
fc = backup;
|
||||
if (UseOpenGL) {
|
||||
g = FontColorGraphics[font][fc];
|
||||
}
|
||||
g = font->GetFontColorGraphic(fc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue