add a simple explore action

flies around randomly, much room for improvement
This commit is contained in:
Talas 2019-07-07 12:22:00 +02:00
parent 9f36458389
commit accaaf56e1
15 changed files with 347 additions and 0 deletions

View file

@ -65,6 +65,7 @@ set(action_SRCS
src/action/action_built.cpp
src/action/action_defend.cpp
src/action/action_die.cpp
src/action/action_explore.cpp
src/action/action_follow.cpp
src/action/action_move.cpp
src/action/action_patrol.cpp

View file

@ -0,0 +1,204 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name action_explore.cpp - The explore action. */
//
// (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon and Talas
//
// 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_explore.h"
#include "animation.h"
#include "iolib.h"
#include "map.h"
#include "pathfinder.h"
#include "script.h"
#include "tile.h"
#include "ui.h"
#include "unit.h"
#include "unittype.h"
#include "video.h"
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
static void GetExplorationTarget(const CUnit &unit, Vec2i &dest)
{
int triesLeft = Map.NoFogOfWar ? 0 : 3;
CMapField *field;
const CPlayer &player = *unit.Player;
dest.x = SyncRand(Map.Info.MapWidth - 1) + 1;
dest.y = SyncRand(Map.Info.MapHeight - 1) + 1;
while (triesLeft > 0) {
field = Map.Field(dest);
if (field && !field->playerInfo.IsExplored(player))
return; // unexplored, go here!
dest.x = SyncRand(Map.Info.MapWidth - 1) + 1;
dest.y = SyncRand(Map.Info.MapHeight - 1) + 1;
--triesLeft;
}
}
/* static */ COrder *COrder::NewActionExplore(const CUnit &unit)
{
Vec2i dest;
GetExplorationTarget(unit, dest);
Assert(Map.Info.IsPointOnMap(dest));
COrder_Explore *order = new COrder_Explore();
order->goalPos = dest;
return order;
}
/* virtual */ void COrder_Explore::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-explore\",");
if (this->Finished) {
file.printf(" \"finished\", ");
}
file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
file.printf(" \"range\", %d,", this->Range);
if (this->WaitingCycle != 0) {
file.printf(" \"waiting-cycle\", %d,", this->WaitingCycle);
}
file.printf("}");
}
/* virtual */ bool COrder_Explore::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (!strcmp(value, "waiting-cycle")) {
++j;
this->WaitingCycle = LuaToNumber(l, -1, j + 1);
} else if (!strcmp(value, "range")) {
++j;
this->Range = LuaToNumber(l, -1, j + 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_Explore::IsValid() const
{
return true;
}
/* virtual */ PixelPos COrder_Explore::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
{
const PixelPos pos1 = vp.TilePosToScreen_Center(this->goalPos);
Video.DrawLineClip(ColorGreen, lastScreenPos, pos1);
Video.FillCircleClip(ColorBlue, pos1, 2);
return pos1;
}
/* virtual */ void COrder_Explore::UpdatePathFinderData(PathFinderInput &input)
{
input.SetMinRange(0);
input.SetMaxRange(this->Range);
const Vec2i tileSize(0, 0);
input.SetGoal(this->goalPos, tileSize);
}
/* virtual */ void COrder_Explore::Execute(CUnit &unit)
{
if (unit.Wait) {
if (!unit.Waiting) {
unit.Waiting = 1;
unit.WaitBackup = unit.Anim;
}
UnitShowAnimation(unit, unit.Type->Animations->Still);
unit.Wait--;
return;
}
if (unit.Waiting) {
unit.Anim = unit.WaitBackup;
unit.Waiting = 0;
}
switch (DoActionMove(unit)) {
case PF_FAILED:
this->WaitingCycle = 0;
break;
case PF_UNREACHABLE:
// Increase range and try again
this->WaitingCycle = 1;
this->Range++;
break;
case PF_REACHED:
{
this->WaitingCycle = 1;
this->Range = 0;
// pick a new place to explore
GetExplorationTarget(unit, this->goalPos);
}
break;
case PF_WAIT:
{
// Wait for a while then give up
this->WaitingCycle++;
if (this->WaitingCycle == 5) {
this->WaitingCycle = 0;
this->Range = 0;
// pick a new place to explore
GetExplorationTarget(unit, this->goalPos);
unit.pathFinderData->output.Cycles = 0; //moving counter
}
}
break;
default: // moving
this->WaitingCycle = 0;
break;
}
if (!unit.Anim.Unbreakable) {
if (AutoAttack(unit) || AutoRepair(unit) || AutoCast(unit)) {
this->Finished = true;
}
}
}
//@}

View file

@ -46,6 +46,7 @@
#include "action/action_built.h"
#include "action/action_defend.h"
#include "action/action_die.h"
#include "action/action_explore.h"
#include "action/action_follow.h"
#include "action/action_move.h"
#include "action/action_patrol.h"
@ -200,6 +201,8 @@ void CclParseOrder(lua_State *l, CUnit &unit, COrderPtr *orderPtr)
*orderPtr = new COrder_Defend;
} else if (!strcmp(actiontype, "action-die")) {
*orderPtr = new COrder_Die;
} else if (!strcmp(actiontype, "action-explore")) {
*orderPtr = new COrder_Explore;
} else if (!strcmp(actiontype, "action-follow")) {
*orderPtr = new COrder_Follow;
} else if (!strcmp(actiontype, "action-move")) {

View file

@ -499,6 +499,33 @@ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int fl
ClearSavedAction(unit);
}
/**
** Send a unit exploring
**
** @param unit pointer to unit.
** @param flush if true, flush command queue.
*/
void CommandExplore(CUnit &unit, 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::NewActionExplore(unit);
ClearSavedAction(unit);
}
/**
** Cancel the building construction, or kill a unit.
**

View file

@ -850,6 +850,8 @@ static void DoNextReplay()
SendCommandUnload(*unit, pos, dunit, flags);
} else if (!strcmp(action, "build")) {
SendCommandBuildBuilding(*unit, pos, *UnitTypeByIdent(val), flags);
} else if (!strcmp(action, "explore")) {
SendCommandExplore(*unit, flags);
} else if (!strcmp(action, "dismiss")) {
SendCommandDismiss(*unit);
} else if (!strcmp(action, "resource-loc")) {

View file

@ -0,0 +1,65 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name action_explore.h - The actions headerfile. */
//
// (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon and Talas
//
// 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_EXPLORE_H__
#define __ACTION_EXPLORE_H__
#include "actions.h"
//@{
class COrder_Explore : public COrder
{
friend COrder *COrder::NewActionExplore(const CUnit &unit);
public:
COrder_Explore() : COrder(UnitActionExplore), WaitingCycle(0), Range(0)
{
goalPos.x = -1;
goalPos.y = -1;
}
virtual COrder_Explore *Clone() const { return new COrder_Explore(*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 WaitingCycle; /// number of cycle pathfinder wait.
int Range;
Vec2i goalPos;
};
//@}
#endif // !__ACTION_EXPLORE_H__

View file

@ -70,6 +70,7 @@ enum UnitAction {
UnitActionUnload, /// unit leaving transporter
UnitActionPatrol, /// unit paroling area
UnitActionBuild, /// unit builds building
UnitActionExplore, /// unit explores map
UnitActionRepair, /// unit repairing
UnitActionResource, /// unit harvesting resources
@ -133,6 +134,7 @@ public:
static COrder *NewActionBuilt(CUnit &builder, CUnit &unit);
static COrder *NewActionDefend(CUnit &dest);
static COrder *NewActionDie();
static COrder *NewActionExplore(const CUnit &unit);
static COrder *NewActionFollow(CUnit &dest);
static COrder *NewActionMove(const Vec2i &pos);
static COrder *NewActionPatrol(const Vec2i &currentPos, const Vec2i &dest);

View file

@ -84,6 +84,8 @@ extern void CommandBoard(CUnit &unit, CUnit &dest, int flush);
extern void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush);
/// Prepare command build
extern void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &, int flush);
/// Prepare command explore
extern void CommandExplore(CUnit &unit, int flush);
/// Prepare command dismiss
extern void CommandDismiss(CUnit &unit);
/// Prepare command resource location
@ -152,6 +154,8 @@ extern void SendCommandBoard(CUnit &unit, CUnit &dest, int flush);
extern void SendCommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush);
/// Send build building command
extern void SendCommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int flush);
/// Send explore command
extern void SendCommandExplore(CUnit &unit, int flush);
/// Send cancel building command
extern void SendCommandDismiss(CUnit &unit);
/// Send harvest location command

View file

@ -63,6 +63,7 @@ enum ButtonCmd {
ButtonHarvest, /// order harvest
ButtonBuild, /// order build
ButtonPatrol, /// order patrol
ButtonExplore, /// order explore
ButtonAttackGround, /// order attack ground
ButtonSpellCast, /// order cast spell
ButtonUnload, /// order unload unit

View file

@ -299,6 +299,7 @@ enum _message_type_ {
MessageCommandBoard, /// Unit command board
MessageCommandUnload, /// Unit command unload
MessageCommandBuild, /// Unit command build building
MessageCommandExplore, /// Unit command explore
MessageCommandDismiss, /// Unit command dismiss unit
MessageCommandResourceLoc, /// Unit command resource location
MessageCommandResource, /// Unit command resource

View file

@ -288,6 +288,7 @@ private:
void DoClicked_Unload(int button);
void DoClicked_SpellCast(int button);
void DoClicked_Repair(int button);
void DoClicked_Explore();
void DoClicked_Return();
void DoClicked_Stop();
void DoClicked_StandGround();

View file

@ -271,6 +271,22 @@ void SendCommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, in
}
}
/**
** Send command: Unit explores the map.
**
** @param unit pointer to unit.
** @param flush Flag flush all pending commands.
*/
void SendCommandExplore(CUnit &unit, int flush)
{
if (!IsNetworkGame()) {
CommandLog("explore", &unit, flush, -1, -1, NoUnitP, NULL, -1);
CommandExplore(unit, flush);
} else {
NetworkSendCommand(MessageCommandExplore, unit, 0, 0, NoUnitP, 0, flush);
}
}
/**
** Send command: Cancel this building construction.
**
@ -668,6 +684,10 @@ void ExecCommand(unsigned char msgnr, UnitRef unum,
CommandLog("build", &unit, status, pos.x, pos.y, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1);
CommandBuildBuilding(unit, pos, *UnitTypes[dstnr], status);
break;
case MessageCommandExplore:
CommandLog("explore", &unit, status, -1, -1, NoUnitP, NULL, -1);
CommandExplore(unit, status);
break;
case MessageCommandDismiss:
CommandLog("dismiss", &unit, FlushCommands, -1, -1, NULL, NULL, -1);
CommandDismiss(unit);

View file

@ -249,6 +249,9 @@ static int GetButtonStatus(const ButtonAction &button, int UnderCursor)
case ButtonPatrol:
action = UnitActionPatrol;
break;
case ButtonExplore:
action = UnitActionExplore;
break;
case ButtonHarvest:
case ButtonReturn:
action = UnitActionResource;
@ -884,6 +887,7 @@ bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction)
res = unit.Type->RepairRange > 0;
break;
case ButtonPatrol:
case ButtonExplore:
res = unit.CanMove();
break;
case ButtonHarvest:
@ -1203,6 +1207,13 @@ void CButtonPanel::DoClicked_Repair(int button)
DoClicked_SelectTarget(button);
}
void CButtonPanel::DoClicked_Explore()
{
for (size_t i = 0; i != Selected.size(); ++i) {
SendCommandExplore(*Selected[i], !(KeyModifiers & ModifierShift));
}
}
void CButtonPanel::DoClicked_Return()
{
for (size_t i = 0; i != Selected.size(); ++i) {
@ -1420,6 +1431,7 @@ void CButtonPanel::DoClicked(int button)
case ButtonUnload: { DoClicked_Unload(button); break; }
case ButtonSpellCast: { DoClicked_SpellCast(button); break; }
case ButtonRepair: { DoClicked_Repair(button); break; }
case ButtonExplore: { DoClicked_Explore(); break; }
case ButtonMove: // Follow Next
case ButtonPatrol: // Follow Next
case ButtonHarvest: // Follow Next

View file

@ -492,6 +492,8 @@ static PopupConditionPanel *ParsePopupConditions(lua_State *l)
condition->ButtonAction = ButtonTrain;
} else if (!strcmp(value, "patrol")) {
condition->ButtonAction = ButtonPatrol;
} else if (!strcmp(value, "explore")) {
condition->ButtonAction = ButtonExplore;
} else if (!strcmp(value, "stand-ground")) {
condition->ButtonAction = ButtonStandGround;
} else if (!strcmp(value, "attack-ground")) {

View file

@ -1006,6 +1006,8 @@ static int CclDefineButton(lua_State *l)
ba.Action = ButtonTrain;
} else if (!strcmp(value, "patrol")) {
ba.Action = ButtonPatrol;
} else if (!strcmp(value, "explore")) {
ba.Action = ButtonExplore;
} else if (!strcmp(value, "stand-ground")) {
ba.Action = ButtonStandGround;
} else if (!strcmp(value, "attack-ground")) {