[+] Added new order COrder_Defend, which allows to send some unit to defend another. You may use right click with ALT, or use the "move" button with ALT button
[*] The coward units in AI force now use Defend order instead of attacking. The same rule applies to summoned units. [*] The summoned units get GroupId = -1 to avoid AI defence force activate [*] Changed CclKillUnitAt to use CclGetPos
This commit is contained in:
parent
53721e1ce9
commit
09e63586c7
17 changed files with 444 additions and 59 deletions
|
@ -43,6 +43,7 @@ set(action_SRCS
|
|||
src/action/action_board.cpp
|
||||
src/action/action_build.cpp
|
||||
src/action/action_built.cpp
|
||||
src/action/action_defend.cpp
|
||||
src/action/action_die.cpp
|
||||
src/action/action_follow.cpp
|
||||
src/action/action_move.cpp
|
||||
|
@ -422,6 +423,7 @@ set(stratagus_action_HDRS
|
|||
src/include/action/action_board.h
|
||||
src/include/action/action_build.h
|
||||
src/include/action/action_built.h
|
||||
src/include/action/action_defend.h
|
||||
src/include/action/action_die.h
|
||||
src/include/action/action_follow.h
|
||||
src/include/action/action_move.h
|
||||
|
|
209
src/action/action_defend.cpp
Normal file
209
src/action/action_defend.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name action_defend.cpp - The defend action. */
|
||||
//
|
||||
// (c) Copyright 2012 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 "action/action_defend.h"
|
||||
|
||||
#include "iolib.h"
|
||||
#include "map.h"
|
||||
#include "pathfinder.h"
|
||||
#include "script.h"
|
||||
#include "ui.h"
|
||||
#include "unit.h"
|
||||
#include "unittype.h"
|
||||
#include "video.h"
|
||||
|
||||
enum {
|
||||
State_Init = 0,
|
||||
State_MovingToTarget,
|
||||
State_Defending
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/* static */ COrder *COrder::NewActionDefend(CUnit &dest)
|
||||
{
|
||||
COrder_Defend *order = new COrder_Defend();
|
||||
|
||||
if (dest.Destroyed) {
|
||||
order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize();
|
||||
} else {
|
||||
order->SetGoal(&dest);
|
||||
order->Range = 1;
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/* virtual */ void COrder_Defend::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-defend\",");
|
||||
|
||||
if (this->Finished) {
|
||||
file.printf(" \"finished\", ");
|
||||
}
|
||||
file.printf(" \"range\", %d,", this->Range);
|
||||
if (this->HasGoal()) {
|
||||
file.printf(" \"goal\", \"%s\",", UnitReference(this->GetGoal()).c_str());
|
||||
}
|
||||
file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
|
||||
|
||||
file.printf(" \"state\", %d", this->State);
|
||||
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Defend::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
if (!strcmp(value, "state")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "range")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->Range = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "tile")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
CclGetPos(l, &this->goalPos.x , &this->goalPos.y);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Defend::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ PixelPos COrder_Defend::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
|
||||
{
|
||||
PixelPos targetPos;
|
||||
|
||||
if (this->HasGoal()) {
|
||||
targetPos = vp.MapToScreenPixelPos(this->GetGoal()->GetMapPixelPosCenter());
|
||||
} else {
|
||||
targetPos = vp.TilePosToScreen_Center(this->goalPos);
|
||||
}
|
||||
Video.FillCircleClip(ColorGreen, lastScreenPos, 2);
|
||||
Video.DrawLineClip(ColorGreen, lastScreenPos, targetPos);
|
||||
Video.FillCircleClip(ColorOrange, targetPos, 3);
|
||||
return targetPos;
|
||||
}
|
||||
|
||||
/* virtual */ void COrder_Defend::UpdatePathFinderData(PathFinderInput &input)
|
||||
{
|
||||
input.SetMinRange(0);
|
||||
input.SetMaxRange(this->Range);
|
||||
|
||||
Vec2i tileSize;
|
||||
if (this->HasGoal()) {
|
||||
CUnit *goal = this->GetGoal();
|
||||
tileSize.x = goal->Type->TileWidth;
|
||||
tileSize.y = goal->Type->TileHeight;
|
||||
input.SetGoal(goal->tilePos, tileSize);
|
||||
} else {
|
||||
tileSize.x = 0;
|
||||
tileSize.y = 0;
|
||||
input.SetGoal(this->goalPos, tileSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void COrder_Defend::Execute(CUnit &unit)
|
||||
{
|
||||
if (unit.Wait) {
|
||||
unit.Wait--;
|
||||
return ;
|
||||
}
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
if (this->State == State_Init) {
|
||||
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
this->Finished = true;
|
||||
return;
|
||||
}
|
||||
this->State = State_MovingToTarget;
|
||||
} else if (this->State == State_Defending) {
|
||||
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
this->Finished = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (DoActionMove(unit)) {
|
||||
case PF_UNREACHABLE:
|
||||
// Some tries to reach the goal
|
||||
this->Range++;
|
||||
break;
|
||||
case PF_REACHED: {
|
||||
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died
|
||||
this->Finished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now defend the goal
|
||||
this->goalPos = goal->tilePos;
|
||||
this->State = State_Defending;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Target destroyed?
|
||||
if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("Goal gone\n");
|
||||
this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
|
||||
this->ClearGoal();
|
||||
goal = NULL;
|
||||
if (this->State == State_Defending) {
|
||||
this->Finished = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@
|
|||
#include "action/action_board.h"
|
||||
#include "action/action_build.h"
|
||||
#include "action/action_built.h"
|
||||
#include "action/action_defend.h"
|
||||
#include "action/action_die.h"
|
||||
#include "action/action_follow.h"
|
||||
#include "action/action_move.h"
|
||||
|
@ -185,6 +186,8 @@ void CclParseOrder(lua_State *l, CUnit &unit, COrderPtr *orderPtr)
|
|||
*orderPtr = new COrder_Build;
|
||||
} else if (!strcmp(actiontype, "action-built")) {
|
||||
*orderPtr = new COrder_Built;
|
||||
} else if (!strcmp(actiontype, "action-defend")) {
|
||||
*orderPtr = new COrder_Defend;
|
||||
} else if (!strcmp(actiontype, "action-die")) {
|
||||
*orderPtr = new COrder_Die;
|
||||
} else if (!strcmp(actiontype, "action-follow")) {
|
||||
|
|
|
@ -182,6 +182,33 @@ void CommandStandGround(CUnit &unit, int flush)
|
|||
ClearSavedAction(unit);
|
||||
}
|
||||
|
||||
/**
|
||||
** Follow unit and defend it
|
||||
**
|
||||
** @param unit pointer to unit.
|
||||
** @param dest unit to follow
|
||||
** @param flush if true, flush command queue.
|
||||
*/
|
||||
void CommandDefend(CUnit &unit, CUnit &dest, int flush)
|
||||
{
|
||||
if (IsUnitValidForNetwork(unit) == false) {
|
||||
return ;
|
||||
}
|
||||
COrderPtr *order;
|
||||
|
||||
if (!unit.CanMove()) {
|
||||
ClearNewAction(unit);
|
||||
order = &unit.NewOrder;
|
||||
} else {
|
||||
order = GetNextOrder(unit, flush);
|
||||
if (order == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
*order = COrder::NewActionDefend(dest);
|
||||
ClearSavedAction(unit);
|
||||
}
|
||||
|
||||
/**
|
||||
** Follow unit to new position
|
||||
**
|
||||
|
|
|
@ -399,6 +399,15 @@ void AiForce::Attack(const Vec2i &pos)
|
|||
}
|
||||
// Send all units in the force to enemy.
|
||||
|
||||
CUnit *leader = NULL;
|
||||
for (size_t i = 0; i != this->Units.size(); ++i) {
|
||||
CUnit *const unit = this->Units[i];
|
||||
|
||||
if (unit->IsAgressive()) {
|
||||
leader = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i != this->Units.size(); ++i) {
|
||||
CUnit *const unit = this->Units[i];
|
||||
|
||||
|
@ -406,10 +415,14 @@ void AiForce::Attack(const Vec2i &pos)
|
|||
const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference.
|
||||
|
||||
unit->Wait = delay;
|
||||
if (unit->Type->CanAttack) {
|
||||
if (unit->IsAgressive()) {
|
||||
CommandAttack(*unit, this->GoalPos, NULL, FlushCommands);
|
||||
} else {
|
||||
CommandMove(*unit, this->GoalPos, FlushCommands);
|
||||
if (leader) {
|
||||
CommandDefend(*unit, *leader, FlushCommands);
|
||||
} else {
|
||||
CommandMove(*unit, this->GoalPos, FlushCommands);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -800,9 +813,13 @@ void AiForce::Update()
|
|||
}
|
||||
|
||||
std::vector<CUnit *> idleUnits;
|
||||
CUnit *leader = NULL;
|
||||
for (unsigned int i = 0; i != Size(); ++i) {
|
||||
CUnit &aiunit = *Units[i];
|
||||
|
||||
if (aiunit.IsAgressive()) {
|
||||
leader = &aiunit;
|
||||
}
|
||||
if (aiunit.IsIdle() && aiunit.IsAliveOnMap()) {
|
||||
idleUnits.push_back(&aiunit);
|
||||
}
|
||||
|
@ -854,7 +871,7 @@ void AiForce::Update()
|
|||
const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference.
|
||||
|
||||
aiunit.Wait = delay;
|
||||
if (aiunit.Type->CanAttack) {
|
||||
if (aiunit.IsAgressive()) {
|
||||
CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands);
|
||||
} else if (aiunit.Type->CanTransport()) {
|
||||
if (aiunit.BoardCount != 0) {
|
||||
|
@ -865,7 +882,11 @@ void AiForce::Update()
|
|||
this->Remove(aiunit);
|
||||
}
|
||||
} else {
|
||||
CommandMove(aiunit, this->GoalPos, FlushCommands);
|
||||
if (leader) {
|
||||
CommandDefend(aiunit, *leader, FlushCommands);
|
||||
} else {
|
||||
CommandMove(aiunit, this->GoalPos, FlushCommands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -819,6 +819,8 @@ static void DoNextReplay()
|
|||
SendCommandStopUnit(*unit);
|
||||
} else if (!strcmp(action, "stand-ground")) {
|
||||
SendCommandStandGround(*unit, flags);
|
||||
} else if (!strcmp(action, "defend")) {
|
||||
SendCommandDefend(*unit, *dunit, flags);
|
||||
} else if (!strcmp(action, "follow")) {
|
||||
SendCommandFollow(*unit, *dunit, flags);
|
||||
} else if (!strcmp(action, "move")) {
|
||||
|
|
64
src/include/action/action_defend.h
Normal file
64
src/include/action/action_defend.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name action_defend.h - The actions headerfile. */
|
||||
//
|
||||
// (c) Copyright 2012 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 __ACTION_DEFEND_H__
|
||||
#define __ACTION_DEFEND_H__
|
||||
|
||||
#include "actions.h"
|
||||
|
||||
//@{
|
||||
|
||||
class COrder_Defend : public COrder
|
||||
{
|
||||
friend COrder *COrder::NewActionDefend(CUnit &dest);
|
||||
public:
|
||||
COrder_Defend() : COrder(UnitActionDefend), State(0), Range(0) {
|
||||
goalPos.x = -1;
|
||||
goalPos.y = -1;
|
||||
}
|
||||
|
||||
virtual COrder_Defend *Clone() const { return new COrder_Defend(*this); }
|
||||
|
||||
virtual bool IsValid() 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 void Execute(CUnit &unit);
|
||||
virtual PixelPos Show(const CViewport &vp, const PixelPos &lastScreenPos) const;
|
||||
virtual void UpdatePathFinderData(PathFinderInput &input);
|
||||
private:
|
||||
unsigned int State;
|
||||
int Range;
|
||||
Vec2i goalPos;
|
||||
};
|
||||
|
||||
//@}
|
||||
|
||||
#endif // !__ACTION_DEFEND_H__
|
|
@ -52,6 +52,7 @@ enum UnitAction {
|
|||
UnitActionStill, /// unit stand still, does nothing
|
||||
UnitActionStandGround, /// unit stands ground
|
||||
UnitActionFollow, /// unit follows units
|
||||
UnitActionDefend, /// unit defends unit
|
||||
UnitActionMove, /// unit moves to position/unit
|
||||
UnitActionAttack, /// unit attacks position/unit
|
||||
UnitActionAttackGround, /// unit attacks ground
|
||||
|
@ -128,6 +129,7 @@ public:
|
|||
static COrder *NewActionBoard(CUnit &unit);
|
||||
static COrder *NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building);
|
||||
static COrder *NewActionBuilt(CUnit &builder, CUnit &unit);
|
||||
static COrder *NewActionDefend(CUnit &dest);
|
||||
static COrder *NewActionDie();
|
||||
static COrder *NewActionFollow(CUnit &dest);
|
||||
static COrder *NewActionMove(const Vec2i &pos);
|
||||
|
|
|
@ -62,6 +62,8 @@ extern void CommandQuit(int player);
|
|||
extern void CommandStopUnit(CUnit &unit);
|
||||
/// Prepare command stand ground
|
||||
extern void CommandStandGround(CUnit &unit, int flush);
|
||||
/// Prepare command defend
|
||||
extern void CommandDefend(CUnit &unit, CUnit &dest, int flush);
|
||||
/// Prepare command follow
|
||||
extern void CommandFollow(CUnit &unit, CUnit &dest, int flush);
|
||||
/// Prepare command move
|
||||
|
@ -128,6 +130,8 @@ typedef unsigned short UnitRef;
|
|||
extern void SendCommandStopUnit(CUnit &unit);
|
||||
/// Send stand ground command
|
||||
extern void SendCommandStandGround(CUnit &unit, int flush);
|
||||
/// Send defend command
|
||||
extern void SendCommandDefend(CUnit &unit, CUnit &dest, int flush);
|
||||
/// Send follow command
|
||||
extern void SendCommandFollow(CUnit &unit, CUnit &dest, int flush);
|
||||
/// Send move command
|
||||
|
|
|
@ -75,6 +75,7 @@ enum _message_type_ {
|
|||
|
||||
MessageCommandStop, /// Unit command stop
|
||||
MessageCommandStand, /// Unit command stand ground
|
||||
MessageCommandDefend, /// Unit command defend
|
||||
MessageCommandFollow, /// Unit command follow
|
||||
MessageCommandMove, /// Unit command move
|
||||
MessageCommandRepair, /// Unit command repair
|
||||
|
|
|
@ -78,6 +78,23 @@ void SendCommandStandGround(CUnit &unit, int flush)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Send command: Defend some unit.
|
||||
**
|
||||
** @param unit pointer to unit.
|
||||
** @param dest defend this unit.
|
||||
** @param flush Flag flush all pending commands.
|
||||
*/
|
||||
void SendCommandDefend(CUnit &unit, CUnit &dest, int flush)
|
||||
{
|
||||
if (!IsNetworkGame()) {
|
||||
CommandLog("defend", &unit, flush, -1, -1, &dest, NULL, -1);
|
||||
CommandDefend(unit, dest, flush);
|
||||
} else {
|
||||
NetworkSendCommand(MessageCommandDefend, unit, 0, 0, &dest, 0, flush);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Send command: Follow unit to position.
|
||||
**
|
||||
|
@ -571,6 +588,15 @@ void ParseCommand(unsigned char msgnr, UnitRef unum,
|
|||
CommandLog("stand-ground", &unit, status, -1, -1, NoUnitP, NULL, -1);
|
||||
CommandStandGround(unit, status);
|
||||
break;
|
||||
case MessageCommandDefend: {
|
||||
if (dstnr != (unsigned short)0xFFFF) {
|
||||
CUnit &dest = UnitManager.GetSlotUnit(dstnr);
|
||||
Assert(dest.Type);
|
||||
CommandLog("defend", &unit, status, -1, -1, &dest, NULL, -1);
|
||||
CommandDefend(unit, dest, status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MessageCommandFollow: {
|
||||
if (dstnr != (unsigned short)0xFFFF) {
|
||||
CUnit &dest = UnitManager.GetSlotUnit(dstnr);
|
||||
|
|
|
@ -32,9 +32,12 @@
|
|||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "action/action_defend.h"
|
||||
|
||||
#include "spell/spell_summon.h"
|
||||
|
||||
#include "actions.h"
|
||||
#include "commands.h"
|
||||
#include "script.h"
|
||||
#include "unit.h"
|
||||
#include "unit_find.h"
|
||||
|
@ -133,8 +136,15 @@ public:
|
|||
if (ttl) {
|
||||
target->TTL = GameCycle + ttl;
|
||||
}
|
||||
if (caster.GroupId && caster.Player->AiEnabled) {
|
||||
target->GroupId = caster.GroupId;
|
||||
|
||||
// To avoid defending summoned unit for AI
|
||||
if (caster.Player->AiEnabled) {
|
||||
if (caster.GroupId) {
|
||||
target->GroupId = caster.GroupId;
|
||||
CommandDefend(*target, caster, FlushCommands);
|
||||
} else {
|
||||
target->GroupId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
|
|
|
@ -815,7 +815,7 @@ void CPlayer::UpdateFreeWorkers()
|
|||
|
||||
for (int i = 0; i < nunits; ++i) {
|
||||
CUnit &unit = this->GetUnit(i);
|
||||
if (unit.Type->Harvester && unit.Type->ResInfo && !unit.Removed) {
|
||||
if (unit.IsAlive() && unit.Type->Harvester && unit.Type->ResInfo && !unit.Removed) {
|
||||
if (unit.CurrentAction() == UnitActionStill) {
|
||||
FreeWorkers.push_back(&unit);
|
||||
}
|
||||
|
|
|
@ -184,6 +184,7 @@ void LoadPO(const char *file)
|
|||
**/
|
||||
void SetTranslationsFiles(const char *stratagusfile, const char *gamefile)
|
||||
{
|
||||
Entries.clear();
|
||||
LoadPO(stratagusfile);
|
||||
LoadPO(gamefile);
|
||||
}
|
||||
|
|
|
@ -274,7 +274,8 @@ static int GetButtonStatus(const ButtonAction &button, int UnderCursor)
|
|||
int saction = Selected[i]->CurrentAction();
|
||||
if (saction != UnitActionMove &&
|
||||
saction != UnitActionBuild &&
|
||||
saction != UnitActionFollow) {
|
||||
saction != UnitActionFollow &&
|
||||
saction != UnitActionDefend) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -458,6 +458,17 @@ static void DoRightButton_ForSelectedUnit(CUnit &unit, CUnit *dest, const Vec2i
|
|||
return;
|
||||
}
|
||||
|
||||
// Alt + right click on unit is defend anything.
|
||||
if ((KeyModifiers & ModifierAlt) && dest) {
|
||||
dest->Blink = 4;
|
||||
if (!acknowledged) {
|
||||
PlayUnitSound(unit, VoiceAcknowledging);
|
||||
acknowledged = 1;
|
||||
}
|
||||
SendCommandDefend(unit, *dest, flush);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DoRightButton_Transporter(unit, dest, flush, acknowledged)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1014,39 +1025,49 @@ static int SendRepair(const Vec2i &tilePos)
|
|||
*/
|
||||
static int SendMove(const Vec2i &tilePos)
|
||||
{
|
||||
CUnit *transporter = UnitUnderCursor;
|
||||
CUnit *goal = UnitUnderCursor;
|
||||
int ret = 0;
|
||||
|
||||
// Move to a transporter.
|
||||
if (transporter && transporter->Type->CanTransport()) {
|
||||
int i;
|
||||
for (i = 0; i < NumSelected; ++i) {
|
||||
if (CanTransport(*transporter, *Selected[i])) {
|
||||
SendCommandStopUnit(*transporter);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == NumSelected) {
|
||||
transporter = NULL;
|
||||
}
|
||||
} else {
|
||||
transporter = NULL;
|
||||
}
|
||||
|
||||
const int flush = !(KeyModifiers & ModifierShift);
|
||||
|
||||
for (int i = 0; i < NumSelected; ++i) {
|
||||
CUnit *unit = Selected[i];
|
||||
// Alt makes unit to defend goal
|
||||
if (goal && (KeyModifiers & ModifierAlt)) {
|
||||
for (int i = 0; i < NumSelected; ++i) {
|
||||
CUnit *unit = Selected[i];
|
||||
|
||||
if (transporter && CanTransport(*transporter, *unit)) {
|
||||
transporter->Blink = 4;
|
||||
SendCommandFollow(*transporter, *unit, 0);
|
||||
SendCommandBoard(*unit, *transporter, flush);
|
||||
goal->Blink = 4;
|
||||
SendCommandDefend(*unit, *goal, flush);
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
// Move to a transporter.
|
||||
if (goal && goal->Type->CanTransport()) {
|
||||
int i;
|
||||
for (i = 0; i < NumSelected; ++i) {
|
||||
if (CanTransport(*goal, *Selected[i])) {
|
||||
SendCommandStopUnit(*goal);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == NumSelected) {
|
||||
goal = NULL;
|
||||
}
|
||||
} else {
|
||||
SendCommandMove(*unit, tilePos, flush);
|
||||
ret = 1;
|
||||
goal = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumSelected; ++i) {
|
||||
CUnit *unit = Selected[i];
|
||||
|
||||
if (goal && CanTransport(*goal, *unit)) {
|
||||
goal->Blink = 4;
|
||||
SendCommandFollow(*goal, *unit, 0);
|
||||
SendCommandBoard(*unit, *goal, flush);
|
||||
ret = 1;
|
||||
} else {
|
||||
SendCommandMove(*unit, tilePos, flush);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -911,47 +911,38 @@ static int CclKillUnit(lua_State *l)
|
|||
*/
|
||||
static int CclKillUnitAt(lua_State *l)
|
||||
{
|
||||
LuaCheckArgs(l, 2);
|
||||
LuaCheckArgs(l, 5);
|
||||
|
||||
lua_pushvalue(l, 1);
|
||||
const CUnitType *unittype = TriggerGetUnitType(l);
|
||||
lua_pop(l, 1);
|
||||
lua_pushvalue(l, 2);
|
||||
int plynr = TriggerGetPlayer(l);
|
||||
lua_pop(l, 1);
|
||||
int q = LuaToNumber(l, 3);
|
||||
lua_pushvalue(l, 1);
|
||||
const CUnitType *unittype = TriggerGetUnitType(l);
|
||||
lua_pop(l, 1);
|
||||
if (!lua_istable(l, 4)) {
|
||||
|
||||
if (!lua_istable(l, 4) || !lua_istable(l, 5)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
}
|
||||
Vec2i pos1;
|
||||
Vec2i pos2;
|
||||
lua_rawgeti(l, 4, 1);
|
||||
pos1.x = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
lua_rawgeti(l, 4, 2);
|
||||
pos1.y = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
lua_rawgeti(l, 4, 3);
|
||||
pos2.x = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
lua_rawgeti(l, 4, 4);
|
||||
pos2.y = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
CclGetPos(l, &pos1.x, &pos1.y, 4);
|
||||
CclGetPos(l, &pos2.x, &pos2.y, 5);
|
||||
|
||||
std::vector<CUnit *> table;
|
||||
|
||||
Select(pos1, pos2, table);
|
||||
|
||||
int s = 0;
|
||||
for (size_t j = 0; j < table.size() && s < q; ++j) {
|
||||
CUnit *unit = table[j];
|
||||
for (std::vector<CUnit *>::iterator it = table.begin(); it != table.end() && s < q; ++it) {
|
||||
CUnit &unit = **it;
|
||||
|
||||
if (unittype == ANY_UNIT
|
||||
|| (unittype == ALL_FOODUNITS && !unit->Type->Building)
|
||||
|| (unittype == ALL_BUILDINGS && unit->Type->Building)
|
||||
|| unittype == unit->Type) {
|
||||
if (plynr == -1 || plynr == unit->Player->Index) {
|
||||
LetUnitDie(*unit);
|
||||
|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
|
||||
|| (unittype == ALL_BUILDINGS && unit.Type->Building)
|
||||
|| unittype == unit.Type) {
|
||||
if (plynr == -1 || plynr == unit.Player->Index) {
|
||||
LetUnitDie(unit);
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue