Gobligine/src/action/action_upgradeto.cpp
2015-11-27 23:28:25 +01:00

314 lines
9 KiB
C++

// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name action_upgradeto.cpp - The unit upgrading to new action. */
//
// (c) Copyright 1998-2015 by Lutz Sammer, Jimmy Salmon and Andrettin
//
// 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 "action/action_upgradeto.h"
#include "ai.h"
#include "animation.h"
#include "iolib.h"
#include "map.h"
#include "player.h"
#include "script.h"
#include "spells.h"
#include "translate.h"
#include "unit.h"
#include "unittype.h"
/// How many resources the player gets back if canceling upgrade
#define CancelUpgradeCostsFactor 100
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/* static */ COrder *COrder::NewActionTransformInto(CUnitType &type)
{
COrder_TransformInto *order = new COrder_TransformInto;
order->Type = &type;
return order;
}
/* static */ COrder *COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type)
{
COrder_UpgradeTo *order = new COrder_UpgradeTo;
// FIXME: if you give quick an other order, the resources are lost!
unit.Player->SubUnitType(type);
order->Type = &type;
return order;
}
/**
** Transform a unit in another.
**
** @param unit unit to transform.
** @param newtype new type of the unit.
**
** @return 0 on error, 1 if nothing happens, 2 else.
*/
static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
{
const CUnitType &oldtype = *unit.Type;
if (&oldtype == &newtype) { // nothing to do
return 1;
}
const Vec2i pos = unit.tilePos + oldtype.GetHalfTileSize() - newtype.GetHalfTileSize();
CUnit *container = unit.Container;
if (container) {
MapUnmarkUnitSight(unit);
} else {
SaveSelection();
unit.Remove(NULL);
if (!UnitTypeCanBeAt(newtype, pos)) {
unit.Place(unit.tilePos);
RestoreSelection();
// FIXME unit is not modified, try later ?
return 0;
}
}
CPlayer &player = *unit.Player;
player.UnitTypesCount[oldtype.Slot]--;
player.UnitTypesCount[newtype.Slot]++;
if (unit.Active) {
player.UnitTypesAiActiveCount[oldtype.Slot]--;
player.UnitTypesAiActiveCount[newtype.Slot]++;
}
player.Demand += newtype.Stats[player.Index].Variables[DEMAND_INDEX].Value - oldtype.Stats[player.Index].Variables[DEMAND_INDEX].Value;
player.Supply += newtype.Stats[player.Index].Variables[SUPPLY_INDEX].Value - oldtype.Stats[player.Index].Variables[SUPPLY_INDEX].Value;
// Change resource limit
for (int i = 0; i < MaxCosts; ++i) {
if (player.MaxResources[i] != -1) {
player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i];
player.SetResource(i, player.StoredResources[i], STORE_BUILDING);
}
}
// adjust Variables with percent.
const CUnitStats &newstats = newtype.Stats[player.Index];
for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) {
if (i == KILL_INDEX || i == XP_INDEX) {
unit.Variable[i].Value = unit.Variable[i].Max;
} else if (unit.Variable[i].Max && unit.Variable[i].Value) {
unit.Variable[i].Value = newstats.Variables[i].Max *
unit.Variable[i].Value / unit.Variable[i].Max;
unit.Variable[i].Max = std::max(newstats.Variables[i].Max, unit.Variable[i].Max);
unit.Variable[i].Increase = newstats.Variables[i].Increase;
unit.Variable[i].Enable = newstats.Variables[i].Enable;
} else {
unit.Variable[i].Value = newstats.Variables[i].Value;
unit.Variable[i].Max = unit.Variable[i].Value;
unit.Variable[i].Enable = newstats.Variables[i].Enable;
}
}
unit.Type = const_cast<CUnitType *>(&newtype);
unit.Stats = &unit.Type->Stats[player.Index];
if (newtype.CanCastSpell && !unit.AutoCastSpell) {
unit.AutoCastSpell = new char[SpellTypeTable.size()];
unit.SpellCoolDownTimers = new int[SpellTypeTable.size()];
memset(unit.AutoCastSpell, 0, SpellTypeTable.size() * sizeof(char));
memset(unit.SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int));
}
UpdateForNewUnit(unit, 1);
// Update Possible sight range change
UpdateUnitSightRange(unit);
if (!container) {
unit.Place(pos);
RestoreSelection();
} else {
MapMarkUnitSight(unit);
}
//
// Update possible changed buttons.
//
if (IsOnlySelected(unit) || &player == ThisPlayer) {
// could affect the buttons of any selected unit
SelectedUnitChanged();
}
return 1;
}
#if 1 // TransFormInto
/* virtual */ void COrder_TransformInto::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-transform-into\",");
if (this->Finished) {
file.printf(" \"finished\", ");
}
file.printf(" \"type\", \"%s\"", this->Type->Ident.c_str());
file.printf("}");
}
/* virtual */ bool COrder_TransformInto::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (!strcmp(value, "type")) {
++j;
this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1));
} else {
return false;
}
return true;
}
/* virtual */ bool COrder_TransformInto::IsValid() const
{
return true;
}
/* virtual */ PixelPos COrder_TransformInto::Show(const CViewport &, const PixelPos &lastScreenPos) const
{
return lastScreenPos;
}
/* virtual */ void COrder_TransformInto::Execute(CUnit &unit)
{
TransformUnitIntoType(unit, *this->Type);
this->Finished = true;
}
#endif
#if 1 // COrder_UpgradeTo
/* virtual */ void COrder_UpgradeTo::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-upgrade-to\",");
if (this->Finished) {
file.printf(" \"finished\", ");
}
file.printf(" \"type\", \"%s\",", this->Type->Ident.c_str());
file.printf(" \"ticks\", %d", this->Ticks);
file.printf("}");
}
/* virtual */ bool COrder_UpgradeTo::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (!strcmp(value, "type")) {
++j;
this->Type = UnitTypeByIdent(LuaToString(l, -1, j + 1));
} else if (!strcmp(value, "ticks")) {
++j;
this->Ticks = LuaToNumber(l, -1, j + 1);
} else {
return false;
}
return true;
}
/* virtual */ bool COrder_UpgradeTo::IsValid() const
{
return true;
}
/* virtual */ PixelPos COrder_UpgradeTo::Show(const CViewport &, const PixelPos &lastScreenPos) const
{
return lastScreenPos;
}
static void AnimateActionUpgradeTo(CUnit &unit)
{
CAnimations &animations = *unit.Type->Animations;
UnitShowAnimation(unit, animations.Upgrade ? animations.Upgrade : animations.Still);
}
/* virtual */ void COrder_UpgradeTo::Execute(CUnit &unit)
{
AnimateActionUpgradeTo(unit);
if (unit.Wait) {
unit.Wait--;
return ;
}
CPlayer &player = *unit.Player;
const CUnitType &newtype = *this->Type;
const CUnitStats &newstats = newtype.Stats[player.Index];
this->Ticks += std::max(1, player.SpeedUpgrade / SPEEDUP_FACTOR);
if (this->Ticks < newstats.Costs[TimeCost]) {
unit.Wait = CYCLES_PER_SECOND / 6;
return ;
}
if (unit.Anim.Unbreakable) {
this->Ticks = newstats.Costs[TimeCost];
return ;
}
if (TransformUnitIntoType(unit, newtype) == 0) {
player.Notify(NotifyYellow, unit.tilePos, _("Upgrade to %s canceled"), newtype.Name.c_str());
this->Finished = true;
return ;
}
player.Notify(NotifyGreen, unit.tilePos, _("Upgrade to %s complete"), unit.Type->Name.c_str());
// Warn AI.
if (player.AiEnabled) {
AiUpgradeToComplete(unit, newtype);
}
this->Finished = true;
}
/* virtual */ void COrder_UpgradeTo::Cancel(CUnit &unit)
{
CPlayer &player = *unit.Player;
player.AddCostsFactor(this->Type->Stats[player.Index].Costs, CancelUpgradeCostsFactor);
}
/* virtual */ void COrder_UpgradeTo::UpdateUnitVariables(CUnit &unit) const
{
Assert(unit.CurrentOrder() == this);
unit.Variable[UPGRADINGTO_INDEX].Value = this->Ticks;
unit.Variable[UPGRADINGTO_INDEX].Max = this->Type->Stats[unit.Player->Index].Costs[TimeCost];
}
#endif
//@}