Add COrder_Built

This commit is contained in:
joris 2012-02-21 15:39:36 +01:00
parent 0ad3061456
commit 58f777c425
22 changed files with 482 additions and 455 deletions

View file

@ -49,42 +49,13 @@
#include "interface.h"
#include "pathfinder.h"
#include "construct.h"
#include "iolib.h"
#include "script.h"
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Update construction frame
**
** @param unit The building under construction.
*/
static void UpdateConstructionFrame(CUnit &unit)
{
CConstructionFrame *cframe;
CConstructionFrame *tmp;
int percent;
percent = unit.CurrentOrder()->Data.Built.Progress /
(unit.Type->Stats[unit.Player->Index].Costs[TimeCost] * 6);
cframe = tmp = unit.Type->Construction->Frames;
while (tmp) {
if (percent < tmp->Percent) {
break;
}
cframe = tmp;
tmp = tmp->Next;
}
if (cframe != unit.CurrentOrder()->Data.Built.Frame) {
unit.CurrentOrder()->Data.Built.Frame = cframe;
if (unit.Frame < 0) {
unit.Frame = -cframe->Frame - 1;
} else {
unit.Frame = cframe->Frame;
}
}
}
/**
** Move to build location
**
@ -287,7 +258,8 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
}
// Must set action before placing, otherwise it will incorrectly mark radar
build->CurrentOrder()->Action = UnitActionBuilt;
delete build->CurrentOrder();
build->Orders[0] = COrder::NewActionBuilt(unit, *build);
// Must place after previous for map flags
build->Place(pos);
@ -298,18 +270,10 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
// HACK: the building is not ready yet
build->Player->UnitTypesCount[type.Slot]--;
// Make sure the bulding doesn't cancel itself out right away.
build->CurrentOrder()->Data.Built.Progress = 0;//FIXME ? 100 : 0
build->Variable[HP_INDEX].Value = 1;
if (build->Variable[SHIELD_INDEX].Max)
build->Variable[SHIELD_INDEX].Value = 1;
UpdateConstructionFrame(*build);
// We need somebody to work on it.
if (!type.BuilderOutside) {
//FIXME: cancel buld gen crash
// Place the builder inside the building
build->CurrentOrder()->Data.Built.Worker = &unit;
// HACK: allows the unit to be removed
build->CurrentSightRange = 1;
//HACK: reset anim
@ -337,7 +301,6 @@ static void StartBuilding(CUnit &unit, CUnit &ontop)
// Mark the new building seen.
MapMarkUnitSight(*build);
}
UpdateConstructionFrame(*build);
}
/**
@ -359,48 +322,6 @@ static void BuildBuilding(CUnit &unit)
//
//int animlength = unit.Data.Build.Cycles;
unit.CurrentOrder()->Data.Build.Cycles = 0;
#if 0
CUnit *goal;
int hp;
//goal hp are mod by HandleActionBuilt
//and outsid builder use repair now.
goal = unit.CurrentOrder()->GetGoal();
//Assert(goal);
if(!goal) {
return;
}
if (goal->CurrentAction() == UnitActionDie) {
unit.CurrentOrder()->ClearGoal();
unit.State = 0;
unit.ClearAction();
return;
}
// hp is the current damage taken by the unit.
hp = (goal->CurrentOrder()->Data.Built.Progress * goal->Variable[HP_INDEX].Max) /
(goal->Stats->Costs[TimeCost] * 600) - goal->Variable[HP_INDEX].Value;
// FIXME: implement this below:
// unit.CurrentOrder()->Data.Built.Worker->Type->BuilderSpeedFactor;
goal->CurrentOrder()->Data.Built.Progress += 100 * animlength * SpeedBuild;
// Keep the same level of damage while increasing HP.
goal->Variable[HP_INDEX].Value = (goal->Data.Built.Progress * goal->Variable[HP_INDEX].Max) /
(goal->Stats->Costs[TimeCost] * 600) - hp;
if (goal->Variable[HP_INDEX].Value > goal->Variable[HP_INDEX].Max) {
goal->Variable[HP_INDEX].Value = goal->Variable[HP_INDEX].Max;
}
//
// Building is gone or finished
//
if (goal->Variable[HP_INDEX].Value == goal->Variable[HP_INDEX].Max) {
unit.CurrentOrder()->ClearGoal();
unit.State = 0;
unit.ClearAction();
}
#endif
}
/**
@ -425,6 +346,317 @@ void HandleActionBuild(COrder& /*order*/, CUnit &unit)
}
}
///////////////////////////
// Action_built
//////////////////////////
/* virtual */ COrder_Built *COrder_Built::Clone() const
{
return new COrder_Built(*this);
}
/* virtual */ void COrder_Built::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-built\", ");
CConstructionFrame *cframe = unit.Type->Construction->Frames;
int frame = 0;
while (cframe != this->Data.Frame) {
cframe = cframe->Next;
++frame;
}
if (this->Data.Worker == NULL) {
file.printf("\"worker\", \"%s\", ", UnitReference(this->Data.Worker).c_str());
}
file.printf("\"progress\", %d, \"frame\", %d", this->Data.Progress, frame);
if (this->Data.Cancel) {
file.printf(", \"cancel\"");
}
file.printf("}");
}
/* virtual */ bool COrder_Built::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (!strcmp(value, "worker")) {
++j;
lua_rawgeti(l, -1, j + 1);
this->Data.Worker = CclGetUnitFromRef(l);
lua_pop(l, 1);
} else if (!strcmp(value, "progress")) {
++j;
lua_rawgeti(l, -1, j + 1);
this->Data.Progress = LuaToNumber(l, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "cancel")) {
this->Data.Cancel = 1;
} else if (!strcmp(value, "frame")) {
++j;
lua_rawgeti(l, -1, j + 1);
int frame = LuaToNumber(l, -1);
lua_pop(l, 1);
CConstructionFrame *cframe = unit.Type->Construction->Frames;
while (frame--) {
cframe = cframe->Next;
}
this->Data.Frame = cframe;
} else {
return false;
}
return true;
}
static void CancelBuilt(COrder_Built &order, CUnit &unit)
{
Assert(unit.CurrentOrder() == &order);
CUnit *worker = order.GetWorkerPtr();
// Drop out unit
if (worker != NULL) {
worker->ClearAction();
// HACK: make sure the sight is updated correctly
// unit.CurrentSightRange = 1;
DropOutOnSide(*worker, LookingW, &unit);
// unit.CurrentSightRange = 0;
}
// Player gets back 75% of the original cost for a building.
unit.Player->AddCostsFactor(unit.Stats->Costs, CancelBuildingCostsFactor);
// Cancel building
LetUnitDie(unit);
}
static bool Finish(COrder_Built &order, CUnit& unit)
{
const CUnitType &type = *unit.Type;
CPlayer &player = *unit.Player;
DebugPrint("%d: Building %s(%s) ready.\n" _C_ player.Index _C_ type.Ident.c_str() _C_ type.Name.c_str() );
// HACK: the building is ready now
player.UnitTypesCount[type.Slot]++;
unit.Constructed = 0;
if (unit.Frame < 0) {
unit.Frame = -1;
} else {
unit.Frame = 0;
}
CUnit *worker = order.GetWorkerPtr();
if (worker != NULL) {
if (type.BuilderLost) {
// Bye bye worker.
LetUnitDie(*worker);
worker = NULL;
} else { // Drop out the worker.
worker->ClearAction();
#if 0
// HACK: make sure the sight is updated correctly
// unit.CurrentSightRange = 1;
#endif
DropOutOnSide(*worker, LookingW, &unit);
// If we can harvest from the new building, do it.
if (worker->Type->ResInfo[type.GivesResource]) {
CommandResource(*worker, unit, 0);
}
}
}
if (type.GivesResource && type.StartingResources != 0) {
// Has StartingResources, Use those
unit.ResourcesHeld = type.StartingResources;
}
player.Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y, _("New %s done"), type.Name.c_str());
if (&player == ThisPlayer) {
if (type.Sound.Ready.Sound) {
PlayUnitSound(unit, VoiceReady);
} else if (worker) {
PlayUnitSound(*worker, VoiceWorkCompleted);
} else {
PlayUnitSound(unit, VoiceBuilding);
}
}
if (player.AiEnabled) {
/* Worker can be NULL */
AiWorkComplete(worker, unit);
}
// FIXME: Vladi: this is just a hack to test wall fixing,
// FIXME: also not sure if the right place...
// FIXME: Johns: hardcoded unit-type wall / more races!
if (&type == UnitTypeOrcWall || &type == UnitTypeHumanWall) {
Map.SetWall(unit.tilePos, &type == UnitTypeHumanWall);
unit.Remove(NULL);
UnitLost(unit);
UnitClearOrders(unit);
unit.Release();
return false;
}
UpdateForNewUnit(unit, 0);
// Set the direction of the building if it supports them
if (type.NumDirections > 1) {
if (type.Wall) { // Special logic for walls
CorrectWallDirections(unit);
CorrectWallNeighBours(unit);
} else {
unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
}
UnitUpdateHeading(unit);
}
if (IsOnlySelected(unit) || &player == ThisPlayer) {
SelectedUnitChanged();
}
MapUnmarkUnitSight(unit);
unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max;
MapMarkUnitSight(unit);
return true;
}
/* virtual */ bool COrder_Built::Execute(CUnit &unit)
{
const CUnitType &type = *unit.Type;
int amount;
if (type.BuilderOutside) {
amount = type.AutoBuildRate;
} else {
// FIXME: implement this below:
// this->Data.Worker->Type->BuilderSpeedFactor;
amount = 100;
}
this->Progress(unit, amount);
// Check if construction should be canceled...
if (this->Data.Cancel || this->Data.Progress < 0) {
DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index _C_ unit.Type->Name.c_str());
CancelBuilt(*this, unit);
return false;
}
const int maxProgress = type.Stats[unit.Player->Index].Costs[TimeCost] * 600;
// Check if building ready. Note we can both build and repair.
if (!unit.Anim.Unbreakable && this->Data.Progress >= maxProgress) {
return Finish(*this, unit);
}
return false;
}
/* virtual */ void COrder_Built::Cancel(CUnit &unit)
{
this->Data.Cancel = 1;
}
/* virtual */ void COrder_Built::UpdateUnitVariables(CUnit &unit) const
{
Assert(unit.CurrentOrder() == this);
unit.Variable[BUILD_INDEX].Value = this->Data.Progress;
unit.Variable[BUILD_INDEX].Max = unit.Type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
// This should happen when building unit with several peons
// Maybe also with only one.
// FIXME : Should be better to fix it in action_{build,repair}.c ?
if (unit.Variable[BUILD_INDEX].Value > unit.Variable[BUILD_INDEX].Max) {
// assume value is wrong.
unit.Variable[BUILD_INDEX].Value = unit.Variable[BUILD_INDEX].Max;
}
}
/* virtual */ void COrder_Built::FillSeenValues(CUnit &unit) const
{
unit.Seen.State = 1;
unit.Seen.CFrame = this->Data.Frame;
}
static const CConstructionFrame *FindCFramePercent(const CConstructionFrame &cframe, int percent)
{
const CConstructionFrame *prev = &cframe;
for (const CConstructionFrame *it = cframe.Next; it; it = it->Next) {
if (percent < it->Percent) {
return prev;
}
prev = it;
}
return prev;
}
/**
** Update construction frame
**
** @param unit The building under construction.
*/
void COrder_Built::UpdateConstructionFrame(CUnit &unit)
{
const CUnitType &type = *unit.Type;
const int percent = this->Data.Progress / (type.Stats[unit.Player->Index].Costs[TimeCost] * 6);
const CConstructionFrame *cframe = FindCFramePercent(*type.Construction->Frames, percent);
Assert(cframe != NULL);
if (cframe != this->Data.Frame) {
this->Data.Frame = cframe;
if (unit.Frame < 0) {
unit.Frame = -cframe->Frame - 1;
} else {
unit.Frame = cframe->Frame;
}
}
}
void COrder_Built::Progress(CUnit &unit, int amount)
{
Boost(unit, amount, HP_INDEX);
Boost(unit, amount, SHIELD_INDEX);
this->Data.Progress += amount * SpeedBuild;
UpdateConstructionFrame(unit);
}
void COrder_Built::ProgressHp(CUnit &unit, int amount)
{
Boost(unit, amount, HP_INDEX);
this->Data.Progress += amount * SpeedBuild;
UpdateConstructionFrame(unit);
}
void COrder_Built::Boost(CUnit &building, int amount, int varIndex) const
{
Assert(building.CurrentOrder() == this);
const int costs = building.Stats->Costs[TimeCost] * 600;
const int progress = this->Data.Progress;
const int newProgress = progress + amount * SpeedBuild;
const int maxValue = building.Variable[varIndex].Max;
int &currentValue = building.Variable[varIndex].Value;
// damageValue is the current damage taken by the unit.
const int damageValue = (progress * maxValue) / costs - currentValue;
// Keep the same level of damage while increasing Value.
currentValue = (newProgress * maxValue) / costs - damageValue;
currentValue = std::min(currentValue, maxValue);
}
/**
** Unit under Construction
**
@ -432,183 +664,12 @@ void HandleActionBuild(COrder& /*order*/, CUnit &unit)
*/
void HandleActionBuilt(COrder& order, CUnit &unit)
{
CUnit *worker;
CUnitType *type;
int n, mod;
int progress, oldprogress;
//For shields
int sn, smod;
Assert(order.Action == UnitActionBuilt);
type = unit.Type;
// mod is use for round to upper
mod = (unit.Stats->Costs[TimeCost] * 600) - unit.Variable[HP_INDEX].Value;
smod = (unit.Stats->Costs[TimeCost] * 600) - unit.Variable[SHIELD_INDEX].Value;
// n is the current damage taken by the unit.
n = (order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - 1)) / mod;
sn = (order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (smod - 1)) / smod;
// This below is most often 0
if (type->BuilderOutside) {
progress = unit.Type->AutoBuildRate;
} else {
progress = 100;
// FIXME: implement this below:
// unit.Data.Built.Worker->Type->BuilderSpeedFactor;
}
// Building speeds increase or decrease.
progress *= SpeedBuild;
oldprogress = order.Data.Built.Progress;
order.Data.Built.Progress += progress;
// mod is use for round to upper and use it as cache
mod = type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
// Keep the same level of damage while increasing HP.
unit.Variable[HP_INDEX].Value +=
(order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n) -
(oldprogress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n);
if (unit.Variable[HP_INDEX].Value > unit.Stats->Variables[HP_INDEX].Max) {
unit.Variable[HP_INDEX].Value = unit.Stats->Variables[HP_INDEX].Max;
}
if (unit.Variable[SHIELD_INDEX].Max > 0)
{
unit.Variable[SHIELD_INDEX].Value +=
(order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn) -
(oldprogress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn);
if (unit.Variable[SHIELD_INDEX].Value > unit.Stats->Variables[SHIELD_INDEX].Max) {
unit.Variable[SHIELD_INDEX].Value = unit.Stats->Variables[SHIELD_INDEX].Max;
}
}
// Check if construction should be canceled...
if (order.Data.Built.Cancel || order.Data.Built.Progress < 0) {
DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index _C_ unit.Type->Name.c_str());
// Drop out unit
if ((worker = order.Data.Built.Worker)) {
worker->CurrentOrder()->ClearGoal();
worker->ClearAction();
//worker->State = 0;
unit.CurrentOrder()->Data.Built.Worker = NoUnitP;
// HACK: make sure the sight is updated correctly
unit.CurrentSightRange = 1;
DropOutOnSide(*worker, LookingW, &unit);
unit.CurrentSightRange = 0;
}
// Player gets back 75% of the original cost for a building.
unit.Player->AddCostsFactor(unit.Stats->Costs, CancelBuildingCostsFactor);
// Cancel building
LetUnitDie(unit);
return;
}
//
// Check if building ready. Note we can both build and repair.
//
//if (unit.CurrentOrder()->Data.Built.Progress >= unit.Stats->Costs[TimeCost] * 600 ||
if (!order.Data.Built.Worker->Anim.Unbreakable && (order.Data.Built.Progress >= mod ||
unit.Variable[HP_INDEX].Value >= unit.Stats->Variables[HP_INDEX].Max)) {
DebugPrint("%d: Building %s(%s) ready.\n" _C_ unit.Player->Index
_C_ unit.Type->Ident.c_str() _C_ unit.Type->Name.c_str() );
if (unit.Variable[HP_INDEX].Value > unit.Stats->Variables[HP_INDEX].Max) {
unit.Variable[HP_INDEX].Value = unit.Stats->Variables[HP_INDEX].Max;
}
if (order.Execute(unit)) {
order.ClearGoal();
unit.ClearAction();
// HACK: the building is ready now
unit.Player->UnitTypesCount[type->Slot]++;
unit.Constructed = 0;
if (unit.Frame < 0) {
unit.Frame = -1;
} else {
unit.Frame = 0;
}
if ((worker = unit.CurrentOrder()->Data.Built.Worker)) {
// Bye bye worker.
if (type->BuilderLost) {
// FIXME: enough?
LetUnitDie(*worker);
worker = NULL;
// Drop out the worker.
} else {
worker->ClearAction();
worker->SubAction = 0;//may be 40
// HACK: make sure the sight is updated correctly
unit.CurrentSightRange = 1;
DropOutOnSide(*worker, LookingW, &unit);
worker->CurrentOrder()->ClearGoal();
//
// If we can harvest from the new building, do it.
//
if (worker->Type->ResInfo[type->GivesResource]) {
CommandResource(*worker, unit, 0);
}
}
}
if (type->GivesResource) {
// Set to Zero as it's part of a union
memset(&unit.CurrentOrder()->Data, 0, sizeof(unit.CurrentOrder()->Data));
// Has StartingResources, Use those
unit.ResourcesHeld = type->StartingResources;
}
unit.Player->Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y,
_("New %s done"), type->Name.c_str());
if (unit.Player == ThisPlayer) {
if (unit.Type->Sound.Ready.Sound) {
PlayUnitSound(unit, VoiceReady);
} else if (worker) {
PlayUnitSound(*worker, VoiceWorkCompleted);
} else {
PlayUnitSound(unit, VoiceBuilding);
}
}
if (unit.Player->AiEnabled) {
/* Worker can be NULL */
AiWorkComplete(worker, unit);
}
// FIXME: Vladi: this is just a hack to test wall fixing,
// FIXME: also not sure if the right place...
// FIXME: Johns: hardcoded unit-type wall / more races!
if (unit.Type == UnitTypeOrcWall || unit.Type == UnitTypeHumanWall) {
Map.SetWall(unit.tilePos, unit.Type == UnitTypeHumanWall);
unit.Remove(NULL);
UnitLost(unit);
UnitClearOrders(unit);
unit.Release();
return;
}
UpdateForNewUnit(unit, 0);
// Set the direction of the building if it supports them
if (unit.Type->NumDirections > 1) {
if (unit.Type->Wall) { // Special logic for walls
CorrectWallDirections(unit);
CorrectWallNeighBours(unit);
} else {
unit.Direction = (MyRand() >> 8) & 0xFF; // random heading
}
UnitUpdateHeading(unit);
}
if (IsOnlySelected(unit) || unit.Player == ThisPlayer) {
SelectedUnitChanged();
}
unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max;
MapMarkUnitSight(unit);
return;
}
UpdateConstructionFrame(unit);
}
//@}

View file

@ -62,69 +62,45 @@
*/
static void RepairUnit(CUnit &unit, CUnit &goal)
{
CPlayer *player;
int animlength;
int hp;
if (goal.CurrentAction() == UnitActionBuilt) {
COrder_Built &order = *static_cast<COrder_Built *>(goal.CurrentOrder());
order.ProgressHp(goal, 100 * unit.CurrentOrder()->Data.Repair.Cycles);
unit.CurrentOrder()->Data.Repair.Cycles = 0;
return ;
}
CPlayer *player = unit.Player;
char buf[100];
player = unit.Player;
// Calculate the repair costs.
Assert(goal.Stats->Variables[HP_INDEX].Max);
if (goal.CurrentAction() != UnitActionBuilt) {
//
// Calculate the repair costs.
//
Assert(goal.Stats->Variables[HP_INDEX].Max);
//
// Check if enough resources are available
//
for (int i = 1; i < MaxCosts; ++i) {
if (player->Resources[i] < goal.Type->RepairCosts[i]) {
snprintf(buf, 100, _("We need more %s for repair!"),
DefaultResourceNames[i].c_str());
player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
if (player->AiEnabled) {
// FIXME: call back to AI?
unit.CurrentOrder()->ClearGoal();
if (!unit.RestoreOrder()) {
unit.ClearAction();
unit.State = 0;
}
// Check if enough resources are available
for (int i = 1; i < MaxCosts; ++i) {
if (player->Resources[i] < goal.Type->RepairCosts[i]) {
snprintf(buf, 100, _("We need more %s for repair!"),
DefaultResourceNames[i].c_str());
player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
if (player->AiEnabled) {
// FIXME: call back to AI?
unit.CurrentOrder()->ClearGoal();
if (!unit.RestoreOrder()) {
unit.ClearAction();
unit.State = 0;
}
// FIXME: We shouldn't animate if no resources are available.
return;
}
// FIXME: We shouldn't animate if no resources are available.
return;
}
//
// Subtract the resources
//
player->SubCosts(goal.Type->RepairCosts);
}
//
// Subtract the resources
//
player->SubCosts(goal.Type->RepairCosts);
goal.Variable[HP_INDEX].Value += goal.Type->RepairHP;
if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
}
} else {
int costs = goal.Stats->Costs[TimeCost] * 600;
// hp is the current damage taken by the unit.
hp = (goal.CurrentOrder()->Data.Built.Progress * goal.Variable[HP_INDEX].Max) /
costs - goal.Variable[HP_INDEX].Value;
//
// Calculate the length of the attack (repair) anim.
//
animlength = unit.CurrentOrder()->Data.Repair.Cycles;
unit.CurrentOrder()->Data.Repair.Cycles = 0;
// FIXME: implement this below:
//unit.Data.Built.Worker->Type->BuilderSpeedFactor;
goal.CurrentOrder()->Data.Built.Progress += 100 * animlength * SpeedBuild;
// Keep the same level of damage while increasing HP.
goal.Variable[HP_INDEX].Value =
(goal.CurrentOrder()->Data.Built.Progress * goal.Stats->Variables[HP_INDEX].Max) /
costs - hp;
if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
}
goal.Variable[HP_INDEX].Value += goal.Type->RepairHP;
if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
}
}

View file

@ -176,14 +176,28 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
return order;
}
/* static */ COrder* COrder::NewActionBuilt()
/* static */ COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit)
{
COrder *order = new COrder;
COrder_Built* order = new COrder_Built();
order->Action = UnitActionBuilt;
// Make sure the bulding doesn't cancel itself out right away.
order->Data.Progress = 0;//FIXME ? 100 : 0
unit.Variable[HP_INDEX].Value = 1;
if (unit.Variable[SHIELD_INDEX].Max) {
unit.Variable[SHIELD_INDEX].Value = 1;
}
order->UpdateConstructionFrame(unit);
if (unit.Type->BuilderOutside == false) {
order->Data.Worker = &builder;
}
return order;
}
/* static */ COrder* COrder::NewActionDie()
{
COrder *order = new COrder;
@ -460,6 +474,14 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
return order;
}
/* static */ COrder* COrder::NewActionBuilt()
{
COrder *order = new COrder_Built;
order->Action = UnitActionBuilt;
return order;
}
/* static */ COrder* COrder::NewActionFollow()
{
COrder *order = new COrder;
@ -518,7 +540,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
/* static */ COrder* COrder::NewActionSpellCast()
{
COrder *order = new COrder;
COrder *order = new COrder_SpellCast;
order->Action = UnitActionSpellCast;
return order;
@ -655,17 +677,13 @@ bool COrder::CheckRange() const
return (Range <= Map.Info.MapWidth || Range <= Map.Info.MapHeight);
}
void COrder::FillSeenValues(CUnit &unit) const
/* virtual */ void COrder::FillSeenValues(CUnit &unit) const
{
unit.Seen.State = (Action == UnitActionBuilt) | ((Action == UnitActionUpgradeTo) << 1);
unit.Seen.State = ((Action == UnitActionUpgradeTo) << 1);
if (unit.CurrentAction() == UnitActionDie) {
unit.Seen.State = 3;
}
if (Action == UnitActionBuilt) {
unit.Seen.CFrame = Data.Built.Frame;
} else {
unit.Seen.CFrame = NULL;
}
unit.Seen.CFrame = NULL;
}
bool COrder::OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/)

View file

@ -471,7 +471,7 @@ void CommandDismiss(CUnit &unit)
{
// Check if building is still under construction? (NETWORK!)
if (unit.CurrentAction() == UnitActionBuilt) {
unit.CurrentOrder()->Data.Built.Cancel = 1;
unit.CurrentOrder()->Cancel(unit);
} else {
DebugPrint("Suicide unit ... \n");
LetUnitDie(unit);

View file

@ -31,16 +31,14 @@
#define __ACTIONS_H__
//@{
#ifndef __UNIT_CACHE_H__
#include "unit_cache.h"
#ifndef __UNIT_H__
#include "unit.h"
#endif
#ifndef __VEC2I_H__
#include "vec2i.h"
#endif
//#include "vec2i.h"
/*----------------------------------------------------------------------------
-- Declarations
----------------------------------------------------------------------------*/
@ -124,6 +122,7 @@ public:
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
virtual void UpdateUnitVariables(CUnit &unit) const;
virtual void FillSeenValues(CUnit &unit) const;
void ReleaseRefs(CUnit &owner);
@ -156,7 +155,6 @@ public:
void NewResetPath() { Data.Move.Fast = 1; Data.Move.Length = 0; }
void SaveDataMove(CFile &file) const;
void FillSeenValues(CUnit &unit) const;
bool OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/);
void AiUnitKilled(CUnit &unit);
@ -168,6 +166,7 @@ public:
static COrder* NewActionBoard(CUnit &unit);
static COrder* NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building);
static COrder* NewActionBuilt();
static COrder* NewActionBuilt(CUnit &builder, CUnit &unit);
static COrder* NewActionDie();
static COrder* NewActionFollow(CUnit &dest);
static COrder* NewActionMove(const Vec2i &pos);
@ -235,12 +234,6 @@ public:
#define MAX_PATH_LENGTH 28 /// max length of precalculated path
char Path[MAX_PATH_LENGTH]; /// directions of stored path
} Move; /// ActionMove,...
struct _order_built_ {
CUnit *Worker; /// Worker building this unit
int Progress; /// Progress counter, in 1/100 cycles.
int Cancel; /// Cancel construction
CConstructionFrame *Frame; /// Construction frame
} Built; /// ActionBuilt,...
struct _order_build_ {
int Cycles; /// Cycles unit has been building for
} Build; /// ActionBuild
@ -260,6 +253,43 @@ public:
} Data; /// Storage room for different commands
};
class COrder_Built : public COrder
{
friend COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit);
public:
virtual COrder_Built *Clone() const;
virtual void Save(CFile &file, const CUnit &unit) const;
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
virtual bool Execute(CUnit &unit);
virtual void Cancel(CUnit &unit);
virtual void UpdateUnitVariables(CUnit &unit) const;
virtual void FillSeenValues(CUnit &unit) const;
void Progress(CUnit & unit, int amount);
void ProgressHp(CUnit &unit, int amount);
const CConstructionFrame& GetFrame() const { return *Data.Frame; }
const CUnitPtr &GetWorker() const { return Data.Worker; }
CUnit *GetWorkerPtr() { return Data.Worker; }
private:
void Boost(CUnit &building, int amount, int varIndex) const;
void UpdateConstructionFrame(CUnit &unit);
private:
struct {
CUnitPtr Worker; /// Worker building this unit
int Progress; /// Progress counter, in 1/100 cycles.
int Cancel; /// Cancel construction
const CConstructionFrame *Frame; /// Construction frame
} Data; /// ActionBuilt,...
};
class COrder_Research : public COrder
{
public:

View file

@ -284,6 +284,11 @@ extern void SaveCcl(CFile *file); /// Save CCL module
extern void SavePreferences(); /// Save user preferences
extern int CclCommand(const std::string &command, bool exitOnError = true);
CUnit *CclGetUnitFromRef(lua_State *l);
extern NumberDesc *Damage; /// Damage calculation for missile.
/// transform string in corresponding index.

View file

@ -354,8 +354,6 @@
#include "player.h"
#endif
#include "actions.h"
#include "vec2i.h"
/*----------------------------------------------------------------------------
@ -546,7 +544,7 @@ public:
/* Seen stuff. */
int VisCount[PlayerMax]; /// Unit visibility counts
struct _seen_stuff_ {
CConstructionFrame *CFrame; /// Seen construction frame
const CConstructionFrame *CFrame; /// Seen construction frame
int Frame; /// last seen frame/stage of buildings
CUnitType *Type; /// Pointer to last seen unit-type
int X; /// Last unit->X Seen
@ -1105,6 +1103,9 @@ extern int CanTransport(const CUnit &transporter, const CUnit &unit);
/// Generate a unit reference, a printable unique string for unit
extern std::string UnitReference(const CUnit &unit);
/// Generate a unit reference, a printable unique string for unit
extern std::string UnitReference(const CUnitPtr &unit);
/// Save an order
extern void SaveOrder(const COrder &order, const CUnit &unit, CFile *file);
/// save unit-structure

View file

@ -44,7 +44,6 @@
#include "map.h"
#include "tileset.h"
#include "minimap.h"
#include "actions.h"
#include "results.h"
#include "ui.h"
#include "player.h"

View file

@ -40,6 +40,7 @@
#include "unittype.h"
#include "unit.h"
#include "pathfinder.h"
#include "actions.h"
//astar.cpp

View file

@ -56,6 +56,7 @@
#include "missile.h"
#include "sound.h"
#include "ui.h"
#include "actions.h"
#include "iolib.h"
#include "util.h"

View file

@ -165,7 +165,7 @@ void ChangeSelectedUnits(CUnit **units, int count)
if (count == 1 && units[0]->Type->ClicksToExplode &&
!units[0]->Type->IsNotSelectable) {
HandleSuicideClick(*units[0]);
if (units[0]->CurrentAction() == UnitActionDie) {
if (!units[0]->IsAlive()) {
NetworkSendSelection(units, count);
return ;
}
@ -379,7 +379,7 @@ int SelectUnitsByType(CUnit &base)
// if unit is a cadaver or hidden (not on map)
// no unit can be selected.
if (base.Removed || base.CurrentAction() == UnitActionDie) {
if (base.Removed || base.IsAlive() == false) {
return 0;
}
@ -464,7 +464,7 @@ int ToggleUnitsByType(CUnit &base)
// if unit is a cadaver or hidden (not on map)
// no unit can be selected.
if (base.Removed || base.CurrentAction() == UnitActionDie) {
if (base.Removed || base.IsAlive() == false) {
return 0;
}
// if unit isn't belonging to the player, or is a static unit
@ -709,7 +709,7 @@ CUnit**table, int num_units = UnitMax)
continue;
}
// FIXME: Can we get this?
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (!unit.Removed && unit.IsAlive()) {
SelectSingleUnit(unit);
return 1;
}

View file

@ -56,6 +56,7 @@
#include "commands.h"
#include "video.h"
#include "font.h"
#include "actions.h"
#include "guichan/key.h"
#include "guichan/sdl/sdlinput.h"

View file

@ -44,6 +44,7 @@
#include "interface.h"
#include "network.h"
#include "player.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Functions

View file

@ -60,6 +60,7 @@
#include "ai.h"
#include "widgets.h"
#include "replay.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Defines

View file

@ -59,6 +59,7 @@
#include "network.h"
#include "menus.h"
#include "spells.h"
#include "actions.h"
#ifdef DEBUG
#include "../ai/ai_local.h"
#endif
@ -285,7 +286,7 @@ UStrInt GetComponent(const CUnit &unit, int index, EnumVariable e, int t)
**
** @return The desired unit.
*/
const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
static const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
{
switch (e) {
case UnitRefItSelf:
@ -296,7 +297,9 @@ const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
return unit.Container;
case UnitRefWorker :
if (unit.CurrentAction() == UnitActionBuilt) {
return unit.CurrentOrder()->Data.Built.Worker;
COrder_Built &order = *static_cast<COrder_Built*>(unit.CurrentOrder());
return order.GetWorkerPtr();
} else {
return NoUnitP;
}

View file

@ -61,6 +61,7 @@
#include "network.h"
#include "spells.h"
#include "widgets.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Variables

View file

@ -38,6 +38,7 @@
#include "unittype.h"
#include "map.h"
#include "player.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Functions

View file

@ -155,53 +155,6 @@ static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1)
lua_pop(l, 1);
}
/**
** Parse built
**
** @param l Lua state.
** @param order Unit pointer which should be filled with the data.
*/
static void CclParseBuilt(lua_State *l, const CUnit &unit, COrderPtr order)
{
const char *value;
int args;
int j;
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
args = lua_objlen(l, -1);
for (j = 0; j < args; ++j) {
lua_rawgeti(l, -1, j + 1);
value = LuaToString(l, -1);
lua_pop(l, 1);
++j;
if (!strcmp(value, "worker")) {
lua_rawgeti(l, -1, j + 1);
order->Data.Built.Worker = CclGetUnitFromRef(l);
lua_pop(l, 1);
} else if (!strcmp(value, "progress")) {
lua_rawgeti(l, -1, j + 1);
order->Data.Built.Progress = LuaToNumber(l, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "cancel")) {
order->Data.Built.Cancel = 1;
--j;
} else if (!strcmp(value, "frame")) {
lua_rawgeti(l, -1, j + 1);
int frame = LuaToNumber(l, -1);
lua_pop(l, 1);
CConstructionFrame *cframe = unit.Type->Construction->Frames;
while (frame--) {
cframe = cframe->Next;
}
order->Data.Built.Frame = cframe;
} else {
LuaError(l, "ParseBuilt: Unsupported tag: %s" _C_ value);
}
}
}
/**
** Parse res worker data
**
@ -419,11 +372,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU
this->Arg1.Resource.Pos = invalidPos;
this->Arg1.Resource.Mine = CclGetUnitFromRef(l);
lua_pop(l, 1);
} else if (!strcmp(value, "data-built")) {
++j;
lua_rawgeti(l, -1, j + 1);
CclParseBuilt(l, unit, this);
lua_pop(l, 1);
} else if (!strcmp(value, "data-res-worker")) {
++j;
lua_rawgeti(l, -1, j + 1);

View file

@ -53,6 +53,7 @@
#include "unit.h"
#include "unit_manager.h"
#include "player.h"
#include "actions.h"
#include "luacallback.h"
/*----------------------------------------------------------------------------
@ -2158,22 +2159,7 @@ static int CclDefineDecorations(lua_State *l)
/* virtual */ void COrder::UpdateUnitVariables(CUnit &unit) const
{
const CUnitType *type = unit.Type;
switch (unit.CurrentAction()) {
// Build
case UnitActionBuilt:
unit.Variable[BUILD_INDEX].Value = unit.CurrentOrder()->Data.Built.Progress;
unit.Variable[BUILD_INDEX].Max = type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
// This should happen when building unit with several peons
// Maybe also with only one.
// FIXME : Should be better to fix it in action_{build,repair}.c ?
if (unit.Variable[BUILD_INDEX].Value > unit.Variable[BUILD_INDEX].Max) {
// assume value is wrong.
unit.Variable[BUILD_INDEX].Value = unit.Variable[BUILD_INDEX].Max;
}
break;
// Training
case UnitActionTrain:
unit.Variable[TRAINING_INDEX].Value = unit.CurrentOrder()->Data.Train.Ticks;

View file

@ -266,7 +266,9 @@ unsigned int CUnit::CurrentAction() const
void CUnit::ClearAction()
{
CurrentOrder()->Action = UnitActionStill;
delete CurrentOrder();
Orders[0] = COrder::NewActionStill();
SubAction = 0;
if (Selected) {
SelectedUnitChanged();
@ -2821,16 +2823,6 @@ void LetUnitDie(CUnit &unit)
unit.Goal = NULL;
}
// During resource build, the worker holds the resource amount,
// but if canceling building the platform, the worker is already
// outside.
if (type->GivesResource &&
unit.CurrentAction() == UnitActionBuilt &&
unit.CurrentOrder()->Data.Built.Worker) {
// Restore value for oil-patch
unit.ResourcesHeld = unit.CurrentOrder()->Data.Built.Worker->ResourcesHeld;
}
// Transporters lose or save their units and building their workers
if (unit.UnitInside && unit.Type->SaveCargo)
DropOutAll(unit);
@ -2842,7 +2834,6 @@ void LetUnitDie(CUnit &unit)
UnitClearOrders(unit);
// Unit has death animation.
// Not good: UnitUpdateHeading(unit);

View file

@ -55,6 +55,7 @@
#include "interface.h"
#include "font.h"
#include "ui.h"
#include "actions.h"
#include "script.h"
/*----------------------------------------------------------------------------
@ -173,7 +174,7 @@ void DrawUnitSelection(const CViewport *vp, const CUnit &unit)
const CUnitType &type = *unit.Type;
const PixelPos screenPos = vp->TilePosToScreen_TopLeft(unit.tilePos);
const int x = screenPos.x + unit.IX +type.TileWidth * PixelTileSize.x / 2
const int x = screenPos.x + unit.IX + type.TileWidth * PixelTileSize.x / 2
- type.BoxWidth / 2 - (type.Width - type.Sprite->Width) / 2;
const int y = screenPos.y + unit.IY + type.TileHeight * PixelTileSize.y / 2
- type.BoxHeight / 2 - (type.Height - type.Sprite->Height) / 2;
@ -1080,7 +1081,7 @@ void CUnit::Draw(const CViewport *vp) const
int constructed;
CPlayerColorGraphic *sprite;
ResourceInfo *resinfo;
CConstructionFrame *cframe;
const CConstructionFrame *cframe;
CUnitType *type;
/*
@ -1113,8 +1114,14 @@ void CUnit::Draw(const CViewport *vp) const
if (state == 2) {
type = this->CurrentOrder()->Arg1.Type;
}
// This is trash unless the unit is being built, and that's when we use it.
cframe = this->CurrentOrder()->Data.Built.Frame;
if (this->CurrentAction() == UnitActionBuilt) {
COrder_Built &order = *static_cast<COrder_Built*>(this->CurrentOrder());
cframe = &order.GetFrame();
} else {
cframe = NULL;
}
} else {
const Vec2i seenTilePos = {this->Seen.X, this->Seen.Y};
const PixelPos &screenPos = vp->TilePosToScreen_TopLeft(seenTilePos);
@ -1257,8 +1264,13 @@ void CUnitDrawProxy::operator=(const CUnit *unit)
}
if (unit->Constructed) {
// This is trash unless the unit is being built, and that's when we use it.
cframe = unit->CurrentOrder()->Data.Built.Frame;
if (unit->CurrentAction() == UnitActionBuilt) {
COrder_Built &order = *static_cast<COrder_Built*>(unit->CurrentOrder());
cframe = &order.GetFrame();
} else {
cframe = NULL;
}
}
} else {
IY = unit->Seen.IY;

View file

@ -45,6 +45,7 @@
#include "spells.h"
#include "construct.h"
#include "iolib.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Functions
@ -61,6 +62,20 @@ std::string UnitReference(const CUnit &unit)
return ss.str();
}
/**
** Generate a unit reference, a printable unique string for unit.
*/
std::string UnitReference(const CUnitPtr &unit)
{
Assert(unit != NULL);
std::ostringstream ss;
ss << "U" << std::setfill('0') << std::setw(4) << std::uppercase <<
std::hex << unit->Slot;
return ss.str();
}
/**
** Save an order.
**
@ -108,9 +123,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
case UnitActionUpgradeTo:
file.printf("\"action-upgrade-to\",");
break;
case UnitActionBuilt:
file.printf("\"action-built\",");
break;
case UnitActionBoard:
file.printf("\"action-board\",");
break;
@ -203,28 +215,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
file.printf("}");
break;
case UnitActionBuilt:
{
CConstructionFrame *cframe;
int frame;
cframe = unit.Type->Construction->Frames;
frame = 0;
while (cframe != order.Data.Built.Frame) {
cframe = cframe->Next;
++frame;
}
file.printf(",\n \"data-built\", {");
if (order.Data.Built.Worker) {
file.printf("\"worker\", \"%s\", ", UnitReference(*order.Data.Built.Worker).c_str());
}
file.printf("\"progress\", %d, \"frame\", %d", order.Data.Built.Progress, frame);
if (order.Data.Built.Cancel) {
file.printf(", \"cancel\"");
}
file.printf("}");
break;
}
case UnitActionResearch:
break;
case UnitActionUpgradeTo: