mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-30 21:30:58 +00:00
- add TDBots 2.7 to replace ZCajun
This commit is contained in:
parent
d36ca650e3
commit
6e73adff20
49 changed files with 5947 additions and 1489 deletions
|
@ -404,6 +404,7 @@ add_subdirectory( wadsrc )
|
|||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
add_subdirectory( wadsrc_extra )
|
||||
add_subdirectory( wadsrc_tdbots )
|
||||
add_subdirectory( wadsrc_widescreen )
|
||||
add_subdirectory( src )
|
||||
|
||||
|
|
381
bot-config/bots.cfg
Normal file
381
bot-config/bots.cfg
Normal file
|
@ -0,0 +1,381 @@
|
|||
{
|
||||
name "Mact Man"
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 1
|
||||
isp 50
|
||||
color "00 00 00"
|
||||
weaponpref 012345373
|
||||
voice "Arabian"
|
||||
}
|
||||
|
||||
{
|
||||
name "Slayer"
|
||||
aiming 72
|
||||
perfection 35
|
||||
reaction 46
|
||||
isp 77
|
||||
color "ff ff ff"
|
||||
weaponpref 012345876
|
||||
}
|
||||
|
||||
{
|
||||
name "Larry"
|
||||
aiming 67
|
||||
perfection 15
|
||||
reaction 76
|
||||
isp 37
|
||||
color "50 50 60"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Babe"
|
||||
}
|
||||
|
||||
{
|
||||
name "Karen"
|
||||
aiming 25
|
||||
perfection 55
|
||||
reaction 32
|
||||
isp 70
|
||||
color "00 00 ff"
|
||||
skin illucia
|
||||
weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name "Joel"
|
||||
aiming 67
|
||||
perfection 50
|
||||
reaction 10
|
||||
isp 50
|
||||
color "40 cf 00"
|
||||
weaponpref 012385687
|
||||
voice "Bitch"
|
||||
}
|
||||
|
||||
{
|
||||
name "Gustavo"
|
||||
aiming 99
|
||||
perfection 95
|
||||
reaction 98
|
||||
isp 32
|
||||
color "ff ff ff"
|
||||
|
||||
weaponpref 35787120
|
||||
voice "Bond"
|
||||
}
|
||||
|
||||
{
|
||||
name "James"
|
||||
aiming 90
|
||||
perfection 90
|
||||
reaction 10
|
||||
isp 10
|
||||
color "b0 b0 b0"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Bugs"
|
||||
}
|
||||
|
||||
{
|
||||
name "Tyler"
|
||||
aiming 90
|
||||
perfection 90
|
||||
reaction 20
|
||||
isp 90
|
||||
color "ff ff ff"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Daffy"
|
||||
}
|
||||
|
||||
{
|
||||
name "Thomas"
|
||||
aiming 10
|
||||
perfection 10
|
||||
reaction 10
|
||||
isp 30
|
||||
color "ff ff 00"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Darth"
|
||||
}
|
||||
|
||||
{
|
||||
name "Kyle"
|
||||
aiming 90
|
||||
perfection 90
|
||||
reaction 70
|
||||
isp 60
|
||||
color "ff af 3f"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Doom"
|
||||
}
|
||||
|
||||
{
|
||||
name "Louis"
|
||||
aiming 80
|
||||
perfection 50
|
||||
reaction 20
|
||||
isp 37
|
||||
color "40 cf 00"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Duke"
|
||||
}
|
||||
|
||||
{
|
||||
name "Robert"
|
||||
aiming 90
|
||||
perfection 90
|
||||
reaction 72
|
||||
isp 87
|
||||
color "50 50 60"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Elexis"
|
||||
}
|
||||
|
||||
{
|
||||
name "Jean Romeo"
|
||||
aiming 90
|
||||
perfection 50
|
||||
reaction 50
|
||||
isp 50
|
||||
color "8f 00 00"
|
||||
|
||||
weaponpref 082345678
|
||||
voice "Homer"
|
||||
}
|
||||
|
||||
{
|
||||
name "Steve"
|
||||
aiming 80
|
||||
perfection 80
|
||||
reaction 15
|
||||
isp 90
|
||||
color "b0 b0 b0"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "LoonyMix"
|
||||
}
|
||||
|
||||
{
|
||||
name "Gaz"
|
||||
aiming 10
|
||||
perfection 10
|
||||
reaction 23
|
||||
isp 32
|
||||
color "00 00 7f"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Picard"
|
||||
}
|
||||
|
||||
{
|
||||
name "Josh"
|
||||
aiming 52
|
||||
perfection 35
|
||||
reaction 50
|
||||
isp 37
|
||||
color "8f 00 00"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Protoss"
|
||||
}
|
||||
|
||||
{
|
||||
name "Alex"
|
||||
aiming 70
|
||||
perfection 60
|
||||
reaction 10
|
||||
isp 50
|
||||
color "bf 00 00"
|
||||
|
||||
weaponpref 012345678
|
||||
voice "Snide"
|
||||
}
|
||||
|
||||
{
|
||||
name "Patrick"
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "ff 00 00"
|
||||
skin Crash
|
||||
gender other
|
||||
team "blue"
|
||||
//weaponpref 012385687
|
||||
}
|
||||
|
||||
{
|
||||
name Sarah
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "ff 00 00"
|
||||
skin Crash
|
||||
gender female
|
||||
team "blue"
|
||||
//weaponpref 012385687
|
||||
}
|
||||
|
||||
{
|
||||
name "Sgt. Nigel"
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "b0 b0 b0"
|
||||
skin "Doom 64 Guy"
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Flynn
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "00 ff 00"
|
||||
skin base
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Richard
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "00 ff 00"
|
||||
skin "Big fat doomguy"
|
||||
team "red"
|
||||
//weaponpref 082345678
|
||||
}
|
||||
|
||||
{
|
||||
name "Carl"
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color brown
|
||||
skin "Chaingun marine"
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Illucia
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "ff ff 00"
|
||||
skin Illucia
|
||||
gender female
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name NitroActive
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color green
|
||||
skin "base iii"
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Javier
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "00 00 ff"
|
||||
skin Phobos
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Procyon
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "ff ff 00"
|
||||
skin Procyon
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Seenas
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color red
|
||||
skin Seenas
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name "Oscar"
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "bf 8f 5f"
|
||||
skin "Strife Guy"
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Synas
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "00 b0 ff"
|
||||
skin Synas
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name Linguica
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color red
|
||||
skin base
|
||||
team "blue"
|
||||
//weaponpref 012345678
|
||||
}
|
||||
|
||||
{
|
||||
name H4X0R
|
||||
aiming 100
|
||||
perfection 100
|
||||
reaction 100
|
||||
isp 100
|
||||
color "8f 01 ff"
|
||||
skin base
|
||||
team "red"
|
||||
//weaponpref 012345678
|
||||
}
|
|
@ -815,8 +815,6 @@ set (PCH_SOURCES
|
|||
playsim/bots/b_bot.cpp
|
||||
playsim/bots/b_func.cpp
|
||||
playsim/bots/b_game.cpp
|
||||
playsim/bots/b_move.cpp
|
||||
playsim/bots/b_think.cpp
|
||||
bbannouncer.cpp
|
||||
console/c_cmds.cpp
|
||||
console/c_notifybuffer.cpp
|
||||
|
|
|
@ -13,6 +13,7 @@ struct FStartupInfo
|
|||
int LoadLights = -1;
|
||||
int LoadBrightmaps = -1;
|
||||
int LoadWidescreen = -1;
|
||||
int LoadBots = -1;
|
||||
int modern = 0;
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -288,6 +288,7 @@ CVAR (Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBAL
|
|||
CVAR (Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, autoloadwidescreen, true, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, autoloadbots, true, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, r_debug_disable_vis_filter, false, 0)
|
||||
CVAR(Bool, vid_fps, false, 0)
|
||||
CVAR(Int, vid_showpalette, 0, 0)
|
||||
|
@ -1945,6 +1946,11 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
|
|||
sc.MustGetNumber();
|
||||
GameStartupInfo.LoadWidescreen = !!sc.Number;
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("LOADBOTS"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
GameStartupInfo.LoadBots = !!sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Silently ignore unknown properties
|
||||
|
@ -2085,6 +2091,12 @@ static void AddAutoloadFiles(const char *autoname)
|
|||
if (wswad)
|
||||
D_AddFile (allwads, wswad, true, -1, GameConfig);
|
||||
}
|
||||
if (GameStartupInfo.LoadBots == 1 || (GameStartupInfo.LoadBots != 0 && autoloadbots))
|
||||
{
|
||||
const char *wswad = BaseFileSearch ("gzdoom-tdbots.pk3", NULL, true, GameConfig);
|
||||
if (wswad)
|
||||
D_AddFile (allwads, wswad, true, -1, GameConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload") && !disableautoload)
|
||||
|
@ -3742,7 +3754,12 @@ void D_Cleanup()
|
|||
// delete GameStartupInfo data
|
||||
GameStartupInfo.Name = "";
|
||||
GameStartupInfo.BkColor = GameStartupInfo.FgColor = GameStartupInfo.Type = 0;
|
||||
GameStartupInfo.LoadWidescreen = GameStartupInfo.LoadLights = GameStartupInfo.LoadBrightmaps = -1;
|
||||
|
||||
// this statement is starting to get a little messy!
|
||||
GameStartupInfo.LoadBots =
|
||||
GameStartupInfo.LoadWidescreen =
|
||||
GameStartupInfo.LoadLights =
|
||||
GameStartupInfo.LoadBrightmaps = -1;
|
||||
|
||||
GC::FullGC(); // clean up before taking down the object list.
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
#include "texturemanager.h"
|
||||
|
||||
extern void LoadActors ();
|
||||
extern void InitBotStuff();
|
||||
extern void ClearStrifeTypes();
|
||||
|
||||
TArray<PClassActor *> PClassActor::AllActorClasses;
|
||||
|
@ -402,7 +401,6 @@ void PClassActor::StaticInit()
|
|||
}
|
||||
|
||||
LoadAltHudStuff();
|
||||
InitBotStuff();
|
||||
|
||||
// reinit GLOBAL static stuff from gameinfo, once classes are loaded.
|
||||
staticEventManager.InitStaticHandlers(primaryLevel, false);
|
||||
|
|
|
@ -143,12 +143,6 @@ void DBot::Tick ()
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BotThinkCycles.Clock();
|
||||
Level->BotInfo.m_Thinking = true;
|
||||
Think ();
|
||||
Level->BotInfo.m_Thinking = false;
|
||||
BotThinkCycles.Unclock();
|
||||
}
|
||||
|
||||
CVAR (Int, bot_next_color, 11, 0)
|
||||
|
@ -245,70 +239,3 @@ CCMD (listbots)
|
|||
Printf ("> %d bots\n", count);
|
||||
}
|
||||
|
||||
// set the bot specific weapon information
|
||||
// This is intentionally not in the weapon definition anymore.
|
||||
|
||||
BotInfoMap BotInfo;
|
||||
|
||||
void InitBotStuff()
|
||||
{
|
||||
int lump;
|
||||
int lastlump = 0;
|
||||
while (-1 != (lump = fileSystem.FindLump("BOTSUPP", &lastlump)))
|
||||
{
|
||||
FScanner sc(lump);
|
||||
sc.SetCMode(true);
|
||||
while (sc.GetString())
|
||||
{
|
||||
PClassActor *wcls = PClass::FindActor(sc.String);
|
||||
if (wcls != nullptr && wcls->IsDescendantOf(NAME_Weapon))
|
||||
{
|
||||
BotInfoData bi = {};
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetNumber();
|
||||
bi.MoveCombatDist = sc.Number;
|
||||
while (sc.CheckString(","))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("BOT_REACTION_SKILL_THING"))
|
||||
{
|
||||
bi.flags |= BIF_BOT_REACTION_SKILL_THING;
|
||||
}
|
||||
else if (sc.Compare("BOT_EXPLOSIVE"))
|
||||
{
|
||||
bi.flags |= BIF_BOT_EXPLOSIVE;
|
||||
}
|
||||
else if (sc.Compare("BOT_BFG"))
|
||||
{
|
||||
bi.flags |= BIF_BOT_BFG;
|
||||
}
|
||||
else
|
||||
{
|
||||
PClassActor *cls = PClass::FindActor(sc.String);
|
||||
bi.projectileType = cls;
|
||||
if (cls == nullptr)
|
||||
{
|
||||
sc.ScriptError("Unknown token %s", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
BotInfo[wcls->TypeName] = bi;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("%s is not a weapon type", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixme: Export these, too.
|
||||
static const char *warnbotmissiles[] = { "PlasmaBall", "Ripper", "HornRodFX1" };
|
||||
for(unsigned i=0;i<countof(warnbotmissiles);i++)
|
||||
{
|
||||
AActor *a = GetDefaultByName (warnbotmissiles[i]);
|
||||
if (a != nullptr)
|
||||
{
|
||||
a->flags3|=MF3_WARNBOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,15 +128,8 @@ public:
|
|||
//(b_func.cpp)
|
||||
void StartTravel ();
|
||||
void FinishTravel ();
|
||||
bool IsLeader (player_t *player);
|
||||
void SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum);
|
||||
double FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
|
||||
bool SafeCheckPosition (AActor *actor, double x, double y, FCheckPosition &tm);
|
||||
void BotTick(AActor *mo);
|
||||
|
||||
//(b_move.cpp)
|
||||
bool CleanAhead (AActor *thing, double x, double y, ticcmd_t *cmd);
|
||||
bool IsDangerous (sector_t *sec);
|
||||
|
||||
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
|
||||
|
||||
|
@ -214,25 +207,6 @@ public:
|
|||
DVector2 old;
|
||||
|
||||
private:
|
||||
//(b_think.cpp)
|
||||
void Think ();
|
||||
void ThinkForMove (ticcmd_t *cmd);
|
||||
void Set_enemy ();
|
||||
|
||||
//(b_func.cpp)
|
||||
bool Reachable (AActor *target);
|
||||
void Dofire (ticcmd_t *cmd);
|
||||
AActor *Choose_Mate ();
|
||||
AActor *Find_enemy ();
|
||||
DAngle FireRox (AActor *enemy, ticcmd_t *cmd);
|
||||
|
||||
//(b_move.cpp)
|
||||
void Roam (ticcmd_t *cmd);
|
||||
bool Move (ticcmd_t *cmd);
|
||||
bool TryWalk (ticcmd_t *cmd);
|
||||
void NewChaseDir (ticcmd_t *cmd);
|
||||
void TurnToAng ();
|
||||
void Pitch (AActor *target);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -44,539 +44,8 @@
|
|||
#include "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "p_local.h"
|
||||
#include "p_maputl.h"
|
||||
#include "b_bot.h"
|
||||
#include "g_game.h"
|
||||
#include "d_event.h"
|
||||
#include "d_player.h"
|
||||
#include "p_spec.h"
|
||||
#include "p_checkposition.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
static FRandom pr_botdofire ("BotDoFire");
|
||||
|
||||
|
||||
//Checks TRUE reachability from bot to a looker.
|
||||
bool DBot::Reachable (AActor *rtarget)
|
||||
{
|
||||
if (player->mo == rtarget)
|
||||
return false;
|
||||
|
||||
if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget) -
|
||||
rtarget->Sector->floorplane.ZatPoint (rtarget))
|
||||
< player->mo->Height) //Where rtarget is, player->mo can't be.
|
||||
return false;
|
||||
|
||||
sector_t *last_s = player->mo->Sector;
|
||||
double last_z = last_s->floorplane.ZatPoint (player->mo);
|
||||
double estimated_dist = player->mo->Distance2D(rtarget);
|
||||
bool reachable = true;
|
||||
|
||||
FPathTraverse it(Level, player->mo->X()+player->mo->Vel.X, player->mo->Y()+player->mo->Vel.Y, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS);
|
||||
intercept_t *in;
|
||||
while ((in = it.Next()))
|
||||
{
|
||||
double hitx, hity;
|
||||
double frac;
|
||||
line_t *line;
|
||||
AActor *thing;
|
||||
double dist;
|
||||
sector_t *s;
|
||||
|
||||
frac = in->frac - 4 /MAX_TRAVERSE_DIST;
|
||||
dist = frac * MAX_TRAVERSE_DIST;
|
||||
|
||||
hitx = it.Trace().x + player->mo->Vel.X * frac;
|
||||
hity = it.Trace().y + player->mo->Vel.Y * frac;
|
||||
|
||||
if (in->isaline)
|
||||
{
|
||||
line = in->d.line;
|
||||
|
||||
if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)))
|
||||
{
|
||||
return false; //Cannot continue.
|
||||
}
|
||||
else
|
||||
{
|
||||
//Determine if going to use backsector/frontsector.
|
||||
s = (line->backsector == last_s) ? line->frontsector : line->backsector;
|
||||
double ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
|
||||
double floorheight = s->floorplane.ZatPoint (hitx, hity);
|
||||
|
||||
if (!Level->BotInfo.IsDangerous (s) && //Any nukage/lava?
|
||||
(floorheight <= (last_z+MAXMOVEHEIGHT)
|
||||
&& ((ceilingheight == floorheight && line->special)
|
||||
|| (ceilingheight - floorheight) >= player->mo->Height))) //Does it fit?
|
||||
{
|
||||
last_z = floorheight;
|
||||
last_s = s;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dist > estimated_dist)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
thing = in->d.thing;
|
||||
if (thing == player->mo) //Can't reach self in this case.
|
||||
continue;
|
||||
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget) <= (last_z+MAXMOVEHEIGHT)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
reachable = false;
|
||||
}
|
||||
return reachable;
|
||||
}
|
||||
|
||||
//doesnt check LOS, checks visibility with a set view angle.
|
||||
//B_Checksight checks LOS (straight line)
|
||||
//----------------------------------------------------------------------
|
||||
//Check if mo1 has free line to mo2
|
||||
//and if mo2 is within mo1 viewangle (vangle) given with normal degrees.
|
||||
//if these conditions are true, the function returns true.
|
||||
//GOOD TO KNOW is that the player's view angle
|
||||
//in doom is 90 degrees infront.
|
||||
bool DBot::Check_LOS (AActor *to, DAngle vangle)
|
||||
{
|
||||
if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING))
|
||||
return false; // out of sight
|
||||
if (vangle >= 360.)
|
||||
return true;
|
||||
if (vangle == 0)
|
||||
return false; //Looker seems to be blind.
|
||||
|
||||
return absangle(player->mo->AngleTo(to), player->mo->Angles.Yaw) <= (vangle/2);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
//Bot_Dofire()
|
||||
//-------------------------------------
|
||||
//The bot will check if it's time to fire
|
||||
//and do so if that is the case.
|
||||
void DBot::Dofire (ticcmd_t *cmd)
|
||||
{
|
||||
bool no_fire; //used to prevent bot from pumping rockets into nearby walls.
|
||||
int aiming_penalty=0; //For shooting at shading target, if screen is red, MAKEME: When screen red.
|
||||
int aiming_value; //The final aiming value.
|
||||
double Dist;
|
||||
DAngle an;
|
||||
DAngle m;
|
||||
double fm;
|
||||
|
||||
if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0)
|
||||
return;
|
||||
|
||||
if (player->ReadyWeapon == NULL)
|
||||
return;
|
||||
|
||||
if (player->damagecount > skill.isp)
|
||||
{
|
||||
first_shot = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//Reaction skill thing.
|
||||
if (first_shot &&
|
||||
!(GetBotInfo(player->ReadyWeapon).flags & BIF_BOT_REACTION_SKILL_THING))
|
||||
{
|
||||
t_react = (100-skill.reaction+1)/((pr_botdofire()%3)+3);
|
||||
}
|
||||
first_shot = false;
|
||||
if (t_react)
|
||||
return;
|
||||
|
||||
//MAKEME: Decrease the rocket suicides even more.
|
||||
|
||||
no_fire = true;
|
||||
//Distance to enemy.
|
||||
Dist = player->mo->Distance2D(enemy, player->mo->Vel.X - enemy->Vel.X, player->mo->Vel.Y - enemy->Vel.Y);
|
||||
|
||||
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
|
||||
if (GetBotInfo(player->ReadyWeapon).MoveCombatDist == 0)
|
||||
{
|
||||
//*4 is for atmosphere, the chainsaws sounding and all..
|
||||
no_fire = (Dist > DEFMELEERANGE*4);
|
||||
}
|
||||
else if (GetBotInfo(player->ReadyWeapon).flags & BIF_BOT_BFG)
|
||||
{
|
||||
//MAKEME: This should be smarter.
|
||||
if ((pr_botdofire()%200)<=skill.reaction)
|
||||
if(Check_LOS(enemy, SHOOTFOV))
|
||||
no_fire = false;
|
||||
}
|
||||
else if (GetBotInfo(player->ReadyWeapon).projectileType != NULL)
|
||||
{
|
||||
if (GetBotInfo(player->ReadyWeapon).flags & BIF_BOT_EXPLOSIVE)
|
||||
{
|
||||
//Special rules for RL
|
||||
an = FireRox (enemy, cmd);
|
||||
if(an != 0)
|
||||
{
|
||||
Angle = an;
|
||||
//have to be somewhat precise. to avoid suicide.
|
||||
if (absangle(an, player->mo->Angles.Yaw) < 12.)
|
||||
{
|
||||
t_rocket = 9;
|
||||
no_fire = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// prediction aiming
|
||||
Dist = player->mo->Distance2D(enemy);
|
||||
fm = Dist / GetDefaultByType (GetBotInfo(player->ReadyWeapon).projectileType)->Speed;
|
||||
Level->BotInfo.SetBodyAt(Level, enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);
|
||||
Angle = player->mo->AngleTo(Level->BotInfo.body1);
|
||||
if (Check_LOS (enemy, SHOOTFOV))
|
||||
no_fire = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Other weapons, mostly instant hit stuff.
|
||||
Angle = player->mo->AngleTo(enemy);
|
||||
aiming_penalty = 0;
|
||||
if (enemy->flags & MF_SHADOW)
|
||||
aiming_penalty += (pr_botdofire()%25)+10;
|
||||
if (enemy->Sector->lightlevel<WHATS_DARK/* && !(player->powers & PW_INFRARED)*/)
|
||||
aiming_penalty += pr_botdofire()%40;//Dark
|
||||
if (player->damagecount)
|
||||
aiming_penalty += player->damagecount; //Blood in face makes it hard to aim
|
||||
aiming_value = skill.aiming - aiming_penalty;
|
||||
if (aiming_value <= 0)
|
||||
aiming_value = 1;
|
||||
m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate
|
||||
if (m <= 0)
|
||||
m = 1.; //Prevents lock.
|
||||
|
||||
if (m != 0)
|
||||
{
|
||||
if (increase)
|
||||
Angle += m;
|
||||
else
|
||||
Angle -= m;
|
||||
}
|
||||
|
||||
if (absangle(Angle, player->mo->Angles.Yaw) < 4.)
|
||||
{
|
||||
increase = !increase;
|
||||
}
|
||||
|
||||
if (Check_LOS (enemy, (SHOOTFOV/2)))
|
||||
no_fire = false;
|
||||
}
|
||||
if (!no_fire) //If going to fire weapon
|
||||
{
|
||||
cmd->ucmd.buttons |= BT_ATTACK;
|
||||
}
|
||||
//Prevents bot from jerking, when firing automatic things with low skill.
|
||||
}
|
||||
|
||||
bool FCajunMaster::IsLeader (player_t *player)
|
||||
{
|
||||
for (int count = 0; count < MAXPLAYERS; count++)
|
||||
{
|
||||
if (players[count].Bot != NULL
|
||||
&& players[count].Bot->mate == player->mo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern int BotWTG;
|
||||
|
||||
void FCajunMaster::BotTick(AActor *mo)
|
||||
{
|
||||
BotSupportCycles.Clock();
|
||||
m_Thinking = true;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].Bot == NULL)
|
||||
continue;
|
||||
|
||||
if (mo->flags3 & MF3_ISMONSTER)
|
||||
{
|
||||
if (mo->health > 0
|
||||
&& !players[i].Bot->enemy
|
||||
&& mo->player ? !mo->IsTeammate(players[i].mo) : true
|
||||
&& mo->Distance2D(players[i].mo) < MAX_MONSTER_TARGET_DIST
|
||||
&& P_CheckSight(players[i].mo, mo, SF_SEEPASTBLOCKEVERYTHING))
|
||||
{ //Probably a monster, so go kill it.
|
||||
players[i].Bot->enemy = mo;
|
||||
}
|
||||
}
|
||||
else if (mo->flags & MF_SPECIAL)
|
||||
{ //Item pickup time
|
||||
//clock (BotWTG);
|
||||
players[i].Bot->WhatToGet(mo);
|
||||
//unclock (BotWTG);
|
||||
BotWTG++;
|
||||
}
|
||||
else if (mo->flags & MF_MISSILE)
|
||||
{
|
||||
if (!players[i].Bot->missile && (mo->flags3 & MF3_WARNBOT))
|
||||
{ //warn for incoming missiles.
|
||||
if (mo->target != players[i].mo && players[i].Bot->Check_LOS(mo, 90.))
|
||||
players[i].Bot->missile = mo;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Thinking = false;
|
||||
BotSupportCycles.Unclock();
|
||||
}
|
||||
|
||||
//This function is called every
|
||||
//tick (for each bot) to set
|
||||
//the mate (teammate coop mate).
|
||||
AActor *DBot::Choose_Mate ()
|
||||
{
|
||||
int count;
|
||||
double closest_dist, test;
|
||||
AActor *target;
|
||||
|
||||
//is mate alive?
|
||||
if (mate)
|
||||
{
|
||||
if (mate->health <= 0)
|
||||
mate = nullptr;
|
||||
else
|
||||
last_mate = mate;
|
||||
}
|
||||
if (mate) //Still is..
|
||||
return mate;
|
||||
|
||||
//Check old_mates status.
|
||||
if (last_mate)
|
||||
if (last_mate->health <= 0)
|
||||
last_mate = nullptr;
|
||||
|
||||
target = NULL;
|
||||
closest_dist = FLT_MAX;
|
||||
|
||||
//Check for player friends
|
||||
for (count = 0; count < MAXPLAYERS; count++)
|
||||
{
|
||||
player_t *client = &players[count];
|
||||
|
||||
if (playeringame[count]
|
||||
&& client->mo
|
||||
&& player->mo != client->mo
|
||||
&& (player->mo->IsTeammate (client->mo) || !deathmatch)
|
||||
&& client->mo->health > 0
|
||||
&& ((player->mo->health/2) <= client->mo->health || !deathmatch)
|
||||
&& !Level->BotInfo.IsLeader(client)) //taken?
|
||||
{
|
||||
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
|
||||
{
|
||||
test = client->mo->Distance2D(player->mo);
|
||||
|
||||
if (test < closest_dist)
|
||||
{
|
||||
closest_dist = test;
|
||||
target = client->mo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//Make a introducing to mate.
|
||||
if(target && target!=last_mate)
|
||||
{
|
||||
if((P_Random()%(200*Level->BotInfo.botnum))<3)
|
||||
{
|
||||
chat = c_teamup;
|
||||
if(target->bot)
|
||||
strcpy(c_target, botsingame[target->bot_id]);
|
||||
else if(target->player)
|
||||
strcpy(c_target, player_names[target->play_id]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return target;
|
||||
|
||||
}
|
||||
|
||||
//MAKEME: Make this a smart decision
|
||||
AActor *DBot::Find_enemy ()
|
||||
{
|
||||
int count;
|
||||
double closest_dist, temp; //To target.
|
||||
AActor *target;
|
||||
DAngle vangle;
|
||||
|
||||
if (!deathmatch)
|
||||
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
|
||||
return P_RoughMonsterSearch (player->mo, 20);
|
||||
}
|
||||
|
||||
//Note: It's hard to ambush a bot who is not alone
|
||||
if (allround || mate)
|
||||
vangle = 360.;
|
||||
else
|
||||
vangle = ENEMY_SCAN_FOV;
|
||||
allround = false;
|
||||
|
||||
target = NULL;
|
||||
closest_dist = FLT_MAX;
|
||||
|
||||
for (count = 0; count < MAXPLAYERS; count++)
|
||||
{
|
||||
player_t *client = &players[count];
|
||||
if (playeringame[count]
|
||||
&& !player->mo->IsTeammate (client->mo)
|
||||
&& client->mo->health > 0
|
||||
&& player->mo != client->mo)
|
||||
{
|
||||
if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
|
||||
//if(P_CheckSight(player->mo, players[count].mo))
|
||||
{
|
||||
temp = client->mo->Distance2D(player->mo);
|
||||
|
||||
//Too dark?
|
||||
if (temp > DARK_DIST &&
|
||||
client->mo->Sector->lightlevel < WHATS_DARK /*&&
|
||||
player->Powers & PW_INFRARED*/)
|
||||
continue;
|
||||
|
||||
if (temp < closest_dist)
|
||||
{
|
||||
closest_dist = temp;
|
||||
target = client->mo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Creates a temporary mobj (invisible) at the given location.
|
||||
void FCajunMaster::SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum)
|
||||
{
|
||||
if (hostnum == 1)
|
||||
{
|
||||
if (body1)
|
||||
{
|
||||
body1->SetOrigin (pos, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
body1 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
|
||||
}
|
||||
}
|
||||
else if (hostnum == 2)
|
||||
{
|
||||
if (body2)
|
||||
{
|
||||
body2->SetOrigin (pos, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
body2 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// FireRox()
|
||||
//
|
||||
//Returns NULL if shouldn't fire
|
||||
//else an angle (in degrees) are given
|
||||
//This function assumes actor->player->angle
|
||||
//has been set an is the main aiming angle.
|
||||
|
||||
|
||||
//Emulates missile travel. Returns distance travelled.
|
||||
double FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
|
||||
{
|
||||
AActor *th = Spawn (source->Level, "CajunTrace", source->PosPlusZ(4*8.), NO_REPLACE);
|
||||
|
||||
th->target = source; // where it came from
|
||||
|
||||
|
||||
th->Vel = source->Vec3To(dest).Resized(th->Speed);
|
||||
|
||||
double dist = 0;
|
||||
|
||||
while (dist < SAFE_SELF_MISDIST)
|
||||
{
|
||||
dist += th->Speed;
|
||||
th->Move(th->Vel);
|
||||
if (!CleanAhead (th, th->X(), th->Y(), cmd))
|
||||
break;
|
||||
}
|
||||
th->Destroy ();
|
||||
return dist;
|
||||
}
|
||||
|
||||
DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
|
||||
{
|
||||
double dist;
|
||||
AActor *actor;
|
||||
double m;
|
||||
|
||||
Level->BotInfo.SetBodyAt(Level, player->mo->PosPlusZ(player->mo->Height / 2) + player->mo->Vel.XY() * 5, 2);
|
||||
|
||||
actor = Level->BotInfo.body2;
|
||||
|
||||
dist = actor->Distance2D (enemy);
|
||||
if (dist < SAFE_SELF_MISDIST)
|
||||
return 0.;
|
||||
//Predict.
|
||||
m = ((dist+1) / GetDefaultByName("Rocket")->Speed);
|
||||
|
||||
Level->BotInfo.SetBodyAt(Level, DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1);
|
||||
|
||||
//try the predicted location
|
||||
if (P_CheckSight (actor, Level->BotInfo.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
|
||||
{
|
||||
FCheckPosition tm;
|
||||
if (Level->BotInfo.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm))
|
||||
{
|
||||
if (Level->BotInfo.FakeFire (actor, Level->BotInfo.body1, cmd) >= SAFE_SELF_MISDIST)
|
||||
{
|
||||
return actor->AngleTo(Level->BotInfo.body1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Try fire straight.
|
||||
if (P_CheckSight (actor, enemy, 0))
|
||||
{
|
||||
if (Level->BotInfo.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
|
||||
{
|
||||
return player->mo->AngleTo(enemy);
|
||||
}
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
// [RH] We absolutely do not want to pick things up here. The bot code is
|
||||
// executed apart from all the other simulation code, so we don't want it
|
||||
// creating side-effects during gameplay.
|
||||
bool FCajunMaster::SafeCheckPosition (AActor *actor, double x, double y, FCheckPosition &tm)
|
||||
{
|
||||
ActorFlags savedFlags = actor->flags;
|
||||
actor->flags &= ~MF_PICKUP;
|
||||
bool res = P_CheckPosition (actor, DVector2(x, y), tm);
|
||||
actor->flags = savedFlags;
|
||||
return res;
|
||||
}
|
||||
|
||||
void FCajunMaster::StartTravel ()
|
||||
{
|
||||
|
|
|
@ -476,11 +476,11 @@ void FCajunMaster::ForgetBots ()
|
|||
|
||||
#if defined _WIN32 || defined __APPLE__
|
||||
|
||||
FString M_GetCajunPath(const char* botfilename)
|
||||
FString M_GetBotPath(const char* botfilename)
|
||||
{
|
||||
FString path;
|
||||
|
||||
path << progdir << "zcajun/" << botfilename;
|
||||
path << progdir << botfilename;
|
||||
if (!FileExists(path))
|
||||
{
|
||||
path = "";
|
||||
|
@ -490,7 +490,7 @@ FString M_GetCajunPath(const char* botfilename)
|
|||
|
||||
#else
|
||||
|
||||
FString M_GetCajunPath(const char* botfilename)
|
||||
FString M_GetBotPath(const char* botfilename)
|
||||
{
|
||||
FString path;
|
||||
|
||||
|
@ -519,7 +519,7 @@ bool FCajunMaster::LoadBots ()
|
|||
int loaded_bots = 0;
|
||||
|
||||
ForgetBots ();
|
||||
tmp = M_GetCajunPath(BOTFILENAME);
|
||||
tmp = M_GetBotPath(BOTFILENAME);
|
||||
if (tmp.IsEmpty())
|
||||
{
|
||||
DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n");
|
||||
|
|
|
@ -1,390 +0,0 @@
|
|||
/*
|
||||
**
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1999 Martin Colberg
|
||||
** Copyright 1999-2016 Randy Heit
|
||||
** Copyright 2005-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
/********************************
|
||||
* B_Think.c *
|
||||
* Description: *
|
||||
* Movement/Roaming code for *
|
||||
* the bot's *
|
||||
*********************************/
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "p_local.h"
|
||||
#include "b_bot.h"
|
||||
#include "g_game.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_keys.h"
|
||||
#include "d_event.h"
|
||||
#include "p_enemy.h"
|
||||
#include "d_player.h"
|
||||
#include "p_spec.h"
|
||||
#include "p_checkposition.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
static FRandom pr_botopendoor ("BotOpenDoor");
|
||||
static FRandom pr_bottrywalk ("BotTryWalk");
|
||||
static FRandom pr_botnewchasedir ("BotNewChaseDir");
|
||||
|
||||
// borrow some tables from p_enemy.cpp
|
||||
extern dirtype_t opposite[9];
|
||||
extern dirtype_t diags[4];
|
||||
|
||||
//Called while the bot moves after its dest mobj
|
||||
//which can be a weapon/enemy/item whatever.
|
||||
void DBot::Roam (ticcmd_t *cmd)
|
||||
{
|
||||
|
||||
if (Reachable(dest))
|
||||
{ // Straight towards it.
|
||||
Angle = player->mo->AngleTo(dest);
|
||||
}
|
||||
else if (player->mo->movedir < 8) // turn towards movement direction if not there yet
|
||||
{
|
||||
// no point doing this with floating point angles...
|
||||
unsigned angle = Angle.BAMs() & (unsigned)(7 << 29);
|
||||
int delta = angle - (player->mo->movedir << 29);
|
||||
|
||||
if (delta > 0)
|
||||
Angle -= 45;
|
||||
else if (delta < 0)
|
||||
Angle += 45;
|
||||
}
|
||||
|
||||
// chase towards destination.
|
||||
if (--player->mo->movecount < 0 || !Move (cmd))
|
||||
{
|
||||
NewChaseDir (cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool DBot::Move (ticcmd_t *cmd)
|
||||
{
|
||||
double tryx, tryy;
|
||||
bool try_ok;
|
||||
int good;
|
||||
|
||||
if (player->mo->movedir >= DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = DI_NODIR; // make sure it's valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
tryx = player->mo->X() + 8*xspeed[player->mo->movedir];
|
||||
tryy = player->mo->Y() + 8*yspeed[player->mo->movedir];
|
||||
|
||||
try_ok = Level->BotInfo.CleanAhead (player->mo, tryx, tryy, cmd);
|
||||
|
||||
if (!try_ok) //Anything blocking that could be opened etc..
|
||||
{
|
||||
if (!spechit.Size ())
|
||||
return false;
|
||||
|
||||
player->mo->movedir = DI_NODIR;
|
||||
|
||||
good = 0;
|
||||
spechit_t spechit1;
|
||||
line_t *ld;
|
||||
|
||||
while (spechit.Pop (spechit1))
|
||||
{
|
||||
ld = spechit1.line;
|
||||
bool tryit = true;
|
||||
|
||||
if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false))
|
||||
tryit = false;
|
||||
else if (ld->special == Generic_Door && !P_CheckKeys (player->mo, ld->args[4], false))
|
||||
tryit = false;
|
||||
|
||||
if (tryit &&
|
||||
(P_TestActivateLine (ld, player->mo, 0, SPAC_Use) ||
|
||||
P_TestActivateLine (ld, player->mo, 0, SPAC_Push)))
|
||||
{
|
||||
good |= ld == player->mo->BlockingLine ? 1 : 2;
|
||||
}
|
||||
}
|
||||
if (good && ((pr_botopendoor() >= 203) ^ (good & 1)))
|
||||
{
|
||||
cmd->ucmd.buttons |= BT_USE;
|
||||
cmd->ucmd.forwardmove = FORWARDRUN;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else //Move forward.
|
||||
cmd->ucmd.forwardmove = FORWARDRUN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBot::TryWalk (ticcmd_t *cmd)
|
||||
{
|
||||
if (!Move (cmd))
|
||||
return false;
|
||||
|
||||
player->mo->movecount = pr_bottrywalk() & 60;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBot::NewChaseDir (ticcmd_t *cmd)
|
||||
{
|
||||
dirtype_t d[3];
|
||||
|
||||
int tdir;
|
||||
dirtype_t olddir;
|
||||
|
||||
dirtype_t turnaround;
|
||||
|
||||
if (!dest)
|
||||
{
|
||||
#ifndef BOT_RELEASE_COMPILE
|
||||
Printf ("Bot tried move without destination\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
olddir = (dirtype_t)player->mo->movedir;
|
||||
turnaround = opposite[olddir];
|
||||
|
||||
DVector2 delta = player->mo->Vec2To(dest);
|
||||
|
||||
if (delta.X > 10)
|
||||
d[1] = DI_EAST;
|
||||
else if (delta.X < -10)
|
||||
d[1] = DI_WEST;
|
||||
else
|
||||
d[1] = DI_NODIR;
|
||||
|
||||
if (delta.Y < -10)
|
||||
d[2] = DI_SOUTH;
|
||||
else if (delta.Y > 10)
|
||||
d[2] = DI_NORTH;
|
||||
else
|
||||
d[2] = DI_NODIR;
|
||||
|
||||
// try direct route
|
||||
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = diags[((delta.Y < 0) << 1) + (delta.X > 0)];
|
||||
if (player->mo->movedir != turnaround && TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
// try other directions
|
||||
if (pr_botnewchasedir() > 200
|
||||
|| fabs(delta.Y) > fabs(delta.X))
|
||||
{
|
||||
tdir = d[1];
|
||||
d[1] = d[2];
|
||||
d[2] = (dirtype_t)tdir;
|
||||
}
|
||||
|
||||
if (d[1]==turnaround)
|
||||
d[1]=DI_NODIR;
|
||||
if (d[2]==turnaround)
|
||||
d[2]=DI_NODIR;
|
||||
|
||||
if (d[1]!=DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = d[1];
|
||||
if (TryWalk (cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
if (d[2]!=DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = d[2];
|
||||
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
// there is no direct path to the player,
|
||||
// so pick another direction.
|
||||
if (olddir!=DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = olddir;
|
||||
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
// randomly determine direction of search
|
||||
if (pr_botnewchasedir()&1)
|
||||
{
|
||||
for ( tdir=DI_EAST;
|
||||
tdir<=DI_SOUTHEAST;
|
||||
tdir++ )
|
||||
{
|
||||
if (tdir!=turnaround)
|
||||
{
|
||||
player->mo->movedir = tdir;
|
||||
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( tdir=DI_SOUTHEAST;
|
||||
tdir != (DI_EAST-1);
|
||||
tdir-- )
|
||||
{
|
||||
if (tdir!=turnaround)
|
||||
{
|
||||
player->mo->movedir = tdir;
|
||||
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (turnaround != DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = turnaround;
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
player->mo->movedir = DI_NODIR; // can not move
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// B_CleanAhead
|
||||
// Check if a place is ok to move towards.
|
||||
// This is also a traverse function for
|
||||
// bots pre-rocket fire (preventing suicide)
|
||||
//
|
||||
bool FCajunMaster::CleanAhead (AActor *thing, double x, double y, ticcmd_t *cmd)
|
||||
{
|
||||
FCheckPosition tm;
|
||||
|
||||
if (!SafeCheckPosition (thing, x, y, tm))
|
||||
return false; // solid wall or thing
|
||||
|
||||
if (!(thing->flags & MF_NOCLIP) )
|
||||
{
|
||||
if (tm.ceilingz - tm.floorz < thing->Height)
|
||||
return false; // doesn't fit
|
||||
|
||||
double maxmove = MAXMOVEHEIGHT;
|
||||
if (!(thing->flags&MF_MISSILE))
|
||||
{
|
||||
if(tm.floorz > (thing->Sector->floorplane.ZatPoint(x, y)+maxmove)) //Too high wall
|
||||
return false;
|
||||
|
||||
//Jumpable
|
||||
if(tm.floorz > (thing->Sector->floorplane.ZatPoint(x, y)+thing->MaxStepHeight))
|
||||
cmd->ucmd.buttons |= BT_JUMP;
|
||||
|
||||
|
||||
if ( !(thing->flags & MF_TELEPORT) &&
|
||||
tm.ceilingz < thing->Top())
|
||||
return false; // mobj must lower itself to fit
|
||||
|
||||
// jump out of water
|
||||
// if((thing->eflags & (MF_UNDERWATER|MF_TOUCHWATER))==(MF_UNDERWATER|MF_TOUCHWATER))
|
||||
// maxstep=37;
|
||||
|
||||
if ( !(thing->flags & MF_TELEPORT) &&
|
||||
(tm.floorz - thing->Z() > thing->MaxStepHeight) )
|
||||
return false; // too big a step up
|
||||
|
||||
|
||||
if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
|
||||
&& tm.floorz - tm.dropoffz > thing->MaxDropOffHeight )
|
||||
return false; // don't stand over a dropoff
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define OKAYRANGE (5) //counts *2, when angle is in range, turning is not executed.
|
||||
#define MAXTURN (15) //Max degrees turned in one tic. Lower is smother but may cause the bot not getting where it should = crash
|
||||
#define TURNSENS 3 //Higher is smoother but slower turn.
|
||||
|
||||
void DBot::TurnToAng ()
|
||||
{
|
||||
double maxturn = MAXTURN;
|
||||
|
||||
if (player->ReadyWeapon != NULL)
|
||||
{
|
||||
if (GetBotInfo(player->ReadyWeapon).flags & BIF_BOT_EXPLOSIVE)
|
||||
{
|
||||
if (t_roam && !missile)
|
||||
{ //Keep angle that where when shot where decided.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(enemy)
|
||||
if(!dest) //happens when running after item in combat situations, or normal, prevents weak turns
|
||||
if(GetBotInfo(player->ReadyWeapon).projectileType == NULL && GetBotInfo(player->ReadyWeapon).MoveCombatDist > 0)
|
||||
if(Check_LOS(enemy, SHOOTFOV+5))
|
||||
maxturn = 3;
|
||||
}
|
||||
|
||||
DAngle distance = deltaangle(player->mo->Angles.Yaw, Angle);
|
||||
|
||||
if (fabs (distance) < OKAYRANGE && !enemy)
|
||||
return;
|
||||
|
||||
distance /= TURNSENS;
|
||||
if (fabs (distance) > maxturn)
|
||||
distance = distance < 0 ? -maxturn : maxturn;
|
||||
|
||||
player->mo->Angles.Yaw += distance;
|
||||
}
|
||||
|
||||
void DBot::Pitch (AActor *target)
|
||||
{
|
||||
double aim;
|
||||
double diff;
|
||||
|
||||
diff = target->Z() - player->mo->Z();
|
||||
aim = g_atan(diff / player->mo->Distance2D(target));
|
||||
player->mo->Angles.Pitch = DAngle::ToDegrees(aim);
|
||||
}
|
||||
|
||||
//Checks if a sector is dangerous.
|
||||
bool FCajunMaster::IsDangerous (sector_t *sec)
|
||||
{
|
||||
return sec->damageamount > 0;
|
||||
}
|
|
@ -1,439 +0,0 @@
|
|||
/*
|
||||
**
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1999 Martin Colberg
|
||||
** Copyright 1999-2016 Randy Heit
|
||||
** Copyright 2005-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
/********************************
|
||||
* B_Think.c *
|
||||
* Description: *
|
||||
* Functions for the different *
|
||||
* states that the bot *
|
||||
* uses. These functions are *
|
||||
* the main AI *
|
||||
* *
|
||||
*********************************/
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "p_local.h"
|
||||
#include "b_bot.h"
|
||||
#include "g_game.h"
|
||||
#include "d_net.h"
|
||||
#include "d_event.h"
|
||||
#include "d_player.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
static FRandom pr_botmove ("BotMove");
|
||||
|
||||
//This function is called each tic for each bot,
|
||||
//so this is what the bot does.
|
||||
void DBot::Think ()
|
||||
{
|
||||
ticcmd_t *cmd = &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS];
|
||||
|
||||
memset (cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (enemy && enemy->health <= 0)
|
||||
enemy = nullptr;
|
||||
|
||||
if (player->mo->health > 0) //Still alive
|
||||
{
|
||||
if (teamplay || !deathmatch)
|
||||
mate = Choose_Mate ();
|
||||
|
||||
AActor *actor = player->mo;
|
||||
DAngle oldyaw = actor->Angles.Yaw;
|
||||
DAngle oldpitch = actor->Angles.Pitch;
|
||||
|
||||
Set_enemy ();
|
||||
ThinkForMove (cmd);
|
||||
TurnToAng ();
|
||||
|
||||
cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / ticdup;
|
||||
cmd->ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f));
|
||||
if (cmd->ucmd.pitch == -32768)
|
||||
cmd->ucmd.pitch = -32767;
|
||||
cmd->ucmd.pitch /= ticdup;
|
||||
actor->Angles.Yaw = oldyaw + DAngle(cmd->ucmd.yaw * ticdup * (360 / 65536.f));
|
||||
actor->Angles.Pitch = oldpitch - DAngle(cmd->ucmd.pitch * ticdup * (360 / 65536.f));
|
||||
}
|
||||
|
||||
if (t_active) t_active--;
|
||||
if (t_strafe) t_strafe--;
|
||||
if (t_react) t_react--;
|
||||
if (t_fight) t_fight--;
|
||||
if (t_rocket) t_rocket--;
|
||||
if (t_roam) t_roam--;
|
||||
|
||||
//Respawn ticker
|
||||
if (t_respawn)
|
||||
{
|
||||
t_respawn--;
|
||||
}
|
||||
else if (player->mo->health <= 0)
|
||||
{ // Time to respawn
|
||||
cmd->ucmd.buttons |= BT_USE;
|
||||
}
|
||||
}
|
||||
|
||||
#define THINKDISTSQ (50000.*50000./(65536.*65536.))
|
||||
//how the bot moves.
|
||||
//MAIN movement function.
|
||||
void DBot::ThinkForMove (ticcmd_t *cmd)
|
||||
{
|
||||
double dist;
|
||||
bool stuck;
|
||||
int r;
|
||||
|
||||
stuck = false;
|
||||
dist = dest ? player->mo->Distance2D(dest) : 0;
|
||||
|
||||
if (missile &&
|
||||
(!missile->Vel.X || !missile->Vel.Y || !Check_LOS(missile, SHOOTFOV*3/2)))
|
||||
{
|
||||
sleft = !sleft;
|
||||
missile = nullptr; //Probably ended its travel.
|
||||
}
|
||||
|
||||
#if 0 // this has always been broken and without any reference it cannot be fixed.
|
||||
if (player->mo->Angles.Pitch > 0)
|
||||
player->mo->Angles.Pitch -= 80;
|
||||
else if (player->mo->Angles.Pitch <= -60)
|
||||
player->mo->Angles.Pitch += 80;
|
||||
#endif
|
||||
|
||||
//HOW TO MOVE:
|
||||
if (missile && (player->mo->Distance2D(missile)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part.
|
||||
{
|
||||
Pitch (missile);
|
||||
Angle = player->mo->AngleTo(missile);
|
||||
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
|
||||
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
|
||||
|
||||
if ((player->mo->Pos() - old).LengthSquared() < THINKDISTSQ
|
||||
&& t_strafe<=0)
|
||||
{
|
||||
t_strafe = 5;
|
||||
sleft = !sleft;
|
||||
}
|
||||
|
||||
//If able to see enemy while avoiding missile, still fire at enemy.
|
||||
if (enemy && Check_LOS (enemy, SHOOTFOV))
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
}
|
||||
else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight!
|
||||
{
|
||||
Pitch (enemy);
|
||||
|
||||
//Check if it's more important to get an item than fight.
|
||||
if (dest && (dest->flags&MF_SPECIAL)) //Must be an item, that is close enough.
|
||||
{
|
||||
#define is(x) dest->IsKindOf (PClass::FindClass (#x))
|
||||
if (
|
||||
(
|
||||
(player->mo->health < skill.isp &&
|
||||
(is (Medikit) ||
|
||||
is (Stimpack) ||
|
||||
is (Soulsphere) ||
|
||||
is (Megasphere) ||
|
||||
is (CrystalVial)
|
||||
)
|
||||
) || (
|
||||
is (Invulnerability) ||
|
||||
is (Invisibility) ||
|
||||
is (Megasphere)
|
||||
) ||
|
||||
dist < (GETINCOMBAT/4) ||
|
||||
(GetBotInfo(player->ReadyWeapon).MoveCombatDist == 0)
|
||||
)
|
||||
&& (dist < GETINCOMBAT || (GetBotInfo(player->ReadyWeapon).MoveCombatDist == 0))
|
||||
&& Reachable (dest))
|
||||
#undef is
|
||||
{
|
||||
goto roam; //Pick it up, no matter the situation. All bonuses are nice close up.
|
||||
}
|
||||
}
|
||||
|
||||
dest = nullptr; //To let bot turn right
|
||||
|
||||
if (GetBotInfo(player->ReadyWeapon).MoveCombatDist == 0)
|
||||
player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
|
||||
|
||||
if (!(enemy->flags3 & MF3_ISMONSTER))
|
||||
t_fight = AFTERTICS;
|
||||
|
||||
if (t_strafe <= 0 &&
|
||||
((player->mo->Pos() - old).LengthSquared() < THINKDISTSQ
|
||||
|| ((pr_botmove()%30)==10))
|
||||
)
|
||||
{
|
||||
stuck = true;
|
||||
t_strafe = 5;
|
||||
sleft = !sleft;
|
||||
}
|
||||
|
||||
Angle = player->mo->AngleTo(enemy);
|
||||
|
||||
if (player->ReadyWeapon == NULL ||
|
||||
player->mo->Distance2D(enemy) >
|
||||
GetBotInfo(player->ReadyWeapon).MoveCombatDist)
|
||||
{
|
||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
||||
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN;
|
||||
}
|
||||
else if (!stuck) //Too close, so move away.
|
||||
{
|
||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
||||
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN;
|
||||
}
|
||||
|
||||
//Strafing.
|
||||
if (enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool.
|
||||
{
|
||||
cmd->ucmd.sidemove = sleft ? -SIDEWALK : SIDEWALK;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
|
||||
}
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
}
|
||||
else if (mate && !enemy && (!dest || dest==mate)) //Follow mate move.
|
||||
{
|
||||
double matedist;
|
||||
|
||||
Pitch (mate);
|
||||
|
||||
if (!Reachable (mate))
|
||||
{
|
||||
if (mate == dest && pr_botmove.Random() < 32)
|
||||
{ // [RH] If the mate is the dest, pick a new dest sometimes
|
||||
dest = nullptr;
|
||||
}
|
||||
goto roam;
|
||||
}
|
||||
|
||||
Angle = player->mo->AngleTo(mate);
|
||||
|
||||
matedist = player->mo->Distance2D(mate);
|
||||
if (matedist > (FRIEND_DIST*2))
|
||||
cmd->ucmd.forwardmove = FORWARDRUN;
|
||||
else if (matedist > FRIEND_DIST)
|
||||
cmd->ucmd.forwardmove = FORWARDWALK; //Walk, when starting to get close.
|
||||
else if (matedist < FRIEND_DIST-(FRIEND_DIST/3)) //Got too close, so move away.
|
||||
cmd->ucmd.forwardmove = -FORWARDWALK;
|
||||
}
|
||||
else //Roam after something.
|
||||
{
|
||||
first_shot = true;
|
||||
|
||||
/////
|
||||
roam:
|
||||
/////
|
||||
if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
|
||||
if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0)
|
||||
{ //Roaming after something dead.
|
||||
dest = nullptr;
|
||||
}
|
||||
|
||||
if (dest == NULL)
|
||||
{
|
||||
if (t_fight && enemy) //Enemy/bot has jumped around corner. So what to do?
|
||||
{
|
||||
if (enemy->player)
|
||||
{
|
||||
if (((enemy->player->ReadyWeapon != NULL && GetBotInfo(enemy->player->ReadyWeapon).flags & BIF_BOT_EXPLOSIVE) ||
|
||||
(pr_botmove()%100)>skill.isp) && (GetBotInfo(player->ReadyWeapon).MoveCombatDist != 0))
|
||||
dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
|
||||
else //hide while t_fight, but keep view at enemy.
|
||||
Angle = player->mo->AngleTo(enemy);
|
||||
} //Just a monster, so kill it.
|
||||
else
|
||||
dest = enemy;
|
||||
|
||||
//VerifFavoritWeapon(player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh.
|
||||
}
|
||||
else //Choose a distant target. to get things going.
|
||||
{
|
||||
r = pr_botmove();
|
||||
if (r < 128)
|
||||
{
|
||||
auto it = player->mo->Level->GetThinkerIterator<AActor>(NAME_Inventory, MAX_STATNUM+1, Level->BotInfo.firstthing);
|
||||
auto item = it.Next();
|
||||
|
||||
if (item != NULL || (item = it.Next()) != NULL)
|
||||
{
|
||||
r &= 63; // Only scan up to 64 entries at a time
|
||||
while (r)
|
||||
{
|
||||
--r;
|
||||
item = it.Next();
|
||||
}
|
||||
if (item == NULL)
|
||||
{
|
||||
item = it.Next();
|
||||
}
|
||||
Level->BotInfo.firstthing = item;
|
||||
dest = item;
|
||||
}
|
||||
}
|
||||
else if (mate && (r < 179 || P_CheckSight(player->mo, mate)))
|
||||
{
|
||||
dest = mate;
|
||||
}
|
||||
else if ((playeringame[(r&(MAXPLAYERS-1))]) && players[(r&(MAXPLAYERS-1))].mo->health > 0)
|
||||
{
|
||||
dest = players[(r&(MAXPLAYERS-1))].mo;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest)
|
||||
{
|
||||
t_roam = MAXROAM;
|
||||
}
|
||||
}
|
||||
if (dest)
|
||||
{ //Bot has a target so roam after it.
|
||||
Roam (cmd);
|
||||
}
|
||||
|
||||
} //End of movement main part.
|
||||
|
||||
if (!t_roam && dest)
|
||||
{
|
||||
prev = dest;
|
||||
dest = nullptr;
|
||||
}
|
||||
|
||||
if (t_fight<(AFTERTICS/2))
|
||||
player->mo->flags |= MF_DROPOFF;
|
||||
|
||||
old = player->mo->Pos();
|
||||
}
|
||||
|
||||
int P_GetRealMaxHealth(AActor *actor, int max);
|
||||
|
||||
//BOT_WhatToGet
|
||||
//
|
||||
//Determines if the bot will roam after an item or not.
|
||||
void DBot::WhatToGet (AActor *item)
|
||||
{
|
||||
if ((item->renderflags & RF_INVISIBLE) //Under respawn and away.
|
||||
|| item == prev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int weapgiveammo = (alwaysapplydmflags || deathmatch) && !(dmflags & DF_WEAPONS_STAY);
|
||||
|
||||
if (item->IsKindOf(NAME_Weapon))
|
||||
{
|
||||
// FIXME
|
||||
auto heldWeapon = player->mo->FindInventory(item->GetClass());
|
||||
if (heldWeapon != NULL)
|
||||
{
|
||||
if (!weapgiveammo)
|
||||
return;
|
||||
auto ammo1 = heldWeapon->PointerVar<AActor>(NAME_Ammo1);
|
||||
auto ammo2 = heldWeapon->PointerVar<AActor>(NAME_Ammo2);
|
||||
if ((ammo1 == NULL || ammo1->IntVar(NAME_Amount) >= ammo1->IntVar(NAME_MaxAmount)) &&
|
||||
(ammo2 == NULL || ammo2->IntVar(NAME_Amount) >= ammo2->IntVar(NAME_MaxAmount)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Ammo)))
|
||||
{
|
||||
auto ac = PClass::FindActor(NAME_Ammo);
|
||||
auto parent = item->GetClass();
|
||||
while (parent->ParentClass != ac) parent = static_cast<PClassActor*>(parent->ParentClass);
|
||||
AActor *holdingammo = player->mo->FindInventory(parent);
|
||||
if (holdingammo != NULL && holdingammo->IntVar(NAME_Amount) >= holdingammo->IntVar(NAME_MaxAmount))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (item->GetClass()->TypeName == NAME_Megasphere || item->IsKindOf(NAME_Health))
|
||||
{
|
||||
// do the test with the health item that's actually given.
|
||||
AActor* const testItem = item->GetClass()->TypeName == NAME_Megasphere
|
||||
? GetDefaultByName(NAME_MegasphereHealth)
|
||||
: item;
|
||||
if (nullptr != testItem)
|
||||
{
|
||||
const int maxhealth = P_GetRealMaxHealth(player->mo, testItem->IntVar(NAME_MaxAmount));
|
||||
if (player->mo->health >= maxhealth)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dest == NULL ||
|
||||
!(dest->flags & MF_SPECIAL)/* ||
|
||||
!Reachable (dest)*/)/* &&
|
||||
Reachable (item)*/) // Calling Reachable slows this down tremendously
|
||||
{
|
||||
prev = dest;
|
||||
dest = item;
|
||||
t_roam = MAXROAM;
|
||||
}
|
||||
}
|
||||
|
||||
void DBot::Set_enemy ()
|
||||
{
|
||||
AActor *oldenemy;
|
||||
|
||||
if (enemy
|
||||
&& enemy->health > 0
|
||||
&& P_CheckSight (player->mo, enemy))
|
||||
{
|
||||
oldenemy = enemy;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldenemy = NULL;
|
||||
}
|
||||
|
||||
// [RH] Don't even bother looking for a different enemy if this is not deathmatch
|
||||
// and we already have an existing enemy.
|
||||
if (deathmatch || !enemy)
|
||||
{
|
||||
allround = !!enemy;
|
||||
enemy = Find_enemy();
|
||||
if (!enemy)
|
||||
enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
|
||||
}
|
||||
//Verify that that enemy is really something alive that bot can kill.
|
||||
if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy)))
|
||||
enemy = nullptr;
|
||||
}
|
|
@ -2374,21 +2374,6 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
|
|||
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Added by MC: To prevent bot from getting into dangerous sectors.
|
||||
if (thing->player && thing->player->Bot != NULL && thing->flags & MF_SHOOTABLE)
|
||||
{
|
||||
if (tm.sector != thing->Sector
|
||||
&& thing->Level->BotInfo.IsDangerous(tm.sector))
|
||||
{
|
||||
thing->player->Bot->prev = thing->player->Bot->dest;
|
||||
thing->player->Bot->dest = nullptr;
|
||||
thing->Vel.X = thing->Vel.Y = 0;
|
||||
thing->SetZ(oldz);
|
||||
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Check status of eyes against fake floor/ceiling in case
|
||||
|
|
|
@ -3760,12 +3760,6 @@ void AActor::Tick ()
|
|||
}
|
||||
}
|
||||
|
||||
if (Level->BotInfo.botnum && !demoplayback &&
|
||||
((flags & (MF_SPECIAL|MF_MISSILE)) || (flags3 & MF3_ISMONSTER)))
|
||||
{
|
||||
Level->BotInfo.BotTick(this);
|
||||
}
|
||||
|
||||
// [RH] Consider carrying sectors here
|
||||
DVector2 cumm(0, 0);
|
||||
|
||||
|
|
3
wadsrc_tdbots/CMakeLists.txt
Normal file
3
wadsrc_tdbots/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
add_pk3(gzdoom-tdbots.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static)
|
322
wadsrc_tdbots/static/BOTINFO.zandro
Normal file
322
wadsrc_tdbots/static/BOTINFO.zandro
Normal file
|
@ -0,0 +1,322 @@
|
|||
//These bots don't do anything at all, and that's exactly what i want!
|
||||
clearbots
|
||||
|
||||
{
|
||||
name = "Mact Man"
|
||||
color = "00 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Slayer"
|
||||
color = "ff ff ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Larry"
|
||||
color = "50 50 60"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Karen"
|
||||
color = "00 00 ff"
|
||||
gender = "female"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Joel"
|
||||
color = "40 cf 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Gustavo"
|
||||
color = "ff ff ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "James"
|
||||
color = "b0 b0 b0"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Tyler"
|
||||
color = "ff ff ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Thomas"
|
||||
color = "ff ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Kyle"
|
||||
color = "ff af 3f"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Louis"
|
||||
color = "40 cf 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Robert"
|
||||
color = "50 50 60"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Jean Romero"
|
||||
color = "8f 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Steve"
|
||||
color = "b0 b0 b0"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Gaz"
|
||||
color = "00 00 7f"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Josh"
|
||||
color = "8f 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Alex"
|
||||
color = "bf 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Patrick"
|
||||
color = "ff 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Sarah"
|
||||
color = "ff 00 00"
|
||||
gender = "female"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Sgt. Nigel"
|
||||
color = "b0 b0 b0"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Flynn"
|
||||
color = "00 ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Richard"
|
||||
color = "00 ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Carl"
|
||||
color = "ff ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Illucia"
|
||||
color = "ff ff 00"
|
||||
gender = "female"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Nitroactive"
|
||||
color = "00 ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Javier"
|
||||
color = "00 00 ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Procyon"
|
||||
color = "ff ff 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Seenas"
|
||||
color = "ff 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Oscar"
|
||||
color = "bf 8f 5f"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Synas"
|
||||
color = "00 b0 ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "Linguica"
|
||||
color = "ff 00 00"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
||||
|
||||
{
|
||||
name = "TheLegend27"
|
||||
color = "8f 01 ff"
|
||||
gender = "male"
|
||||
class = "random"
|
||||
chatfrequency = 0
|
||||
revealed = true
|
||||
script = ""
|
||||
}
|
29
wadsrc_tdbots/static/CHANGELOG.txt
Normal file
29
wadsrc_tdbots/static/CHANGELOG.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
This file was made to help me not mess changelogs up as i'm writing down things
|
||||
here as i make them.
|
||||
|
||||
v27 THE WE'RE ONE UPDATE
|
||||
|
||||
-Merged both the GZDoom and Zandronum version into one, so now Zandronum
|
||||
players can play using the normal version.
|
||||
(The bots still work much better in Zandronum vs GZDoom, please use it
|
||||
if you can)
|
||||
|
||||
-Bots will no longer shoot neither friendly monsters nor players in co-op, and
|
||||
they also won't shoot players in their own team (in team-based modes).
|
||||
Yes, for real this time, and it works in Zandronum too.
|
||||
|
||||
-Bots can now follow players in Zandronum too, and they'll pick the closest
|
||||
player to follow online.
|
||||
|
||||
-Bots now switch between weapons they have in vanilla.
|
||||
|
||||
-tdbots_usenodes no longer needs to be enabled for following the player, or
|
||||
learning the map.
|
||||
|
||||
-Slightly cleaned up the TDBot_Main script (less duplicate code).
|
||||
|
||||
-Removed the ability for bots to seek items. The only place where this was
|
||||
even remotely useful, was in bot-only matches, other than that the
|
||||
map learning renders it obsolete, and it stops bots from eating up your
|
||||
ammo in co-op. This change was done as it was the only feature left that
|
||||
the Zandronum version didn't have, and it wasn't worth keeping the split.
|
25
wadsrc_tdbots/static/CVARINFO
Normal file
25
wadsrc_tdbots/static/CVARINFO
Normal file
|
@ -0,0 +1,25 @@
|
|||
//Cosmetic options
|
||||
server bool tdbots_chat = true;
|
||||
server bool tdbots_roamchat = true;
|
||||
|
||||
//Difficulty options
|
||||
server bool tdbots_easymode = false;
|
||||
server bool tdbots_buff = false;
|
||||
server bool tdbots_lessfov = false;
|
||||
server int tdbots_reactiontime = 0;
|
||||
server int tdbots_weaponize = 0;
|
||||
|
||||
//Other options
|
||||
server noarchive bool tdbots_enable = true;
|
||||
server noarchive bool tdbots_playerbot = false;
|
||||
server bool tdbots_follow = true;
|
||||
server bool tdbots_usenodes = true;
|
||||
server bool tdbots_allowteleport = false;
|
||||
server int tdbots_teleportdelaytime = 30;
|
||||
server bool tdbots_learnfromplayer = true;
|
||||
|
||||
//Gameplay modifiers
|
||||
server noarchive bool tdbots_rocketarena = false;
|
||||
|
||||
//Info CVARs (Not intended to be modified by players)
|
||||
server noarchive int tdbots_currentgame = -1;
|
482
wadsrc_tdbots/static/DECORATE.dec
Normal file
482
wadsrc_tdbots/static/DECORATE.dec
Normal file
|
@ -0,0 +1,482 @@
|
|||
//TDBots: The fast-performing bots
|
||||
//
|
||||
//(C) 2019 Moises Aguirre / Koneoi / TDRR
|
||||
//
|
||||
//Licensed under the MIT license
|
||||
|
||||
#include "TDBots/PATHNODING.dec" //Waypointing and such things
|
||||
#include "TDBots/NODESTUDIO.dec"
|
||||
|
||||
#include "TDBots/DOOMWEAPONS.dec" //Doom weapons
|
||||
#include "TDBots/HTICWEAPONS.dec" //Heretic weapons
|
||||
#include "TDBots/HEXNWEAPONS.dec" //Hexen weapons
|
||||
#include "TDBots/STRFWEAPONS.dec" //Strife weapons
|
||||
#include "TDBots/CHEXWEAPONS.dec" //Chex weapons
|
||||
|
||||
//Remember to also check the constants in PATHNODING.dec
|
||||
|
||||
//Bot_MoveSpeed got moved to ACS, make sure to look for it there.
|
||||
|
||||
//Bot button presses, BotAltAttack is unused in the main games
|
||||
Actor BotAttack : Inventory {}
|
||||
Actor BotAltAttack : Inventory {}
|
||||
|
||||
//Bot state tokens
|
||||
Actor BotSeekingItem : Inventory {}
|
||||
Actor BotPrecisionMode : Inventory {}
|
||||
|
||||
//Weapon flags
|
||||
Actor BotExplosiveWeapon : Inventory {}
|
||||
Actor BotMeleeWeapon : Inventory {}
|
||||
Actor BotForceInacc : Inventory {} //Simulate A_Refire bullet spread
|
||||
Actor BotCloseRange : Inventory {} //Bot stays close to target but outside of
|
||||
//melee range. Useful for Shotguns.
|
||||
|
||||
//CVAR option tokens
|
||||
Actor TDBots_NavNodes : Inventory {}
|
||||
Actor TDBots_LessFOV : Inventory {}
|
||||
Actor TDBots_FollowNodeZan : Inventory {}
|
||||
|
||||
//Bot info tokens
|
||||
Actor TDBots_Success : Inventory {}
|
||||
ACtor TDBots_IsFriend : Inventory {}
|
||||
Actor TDBots_IsBot : Inventory {} //So pathnodes are only used by bots
|
||||
|
||||
//Timers
|
||||
Actor BotAttentionTimer : Inventory {Inventory.MaxAmount 40} //Item attention
|
||||
Actor BotAttentionCooldown : Inventory {Inventory.MaxAmount 48} //Time to look for items again
|
||||
|
||||
//Unused
|
||||
Actor TDBot_WeaponFiring : Inventory {}
|
||||
Actor TDBots_BotFound : Inventory {}
|
||||
|
||||
//Base actor for all bot functions, given by ACS script TDBots_BotThink
|
||||
Actor BotFunc : CustomInventory
|
||||
{
|
||||
Inventory.PickupMessage ""
|
||||
Inventory.MaxAmount 1
|
||||
+Inventory.InterHubStrip
|
||||
+Inventory.AutoActivate
|
||||
}
|
||||
|
||||
|
||||
Actor BotFunc_Strafe : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_ChangeVelocity(0, Accuracy/2, momz, CVF_REPLACE|CVF_RELATIVE)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_Strafe2 : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_ChangeVelocity(0,-Accuracy/2, momz, CVF_REPLACE|CVF_RELATIVE)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
//Resets the bot's target pointer so it doesn't circle around a dead bot
|
||||
//Doesn't work sadly.
|
||||
Actor BotFunc_Die : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_TransferPointer(AAPTR_DEFAULT, AAPTR_TARGET, AAPTR_NULL, AAPTR_TARGET, PTROP_NOSAFEGUARDS)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_StartUp : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_GiveInventory("TDBots_IsBot", 1)
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_BotThink", 0) //Init bot's thinking loop
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_Roam : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_ClearTarget
|
||||
TNT1 A 0 A_SetPitch(0)
|
||||
TNT1 A 0 A_JumpIfTargetInLOS("NormalChecks", 360)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttentionTimer", 40, "Cooldown")
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_NavNodes", 1, "SearchNodes")
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Armor", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "CustomInventory", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Ammo", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Weapon", 512, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
Stop
|
||||
|
||||
SearchNodes:
|
||||
//CheckProx("SeekItem", "Weapon", 128, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
//CheckProx("FollowNode", "TDBots_PathNode", 384, 1, CPXF_CLOSEST | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_FollowNodeZan", 1, "FollowNode")
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
Stop
|
||||
|
||||
Cooldown:
|
||||
TNT1 A 0 A_GiveInventory("BotAttentionCooldown", 1)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttentionCooldown", 48, "ResetTimer")
|
||||
NormalChecks:
|
||||
TNT1 A 0 A_CheckLOF("AvoidWall", CLOFF_SKIPOBSTACLES | CLOFF_JUMP_ON_MISS | CLOFF_SKIPTARGET | CLOFF_ALLOWNULL, 32, 0)
|
||||
TNT1 A 0 A_Jump(32, "TurnLeft", "TurnRight", "TurnLeftStrong", "TurnRightStrong") //Low chance of a random turn
|
||||
TNT1 A 0 A_Jump(256, "Proceed") //Set speed and look for targets
|
||||
Stop
|
||||
|
||||
Proceed:
|
||||
TNT1 A 0 A_JumpIfInventory("BotPrecisionMode", 1, "ProceedPart2")
|
||||
TNT1 A 0 A_Jump(56, "Strafe")
|
||||
TNT1 A 0 A_Jump(256, "ProceedPart2")
|
||||
Stop
|
||||
ProceedPart2:
|
||||
TNT1 A 0 A_JumpIf(momz != 0, "Null")
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/2, 0, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_UseItems",0,TRUE)
|
||||
Stop
|
||||
|
||||
AvoidWall: //Force turning if there's a wall nearby
|
||||
TNT1 A 0 A_Jump(256, "TurnLeft", "TurnRight", "TurnLeftStrong", "TurnRightStrong")
|
||||
Stop
|
||||
|
||||
TurnLeft:
|
||||
TNT1 A 0 A_SetAngle(angle-32)
|
||||
TNT1 A 0 A_Jump(256, "Proceed")
|
||||
Stop
|
||||
|
||||
TurnRight:
|
||||
TNT1 A 0 A_SetAngle(angle+32)
|
||||
TNT1 A 0 A_Jump(256, "Proceed")
|
||||
Stop
|
||||
|
||||
TurnLeftStrong:
|
||||
TNT1 A 0 A_SetAngle(angle-64)
|
||||
TNT1 A 0 A_Jump(256, "Proceed")
|
||||
Stop
|
||||
|
||||
TurnRightStrong:
|
||||
TNT1 A 0 A_SetAngle(angle+64)
|
||||
TNT1 A 0 A_Jump(256, "Proceed")
|
||||
Stop
|
||||
|
||||
Strafe:
|
||||
TNT1 A 0 A_Jump(128, 3)
|
||||
TNT1 A 0 A_JumpIf(momz != 0, "Null")
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/2, -Accuracy/2, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(256, "StrafeEnd")
|
||||
TNT1 A 0 A_JumpIf(momz != 0, "Null")
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/2, Accuracy/2, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(256, "StrafeEnd")
|
||||
Stop
|
||||
|
||||
StrafeEnd:
|
||||
TNT1 A 0 A_RailWait
|
||||
Stop
|
||||
|
||||
SeekHealth:
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Health", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
Stop
|
||||
|
||||
SeekItem:
|
||||
TNT1 A 0 A_GiveInventory("BotAttentionTimer", 1)
|
||||
FollowNode:
|
||||
TNT1 A 0 A_JumpIfInventory("tdbots_lessfov", TRUE, "FollowNodeLessFOV")
|
||||
TNT1 A 0 A_LookEx(0, 0, 0, 0, 360, "")
|
||||
FollowNodeP2:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_CheckLOF("AvoidWall", CLOFF_SKIPOBSTACLES | CLOFF_JUMP_ON_MISS | CLOFF_SKIPTARGET | CLOFF_ALLOWNULL, 32, 0)
|
||||
TNT1 A 0 A_Jump(256, "Proceed")
|
||||
Stop
|
||||
|
||||
FollowNodeLessFOV:
|
||||
TNT1 A 0 A_LookEx(0, 0, 0, 0, 120, "")
|
||||
TNT1 A 0 A_Jump(256, "FollowNodeP2")
|
||||
Stop
|
||||
|
||||
ResetTimer:
|
||||
TNT1 A 0 A_TakeInventory("BotAttentionTimer", 40)
|
||||
TNT1 A 0 A_TakeInventory("BotAttentionCooldown", 48)
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_LightRoam : BotFunc_Roam
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_SetPitch(0)
|
||||
TNT1 A 0 A_JumpIfTargetInLOS("NormalChecks", 360)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttentionTimer", 40, "Cooldown")
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_NavNodes", 1, "SearchNodes")
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Armor", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "CustomInventory", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Ammo", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Weapon", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
|
||||
Cooldown:
|
||||
TNT1 A 0 A_GiveInventory("BotAttentionCooldown", 1)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttentionCooldown", 48, "ResetTimer")
|
||||
NormalChecks:
|
||||
TNT1 A 0 A_ClearTarget
|
||||
TNT1 A 0 A_CheckLOF("AvoidWall", CLOFF_SKIPOBSTACLES | CLOFF_JUMP_ON_MISS | CLOFF_SKIPTARGET | CLOFF_ALLOWNULL, 32, 0)
|
||||
TNT1 A 0 A_Jump(256, "Proceed") //Set speed and look for targets
|
||||
Stop
|
||||
|
||||
SeekHealth:
|
||||
TNT1 A 0 //A_CheckProximity("SeekItem", "Health", 768, 1, CPXF_ANCESTOR | CPXF_SETTARGET | CPXF_CHECKSIGHT)
|
||||
TNT1 A 0 A_Jump(256, "NormalChecks")
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_AimDodge : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_JumpIf(momz != 0, "Finish")
|
||||
TNT1 A 0 A_JumpIfInventory("BotPrecisionMode", 1, "Finish")
|
||||
|
||||
TNT1 A 0 A_JumpIfInventory("BotMeleeWeapon", 1, "MeleeAttack") //Check if melee weapon flag set
|
||||
TNT1 A 0 A_JumpIfInventory("BotExplosiveWeapon", 1, "MoveBackwards") //Check if explosive weapon flag set
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
DodgeMore:
|
||||
TNT1 A 0 A_Jump(256, "DodgeLeft", "DodgeRight")
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
DodgeLeft:
|
||||
TNT1 A 0 A_ChangeVelocity(0, -Accuracy/2, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(32, "MoveForward", "MoveBackwards") //Move further or closer from the target at random
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
DodgeRight:
|
||||
TNT1 A 0 A_ChangeVelocity(0, Accuracy/2, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(32, "MoveForward", "MoveBackwards") //Move further or closer from the target at random
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
MoveForward:
|
||||
TNT1 A 0 A_JumpIfCloser(72, "MoveBackwards")
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/2, momy, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
MoveBackwards:
|
||||
TNT1 A 0 A_ChangeVelocity(-Accuracy/2, momy, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
MeleeAttack:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/8, momy, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
Stop
|
||||
|
||||
Finish:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_CheckLOF("Attack", CLOFF_MUSTBESHOOTABLE | CLOFF_SKIPENEMY | CLOFF_SKIPNONHOSTILE)
|
||||
TNT1 A 0 A_TakeInventory("BotAttack")
|
||||
Stop
|
||||
|
||||
Attack:
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_BotEasyMode", 0)
|
||||
Stop
|
||||
|
||||
ExplosiveCheck: //Too close to target with explosive weapon? Back out!
|
||||
TNT1 A 0 A_JumpIfCloser(200, "MoveBackwards")
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_Aim : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_JumpIfInventory("BotPrecisionMode", 1, "Finish")
|
||||
|
||||
TNT1 A 0 A_JumpIfInventory("BotMeleeWeapon", 1, "MeleeAttack") //Check if melee weapon flag set
|
||||
TNT1 A 0 A_JumpIfInventory("BotExplosiveWeapon", 1, "MoveBackwards") //Check if explosive weapon flag set
|
||||
//TNT1 A 0 A_JumpIfInventory("BotCloseRange", 1, "CloseRange")
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
CloseRange:
|
||||
TNT1 A 0 A_JumpIfCloser(256, "MoveBackwards")
|
||||
TNT1 A 0 A_Jump(256, "MeleeAttack")
|
||||
Stop
|
||||
|
||||
MoveBackwards:
|
||||
TNT1 A 0 A_ChangeVelocity(-Accuracy/4, momy, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_Jump(256, "Finish")
|
||||
Stop
|
||||
|
||||
MeleeAttack:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_ChangeVelocity(Accuracy/4, momy, momz, CVF_RELATIVE|CVF_REPLACE)
|
||||
TNT1 A 0 A_CheckLOF("Attack", CLOFF_MUSTBESHOOTABLE | CLOFF_SKIPENEMY | CLOFF_SKIPNONHOSTILE)
|
||||
TNT1 A 0 A_TakeInventory("BotAttack")
|
||||
Stop
|
||||
|
||||
Finish:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_CheckLOF("Attack", CLOFF_MUSTBESHOOTABLE | CLOFF_SKIPENEMY | CLOFF_SKIPNONHOSTILE)
|
||||
TNT1 A 0 A_TakeInventory("BotAttack")
|
||||
Stop
|
||||
|
||||
Attack:
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_BotEasyMode", 0)
|
||||
TNT1 A 0 A_GiveInventory("BotAttack")
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_CheckLOS : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_JumpIfInventory("tdbots_lessfov", TRUE, "LessFOVLook")
|
||||
TNT1 A 0 A_LookEx(0, 0, 0, 0, 360, "")
|
||||
UseP2:
|
||||
TNT1 A 0 A_FaceTarget
|
||||
TNT1 A 0 A_CheckLOF("CheckAttack", CLOFF_MUSTBESHOOTABLE)
|
||||
Stop
|
||||
|
||||
CheckAttack:
|
||||
TNT1 A 0 A_JumpIf(CallACS("TDBots_IsAlly") == TRUE, "Null")
|
||||
TNT1 A 0 A_Jump(256, "Attack")
|
||||
Stop
|
||||
|
||||
Attack:
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_BotEasyMode", 0)
|
||||
TNT1 A 0 A_GiveInventory("BotAttack", 1)
|
||||
Stop
|
||||
|
||||
LessFOVLook:
|
||||
TNT1 A 0 A_LookEx(0, 0, 0, 0, 120, "")
|
||||
TNT1 A 0 A_Jump(256, "UseP2")
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_FireStop : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_TakeInventory("BotAttack", 1)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_BuffDoom : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_SpawnItemEx("Shell", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("Clip", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("RocketAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("Cell", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("HealthBonus", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_BuffHeretic : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_SpawnItemEx("CrossbowAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("GoldWandAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("SkullrodAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("PhoenixRodAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("BlasterAmmo", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("HealthBonus", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_BuffHexen : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_SpawnItemEx("Mana1", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("Mana2", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
TNT1 A 0 A_SpawnItemEx("HealthBonus", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor BotFunc_BuffStrife : BotFunc
|
||||
{
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_SpawnItemEx("AmmoSatchel", 0, 0, 0, 0, 0, 0, 0, 0, 0, 987000)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
//Teleport call stuff
|
||||
Actor TDBot_DoNotAllowTeleport : Inventory {}
|
||||
|
||||
Actor TDBot_TeleportCall : CustomInventory
|
||||
{
|
||||
-INVBAR
|
||||
+INVENTORY.INTERHUBSTRIP
|
||||
states
|
||||
{
|
||||
Use:
|
||||
TNT1 A 0 A_JumpIfInventory("TDBot_DoNotAllowTeleport", 1, "UseButFail")
|
||||
TNT1 A 0 A_JumpIf(ACS_NamedExecuteWithResult("TDBots_NeedSomeHelp") == TRUE, "SpawnSpot")
|
||||
Fail
|
||||
SpawnSpot:
|
||||
TNT1 A 0 A_SpawnItem("Bot_TeleportSpot")
|
||||
Fail
|
||||
UseButFail:
|
||||
TNT1 A 0 A_Print("You can't call a bot right now\nStill cooling down.")
|
||||
Fail
|
||||
}
|
||||
}
|
||||
|
||||
Actor Bot_TeleportSpot
|
||||
{
|
||||
+THRUACTORS
|
||||
-SHOOTABLE
|
||||
Speed 30
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 AA 0 Thing_ChangeTID(0,16231)
|
||||
TNT1 AAAAA 0 A_Wander
|
||||
TNT1 A 1 A_Wander
|
||||
TNT1 AAAAA 0 A_Wander
|
||||
TNT1 A 1 A_Wander
|
||||
TNT1 A -1
|
||||
Stop
|
||||
}
|
||||
}
|
19
wadsrc_tdbots/static/KEYCONF
Normal file
19
wadsrc_tdbots/static/KEYCONF
Normal file
|
@ -0,0 +1,19 @@
|
|||
//Emulates doom2.exe deathmatch as closely as possible
|
||||
alias tdbots_oldschooldm "closemenu; dmflags 5570564; dmflags2 20971776; compatflags -1172751401; compatflags2 11"
|
||||
|
||||
addkeysection "TDBots keys" TDBOTMENUKEYS
|
||||
addmenukey "Open TDBots menu" "openmenu TDBots_Options"
|
||||
addmenukey "Bot Teleport Call" "use TDBot_TeleportCall"
|
||||
|
||||
addmenukey "Change node type" tdbots_changetype
|
||||
alias tdbots_changetype "pukename tdbots_chnodetype"
|
||||
|
||||
alias "tdbots_veryeasypreset" "tdbots_enable 1; tdbots_easymode 1; tdbots_reactiontime 70; tdbots_weaponize 0; tdbots_lessfov 1; tdbots_buff 0"
|
||||
alias "tdbots_easypreset" "tdbots_enable 1; tdbots_easymode 1; tdbots_reactiontime 35; tdbots_weaponize 0; tdbots_lessfov 1; tdbots_buff 0"
|
||||
alias "tdbots_mediumpreset" "tdbots_enable 1; tdbots_easymode 0; tdbots_reactiontime 35; tdbots_weaponize 0; tdbots_lessfov 1; tdbots_buff 0"
|
||||
alias "tdbots_hardpreset" "tdbots_enable 1; tdbots_easymode 0; tdbots_reactiontime 16; tdbots_weaponize 0; tdbots_lessfov 0; tdbots_buff 0"
|
||||
alias "tdbots_veryhardpreset" "tdbots_enable 1; tdbots_easymode 0; tdbots_reactiontime 0; tdbots_weaponize 0; tdbots_lessfov 0; tdbots_buff 0"
|
||||
alias "tdbots_maxpreset" "tdbots_enable 1; tdbots_easymode 0; tdbots_reactiontime 0; tdbots_weaponize 6; tdbots_lessfov 0; tdbots_buff 1"
|
||||
|
||||
alias "tdbots_startdmmap01" "closemenu; deathmatch 1; sv_weaponstay 1; sv_itemrespawn 1; sv_nomonsters 1; map map01"
|
||||
alias "tdbots_startdmE1M1" "closemenu; deathmatch 1; sv_weaponstay 1; sv_itemrespawn 1; sv_nomonsters 1; map e1m1"
|
1
wadsrc_tdbots/static/KEYCONF.nstudio
Normal file
1
wadsrc_tdbots/static/KEYCONF.nstudio
Normal file
|
@ -0,0 +1 @@
|
|||
alias "NStudio_Start" "pukename tdbots_nodestudio_startup"
|
3
wadsrc_tdbots/static/LANGUAGE.pm
Normal file
3
wadsrc_tdbots/static/LANGUAGE.pm
Normal file
|
@ -0,0 +1,3 @@
|
|||
//Post Mortem stuff.
|
||||
[enu default]
|
||||
DUMB_BOTS = "TDBots do what Zandronum bots don't, period.";
|
21
wadsrc_tdbots/static/LICENSE.txt
Normal file
21
wadsrc_tdbots/static/LICENSE.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019-2020 Moises Aguirre / Koneoi / TDRR
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
2
wadsrc_tdbots/static/LOADACS
Normal file
2
wadsrc_tdbots/static/LOADACS
Normal file
|
@ -0,0 +1,2 @@
|
|||
NODESTUDIO
|
||||
TDB_Main
|
103
wadsrc_tdbots/static/MENUDEF
Normal file
103
wadsrc_tdbots/static/MENUDEF
Normal file
|
@ -0,0 +1,103 @@
|
|||
optionmenu TDBOTS_OPTIONS
|
||||
{
|
||||
Title "TDBots options"
|
||||
StaticText "Bot and map Management options"
|
||||
StaticText ""
|
||||
Command "Add one bot", "addbot"
|
||||
StaticText ""
|
||||
Command "Remove all bots", "removebots"
|
||||
StaticText ""
|
||||
Command "Start deathmatch on MAP01", "tdbots_startdmmap01"
|
||||
StaticText ""
|
||||
Command "Start deathmatch on E1M1", "tdbots_startdmE1M1"
|
||||
StaticText ""
|
||||
Command "Start NodeStudio", "NStudio_Start"
|
||||
StaticText ""
|
||||
Command "Go to Next Map", "nextmap"
|
||||
StaticText ""
|
||||
StaticText "Gameplay modifiers"
|
||||
StaticText ""
|
||||
Option "Rocket Arena mode", "tdbots_rocketarena", "OnOff"
|
||||
StaticText "Rocket Arena consists of every player starting",1
|
||||
StaticText "out with all weapons, full ammo, full health",1
|
||||
StaticText "and full armor. Works with most mods.",1
|
||||
StaticText ""
|
||||
StaticText "Cosmetic bot options"
|
||||
StaticText ""
|
||||
Option "TDBots can chat", "tdbots_chat", "OnOff"
|
||||
StaticText ""
|
||||
Option "TDBots chat when idle", "tdbots_roamchat", "OnOff"
|
||||
StaticText ""
|
||||
StaticText "General bot options"
|
||||
StaticText ""
|
||||
Option "Enable TDBots AI", "tdbots_enable", "OnOff"
|
||||
StaticText "When disabled, reverts back to ZDoom's ZCajun AI.",1
|
||||
StaticText "And they are terrible so i don't recommend doing so!",1
|
||||
StaticText "On Zandronum, this causes the bots to stand still.",1
|
||||
StaticText ""
|
||||
Option "Learn the map from players", "tdbots_learnfromplayer", "OnOff"
|
||||
StaticText "If no waypoints are found, the TDBots will instead",1
|
||||
StaticText "try to learn the map from your exploration of it.",1
|
||||
StaticText "May take up to 1 minute before the bots use the info.",1
|
||||
StaticText ""
|
||||
Option "Use waypoints", "tdbots_usenodes", "OnOff"
|
||||
StaticText "If enabled, makes the bots use the loaded waypoint file.",1
|
||||
StaticText "Only useful if you are using a waypoint pack with the bots,",1
|
||||
//StaticText "if not, leave this off or the bots won't search for items.",1
|
||||
StaticText ""
|
||||
Option "Player is a TDBot", "tdbots_playerbot", "OnOff"
|
||||
StaticText "If on, you will also move exactly like a TDBot does.",1
|
||||
StaticText "Type sv_forcerespawn 1 in the console so you respawn",1
|
||||
StaticText "automatically too.",1
|
||||
StaticText ""
|
||||
Option "TDBots follow players", "tdbots_follow", "OnOff"
|
||||
StaticText "When on, bots follow you on cooperative modes.",1
|
||||
StaticText "Automatically disabled for deathmatch.",1
|
||||
StaticText ""
|
||||
Option "Allow teleport call", "tdbots_allowteleport", "OnOff"
|
||||
StaticText "When enabled, you can press the teleport call key",1
|
||||
StaticText "to make a random bot currently in-game teleport to",1
|
||||
StaticText "your location.",1
|
||||
StaticText ""
|
||||
Slider "Teleport cooldown time", "tdbots_teleportdelaytime", 5.0, 120.0, 1.0, 0
|
||||
StaticText "Amount of time in seconds until you can teleport",1
|
||||
StaticText "a bot to your location again.",1
|
||||
StaticText ""
|
||||
StaticText "Bot difficulty options"
|
||||
StaticText ""
|
||||
StaticText "Most options will take effect once the"
|
||||
StaticText "bot dies and then respawns."
|
||||
StaticText ""
|
||||
Option "Health and Ammo regeneration", "tdbots_buff", "OnOff"
|
||||
StaticText "A fair warning: very overpowered. Don't put this on",1
|
||||
StaticText "for Deathmatch, or the bots will be very hard to kill",1
|
||||
StaticText "Instead, use it for Co-op so the bots don't take your ammo.",1
|
||||
StaticText ""
|
||||
Option "Easy mode", "tdbots_easymode", "OnOff"
|
||||
StaticText "Makes the bot's aim significantly worse, use it if",1
|
||||
StaticText "the bot keeps beating you too much on Deathmatch.",1
|
||||
StaticText ""
|
||||
Slider "Reaction time", "tdbots_reactiontime", 0.0, 70.0, 1.0, 0
|
||||
StaticText "The higher the value, the more time the bots take to react.",1
|
||||
StaticText "35 equals one second, so 70 equals two seconds.",1
|
||||
StaticText "Don't set it very high or the bots may stop attacking suddenly.",1
|
||||
StaticText ""
|
||||
Slider "Weapons the bot starts with", "tdbots_weaponize", 0.0, 6.0, 1.0, 0
|
||||
StaticText "The higher, the better weapons the bot spawns with.",1
|
||||
StaticText "In Hexen, try not to set this higher than 2, or the",1
|
||||
StaticText "TDBots will spawn with the best weapon!",1
|
||||
StaticText ""
|
||||
Option "Reduced field of view", "tdbots_lessfov", "OnOff"
|
||||
StaticText "When on, TDBots have a reduced fov of 120",1
|
||||
StaticText "Turn this on if you don't like bots being able",1
|
||||
StaticText "to see behind their back.",1
|
||||
StaticText ""
|
||||
StaticText "TDBot difficulty presets:"
|
||||
Command "Can i play, daddy?", "tdbots_veryeasypreset"
|
||||
Command "I'm too young to die", "tdbots_easypreset"
|
||||
Command "Hurt me plenty", "tdbots_mediumpreset"
|
||||
Command "Bring it on!", "tdbots_hardpreset"
|
||||
Command "Damn i'm good!", "tdbots_veryhardpreset"
|
||||
Command "BFG SPAMMER", "tdbots_maxpreset"
|
||||
StaticText "Note: BFG SPAMMER is a joke skill, and may not be fair at all",1
|
||||
}
|
227
wadsrc_tdbots/static/TO_MODDERS.txt
Normal file
227
wadsrc_tdbots/static/TO_MODDERS.txt
Normal file
|
@ -0,0 +1,227 @@
|
|||
If you are a modder and you want to add support for the TDBots into your mod,
|
||||
look no further, as this file has all information you may need.
|
||||
|
||||
First, the TDBots are more customizable than the ZCajun bots or the Skullbots.
|
||||
So if your mod has special things you would need the bot to do, like reloading
|
||||
or using special items like grenades, altfires in your weapons or special
|
||||
behavior when carrying specific weapons you can do that without editing the bots
|
||||
themselves thanks to the custom actions added in v17.
|
||||
|
||||
These are quite similar to the usual hacks of making the bot do something at
|
||||
random using ACS, but can be set to happen exactly when the bot starts doing
|
||||
something, and don't necessarily require using ACS.
|
||||
|
||||
What this guide covers:
|
||||
-Editing weapons slightly to make them work with the bots
|
||||
(No noticeable changes for the average player though).
|
||||
|
||||
-Usage of weapon flags for special behavior with certain weapons.
|
||||
|
||||
-Playerclass specific properties (Just the speed, because
|
||||
everything else is done automatically).
|
||||
|
||||
-Custom actions, like usage of alt fire and inventory items.
|
||||
|
||||
-Making weapon and ammo lists for Rocket Arena mode.
|
||||
|
||||
-Global flags, which alter TDBots behavior.
|
||||
|
||||
=================================BASIC STUFF====================================
|
||||
|
||||
Let's get over the process to make the bots work with your mod in the most basic
|
||||
way possible, which is adapting the weapons.
|
||||
Thankfully, this process is easy, if a bit tedious sometimes, so take it slow
|
||||
if your mod has many complex weapons.
|
||||
|
||||
Copy-paste these actor definitions before any weapon:
|
||||
|
||||
Actor BotAttack : Inventory {}
|
||||
Actor BotAltAttack : Inventory {}
|
||||
Actor BotExplosiveWeapon : Inventory {}
|
||||
Actor BotMeleeWeapon : Inventory {}
|
||||
Actor BotForceInacc : Inventory {}
|
||||
Actor BotCloseRange : Inventory {}
|
||||
|
||||
These aren't necessary but they fix warnings on startup when the TDBots
|
||||
aren't loaded.
|
||||
|
||||
You must add after every A_WeaponReady call (that doesn't stop the player from
|
||||
firing of course) the following line of code:
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", TRUE, "Fire")
|
||||
|
||||
And in every A_Refire call you should add something similar:
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", TRUE, "Fire")
|
||||
Where "Fire" could also be "Hold" if such a state is defined in your weapon.
|
||||
If the A_Refire call specifies another state (such as A_Refire("HoldP2") )
|
||||
You should change "Fire" to reflect that same state.
|
||||
|
||||
Once this is done with all weapons, the bot should work. At this point, all
|
||||
features of the TDBots that work with the IWADs should work with your mod just
|
||||
the same.
|
||||
|
||||
If you are going to add altfiring with custom actions, add this line right before
|
||||
the "BotAttack" check but after the A_WeaponReady call:
|
||||
TNT1 A 0 A_JumpIfInventory("BotAltAttack", TRUE, "AltFire")
|
||||
All of the rules about A_Refire and this line of code still apply, except that
|
||||
"Hold" is changed to "AltHold" instead.
|
||||
|
||||
===============================USING WEAPON FLAGS===============================
|
||||
|
||||
There are also weapon flags, that allow the bot to act differently depending on
|
||||
what weapon it is holding.
|
||||
|
||||
Currently these flags are accepted by default:
|
||||
BotExplosiveWeapon
|
||||
BotMeleeWeapon
|
||||
BotForceInacc
|
||||
|
||||
To set these, do the following:
|
||||
|
||||
In the Select state of the weapon in question, add a line like this:
|
||||
TNT1 A 0 A_GiveInventory("NameOfFlag")
|
||||
|
||||
And in the Deselect state, add a line like this:
|
||||
TNT1 A 0 A_TakeInventory("NameOfFlag")
|
||||
|
||||
Obviously, both should have the same flag name. BotExplosiveWeapon should only
|
||||
be used if the bot can be damaged with the explosion of the weapon.
|
||||
|
||||
BotMeleeWeapon should only be used if the weapon is very short ranged, like a
|
||||
fist or something similar. It could also be used if the weapon has very drastic
|
||||
damage falloff with distance, like Final Doomer's BTSX Super sonic blaster.
|
||||
|
||||
BotForceInacc is for weapons that are inaccurate until first refire
|
||||
(Like Doom's Pistol and Chaingun, Heretic's gold wand) so they are properly
|
||||
inaccurate instead of pinpoint accurate in the bot's hands. If your weapon
|
||||
fires multiple bullets with one A_FireBullets call (A shotgun, probably) or the
|
||||
numbullets parameter on most A_FireBullets calls is -1, you don't need this.
|
||||
|
||||
It doesn't matter if the actions get repeated again as part of the state loop,
|
||||
as they only have an effect the first time they get executed.
|
||||
|
||||
|
||||
===============================ADVANCED FEATURES================================
|
||||
|
||||
Now comes the advanced features i mentioned earlier.
|
||||
For setting a class' speed, use the Accuracy property. The base Doomguy speed is
|
||||
24, so change it to make it as close as your class' running speed as possible.
|
||||
If you need help seeing the changes in an easy way, tdbots_playerbot 1 will make
|
||||
your player character also work like a bot, which helps you immediately see any
|
||||
changes in speed and stuff quickly and easily.
|
||||
|
||||
If the Accuracy property is 0 or not defined, the TDBots will automatically set
|
||||
it to base Doomguy speed, as in Doom, Hexen, Heretic and Strife.
|
||||
|
||||
I also mentioned custom actions for the bots, which can be done in the following
|
||||
way:
|
||||
|
||||
Define a new actor, named like one of these, inheriting from CustomInventory:
|
||||
TDBots_Custom_RoamLoop1 or TDBots_Custom_RoamLoop2
|
||||
These are if the bot is doing it's basic roaming. These will be executed every
|
||||
4 tics if the bot is not attacking and just running around.
|
||||
|
||||
TDBots_Custom_AttackLoop1 or TDBots_Custom_AttackLoop2
|
||||
These are executed every time the bot is attacking and not strafing at the same
|
||||
time. It is guaranteed to execute when the bots start attacking, and has a
|
||||
chance of being executed again if the bot isn't strafing.
|
||||
|
||||
If any of these are defined, the TDBot's code will detect it and place it in
|
||||
the regular bot action loop. Obviously, it's going to crash and burn if it's not
|
||||
a CustomInventory item (It could also be Inventory, but that's useless).
|
||||
|
||||
============================CODING THE CUSTOM ACTIONS===========================
|
||||
|
||||
It's a very simple to use kind of thing. As an example, let's make a bot use
|
||||
Heretic's tome of power. I'm going to avoid using ACS for this, but you could
|
||||
just use UseInventory("ArtiTomeOfPower"); in an ACS script
|
||||
and call that randomly.
|
||||
|
||||
(note: As of v18, the TDBots already use Heretic items automatically. So
|
||||
it might be a better idea to replace the "A_GiveInventory" call with
|
||||
something different so you can tell if it's actually working)
|
||||
|
||||
This actor must have +INVENTORY.AUTOACTIVATE or else it won't work at all.
|
||||
|
||||
Actor TDBots_Custom_AttackLoop1 : CustomInventory
|
||||
{
|
||||
+INVENTORY.AUTOACTIVATE
|
||||
states
|
||||
{
|
||||
Use: //Check if the bot has the tome of power.
|
||||
TNT1 A 0 A_JumpIfInventory("ArtiTomeOfPower", TRUE, "UseTomeOfPower")
|
||||
Stop
|
||||
UseTomeOfPower: //It has it, so let's roll the dice and see if we use it.
|
||||
TNT1 A 0 A_Jump(128, "ActivateTome")
|
||||
Stop
|
||||
ActivateTome:
|
||||
TNT1 A 0 A_GiveInventory("TOP_ForceActive", 1)
|
||||
TNT1 A 0 A_TakeInventory("ArtiTomeOfPower", 1)//Take the real tome away.
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
And the TOP_ForceActive item is a tome of power that activates immediately when
|
||||
it enters your inventory. So we can activate the item from DECORATE without using
|
||||
ACS.
|
||||
Here's the code:
|
||||
|
||||
Actor TOP_ForceActive : ArtiTomeOfPower {+INVENTORY.AUTOACTIVATE}
|
||||
|
||||
Now, with this code in place, the bot will now use Heretic's tome of power, if
|
||||
it's carrying it in it's inventory, it's attacking, and if the dice roll says
|
||||
that it should. Pretty cool right? You can easily define many other things
|
||||
like this using the custom actions.
|
||||
|
||||
You can use most actions you can use in a weapon, like A_SpawnItemEx, A_Jump and
|
||||
it's variants among many others. All actions that are exclusive to weapons are
|
||||
A_ZoomFactor and A_SetCrosshair, but those don't matter for bots anyways.
|
||||
|
||||
You can even use stuff like A_FireShotgun directly in these actions.
|
||||
|
||||
|
||||
==============================ROCKET ARENA MODE=================================
|
||||
|
||||
Rocket Arena mode will work fine even if you don't make lists for it. However,
|
||||
if you make a weapon and ammo list, you can control which weapons are given
|
||||
to the players and which ones aren't, and bots can pick one random weapon
|
||||
at start instead of always using the same at first.
|
||||
|
||||
If you define these, making both the weapon and ammo lists are required. One
|
||||
won't work without the other.
|
||||
|
||||
Now, to make one, just create a LANGUAGE file, optionally give it the .tdbots
|
||||
extension if you already have one, and put the following:
|
||||
|
||||
[enu default]
|
||||
|
||||
TDBOTS_RA_WEAPONS = "weapon;weapon;weapon";
|
||||
TDBOTS_RA_AMMO = "ammo;ammo;ammo";
|
||||
|
||||
Where "weapon" is a weapon actor, and "ammo" is an ammo or inventory actor.
|
||||
Of course, you aren't limited to just 3, you can add as many weapon actor names
|
||||
as your mod has, as long as you separate every actor name with a ; character.
|
||||
|
||||
Ammo can also contain any inventory items you want the player to start out
|
||||
with in Rocket Arena. Make sure to give health and armor here, since they
|
||||
aren't given by default if a custom weapon list is detected!
|
||||
|
||||
NOTE: When adding the final weapon name, remember to NOT place a ; character
|
||||
at the end inside the quotes, because this may cause undefined behavior!
|
||||
|
||||
And don't put in the starting weapons (Example: If your player starts out with
|
||||
a pistol and fist, you shouldn't put those weapons in the weapon list).
|
||||
|
||||
|
||||
=================================GLOBAL FLAGS===================================
|
||||
|
||||
Global flags serve to change certain TDBots behavior to fix various bugs with
|
||||
certain mod tricks. Global flags of different types could be added in
|
||||
the future though.
|
||||
|
||||
Currently, the only global flag is TDBots_NoAnimation.
|
||||
If an actor with this name is defined, the TDBots won't simulate animations.
|
||||
Use this if walking animations don't look right in your mod, or if the death
|
||||
animations play twice.
|
||||
|
||||
If you have any questions about this or need some more help, contact me
|
||||
in the ZDoom forums or Zandronum forums, where my user name is TDRR.
|
BIN
wadsrc_tdbots/static/acs/NODESTUDIO.o
Normal file
BIN
wadsrc_tdbots/static/acs/NODESTUDIO.o
Normal file
Binary file not shown.
BIN
wadsrc_tdbots/static/acs/TDB_Main.o
Normal file
BIN
wadsrc_tdbots/static/acs/TDB_Main.o
Normal file
Binary file not shown.
288
wadsrc_tdbots/static/scripts/NODESTUDIO.acs
Normal file
288
wadsrc_tdbots/static/scripts/NODESTUDIO.acs
Normal file
|
@ -0,0 +1,288 @@
|
|||
//TDBots: Node Studio
|
||||
//
|
||||
//(C) 2019 Moises Aguirre "TDRR"
|
||||
//
|
||||
//Licensed under the MIT license
|
||||
|
||||
#library "NODESTUDIO"
|
||||
#include "zcommon.acs"
|
||||
|
||||
str IfSomethingBreaksThisAppears = "lol TDRR fix this you moron";
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
// Start of Node Studio
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
//The nodelist is assembled on the fly into this value, and saved to a CVAR
|
||||
//whenever needed.
|
||||
str NodeList = "";
|
||||
str LastListEntry = "";
|
||||
int LastNodeTID;
|
||||
int NodeAmount;
|
||||
bool NodeListVersion = 0;
|
||||
int NodeType;
|
||||
|
||||
#define NODE_NORMAL 0
|
||||
#define NODE_JUMP 1
|
||||
#define NODE_PRECISE 2
|
||||
|
||||
//Save node to the nodelist, based on TID of the node.
|
||||
function void SaveToNodeList (int TID)
|
||||
{
|
||||
str NewString;
|
||||
int X = GetActorX(TID);
|
||||
int Y = GetActorY(TID);
|
||||
int Z = GetActorZ(TID);
|
||||
|
||||
if(NodeListVersion == 0)
|
||||
{
|
||||
NewString = StrParam(i:X/65536,s:";",i:Y/65536,s:";",i:Z/65536,s:";");
|
||||
}
|
||||
else
|
||||
{
|
||||
NewString = StrParam(i:X/65536,s:";",i:Y/65536,s:";",i:Z/65536,s:";",i:NodeType,s:";");
|
||||
}
|
||||
|
||||
NodeAmount++;
|
||||
str stringtosave = StrParam(s:NodeList, s:NewString);
|
||||
NodeList = StringToSave;
|
||||
LastListEntry = NewString;
|
||||
LastNodeTID = TID;
|
||||
}
|
||||
|
||||
//Removes last node placed, and removes it from the nodelist.
|
||||
function void DeleteLastNode (void)
|
||||
{
|
||||
if(LastNodeTID == 0) {return;}
|
||||
str NodeListTemp;
|
||||
int LastListLength = StrLen(LastListEntry);
|
||||
int ListLength = StrLen(NodeList);
|
||||
if(ListLength == 0) {return;}
|
||||
if(LastListLength == 0) {return;}
|
||||
Thing_Remove(LastNodeTID);
|
||||
NodeListTemp = StrLeft(NodeList, ListLength-LastListLength);
|
||||
NodeList = NodeListTemp;
|
||||
NodeAmount--;
|
||||
LastNodeTID = 0;
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_VersionChoice" (void)
|
||||
{
|
||||
SetHUDSize(640, 480, TRUE);
|
||||
SetFont("BIGFONT");
|
||||
|
||||
HUDMessage(s:"Press the use key to DELETE all your player stats!",
|
||||
s:"Press any other key to KEEP all your player stats!";
|
||||
HUDMSG_PLAIN, 13046, CR_YELLOW, 320.0, 240.0, 0);
|
||||
|
||||
delay(16);
|
||||
|
||||
while(GetPlayerInput(-1, INPUT_BUTTONS) == 0)
|
||||
{
|
||||
delay(1);
|
||||
}
|
||||
|
||||
if(GetPlayerInput(-1, INPUT_BUTTONS) == BT_USE)
|
||||
{
|
||||
int pnum = PlayerNumber();
|
||||
SetUserCVAR(pnum, "vd_player_mapsbeat", 0);
|
||||
SetUserCVAR(pnum, "vd_player_secrets", 0);
|
||||
SetUserCVAR(pnum, "vd_player_kills", 0);
|
||||
SetUserCVAR(pnum, "vd_player_maxkills", 0);
|
||||
SetUserCVAR(pnum, "vd_player_sandboxkills", 0);
|
||||
SetUserCVAR(pnum, "vd_player_sandboxbeat", 0);
|
||||
}
|
||||
|
||||
HUDMessage(s:"";HUDMSG_PLAIN, 13046, CR_UNTRANSLATED, 0, 0, 0);
|
||||
}
|
||||
|
||||
Script "tdbots_chnodetype" (void)
|
||||
{
|
||||
NodeType++;
|
||||
if(NodeType > NODE_PRECISE) {NodeType = NODE_NORMAL;}
|
||||
if(NodelistVersion != 0)
|
||||
switch(NodeType)
|
||||
{
|
||||
case NODE_NORMAL:
|
||||
Print(s:"Node type: Normal (purple)");
|
||||
break;
|
||||
|
||||
case NODE_JUMP:
|
||||
Print(s:"Node type: Jump (green)");
|
||||
break;
|
||||
|
||||
case NODE_PRECISE:
|
||||
Print(s:"Node type: Precision (red)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_Startup" (void)
|
||||
{
|
||||
if(PlayerCount() > 1)
|
||||
{Print(s:"Node studio can be only used offline!"); terminate;}
|
||||
if(GetCVAR("sv_freelook") == 1)
|
||||
{Print(s:"Node studio requires freelook!"); terminate;}
|
||||
|
||||
SetHUDSize(640, 480, TRUE);
|
||||
SetFont("BIGFONT");
|
||||
|
||||
HUDMessage(s:"Press the use key to use version 1\n",
|
||||
s:"Press any other key to use version 0\n",
|
||||
s:"v1 allows use of jump and precision nodes\n",
|
||||
s:"while v0 only has the basic node type";
|
||||
HUDMSG_PLAIN, 13076, CR_YELLOW, 320.0, 240.0, 0);
|
||||
|
||||
delay(16);
|
||||
|
||||
while(GetPlayerInput(-1, INPUT_BUTTONS) == 0)
|
||||
{
|
||||
delay(1);
|
||||
}
|
||||
|
||||
if(GetPlayerInput(-1, INPUT_BUTTONS) == BT_USE)
|
||||
{
|
||||
NodeListVersion = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeListVersion = 0;
|
||||
}
|
||||
|
||||
HUDMessage(s:"";HUDMSG_PLAIN, 13076, CR_UNTRANSLATED, 0, 0, 0);
|
||||
|
||||
Print(s:"Welcome to node studio.\nPress Weapon Reload for help with controls");
|
||||
ClearInventory(); Thing_Destroy(0);
|
||||
ACS_NamedExecuteAlways("TDBots_NodeStudio_InputLoop",0);
|
||||
SetPlayerProperty(1, TRUE, PROP_FLY);
|
||||
SetPlayerProperty(1, 2, PROP_INVULNERABILITY);
|
||||
SetActorFlag(0, "PICKUP", FALSE);
|
||||
GiveInventory("TDBots_NodeStudio_Editor", 1);
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_InputLoop" (void)
|
||||
{
|
||||
int buttons;
|
||||
while(TRUE)
|
||||
{
|
||||
buttons = GetPlayerInput(-1, INPUT_BUTTONS);
|
||||
|
||||
if(buttons & BT_RELOAD) {GiveInventory("TDB_NS_Reload",1);}
|
||||
else {TakeInventory("TDB_NS_Reload",1);}
|
||||
|
||||
if(buttons & BT_ZOOM) {GiveInventory("TDB_NS_Zoom",1);}
|
||||
else {TakeInventory("TDB_NS_Zoom",1);}
|
||||
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_PlaceNode" (void)
|
||||
{
|
||||
if(NodeAmount == 512) {Print(s:"Limit of 512 nodes reached."); terminate;}
|
||||
int NodeX = GetActorX(0);
|
||||
int NodeY = GetActorY(0);
|
||||
int NodeZ = GetActorZ(0);
|
||||
int TID = UniqueTID();
|
||||
/*PrintBold(s:"NodeX = ", i:NodeX);
|
||||
PrintBold(s:"NodeY = ", i:NodeY);
|
||||
PrintBold(s:"NodeZ = ", i:NodeZ);
|
||||
PrintBold(s:"TID = ", i:TID);*/
|
||||
if(NodeListVersion == 0)
|
||||
{
|
||||
SpawnForced("TDBots_NodeStudio_FakeNode", NodeX, NodeY, NodeZ, TID);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(NodeType)
|
||||
{
|
||||
case NODE_NORMAL:
|
||||
SpawnForced("TDBots_NodeStudio_FakeNode", NodeX, NodeY, NodeZ, TID);
|
||||
break;
|
||||
|
||||
case NODE_JUMP:
|
||||
SpawnForced("TDBots_NodeStudio_FakeJumpNode", NodeX, NodeY, NodeZ, TID);
|
||||
break;
|
||||
|
||||
case NODE_PRECISE:
|
||||
SpawnForced("TDBots_NodeStudio_FakePreciseNode", NodeX, NodeY, NodeZ, TID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SaveToNodeList(TID);
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_Undo" (void) {DeleteLastNode();}
|
||||
|
||||
Script "TDBots_NodeStudio_Help" (void)
|
||||
{
|
||||
Print(s:"Instructions have been printed to the console.");
|
||||
|
||||
Log(s:"You will move in the direction you look to,");
|
||||
Log(s:"Including Up and Down. A Mouse is recommended");
|
||||
Log(s:"For easy operation of Node Studio.");
|
||||
Log(s:"");
|
||||
Log(s:"Attack/Fire = Place Node on crosshair");
|
||||
Log(s:"Alt Attack = Undo last placed node");
|
||||
Log(s:"Weapon Zoom = Save Nodelist");
|
||||
Log(s:"Weapon Ready = These Instructions");
|
||||
Log(s:"Change Node Type = Change node type (v1 only)");
|
||||
Log(s:"The Change node type key is not bound by default, go bind it!");
|
||||
}
|
||||
|
||||
Script "TDBots_NodeStudio_Save" (void)
|
||||
{
|
||||
int MapLmp = StrParam(n:PRINTNAME_LEVEL);
|
||||
str cvartocheck;
|
||||
if(NodeListVersion == 0)
|
||||
{
|
||||
cvartocheck = StrParam(s:MapLmp, s:"Nodes");
|
||||
}
|
||||
else
|
||||
{
|
||||
cvartocheck = StrParam(s:MapLmp, s:"NodesNew");
|
||||
}
|
||||
str LastListCharacter;
|
||||
int NodeListLength = StrLen(NodeList);
|
||||
str NodeListToSave;
|
||||
//Print(s:"Saving to .ini file...");
|
||||
|
||||
NodeListToSave = NodeList;
|
||||
|
||||
//Chop off the last ; on the list, because it can cause parsing errors.
|
||||
if(NodeListLength > 0)
|
||||
{
|
||||
LastListCharacter = StrRight(NodeList, 1);
|
||||
if(StrCmp(LastListCharacter, ";") == 0)
|
||||
{NodeListToSave = StrLeft(NodeList, NodeListLength-1);}
|
||||
}
|
||||
|
||||
//SetCVARString(cvartocheck, NodeList);
|
||||
Print(s:"The nodelist has been printed to the console.\nAlong with some instructions.");
|
||||
Log(s:"===START OF HELP===");
|
||||
Log(s:"If you don't have a logfile active,");
|
||||
Log(s:"type logfile nodeoutput.txt in the console");
|
||||
Log(s:"and press this button again.");
|
||||
Log(s:"");
|
||||
Log(s:"Then, a text file called nodeoutput should be");
|
||||
Log(s:"In your ZDoom directory, so open it with");
|
||||
Log(s:"Notepad++, copy the line between the");
|
||||
Log(s:"COPY THIS markers, and paste it in another text");
|
||||
Log(s:"file, and name it whatever you want without spaces.");
|
||||
Log(s:"");
|
||||
Log(s:"Finally, to load it from ZDoom, type in the console");
|
||||
Log(s:"exec nameoffile.txt");
|
||||
Log(s:"====END OF HELP====");
|
||||
Log(s:"===COPY NEXT LINE===");
|
||||
Log(s:"set \"",
|
||||
s:cvartocheck, s:"\" \"", s:NodeListToSave, s:"\"");
|
||||
Log(s:"===COPY PREVIOUS LINE==");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
// End of Node Studio
|
||||
//
|
||||
//==============================================================================
|
173
wadsrc_tdbots/static/scripts/TDB_Chat.acs
Normal file
173
wadsrc_tdbots/static/scripts/TDB_Chat.acs
Normal file
|
@ -0,0 +1,173 @@
|
|||
//Bot talking arrays, you should customize them to fit your mod/game.
|
||||
|
||||
#DEFINE MAXMSGS_ENTER 55
|
||||
str BotSpeak_Enter[MAXMSGS_ENTER] =
|
||||
{
|
||||
"Time to rack up some frags!",
|
||||
"Another fight? Oh well.",
|
||||
"Ready for heated combat!",
|
||||
"One battle, hundreds of frags!",
|
||||
"What, wanna lose again? Okay!",
|
||||
"I'm putting all my effort in this fight.",
|
||||
"Hey, want to watch your death counter go up?",
|
||||
"Only the best will win, and that's me.",
|
||||
"Got plans for you all, more pain!",
|
||||
"Look at the time, It's time to kill!",
|
||||
"h3y l00z3rs t1m3 2 g3t p0wn3d",
|
||||
"Hey this isn't OpenArena!",
|
||||
"Hola, no se hablar ingles.",
|
||||
"We all know what happens, i win, you lose.",
|
||||
"I am ready to roll!",
|
||||
"Ohoho, this'll be good!",
|
||||
"Ah, the site of one of my gest kills.",
|
||||
"Back in my old stomping ground.",
|
||||
"Let's get started.",
|
||||
"Now, THIS is my kind of place!",
|
||||
"Reporting for duty.",
|
||||
"Here comes a new challenger!",
|
||||
"I never thought I'd see this place again.",
|
||||
"It's pay-back time!",
|
||||
"Hi there",
|
||||
"Hello",
|
||||
"I bet you missed me",
|
||||
"G'day",
|
||||
"Yo! i'm in the house!",
|
||||
"Wassup",
|
||||
"Run in fear, i'm here!",
|
||||
"Let's get it on!",
|
||||
"Crap. Losers in here again!",
|
||||
"Yessss! Fresh victims!",
|
||||
"I'm back!",
|
||||
"Showtime!",
|
||||
"Let's rock and roll",
|
||||
"Great! Easy frags ahead.",
|
||||
"It's party time!",
|
||||
"Let's kick it",
|
||||
"Time for some fireworks",
|
||||
"I'm here. There will be no survivors!",
|
||||
"Guess its time to mow the grass",
|
||||
"I am so ready for this",
|
||||
"It's time for 'Bowling for Morons'",
|
||||
"Fresh meat!",
|
||||
"Howdy!",
|
||||
"Let's get it ON!",
|
||||
"Let's do it!",
|
||||
"No Prisoners!",
|
||||
"It's time for me to lay down the law here.",
|
||||
"Hey, little kitty-cat, I have a treat for you.",
|
||||
"Time to settle some scores!",
|
||||
"Make this a good day, cuz it'll be your last.",
|
||||
"I'm gonna kick your sorry butt into the next county."
|
||||
};
|
||||
|
||||
#DEFINE MAXMSGS_ENTERCOOP 12
|
||||
str BotSpeak_EnterCoop[MAXMSGS_ENTERCOOP+1] =
|
||||
{
|
||||
"Let's get them.",
|
||||
"Lock and load!",
|
||||
"I hear some monsters, let's kill them!",
|
||||
"I wonder if this map has any keys?",
|
||||
"This place makes me feel nervous.",
|
||||
"Time to complete this operation.",
|
||||
"I heard this place is really dangerous.",
|
||||
"Okay, let's go, but don't steal all the ammo.",
|
||||
"I am ready to roll!",
|
||||
"Ohoho, this'll be good!",
|
||||
"Let's get started.",
|
||||
"I never thought I'd see this place again."
|
||||
};
|
||||
|
||||
#DEFINE MAXMSGS_ROAM 29
|
||||
str BotSpeak_Roam[MAXMSGS_ROAM+1] =
|
||||
{
|
||||
"Stop hiding, i can smell fear!",
|
||||
"Come out, i'm coming for you.",
|
||||
"What's the matter, scared?",
|
||||
"One, two, three, ready or not, here i come!",
|
||||
"This map is pretty nice.",
|
||||
"This battle has been quite lenghty, huh?",
|
||||
"All this fighting is getting me hungry.",
|
||||
"Could you please stop camping? Thanks.",
|
||||
"Come out and play!",
|
||||
"Come on, I hate waiting.",
|
||||
"...Okay, come on, maybe just burn a little something?",
|
||||
"Party time! Need some fireworks?",
|
||||
"Come on, show yourself.",
|
||||
"A single death can change everything.",
|
||||
"What's an aimbot?",
|
||||
"The world could always use more heroes!",
|
||||
"I don't like this standing around.",
|
||||
"Make every second count!",
|
||||
"Come on, i don't have all day",
|
||||
"Lot of memories of this place. They weren't all bad.",
|
||||
"Rocket jump? That sounds dangerous.",
|
||||
"You're going to come with me, dead or alive.",
|
||||
"Don't just stand around, do something.",
|
||||
"Hm. This place is to my liking.",
|
||||
"Come over here!",
|
||||
"Staying out of trouble?",
|
||||
"You might be fast, but you ain't faster than a bullet.",
|
||||
"So many targets, so little time.",
|
||||
"Old soldiers are hard to kill."
|
||||
};
|
||||
|
||||
#DEFINE MAXMSGS_DEATH 30
|
||||
str BotSpeak_Die[MAXMSGS_DEATH] =
|
||||
{
|
||||
"ARGH, YOU WILL PAY FOR THAT!",
|
||||
"Alright, no more letting you win!",
|
||||
"Nice shot, have you been practicing?",
|
||||
"Dang, i better get some frags!",
|
||||
"That was a lucky shot.",
|
||||
"You fooled with the wrong person!",
|
||||
"Beginner luck, but that's it!",
|
||||
"Now you will see what i'm made of!",
|
||||
"If at first you don't succeed... Blow it up again!",
|
||||
"You won't get rid of me that easily.",
|
||||
"Think you can do better than me?",
|
||||
"Well that just happened.",
|
||||
"Back to work!",
|
||||
"That could have gone better.",
|
||||
"This fight is not over yet!",
|
||||
"Don't get me angry.",
|
||||
"It's just a scratch.",
|
||||
"Knock me down, and I'll keep getting back up.",
|
||||
"A speedy recovery.",
|
||||
"Where'd you learn to shoot like that?",
|
||||
"Repetition teaches the smart.",
|
||||
"Heh ... I had the safety on ...",
|
||||
"I'm taking off the kid gloves now!",
|
||||
"Okay, now I start fighting for real!",
|
||||
"Enjoy that one. Your luck is about to run out",
|
||||
"Now the match gets serious.",
|
||||
"This was tragic",
|
||||
"I will accept this as yet another learning experience",
|
||||
"Ouch. That hurt",
|
||||
"There will be some serious payback for this"
|
||||
};
|
||||
|
||||
function void TDBots_Chat (int type)
|
||||
{
|
||||
if(GetCVAR("tdbots_chat") == FALSE)
|
||||
{return;}
|
||||
|
||||
if(type == MSG_ENTER)
|
||||
{Log(s:"\c*", n:0, s:"\c*: ", s:BotSpeak_Enter[random(0,MAXMSGS_ENTER-1)]);}
|
||||
|
||||
else if(type == MSG_ENTERCOOP)
|
||||
{Log(s:"\c*", n:0, s:"\c*: ", s:BotSpeak_EnterCoop[random(0,MAXMSGS_ENTERCOOP-1)]);}
|
||||
|
||||
else if(type == MSG_ROAM)
|
||||
{
|
||||
if(GetCVAR("tdbots_roamchat") == FALSE) {return;}
|
||||
Log(s:"\c*", n:0, s:"\c*: ", s:BotSpeak_Roam[random(0,MAXMSGS_ROAM-1)]);
|
||||
}
|
||||
|
||||
else if(type == MSG_DEATH)
|
||||
{Log(s:"\c*", n:0, s:"\c*: ", s:BotSpeak_Die[random(0,MAXMSGS_DEATH-1)]);}
|
||||
|
||||
else
|
||||
{Log(s:"\c*", n:0, s:"\cg: Unknown message type ", i:type);}
|
||||
|
||||
AmbientSound("misc/chat", 127);
|
||||
}
|
33
wadsrc_tdbots/static/scripts/TDB_Defn.acs
Normal file
33
wadsrc_tdbots/static/scripts/TDB_Defn.acs
Normal file
|
@ -0,0 +1,33 @@
|
|||
int CurrentGame;
|
||||
bool VanillaDoom = FALSE;
|
||||
|
||||
//stupid ACS why can't you be normal with strings
|
||||
str DummyWorkaroundString = "lol get bugged";
|
||||
|
||||
#DEFINE MAX_PLAYERS 64
|
||||
|
||||
#DEFINE BOTSPEED 30
|
||||
|
||||
#DEFINE GAME_DOOM 0 //Also the default for modded games
|
||||
#DEFINE GAME_HERETIC 1
|
||||
#DEFINE GAME_HEXEN 2
|
||||
#DEFINE GAME_STRIFE 3
|
||||
|
||||
#DEFINE GAME_COOP 0
|
||||
#DEFINE GAME_DM 1
|
||||
|
||||
#DEFINE AXIS_X 0
|
||||
#DEFINE AXIS_Y 1
|
||||
#DEFINE AXIS_Z 2
|
||||
#DEFINE NODETYPE 3
|
||||
|
||||
#define NODE_NORMAL 0
|
||||
#define NODE_JUMP 1
|
||||
#define NODE_PRECISE 2
|
||||
|
||||
#DEFINE MSG_ENTER 0
|
||||
#DEFINE MSG_ENTERCOOP 1
|
||||
#DEFINE MSG_ROAM 2
|
||||
#DEFINE MSG_DEATH 3
|
||||
|
||||
#DEFINE TELTID 16231
|
48
wadsrc_tdbots/static/scripts/TDB_Inv.acs
Normal file
48
wadsrc_tdbots/static/scripts/TDB_Inv.acs
Normal file
|
@ -0,0 +1,48 @@
|
|||
//If there's a custom action in the current mod loaded, one or more of these
|
||||
//should be true.
|
||||
|
||||
bool TDB_Custom_Roam1;
|
||||
bool TDB_Custom_Roam2;
|
||||
|
||||
bool TDB_Custom_Attk1;
|
||||
bool TDB_Custom_Attk2;
|
||||
|
||||
function void TDB_GiveItem (str item)
|
||||
{
|
||||
Spawn(item, GetActorX(0), GetActorY(0), GetActorZ(0), 987005);
|
||||
}
|
||||
|
||||
function void TDB_RA_Give (str item)
|
||||
{
|
||||
int x = GetActorX(0);
|
||||
int y = GetActorY(0);
|
||||
int z = GetActorZ(0);
|
||||
|
||||
Spawn(item, x, y, z, 987005);
|
||||
Spawn(item, x, y, z, 987005);
|
||||
Spawn(item, x, y, z, 987005);
|
||||
Spawn(item, x, y, z, 987005);
|
||||
Spawn(item, x, y, z, 987005);
|
||||
}
|
||||
|
||||
function void TDB_MaxGive (str item)
|
||||
{
|
||||
GiveInventory(item, 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
function void Codepointer (str actionfunction)
|
||||
{
|
||||
GiveInventory(actionfunction, 1);
|
||||
SetPlayerProperty(0,1,4); //Reset the frozen property every codepointer
|
||||
}
|
||||
|
||||
//To check for custom thinking modules
|
||||
function bool TDB_ActorExists (str actor)
|
||||
{
|
||||
if(SpawnForced(actor,0,0,0,15423,0))
|
||||
{
|
||||
Thing_Remove(15423);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
330
wadsrc_tdbots/static/scripts/TDB_Main.acs
Normal file
330
wadsrc_tdbots/static/scripts/TDB_Main.acs
Normal file
|
@ -0,0 +1,330 @@
|
|||
//TDBots: The fast-performing bots
|
||||
//
|
||||
//(C) 2021 Moises Aguirre "TDRR"
|
||||
//
|
||||
//Licensed under the MIT license
|
||||
|
||||
#library "TDB_Main"
|
||||
#include "zcommon.acs"
|
||||
|
||||
#include "TDB_Defn.acs"
|
||||
|
||||
#include "TDB_Chat.acs"
|
||||
#include "TDB_Zan.acs"
|
||||
#include "TDB_Inv.acs"
|
||||
#include "TDB_RA.acs"
|
||||
#include "TDB_Misc.acs"
|
||||
|
||||
#include "TDB_Node.acs"
|
||||
|
||||
//Internal variables, i recommend you don't change these.
|
||||
bool LightRoam = TRUE;
|
||||
|
||||
int Gamemode;
|
||||
|
||||
bool BotNeeded;
|
||||
bool OtherBotAssisted;
|
||||
|
||||
Script "TDBots_TeleportBotGiver" ENTER
|
||||
{
|
||||
if(GameType() == GAME_NET_DEATHMATCH) {terminate;}
|
||||
if(PlayerIsBot(PlayerNumber()) == FALSE)
|
||||
{
|
||||
if(GetCVAR("tdbots_allowteleport") == TRUE)
|
||||
{GiveInventory("TDBot_TeleportCall", 1);}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_TeleportBotGiver2" RESPAWN
|
||||
{
|
||||
TakeInventory("TDBot_DoNotAllowTeleport", 1);
|
||||
ACS_NamedExecuteAlways("TDBots_TeleportBotGiver", 0);
|
||||
}
|
||||
|
||||
function bool TDB_AnyBotConnected(void)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (PlayerIsBot(i))
|
||||
{return TRUE;}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Script "TDBots_NeedSomeHelp" (void)
|
||||
{
|
||||
int delayamount = GetCVAR("tdbots_teleportdelaytime")*35;
|
||||
if(delayamount < 35*5) {delayamount = 35*5;}
|
||||
else if(delayamount > 35*120) {delayamount = 35*120;}
|
||||
else if(delayamount == 0) {delayamount = 35*30;}
|
||||
if(BotNeeded == FALSE)
|
||||
{
|
||||
if(TDB_AnyBotConnected() == TRUE)
|
||||
{
|
||||
BotNeeded = TRUE;
|
||||
ACS_NamedExecuteAlways("TDBots_BotNeededWait",0);
|
||||
SetResultValue(TRUE);
|
||||
GiveInventory("TDBot_DoNotAllowTeleport", 1);
|
||||
delay(delayamount);
|
||||
TakeInventory("TDBot_DoNotAllowTeleport", 1);
|
||||
terminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print(s:"No bot is currently connected.");
|
||||
SetResultValue(FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print(s:"Can't call a bot at the same time\nas another player!");
|
||||
SetResultValue(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_BotNeededWait" (void)
|
||||
{
|
||||
delay(35*5);
|
||||
BotNeeded = FALSE;
|
||||
}
|
||||
|
||||
Script "TDBots_IsAlly" (void)
|
||||
{
|
||||
//will be 255 in Co-op, so bots should still avoid shooting players as
|
||||
//they'll have the same teamid.
|
||||
int team = GetPlayerInfo(PlayerNumber(), PLAYERINFO_TEAM);
|
||||
|
||||
//if regular deathmach, nothing to do here, shoot every living thing on sight
|
||||
if( (Gametype() == GAME_NET_DEATHMATCH) && (!GetCVAR("teamplay")))
|
||||
{
|
||||
SetResultValue(FALSE);
|
||||
terminate;
|
||||
}
|
||||
|
||||
SetActivatorToTarget(0);
|
||||
|
||||
if(PlayerNumber() >= 0) //is player
|
||||
{
|
||||
SetResultValue( (team == GetPlayerInfo(PlayerNumber(), PLAYERINFO_TEAM)) );
|
||||
terminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetResultValue(CheckFlag(0, "FRIENDLY"));
|
||||
terminate;
|
||||
}
|
||||
SetResultValue(FALSE); //just in case.
|
||||
}
|
||||
|
||||
Script "TDBots_TeleportBot" (void)
|
||||
{
|
||||
int ImWhoAssisted;
|
||||
delay(random(0,16));
|
||||
while(GetActorProperty(0, APROP_HEALTH) > 0)
|
||||
{
|
||||
delay(60);
|
||||
if(BotNeeded == TRUE)
|
||||
{
|
||||
if(OtherBotAssisted == FALSE || ImWhoAssisted == TRUE)
|
||||
{
|
||||
OtherBotAssisted = TRUE;
|
||||
ImWhoAssisted = TRUE;
|
||||
if(SetActorPosition(0,GetActorX(TELTID), GetActorY(TELTID), GetActorZ(TELTID), TRUE))
|
||||
{
|
||||
delay(1);
|
||||
Thing_Remove(TELTID);
|
||||
BotNeeded = FALSE;
|
||||
OtherBotAssisted = FALSE;
|
||||
ImWhoAssisted = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(1);
|
||||
SpawnForced("Bot_TeleportSpot", GetActorX(TELTID), GetActorY(TELTID), GetActorZ(TELTID), TELTID);
|
||||
Thing_Remove(TELTID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_WalkNoding" (void)
|
||||
{
|
||||
if(PlayerIsBot(PlayerNumber()) || GetCVAR("tdbots_playerbot")) {terminate;}
|
||||
if(GetCVAR("sv_forcerespawn") == FALSE)
|
||||
{ACS_NamedExecuteAlways("TDBots_ZandronumCommands",0);}
|
||||
if(Gametype() > GAME_NET_COOPERATIVE) {terminate;} //Can't follow in competitive gamemodes
|
||||
if(!GetCVAR("tdbots_follow")) {terminate;}
|
||||
|
||||
int TID;
|
||||
|
||||
while(GetActorProperty(0, APROP_HEALTH) > 0)
|
||||
{
|
||||
for(int i = 0; i < MAX_FOLLOW_NODES; i++)
|
||||
{
|
||||
TID = UniqueTID();
|
||||
|
||||
delay(16);
|
||||
SpawnForced("TDBots_TempNode", GetActorX(0), GetActorY(0), GetActorZ(0), TID);
|
||||
|
||||
PlayerFollowTID[PlayerNumber()][i] = TID;
|
||||
PlayerLocation[PlayerNumber()][0] = GetActorX(0);
|
||||
PlayerLocation[PlayerNumber()][1] = GetActorY(0);
|
||||
PlayerLocation[PlayerNumber()][2] = GetActorZ(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_BotAnimation" (void)
|
||||
{
|
||||
int tics;
|
||||
while(TDBotDead() == FALSE)
|
||||
{
|
||||
if(tics % 4 == 0) //if 16 tics have passed
|
||||
{
|
||||
if(CheckInventory("BotAttack") == FALSE) {AnimateTDBot("See");}
|
||||
}
|
||||
delay(4);
|
||||
if(TDBotDead() == TRUE) {terminate;}
|
||||
tics++;
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_BotThink" (void)
|
||||
{
|
||||
int firetime;
|
||||
int tics;
|
||||
|
||||
if(TDBotDead() == TRUE) {terminate;}
|
||||
|
||||
if(TDB_Custom_Roam1 == TRUE) {Codepointer("TDBots_Custom_RoamLoop1");}
|
||||
if(TDB_Custom_Roam2 == TRUE) {Codepointer("TDBots_Custom_RoamLoop2");}
|
||||
|
||||
if(LightRoam == TRUE)
|
||||
{Codepointer("BotFunc_LightRoam"); LightRoam = FALSE;}
|
||||
else
|
||||
{Codepointer("BotFunc_Roam"); LightRoam = TRUE;}
|
||||
Delay(3);
|
||||
|
||||
TDB_FollowNode();
|
||||
|
||||
if(TDBotDead() == TRUE) {terminate;}
|
||||
if(random(0, 256) == 1) {TDBots_Chat(MSG_ROAM);}
|
||||
|
||||
Codepointer("BotFunc_CheckLOS"); delay(1);
|
||||
|
||||
TDB_RandomWeapon();
|
||||
|
||||
for(firetime = 0; firetime < random(26, 52); firetime++)
|
||||
{
|
||||
if(CheckInventory("BotAttack") == TRUE)
|
||||
{
|
||||
if(firetime == 0)
|
||||
{
|
||||
if(GetCVAR("tdbots_reactiontime") <= 70)
|
||||
{
|
||||
if(GetCVAR("tdbots_reactiontime") >= 0)
|
||||
{Delay(GetCVAR("tdbots_reactiontime"));}
|
||||
else {Delay(1);}
|
||||
}
|
||||
else
|
||||
{Delay(70);}
|
||||
}
|
||||
|
||||
if(TDB_Custom_Attk1 == TRUE) {Codepointer("TDBots_Custom_AttackLoop1");}
|
||||
Codepointer("BotFunc_AimDodge");
|
||||
ACS_NamedExecuteAlways("TDBots_UseItems", 0, FALSE);
|
||||
if(TDB_Custom_Attk2 == TRUE) {Codepointer("TDBots_Custom_AttackLoop2");}
|
||||
AnimateTDBot("Missile");
|
||||
|
||||
if(random(0,256) <= 128)
|
||||
{
|
||||
Codepointer("BotFunc_Strafe");
|
||||
Codepointer("BotFunc_Aim");
|
||||
if(TDB_IsZandronum() == TRUE)
|
||||
{
|
||||
for(tics = 0; tics <= 16; tics++)
|
||||
{
|
||||
if(tics % 2 == 0)
|
||||
{if(TDBotDead() == TRUE) {terminate;}}
|
||||
|
||||
if(tics % 4 == 0)
|
||||
{Codepointer("BotFunc_Strafe");}
|
||||
|
||||
Codepointer("BotFunc_Aim"); delay(2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(tics = 0; tics <= 32; tics++)
|
||||
{
|
||||
if(tics % 4 == 0)
|
||||
{if(TDBotDead() == TRUE) {terminate;}}
|
||||
|
||||
if(tics % 8 == 0)
|
||||
{Codepointer("BotFunc_Strafe");}
|
||||
|
||||
Codepointer("BotFunc_Aim"); delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(random(0,256) <= 168)
|
||||
{
|
||||
Codepointer("BotFunc_Strafe2");
|
||||
Codepointer("BotFunc_Aim");
|
||||
if(TDB_IsZandronum() == TRUE)
|
||||
{
|
||||
for(tics = 0; tics <= 16; tics++)
|
||||
{
|
||||
if(tics % 2 == 0)
|
||||
{if(TDBotDead() == TRUE) {terminate;}}
|
||||
|
||||
if(tics % 4 == 0)
|
||||
{Codepointer("BotFunc_Strafe2");}
|
||||
|
||||
Codepointer("BotFunc_Aim"); delay(2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(tics = 0; tics <= 32; tics++)
|
||||
{
|
||||
if(tics % 4 == 0)
|
||||
{if(TDBotDead() == TRUE) {terminate;}}
|
||||
|
||||
if(tics % 8 == 0)
|
||||
{Codepointer("BotFunc_Strafe2");}
|
||||
|
||||
Codepointer("BotFunc_Aim"); delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Codepointer("BotFunc_Roam");
|
||||
Delay(4);
|
||||
break;
|
||||
}
|
||||
Delay(1);
|
||||
if(TDBotDead() == TRUE) {terminate;}
|
||||
}
|
||||
firetime = 0;
|
||||
Codepointer("BotFunc_FireStop");
|
||||
if(GetActorProperty(0, APROP_HEALTH) > 0) {restart;}
|
||||
}
|
||||
|
||||
Script "TDBots_BotDeath" DEATH
|
||||
{
|
||||
TakeInventory("TDBot_DoNotAllowTeleport",9999);
|
||||
if(GetCVAR("sv_forcerespawn") == FALSE)
|
||||
{ACS_NamedExecuteAlways("TDBots_ZandronumCommands",0);}
|
||||
if(PlayerIsBot(PlayerNumber()) == TRUE || GetCVAR("tdbots_playerbot") == TRUE)
|
||||
{
|
||||
if(GetCVAR("tdbots_enable") == TRUE || PlayerIsBot(PlayerNumber()) == FALSE)
|
||||
{
|
||||
if(random(0, 100) < 12)
|
||||
{TDBots_Chat(MSG_DEATH);}
|
||||
}
|
||||
}
|
||||
}
|
417
wadsrc_tdbots/static/scripts/TDB_Misc.acs
Normal file
417
wadsrc_tdbots/static/scripts/TDB_Misc.acs
Normal file
|
@ -0,0 +1,417 @@
|
|||
bool BotAnim = TRUE;
|
||||
|
||||
function void TDBots_SwapWeapons (void)
|
||||
{
|
||||
if(CheckInventory("Pistol"))
|
||||
{
|
||||
TakeInventory("Fist", 1);
|
||||
TakeInventory("Pistol", 1);
|
||||
GiveInventory("BotFist", 1);
|
||||
GiveInventory("BotPistol", 1);
|
||||
|
||||
SetWeapon("BotPistol");
|
||||
|
||||
CurrentGame = GAME_DOOM;
|
||||
VanillaDoom = TRUE;
|
||||
}
|
||||
else if(CheckInventory("GoldWand"))
|
||||
{
|
||||
TakeInventory("Staff", 1);
|
||||
TakeInventory("GoldWand", 1);
|
||||
GiveInventory("BotStaff", 1);
|
||||
GiveInventory("BotGoldWand", 1);
|
||||
|
||||
SetWeapon("BotGoldWand");
|
||||
|
||||
CurrentGame = GAME_HERETIC;
|
||||
}
|
||||
else if(CheckInventory("CWeapMace"))
|
||||
{
|
||||
TakeInventory("CWeapMace", 1);
|
||||
GiveInventory("BotCWeapMace", 1);
|
||||
|
||||
SetWeapon("BotCWeapMace");
|
||||
|
||||
CurrentGame = GAME_HEXEN;
|
||||
}
|
||||
else if(CheckInventory("FWeapFist"))
|
||||
{
|
||||
TakeInventory("FWeapFist", 1);
|
||||
GiveInventory("BotFWeapFist", 1);
|
||||
|
||||
SetWeapon("BotFWeapFist");
|
||||
|
||||
CurrentGame = GAME_HEXEN;
|
||||
}
|
||||
else if(CheckInventory("MWeapWand"))
|
||||
{
|
||||
TakeInventory("MWeapWand", 1);
|
||||
GiveInventory("BotMWeapWand", 1);
|
||||
|
||||
SetWeapon("BotMWeapWand");
|
||||
|
||||
CurrentGame = GAME_HEXEN;
|
||||
}
|
||||
else if(CheckInventory("PunchDagger"))
|
||||
{
|
||||
TakeInventory("PunchDagger", 1);
|
||||
GiveInventory("BotPunchDagger", 1);
|
||||
|
||||
SetWeapon("BotPunchDagger");
|
||||
|
||||
CurrentGame = GAME_STRIFE;
|
||||
}
|
||||
else if(CheckInventory("MiniZorcher"))
|
||||
{
|
||||
TakeInventory("MiniZorcher", 1);
|
||||
TakeInventory("Bootspoon", 1);
|
||||
GiveInventory("BotBootspoon", 1);
|
||||
GiveInventory("BotMiniZorcher", 1);
|
||||
|
||||
SetWeapon("BotMiniZorcher");
|
||||
|
||||
CurrentGame = GAME_DOOM; //For all intents and purposes, Chex is Doom.
|
||||
}
|
||||
|
||||
str CGVAR = GetCVAR("tdbots_currentgame");
|
||||
|
||||
if(CGVAR != -1)
|
||||
{
|
||||
CurrentGame = CGVAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCVAR("tdbots_currentgame", CurrentGame);
|
||||
}
|
||||
}
|
||||
|
||||
function void TDBots_Weaponize (void)
|
||||
{
|
||||
if(GetCVAR("tdbots_rocketarena") == TRUE) {return;}
|
||||
if(GetCVAR("tdbots_weaponize") > 5)
|
||||
{
|
||||
if(random(0,4) == 1)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("BFG9000");}
|
||||
else if(CurrentGame == GAME_HERETIC) {TDB_GiveItem("Mace");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("StrifeGrenadeLauncher");}
|
||||
}
|
||||
}
|
||||
if(GetCVAR("tdbots_weaponize") > 4)
|
||||
{
|
||||
if(random(0,4) == 1)
|
||||
{
|
||||
//No SSG equivalent in Heretic so only Doom here.
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("SuperShotgun");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("Mauler");}
|
||||
}
|
||||
}
|
||||
if(GetCVAR("tdbots_weaponize") > 3)
|
||||
{
|
||||
if(random(0,3) == 1)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("PlasmaRifle");}
|
||||
else if(CurrentGame == GAME_HERETIC) {TDB_GiveItem("SkullRod");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("MiniMissileLauncher");}
|
||||
}
|
||||
}
|
||||
if(GetCVAR("tdbots_weaponize") > 2)
|
||||
{
|
||||
if(random(0,3) == 1)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("RocketLauncher");}
|
||||
else if(CurrentGame == GAME_HERETIC) {TDB_GiveItem("PhoenixRod");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("AssaultGun");}
|
||||
else if(CurrentGame == GAME_HEXEN)
|
||||
{TDB_GiveItem("CWeapWraithverge"); TDB_GiveItem("FWeapQuietus"); TDB_GiveItem("MWeapBloodscourge");}
|
||||
}
|
||||
}
|
||||
if(GetCVAR("tdbots_weaponize") > 1)
|
||||
{
|
||||
if(random(0,3) == 1)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("Chaingun");}
|
||||
else if(CurrentGame == GAME_HERETIC) {TDB_GiveItem("Blaster");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("AssaultGun");}
|
||||
else if(CurrentGame == GAME_HEXEN)
|
||||
{TDB_GiveItem("CWeapFlame"); TDB_GiveItem("FWeapHammer"); TDB_GiveItem("MWeapLighting");}
|
||||
}
|
||||
}
|
||||
if(GetCVAR("tdbots_weaponize") > 0)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {TDB_GiveItem("Shotgun");}
|
||||
else if(CurrentGame == GAME_HERETIC) {TDB_GiveItem("Crossbow");}
|
||||
else if(CurrentGame == GAME_HEXEN)
|
||||
{TDB_GiveItem("CWeapStaff"); TDB_GiveItem("FWeapAxe"); TDB_GiveItem("MWeapFrost");}
|
||||
else if(CurrentGame == GAME_STRIFE) {TDB_GiveItem("StrifeCrossbow");}
|
||||
}
|
||||
}
|
||||
|
||||
function void TDBots_Setup (bool respawning)
|
||||
{
|
||||
if(PlayerIsBot(PlayerNumber()) == TRUE || GetCVAR("tdbots_playerbot") == TRUE)
|
||||
{
|
||||
if( (GetCVAR("tdbots_enable") == TRUE) || (PlayerIsBot(PlayerNumber()) == FALSE) )
|
||||
{
|
||||
if(GetCVAR("tdbots_lessfov") == TRUE) {GiveInventory("tdbots_lessfov",1);}
|
||||
if(BotAnim == TRUE) {ACS_NamedExecuteAlways("TDBots_BotAnimation", 0);}
|
||||
if(GetCVAR("tdbots_buff") == TRUE) {ACS_NamedExecuteAlways("TDBots_BotBuff",0);}
|
||||
Codepointer("BotFunc_StartUp");
|
||||
|
||||
if(Respawning == FALSE)
|
||||
{
|
||||
if(Gametype() <= GAME_NET_COOPERATIVE)
|
||||
{TDBots_Chat(MSG_ENTERCOOP);}
|
||||
else
|
||||
{TDBots_Chat(MSG_ENTER);}
|
||||
}
|
||||
|
||||
ACS_NamedExecuteAlways("TDBots_TeleportBot",0);
|
||||
|
||||
if( (GetCVAR("tdbots_usenodes")) || (GetCVAR("tdbots_learnfromplayer")) )
|
||||
{
|
||||
GiveInventory("TDBots_NavNodes", 1);
|
||||
}
|
||||
|
||||
if(GetActorProperty(0, APROP_ACCURACY) == 0)
|
||||
{SetActorProperty(0, APROP_ACCURACY, BOTSPEED);}
|
||||
|
||||
//Magic value to make the bots not move
|
||||
else if(GetActorProperty(0, APROP_ACCURACY) == -1)
|
||||
{SetActorProperty(0, APROP_ACCURACY, BOTSPEED);}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str TDB_Weapons[27] =
|
||||
{
|
||||
"BotPistol",
|
||||
"BotShotgun",
|
||||
"BotSuperShotgun",
|
||||
"BotChaingun",
|
||||
"BotRocketLauncher",
|
||||
"BotPlasmaRifle",
|
||||
"BotBFG9000",
|
||||
|
||||
"BotGoldWand",
|
||||
"BotMace",
|
||||
"BotSkullRod",
|
||||
"BotPhoenixRod",
|
||||
"BotBlaster",
|
||||
"BotCrossbow",
|
||||
|
||||
"BotStrifeGrenadeLauncher",
|
||||
"BotMauler",
|
||||
"BotMiniMissileLauncher",
|
||||
"BotAssaultGun",
|
||||
"BotStrifeCrossbow",
|
||||
|
||||
"BotCWeapWraithverge",
|
||||
"BotFWeapQuietus",
|
||||
"BotMWeapBloodscourge",
|
||||
"BotCWeapFlame",
|
||||
"BotFWeapHammer",
|
||||
"BotMWeapLighting",
|
||||
"BotCWeapStaff",
|
||||
"BotFWeapAxe",
|
||||
"BotMWeapFrost"
|
||||
};
|
||||
|
||||
function void TDB_RandomWeapon (void)
|
||||
{
|
||||
if(random(0,100) > 2) {return;}
|
||||
switch(CurrentGame)
|
||||
{
|
||||
case GAME_DOOM:
|
||||
if(!VanillaDoom) {return;}
|
||||
SetWeapon( TDB_Weapons[ random(1,6) ] );
|
||||
break;
|
||||
|
||||
case GAME_HERETIC:
|
||||
SetWeapon( TDB_Weapons[ random(8,12) ] );
|
||||
break;
|
||||
|
||||
case GAME_STRIFE:
|
||||
SetWeapon( TDB_Weapons[ random(14,17) ] );
|
||||
break;
|
||||
|
||||
case GAME_HEXEN:
|
||||
SetWeapon( TDB_Weapons[ random(19,26) ] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_BotSetup" ENTER
|
||||
{
|
||||
if(Gametype() <= GAME_NET_COOPERATIVE)
|
||||
{
|
||||
ACS_NamedExecuteAlways("TDBots_WalkNoding", 0);
|
||||
}
|
||||
|
||||
TDBots_SwapWeapons();
|
||||
delay(1);
|
||||
TDBots_Setup(FALSE);
|
||||
delay(2);
|
||||
TDBots_Weaponize();
|
||||
TDBots_RA_Equip();
|
||||
delay(4);
|
||||
Thing_Remove(987005);
|
||||
}
|
||||
|
||||
Script "TDBots_BotSetup_Respawn" RESPAWN
|
||||
{
|
||||
if(Gametype() <= GAME_NET_COOPERATIVE)
|
||||
{
|
||||
ACS_NamedExecuteAlways("TDBots_WalkNoding", 0);
|
||||
}
|
||||
|
||||
TDBots_SwapWeapons();
|
||||
delay(1);
|
||||
TDBots_Setup(TRUE);
|
||||
delay(2);
|
||||
TDBots_Weaponize();
|
||||
TDBots_RA_Equip();
|
||||
delay(4);
|
||||
Thing_Remove(987005);
|
||||
}
|
||||
|
||||
//Gives the bots ammunition and armor every five seconds, to help them a bit
|
||||
Script "TDBots_BotBuff" (void)
|
||||
{
|
||||
delay(35 * 5);
|
||||
if(GetCVAR("tdbots_buff") == 1)
|
||||
{
|
||||
while(GetActorProperty(0, APROP_HEALTH) > 0)
|
||||
{
|
||||
if(CurrentGame == GAME_DOOM) {Codepointer("BotFunc_BuffDoom");}
|
||||
if(CurrentGame == GAME_HERETIC) {Codepointer("BotFunc_BuffHeretic");}
|
||||
if(CurrentGame == GAME_HEXEN) {Codepointer("BotFunc_BuffHexen");}
|
||||
if(CurrentGame == GAME_STRIFE) {Codepointer("BotFunc_BuffStrife");}
|
||||
delay(1);
|
||||
Thing_Remove(987000);
|
||||
delay(35 * 5);
|
||||
}
|
||||
}
|
||||
else {terminate;}
|
||||
}
|
||||
|
||||
Script "TDBots_BotEasyMode" (void)
|
||||
{
|
||||
if( GetCvar("tdbots_easymode") || CheckInventory("BotForceInacc") )
|
||||
{
|
||||
SetActorAngle(0, GetActorAngle(0) + random(-2048, 2048));
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_UseItems" (int Roam)
|
||||
{
|
||||
int Rand;
|
||||
if(Roam == TRUE) //Called from roaming state?
|
||||
{
|
||||
if(CurrentGame == GAME_HERETIC || GAME_HEXEN)
|
||||
{
|
||||
Rand = Random(0,8);
|
||||
|
||||
if(Rand == 0)
|
||||
{UseInventory("ArtiHealth");}
|
||||
else if(Rand == 1)
|
||||
{UseInventory("ArtiSuperHealth");}
|
||||
else if(Rand == 2)
|
||||
{UseInventory("ArtiFly");}
|
||||
else if(Rand == 3)
|
||||
{
|
||||
UseInventory("ArtiInvulnerability"); //Heretic's
|
||||
UseInventory("ArtiInvulnerability2");//Hexen's
|
||||
}
|
||||
else if(Rand == 4)
|
||||
{UseInventory("ArtiTeleport");}
|
||||
//No torch, since obviously bots don't need it
|
||||
}
|
||||
}
|
||||
else //No, so we assume it's been called from the attack state.
|
||||
{
|
||||
if(CurrentGame == GAME_HERETIC)
|
||||
{
|
||||
Rand = Random(0,4);
|
||||
|
||||
if(Rand == 0)
|
||||
{UseInventory("ArtiEgg");}
|
||||
else if(Rand == 1)
|
||||
{UseInventory("ArtiTomeOfPower");}
|
||||
else if(Rand == 2)
|
||||
{UseInventory("ArtiInvisibility");}
|
||||
else if(Rand == 3)
|
||||
{UseInventory("ArtiTimeBomb");}
|
||||
else if(Rand == 4)
|
||||
{UseInventory("ArtiPork");}
|
||||
}
|
||||
else if(CurrentGame == GAME_HEXEN)
|
||||
{
|
||||
Rand = Random(0,6);
|
||||
|
||||
if(Rand == 0)
|
||||
{UseInventory("ArtiEgg");}
|
||||
else if(Rand == 1)
|
||||
{UseInventory("ArtiDarkServant");}
|
||||
else if(Rand == 2)
|
||||
{UseInventory("ArtiTeleportOther");}
|
||||
else if(Rand == 3)
|
||||
{UseInventory("ArtiBoostArmor");}
|
||||
else if(Rand == 4)
|
||||
{UseInventory("ArtiBlastRadius");}
|
||||
else if(Rand == 5)
|
||||
{UseInventory("ArtiPork");}
|
||||
else if(Rand == 6)
|
||||
{
|
||||
UseInventory("ArtiPoisonBag"); //Doesn't look like a bag but ok.
|
||||
UseInventory("ArtiPoisonBag1");
|
||||
UseInventory("ArtiPoisonBag2");
|
||||
UseInventory("ArtiPoisonBag3");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_CheckForCustomModules" OPEN
|
||||
{
|
||||
//Roaming
|
||||
if(TDB_ActorExists("TDBots_Custom_RoamLoop1"))
|
||||
{TDB_Custom_Roam1 = TRUE;}
|
||||
|
||||
if(TDB_ActorExists("TDBots_Custom_RoamLoop2"))
|
||||
{TDB_Custom_Roam2 = TRUE;}
|
||||
|
||||
//Attacking
|
||||
if(TDB_ActorExists("TDBots_Custom_AttackLoop1"))
|
||||
{TDB_Custom_Attk1 = TRUE;}
|
||||
|
||||
if(TDB_ActorExists("TDBots_Custom_AttackLoop2"))
|
||||
{TDB_Custom_Attk2 = TRUE;}
|
||||
|
||||
//Global flags
|
||||
if(TDB_ActorExists("TDBots_NoAnimation"))
|
||||
{BotAnim = FALSE;}
|
||||
}
|
||||
|
||||
function void AnimateTDBot (str state)
|
||||
{
|
||||
if(BotAnim == FALSE) {return;}
|
||||
SetActorState(0, state, 1);
|
||||
SetPlayerProperty(0,1,4);
|
||||
}
|
||||
|
||||
function bool TDBotDead (void)
|
||||
{
|
||||
bool BotIsDead;
|
||||
if(GetActorProperty(0, APROP_HEALTH) <= 0)
|
||||
{
|
||||
Codepointer("BotFunc_Die");
|
||||
SetActorState(0, "Death", 1);
|
||||
BotIsDead = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
BotIsDead = FALSE;
|
||||
}
|
||||
return BotIsDead;
|
||||
}
|
478
wadsrc_tdbots/static/scripts/TDB_Node.acs
Normal file
478
wadsrc_tdbots/static/scripts/TDB_Node.acs
Normal file
|
@ -0,0 +1,478 @@
|
|||
//Nodelist parsing and loading.
|
||||
#DEFINE MAX_NODES 512
|
||||
#DEFINE MAX_PROPS 4
|
||||
#DEFINE MAX_LEARN_TIME_P1 35*30
|
||||
#DEFINE MAX_LEARN_TIME_P2 35*60
|
||||
#DEFINE MAX_LEARN_TIME_P3 35*90
|
||||
#DEFINE MAX_LEARN_TIME 35*120 //2 nice minutes max
|
||||
str NodePropStr[MAX_NODES][MAX_PROPS]; //Raw strings, have to be converted.
|
||||
|
||||
int NodeTID[MAX_NODES];
|
||||
|
||||
//Player-generated nodes, then transfered to NodeTID once finished.
|
||||
int PlayNodeTID[MAX_NODES];
|
||||
int CurrPNTID; //Keep track of current index on above array
|
||||
|
||||
//Player following-related stuff.
|
||||
#DEFINE MAX_FOLLOW_NODES 16
|
||||
int PlayerFollowTID[MAX_PLAYERS][MAX_FOLLOW_NODES];
|
||||
int PlayerLocation[MAX_PLAYERS][3];
|
||||
|
||||
//Time since map start
|
||||
int TSMS = -1;
|
||||
|
||||
int AmountOfNodes;
|
||||
|
||||
//Note: commented log lines are just for debugging, you can uncomment them
|
||||
//if you need to.
|
||||
function void ProcessNodelist (str string, bool version)
|
||||
{
|
||||
//Don't bother doing anything if it's just empty
|
||||
if(strcmp(string, "") == 0) {return;}
|
||||
|
||||
//Length of the string passed
|
||||
int stringlength = strlen(string);
|
||||
|
||||
//StrMid parameters, to copy a full actor name to the StartWeapons array
|
||||
int strmidstart;
|
||||
int strmidend;
|
||||
|
||||
//Keeps track of current character index so i can pass it to strmidstart
|
||||
//even after restarting it
|
||||
int strmidstart2;
|
||||
|
||||
//Actor name and currently stored character
|
||||
int currentarrayindex;
|
||||
str storedchar;
|
||||
|
||||
int curraxis;
|
||||
for(int currchar = 0; currchar <= stringlength; currchar++)
|
||||
{
|
||||
storedchar = StrMid(string, currchar, 1);//GetChar didn't work dunno why
|
||||
|
||||
if(version == 0)
|
||||
{
|
||||
if(curraxis > AXIS_Z) {curraxis = AXIS_X;}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(curraxis > NODETYPE) {curraxis = AXIS_X;}
|
||||
}
|
||||
|
||||
//If a separator is detected, switch to next actor name and clear the
|
||||
//current string saved in memory.
|
||||
if(currchar == stringlength)
|
||||
{
|
||||
amountofnodes = currentarrayindex;
|
||||
//log(s:strmid(string, strmidstart, strmidend));
|
||||
NodePropStr[currentarrayindex][curraxis] = strmid(string, strmidstart, strmidend);
|
||||
if(version == 0)
|
||||
{
|
||||
NodePropStr[currentarrayindex][NODETYPE] = "";
|
||||
currentarrayindex++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(StrCmp(storedchar, ";") == 0)
|
||||
{
|
||||
//log(s:strmid(string, strmidstart, strmidend));
|
||||
NodePropStr[currentarrayindex][curraxis] = strmid(string, strmidstart, strmidend);
|
||||
curraxis++;
|
||||
if( (version == 0) && (curraxis > AXIS_Z) )
|
||||
{
|
||||
NodePropStr[currentarrayindex][NODETYPE] = "";
|
||||
currentarrayindex++;
|
||||
}
|
||||
else if( (version == 1) && (curraxis > NODETYPE) )
|
||||
{
|
||||
currentarrayindex++;
|
||||
}
|
||||
|
||||
strmidstart = strmidstart2+1; //needs to be AFTER the separator
|
||||
strmidstart2++;
|
||||
strmidend = 0;
|
||||
//log(s: "strmidstart = ",i:strmidstart);
|
||||
}
|
||||
//If not, just continue storing the actor name.
|
||||
else
|
||||
{
|
||||
strmidend++;
|
||||
strmidstart2++;
|
||||
//log(s: "strmidend = ",i:strmidend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//I have to parse the values TWICE because you can't use strings as integers.
|
||||
//Thanks, ACS limitations!
|
||||
|
||||
//And more importantly, thanks to Empyre who gave me an example on how to
|
||||
//join numbers. I'm so stupid i didn't imagine just 4 * 10 + 7 would
|
||||
//give me 47 :P
|
||||
function int StrToInt (str string)
|
||||
{
|
||||
//Don't bother doing anything if it's just empty
|
||||
if(strcmp(string, "") == 0) {return FALSE;}
|
||||
|
||||
//Length of the string passed
|
||||
int stringlength = strlen(string);
|
||||
|
||||
//Actor name and currently stored character
|
||||
int currentarrayindex;
|
||||
|
||||
str storedchar;
|
||||
str storedcharcpy;
|
||||
|
||||
int returnvalue;
|
||||
|
||||
str firstchar = StrLeft(string, 1);
|
||||
for(int currchar = 0; currchar <= stringlength; currchar++)
|
||||
{
|
||||
storedchar = StrMid(string, currchar, 1);//GetChar didn't work dunno why
|
||||
storedcharcpy = storedchar;
|
||||
|
||||
if(Strcmp(storedcharcpy, "0") == 0)
|
||||
{returnvalue = returnvalue*10;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "1") == 0)
|
||||
{returnvalue = returnvalue*10+1;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "2") == 0)
|
||||
{returnvalue = returnvalue*10+2;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "3") == 0)
|
||||
{returnvalue = returnvalue*10+3;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "4") == 0)
|
||||
{returnvalue = returnvalue*10+4;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "5") == 0)
|
||||
{returnvalue = returnvalue*10+5;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "6") == 0)
|
||||
{returnvalue = returnvalue*10+6;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "7") == 0)
|
||||
{returnvalue = returnvalue*10+7;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "8") == 0)
|
||||
{returnvalue = returnvalue*10+8;}
|
||||
|
||||
else if(Strcmp(storedcharcpy, "9") == 0)
|
||||
{returnvalue = returnvalue*10+9;}
|
||||
|
||||
currentarrayindex++;
|
||||
}
|
||||
if(Strcmp(firstchar, "-") == 0)
|
||||
{returnvalue = -returnvalue;}
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
//Function from ACSUtils, licensed under the MIT License.
|
||||
//Copyright (c) 2016-2017 By Alexander Korshun and the ACSUtils contributors.
|
||||
//Originally called ActorDistance2D.
|
||||
function int Distance(int tid1, int tid2)
|
||||
{
|
||||
return VectorLength(GetActorX(tid2) - GetActorX(tid1),
|
||||
GetActorY(tid2) - GetActorY(tid1));
|
||||
}
|
||||
|
||||
function void TDB_FollowNode (void)
|
||||
{
|
||||
//Log(s:"Starting up TDB_FollowNode...");
|
||||
|
||||
TakeInventory("TDBots_FollowNodeZan", 1);
|
||||
|
||||
if(Gametype() <= GAME_NET_COOPERATIVE)
|
||||
{
|
||||
TDB_FollowPlayer();
|
||||
return;
|
||||
}
|
||||
|
||||
if( (!GetCVAR("tdbots_usenodes")) && (!GetCVAR("tdbots_learnfromplayer")) ) {return;}
|
||||
if(CheckInventory("BotAttack")) {return;}
|
||||
|
||||
//Log(s:"TDB_FollowNode started up!");
|
||||
|
||||
int dist,node,newdist,retnode;
|
||||
|
||||
dist = 384.0;
|
||||
for(int i_ = 0; i_ <= MAX_NODES; i_++)
|
||||
{
|
||||
node = NodeTID[i_];
|
||||
if(node == 0) {break;}
|
||||
newdist = Distance(0, node);
|
||||
|
||||
if( (newdist < dist) && CheckSight(0, node, CSF_NOFAKEFLOORS))
|
||||
{
|
||||
dist = newdist;
|
||||
retnode = node;
|
||||
}
|
||||
}
|
||||
SetPointer(AAPTR_TARGET, retnode, AAPTR_DEFAULT, PTROP_NOSAFEGUARDS|PTROP_UNSAFEMASTER); //return retnode;
|
||||
GiveInventory("TDBots_FollowNodeZan", 1);
|
||||
//Log(s:"Hating node ", i:retnode);
|
||||
return;
|
||||
}
|
||||
|
||||
function void TDB_FollowPlayer (void)
|
||||
{
|
||||
//Log(s:"Starting up TDB_FollowNode...");
|
||||
|
||||
TakeInventory("TDBots_FollowNodeZan", 1);
|
||||
|
||||
if(!GetCVAR("tdbots_follow")) {return;}
|
||||
if(CheckInventory("BotAttack")) {return;}
|
||||
|
||||
//Log(s:"TDB_FollowNode started up!");
|
||||
|
||||
int dist,node,newdist,retnode;
|
||||
int pnum;
|
||||
|
||||
dist = 2048.0;
|
||||
if(IsNetworkGame()) //if not network game then pnum will always be 0
|
||||
{
|
||||
for(int i_ = 0; i_ < MAX_PLAYERS; i_++)
|
||||
{
|
||||
if(PlayerLocation[i_][0] + PlayerLocation[i_][1] != 0)
|
||||
{
|
||||
newdist = VectorLength(PlayerLocation[i_][0] - GetActorX(0),
|
||||
PlayerLocation[i_][1] - GetActorY(0));
|
||||
|
||||
if(newdist < dist)
|
||||
{
|
||||
dist = newdist;
|
||||
pnum = i_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dist = 768.0;
|
||||
for(int i = 0; i < MAX_FOLLOW_NODES; i++)
|
||||
{
|
||||
node = PlayerFollowTID[pnum][i];
|
||||
if(node == 0) {break;}
|
||||
|
||||
if(ThingCount(0, node) > 0)
|
||||
{
|
||||
newdist = Distance(0, node);
|
||||
|
||||
if( (newdist < dist) && CheckSight(0, node, CSF_NOFAKEFLOORS))
|
||||
{
|
||||
dist = newdist;
|
||||
retnode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetPointer(AAPTR_TARGET, retnode, AAPTR_DEFAULT, PTROP_NOSAFEGUARDS|PTROP_UNSAFEMASTER); //return retnode;
|
||||
GiveInventory("TDBots_FollowNodeZan", 1);
|
||||
//Log(s:"Hating node ", i:retnode);
|
||||
return;
|
||||
}
|
||||
|
||||
function bool TDB_PlayerNoding (void)
|
||||
{
|
||||
if(CurrPNTID > MAX_NODES) {return FALSE;}
|
||||
|
||||
int node,newdist,retnode;
|
||||
int dist = 160.0;
|
||||
|
||||
for(int i_ = 0; i_ <= MAX_NODES; i_++)
|
||||
{
|
||||
node = PlayNodeTID[i_];
|
||||
if(node == 0) {break;}
|
||||
newdist = Distance(0, node);
|
||||
|
||||
if( (newdist < dist) && CheckSight(0, node, CSF_NOFAKEFLOORS) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int TID = UniqueTID();
|
||||
SpawnForced("TDBots_PathNode",GetActorX(0),GetActorY(0),GetActorZ(0),TID);
|
||||
PlayNodeTID[CurrPNTID] = TID;
|
||||
CurrPNTID++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
function void TDB_CopyNodeTIDs (void)
|
||||
{
|
||||
if(NodeTID[0] != 0) {return;}
|
||||
int node;
|
||||
for(int i; i <= MAX_NODES; i++)
|
||||
{
|
||||
node = PlayNodeTID[i];
|
||||
if(node == 0) {break;}
|
||||
NodeTID[i] = node;
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_Jump" (int force) //force param for wall jumps and such in Vault
|
||||
{
|
||||
if( (GetActorVelZ(0) == 0) || (force == TRUE) )
|
||||
{
|
||||
int JumpZ = GetActorProperty(0, APROP_JUMPZ);
|
||||
SetActorVelocity(0, 0, 0, JumpZ, TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
//I couldn't figure out how to put this into the main script without it looking
|
||||
//exceptionally awful, so separated it into a function.
|
||||
|
||||
//And oh boy does this code look messy!
|
||||
bool NodelistVersion;
|
||||
function str GetNodelist (bool silent)
|
||||
{
|
||||
int MapLmp = StrParam(n:PRINTNAME_LEVEL);
|
||||
str cvartocheck = StrParam(s:MapLmp, s:"NodesNew");
|
||||
str StrToProcess = GetCVARString(cvartocheck);
|
||||
|
||||
if( (StrToProcess == 0) || (strlen(StrToProcess) == 0) )
|
||||
{
|
||||
cvartocheck = StrParam(s:MapLmp, s:"Nodes");
|
||||
StrToProcess = GetCVARString(cvartocheck);
|
||||
if( (StrToProcess == 0) || (strlen(StrToProcess) == 0) )
|
||||
{
|
||||
cvartocheck = StrParam(s:MapLmp, s:"NodesNew");
|
||||
StrToProcess = StrParam(l:cvartocheck);
|
||||
|
||||
//It's a weird check but after a lot of fiddling around i figured out
|
||||
//that this is how the L operator on StrParam works.
|
||||
//If you don't get it, basically the L operator will just return
|
||||
//the exact same LANGUAGE string identifier you gave it if that
|
||||
//identifier is undefined.
|
||||
if(strcmp(StrToProcess, cvartocheck) == 0)
|
||||
{
|
||||
cvartocheck = StrParam(s:MapLmp, s:"Nodes");
|
||||
StrToProcess = StrParam(l:cvartocheck);
|
||||
|
||||
if(strcmp(StrToProcess, cvartocheck) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
NodelistVersion = 0;
|
||||
if(!silent)
|
||||
Log(s:"Map-defined nodes found, loading...");
|
||||
}
|
||||
}
|
||||
else {NodelistVersion = 1; Log(s:"Map-defined nodes found, loading...");}
|
||||
}
|
||||
else
|
||||
{
|
||||
NodelistVersion = 0;
|
||||
if(!silent)
|
||||
Log(s:"Nodes found, loading...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NodelistVersion = 1;
|
||||
if(!silent)
|
||||
Log(s:"Nodes found, loading...");
|
||||
}
|
||||
return StrToProcess;
|
||||
}
|
||||
|
||||
Script "TDBots_SetTarget" (int tid)
|
||||
{
|
||||
SetPointer(AAPTR_TARGET, tid, AAPTR_DEFAULT, PTROP_NOSAFEGUARDS|PTROP_UNSAFEMASTER);
|
||||
}
|
||||
|
||||
Script "TDBots_PlayerNoding" ENTER
|
||||
{
|
||||
if( (!PlayerIsBot(PlayerNumber())) && (StrLen(GetNodelist(TRUE)) == 0) && (GetCVAR("tdbots_learnfromplayer")) && (Gametype() > GAME_NET_COOPERATIVE) )
|
||||
{
|
||||
while( (TSMS <= MAX_LEARN_TIME) && (GetActorProperty(0, APROP_HEALTH) > 0))
|
||||
{
|
||||
delay(16);
|
||||
TDB_PlayerNoding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDBots_PlayerNoding2" RESPAWN
|
||||
{ACS_NamedExecuteAlways("TDBots_PlayerNoding",0);}
|
||||
|
||||
Script "TDBots_LoadNodes" OPEN
|
||||
{
|
||||
if(GetCVAR("TDBots_UseNodes") == FALSE) {terminate;}
|
||||
|
||||
ProcessNodelist(GetNodelist(FALSE), NodelistVersion);
|
||||
delay(1);
|
||||
|
||||
int TID,CurrArrayIndex;
|
||||
while(currarrayindex <= amountofnodes)
|
||||
{
|
||||
if(NodePropStr[CurrArrayIndex][AXIS_X])
|
||||
{
|
||||
TID = UniqueTID();
|
||||
|
||||
/*log(s:NodePropStr[CurrArrayIndex][AXIS_X],s:" ",
|
||||
s:NodePropStr[CurrArrayIndex][AXIS_Y],s:" ",
|
||||
s:NodePropStr[CurrArrayIndex][AXIS_Z],s:" ",
|
||||
s:NodePropStr[CurrArrayIndex][NODETYPE]);
|
||||
|
||||
log(i:StrToInt(NodePropStr[CurrArrayIndex][AXIS_X]),s:" ",
|
||||
i:StrToInt(NodePropStr[CurrArrayIndex][AXIS_Y]),s:" ",
|
||||
i:StrToInt(NodePropStr[CurrArrayIndex][AXIS_Z]),s:" ",
|
||||
i:StrToInt(NodePropStr[CurrArrayIndex][NODETYPE]));*/
|
||||
|
||||
switch(StrToInt(NodePropStr[CurrArrayIndex][NODETYPE]))
|
||||
{
|
||||
case NODE_NORMAL:
|
||||
SpawnForced("TDBots_PathNode",
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_X])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Y])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Z])*65536, TID);
|
||||
break;
|
||||
|
||||
case NODE_JUMP:
|
||||
SpawnForced("TDBots_JumpNode",
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_X])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Y])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Z])*65536, TID);
|
||||
break;
|
||||
|
||||
case NODE_PRECISE:
|
||||
SpawnForced("TDBots_PrecisionNode",
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_X])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Y])*65536,
|
||||
StrToInt(NodePropStr[CurrArrayIndex][AXIS_Z])*65536, TID);
|
||||
break;
|
||||
|
||||
default:
|
||||
log(s:"Unknown node type ", s:NodePropStr[CurrArrayIndex][NODETYPE]);
|
||||
}
|
||||
|
||||
NodeTID[CurrArrayIndex] = TID;
|
||||
|
||||
CurrArrayIndex++;
|
||||
delay(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(currarrayindex != 0)
|
||||
{
|
||||
Log(i: currarrayindex, s:" Nodes fully loaded.");
|
||||
Log(s:"Nodelist version: ",i: NodelistVersion);
|
||||
}
|
||||
else if(GetCVAR("tdbots_learnfromplayer"))
|
||||
{
|
||||
while(TSMS <= MAX_LEARN_TIME)
|
||||
{
|
||||
delay(1);
|
||||
TSMS++;
|
||||
if( (TSMS == MAX_LEARN_TIME_P1) || (TSMS == MAX_LEARN_TIME_P2 ) || (TSMS == MAX_LEARN_TIME_P3) )
|
||||
TDB_CopyNodeTIDs();
|
||||
}
|
||||
TDB_CopyNodeTIDs();
|
||||
}
|
||||
}
|
287
wadsrc_tdbots/static/scripts/TDB_RA.acs
Normal file
287
wadsrc_tdbots/static/scripts/TDB_RA.acs
Normal file
|
@ -0,0 +1,287 @@
|
|||
#DEFINE MAX_CWEAP 128
|
||||
#DEFINE MAX_CAMMO 256
|
||||
|
||||
int TDB_TotalCWeap;
|
||||
str TDB_CWeapons[MAX_CWEAP] = {""};
|
||||
str TDB_CAmmo[MAX_CAMMO] = {""};
|
||||
|
||||
function void TDBots_RA_Equip (void)
|
||||
{
|
||||
bool CWLDetected = FALSE;
|
||||
|
||||
if(GetCVAR("tdbots_rocketarena") == FALSE) {return;}
|
||||
|
||||
//Custom weapon list detected, use it.
|
||||
if(StrLen(TDB_CWeapons[0]) > 0)
|
||||
{
|
||||
for(int w; StrLen(TDB_CWeapons[w]) > 0; w++)
|
||||
{
|
||||
GiveInventory(TDB_CWeapons[w],1);
|
||||
}
|
||||
|
||||
if(StrLen(TDB_CAmmo[0]) > 0)
|
||||
{
|
||||
for(int a; StrLen(TDB_CAmmo[a]) > 0; a++)
|
||||
{
|
||||
TDB_MaxGive(TDB_CAmmo[a]);
|
||||
}
|
||||
CWLDetected = TRUE;
|
||||
}
|
||||
|
||||
SetWeapon(TDB_CWeapons[random(0,TDB_TotalCWeap)]);
|
||||
}
|
||||
|
||||
else if(CurrentGame == GAME_DOOM)
|
||||
{
|
||||
if(VanillaDoom)
|
||||
{
|
||||
GiveInventory("BotBFG9000",1);
|
||||
GiveInventory("BotSuperShotgun",1);
|
||||
GiveInventory("BotPlasmaRifle",1);
|
||||
GiveInventory("BotRocketLauncher",1);
|
||||
GiveInventory("BotChaingun",1);
|
||||
GiveInventory("BotShotgun",1);
|
||||
|
||||
if(!PlayerIsBot(PlayerNumber()))
|
||||
{
|
||||
GiveInventory("BotChainsaw",1);
|
||||
}
|
||||
|
||||
GiveInventory("Backpack",1); //To max ammo capacity
|
||||
|
||||
//This max outs all ammo
|
||||
TDB_MaxGive("Clip");
|
||||
TDB_MaxGive("Shell");
|
||||
TDB_MaxGive("Cell");
|
||||
TDB_MaxGive("RocketAmmo");
|
||||
|
||||
GiveInventory("MegaSphere",1);
|
||||
}
|
||||
else //10 backpacks are given, with 5 of each weapon to maximize ammo
|
||||
{
|
||||
TDB_RA_Give("Backpack");
|
||||
TDB_RA_Give("Backpack");
|
||||
|
||||
TDB_RA_Give("BFG9000");
|
||||
TDB_RA_Give("SuperShotgun");
|
||||
TDB_RA_Give("PlasmaRifle");
|
||||
TDB_RA_Give("RocketLauncher");
|
||||
TDB_RA_Give("Chaingun");
|
||||
TDB_RA_Give("Shotgun");
|
||||
|
||||
TDB_GiveItem("MegaSphere");
|
||||
|
||||
if(!PlayerIsBot(PlayerNumber())) {TDB_GiveItem("Chainsaw");}
|
||||
}
|
||||
}
|
||||
|
||||
else if(CurrentGame == GAME_HERETIC)
|
||||
{
|
||||
GiveInventory("BotMace",1);
|
||||
GiveInventory("BotSkullRod",1);
|
||||
GiveInventory("BotPhoenixRod",1);
|
||||
GiveInventory("BotBlaster",1);
|
||||
GiveInventory("BotCrossbow",1);
|
||||
|
||||
GiveInventory("BagOfHolding",1);
|
||||
|
||||
TDB_MaxGive("GoldWandAmmo");
|
||||
TDB_MaxGive("CrossbowAmmo");
|
||||
TDB_MaxGive("MaceAmmo");
|
||||
TDB_MaxGive("BlasterAmmo");
|
||||
TDB_MaxGive("SkullRodAmmo");
|
||||
|
||||
if(!PlayerIsBot(PlayerNumber())) {GiveInventory("BotGauntlets",1);}
|
||||
|
||||
GiveInventory("SoulSphere",1);
|
||||
GiveInventory("EnchantedShield",1);
|
||||
}
|
||||
|
||||
else if(CurrentGame == GAME_STRIFE)
|
||||
{
|
||||
GiveInventory("BotStrifeGrenadeLauncher",1);
|
||||
GiveInventory("BotMauler",1);
|
||||
GiveInventory("BotMiniMissileLauncher",1);
|
||||
GiveInventory("BotAssaultGun",1);
|
||||
GiveInventory("BotStrifeCrossbow",1);
|
||||
|
||||
GiveInventory("AmmoSatchel",1);
|
||||
|
||||
TDB_MaxGive("HEGrenadeRounds");
|
||||
TDB_MaxGive("PhosphorusGrenadeRounds");
|
||||
TDB_MaxGive("ClipOfBullets");
|
||||
TDB_MaxGive("MiniMissiles");
|
||||
TDB_MaxGive("EnergyPod");
|
||||
TDB_MaxGive("PoisonBolts");
|
||||
TDB_MaxGive("ElectricBolts");
|
||||
|
||||
GiveInventory("SoulSphere",1);
|
||||
GiveInventory("MetalArmor",1);
|
||||
}
|
||||
|
||||
else if(CurrentGame == GAME_HEXEN)
|
||||
{
|
||||
GiveInventory("BotCWeapWraithverge",1);
|
||||
GiveInventory("BotFWeapQuietus",1);
|
||||
GiveInventory("BotMWeapBloodscourge",1);
|
||||
|
||||
GiveInventory("BotCWeapFlame",1);
|
||||
GiveInventory("BotFWeapHammer",1);
|
||||
GiveInventory("BotMWeapLightning",1);
|
||||
|
||||
GiveInventory("BotCWeapStaff",1);
|
||||
GiveInventory("BotFWeapAxe",1);
|
||||
GiveInventory("BotMWeapFrost",1);
|
||||
|
||||
TDB_MaxGive("Mana1");
|
||||
TDB_MaxGive("Mana2");
|
||||
|
||||
GiveInventory("SoulSphere",1);
|
||||
GiveInventory("AmuletOfWarding",1);
|
||||
}
|
||||
|
||||
SetActorVelocity(0,0.01,0,0,1,0);
|
||||
|
||||
if(!CWLDetected)
|
||||
{
|
||||
TDB_RandomWeapon();
|
||||
}
|
||||
}
|
||||
|
||||
//Note: commented log lines are just for debugging, you can uncomment them
|
||||
//if you need to.
|
||||
function void TDB_RA_ParseWeaponList (str string)
|
||||
{
|
||||
//Don't bother doing anything if it's just empty
|
||||
if(strcmp(string, "") == 0) {return;}
|
||||
|
||||
//Length of the string passed
|
||||
int stringlength = strlen(string);
|
||||
|
||||
//StrMid parameters, to copy a full actor name to the StartWeapons array
|
||||
int strmidstart;
|
||||
int strmidend;
|
||||
|
||||
//Keeps track of current character index so i can pass it to strmidstart
|
||||
//even after restarting it
|
||||
int strmidstart2;
|
||||
|
||||
//Actor name and currently stored character
|
||||
int currentarrayindex;
|
||||
str storedchar;
|
||||
|
||||
//Processing item amount instead of item name?
|
||||
bool procamount;
|
||||
for(int currchar = 0; currchar <= stringlength; currchar++)
|
||||
{
|
||||
storedchar = StrMid(string, currchar, 1);//GetChar didn't work dunno why
|
||||
|
||||
//Last character? Save this last character and stop.
|
||||
if(currchar == stringlength)
|
||||
{
|
||||
TDB_CWeapons[currentarrayindex] = strmid(string, strmidstart, strmidend);
|
||||
TDB_TotalCWeap = currentarrayindex;
|
||||
return;
|
||||
}
|
||||
|
||||
//Hack to work around a very strange bug where an extra character would
|
||||
//be added depending on whatever the first call of StrCmp contained.
|
||||
StrCmp(storedchar, "", 1);
|
||||
|
||||
//If a separator is detected, switch to next actor name and clear the
|
||||
//current string saved in memory.
|
||||
if(StrCmp(storedchar, ";") == 0)
|
||||
{
|
||||
//log(s:"separator found");
|
||||
TDB_CWeapons[currentarrayindex] = strmid(string, strmidstart, strmidend);
|
||||
|
||||
procamount = FALSE;
|
||||
strmidstart = strmidstart2+1; //needs to be AFTER the separator
|
||||
strmidstart2++;
|
||||
strmidend = 0;
|
||||
//log(s: "strmidstart = ",i:strmidstart);
|
||||
currentarrayindex++;
|
||||
}
|
||||
|
||||
//If not, just continue storing the actor name.
|
||||
else
|
||||
{
|
||||
strmidend++;
|
||||
strmidstart2++;
|
||||
//log(s: "strmidend = ",i:strmidend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Removed comments since this is basically the same code as above
|
||||
function void TDB_RA_ParseAmmoList (str string)
|
||||
{
|
||||
if(strcmp(string, "") == 0) {return;}
|
||||
|
||||
int stringlength = strlen(string);
|
||||
|
||||
int strmidstart;
|
||||
int strmidend;
|
||||
|
||||
int strmidstart2;
|
||||
|
||||
int currentarrayindex;
|
||||
str storedchar;
|
||||
|
||||
bool procamount;
|
||||
for(int currchar = 0; currchar <= stringlength; currchar++)
|
||||
{
|
||||
storedchar = StrMid(string, currchar, 1);
|
||||
|
||||
if(currchar == stringlength)
|
||||
{
|
||||
TDB_CAmmo[currentarrayindex] = strmid(string, strmidstart, strmidend);
|
||||
currentarrayindex++;
|
||||
return;
|
||||
}
|
||||
|
||||
StrCmp(storedchar, "", 1);
|
||||
|
||||
if(StrCmp(storedchar, ";") == 0)
|
||||
{
|
||||
//log(s:"separator found");
|
||||
TDB_CAmmo[currentarrayindex] = strmid(string, strmidstart, strmidend);
|
||||
|
||||
procamount = FALSE;
|
||||
strmidstart = strmidstart2+1;
|
||||
strmidstart2++;
|
||||
strmidend = 0;
|
||||
currentarrayindex++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
strmidend++;
|
||||
strmidstart2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Script "TDB_RA_WeaponListInit" OPEN
|
||||
{
|
||||
if(GetCVAR("tdbots_rocketarena") == FALSE) {terminate;}
|
||||
|
||||
str WeaponListName = "TDBOTS_RA_WEAPONS";
|
||||
str WeaponList = StrParam(l:WeaponListName);
|
||||
|
||||
if(strcmp(WeaponList, WeaponListName) == 0) {terminate;}
|
||||
|
||||
delay(1);
|
||||
|
||||
TDB_RA_ParseWeaponList(WeaponList);
|
||||
|
||||
|
||||
str AmmoListName = "TDBOTS_RA_AMMO";
|
||||
str AmmoList = StrParam(l:AmmoListName);
|
||||
|
||||
if(strcmp(AmmoList, AmmoListName) == 0) {terminate;}
|
||||
|
||||
delay(1);
|
||||
|
||||
TDB_RA_ParseAmmoList(AmmoList);
|
||||
}
|
25
wadsrc_tdbots/static/scripts/TDB_Zan.acs
Normal file
25
wadsrc_tdbots/static/scripts/TDB_Zan.acs
Normal file
|
@ -0,0 +1,25 @@
|
|||
//Because GetPlayerAccountName doesn't quite work with else statements, i had to
|
||||
//do this.
|
||||
function bool TDB_IsZandronum (void)
|
||||
{
|
||||
if(GetPlayerAccountName(0) != 0)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Script "TDBots_ZandronumCommands" OPEN
|
||||
{
|
||||
if(TDB_IsZandronum() == TRUE)
|
||||
{
|
||||
consolecommand("bot_allowchat 0");
|
||||
|
||||
if(GetCVAR("alwaysapplydmflags") == FALSE)
|
||||
{consolecommand("alwaysapplydmflags 1");}
|
||||
|
||||
if(GetCVAR("bot_allowchat") == TRUE)
|
||||
{consolecommand("bot_allowchat 0");}
|
||||
|
||||
if(GetCVAR("sv_forcerespawn") == FALSE)
|
||||
{consolecommand("sv_forcerespawn 1");}
|
||||
}
|
||||
}
|
BIN
wadsrc_tdbots/static/sprites/TBNDA0.png
Normal file
BIN
wadsrc_tdbots/static/sprites/TBNDA0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
BIN
wadsrc_tdbots/static/sprites/TBNDB0.png
Normal file
BIN
wadsrc_tdbots/static/sprites/TBNDB0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 B |
BIN
wadsrc_tdbots/static/sprites/TBNDC0.png
Normal file
BIN
wadsrc_tdbots/static/sprites/TBNDC0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
BIN
wadsrc_tdbots/static/sprites/TBNDD0.png
Normal file
BIN
wadsrc_tdbots/static/sprites/TBNDD0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
BIN
wadsrc_tdbots/static/sprites/TBNDZ0.png
Normal file
BIN
wadsrc_tdbots/static/sprites/TBNDZ0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
111
wadsrc_tdbots/static/tdbots/CHEXWEAPONS.dec
Normal file
111
wadsrc_tdbots/static/tdbots/CHEXWEAPONS.dec
Normal file
|
@ -0,0 +1,111 @@
|
|||
actor BotBootspoon : BotFist replaces Bootspoon
|
||||
{
|
||||
game Chex
|
||||
obituary "$OB_MPSPOON"
|
||||
Tag "$TAG_SPOON"
|
||||
}
|
||||
|
||||
actor BotSuperBootspork : BotChainsaw replaces SuperBootspork
|
||||
{
|
||||
game Chex
|
||||
obituary "$OB_MPBOOTSPORK"
|
||||
Inventory.PickupMessage "$GOTSUPERBOOTSPORK"
|
||||
Tag "$TAG_SPORK"
|
||||
}
|
||||
|
||||
actor BotMiniZorcher : BotPistol replaces MiniZorcher
|
||||
{
|
||||
game Chex
|
||||
obituary "$OP_MPZORCH"
|
||||
inventory.pickupmessage "$GOTMINIZORCHER"
|
||||
Tag "$TAG_MINIZORCHER"
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
stop
|
||||
}
|
||||
}
|
||||
|
||||
actor BotLargeZorcher : BotShotgun replaces LargeZorcher
|
||||
{
|
||||
game Chex
|
||||
obituary "$OP_MPZORCH"
|
||||
inventory.pickupmessage "$GOTLARGEZORCHER"
|
||||
Tag "$TAG_LARGEZORCHER"
|
||||
}
|
||||
|
||||
actor BotSuperLargeZorcher : BotSuperShotgun replaces SuperLargeZorcher
|
||||
{
|
||||
game Chex
|
||||
obituary "$OB_MPMEGAZORCH"
|
||||
inventory.pickupmessage "$GOTSUPERLARGEZORCHER"
|
||||
Tag "$TAG_SUPERLARGEZORCHER"
|
||||
}
|
||||
|
||||
actor BotRapidZorcher : BotChaingun replaces RapidZorcher
|
||||
{
|
||||
game Chex
|
||||
obituary "$OB_MPRAPIDZORCH"
|
||||
inventory.pickupmessage "$GOTRAPIDZORCHER"
|
||||
Tag "$TAG_RAPIDZORCHER"
|
||||
}
|
||||
|
||||
actor BotZorchPropulsor : BotRocketLauncher replaces ZorchPropulsor
|
||||
{
|
||||
game Chex
|
||||
obituary ""
|
||||
inventory.pickupmessage "$GOTZORCHPROPULSOR"
|
||||
Tag "$TAG_ZORCHPROPULSOR"
|
||||
States
|
||||
{
|
||||
Fire:
|
||||
MISG B 8 A_GunFlash
|
||||
MISG B 12 A_FireCustomMissile("PropulsorMissile")
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MISG B 0 A_ReFire
|
||||
TNT1 A 0 A_Jump(256, "Ready")
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
actor BotPhasingZorcher : BotPlasmaRifle replaces PhasingZorcher
|
||||
{
|
||||
game Chex
|
||||
obituary ""
|
||||
inventory.pickupmessage "$GOTPHASINGZORCHER"
|
||||
Tag "$TAG_PHASINGZORCHER"
|
||||
states
|
||||
{
|
||||
Fire:
|
||||
PLSG A 0 A_GunFlash
|
||||
PLSG A 3 A_FireCustomMissile("PhaseZorchMissile")
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
PLSG B 20 A_ReFire
|
||||
Goto Ready
|
||||
Flash:
|
||||
PLSF A 0 A_Jump(128, "Flash2")
|
||||
PLSF A 3 Bright A_Light1
|
||||
Goto LightDone
|
||||
Flash2:
|
||||
PLSF B 3 Bright A_Light1
|
||||
Goto LightDone
|
||||
}
|
||||
}
|
||||
|
||||
actor BotLAZDevice : BotBFG9000 replaces LAZDevice
|
||||
{
|
||||
game Chex
|
||||
obituary ""
|
||||
inventory.pickupmessage "$GOTLAZDEVICE"
|
||||
Tag "$TAG_LAZDEVICE"
|
||||
states
|
||||
{
|
||||
Fire:
|
||||
BFGG A 20 A_BFGsound
|
||||
BFGG B 10 A_GunFlash
|
||||
BFGG B 10 A_FireCustomMissile("LAZBall")
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
BFGG B 20 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
468
wadsrc_tdbots/static/tdbots/DOOMWEAPONS.dec
Normal file
468
wadsrc_tdbots/static/tdbots/DOOMWEAPONS.dec
Normal file
|
@ -0,0 +1,468 @@
|
|||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Fist
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotFist : Weapon
|
||||
{
|
||||
Game Doom
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.SelectionOrder 3700
|
||||
Weapon.Kickback 100
|
||||
Obituary "$OB_MPFIST"
|
||||
Tag "$TAG_FIST"
|
||||
+WEAPON.WIMPY_WEAPON
|
||||
+WEAPON.MELEEWEAPON
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
PUNG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
PUNG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
PUNG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
PUNG B 4
|
||||
PUNG C 4 A_Punch
|
||||
PUNG D 5
|
||||
PUNG C 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
PUNG B 5 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Pistol
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotPistol : DoomWeapon replaces Pistol
|
||||
{
|
||||
Game Doom
|
||||
Weapon.SlotNumber 2
|
||||
Weapon.SelectionOrder 1900
|
||||
Weapon.AmmoUse 1
|
||||
Weapon.AmmoGive 0
|
||||
Weapon.AmmoType "Clip"
|
||||
Obituary "$OB_MPPISTOL"
|
||||
+WEAPON.WIMPY_WEAPON
|
||||
Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"
|
||||
Tag "$TAG_PISTOL"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
PISG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
PISG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
PISG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
PISG A 4
|
||||
PISG B 6 A_FirePistol
|
||||
PISG C 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
PISG B 5 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
PISF A 7 Bright A_Light1
|
||||
Goto LightDone
|
||||
PISF A 7 Bright A_Light1
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
PIST A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Chainsaw
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotChainsaw : Weapon replaces Chainsaw
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 32
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.Kickback 0
|
||||
Weapon.SelectionOrder 2200
|
||||
Weapon.UpSound "weapons/sawup"
|
||||
Weapon.ReadySound "weapons/sawidle"
|
||||
Inventory.PickupMessage "$GOTCHAINSAW"
|
||||
Obituary "$OB_MPCHAINSAW"
|
||||
Tag "$TAG_CHAINSAW"
|
||||
+WEAPON.MELEEWEAPON
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
SAWG C 4 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
SAWG D 4 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
SAWG C 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
SAWG C 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
SAWG AB 4 A_Saw
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
SAWG B 0 A_ReFire
|
||||
Goto Ready
|
||||
Spawn:
|
||||
CSAW A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Shotgun
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotShotgun : DoomWeapon replaces Shotgun
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 27
|
||||
Weapon.SlotNumber 3
|
||||
Weapon.SelectionOrder 1300
|
||||
Weapon.AmmoUse 1
|
||||
Weapon.AmmoGive 8
|
||||
Weapon.AmmoType "Shell"
|
||||
Inventory.PickupMessage "$GOTSHOTGUN"
|
||||
Obituary "$OB_MPSHOTGUN"
|
||||
Tag "$TAG_SHOTGUN"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
SHTG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
SHTG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
SHTG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
SHTG A 3
|
||||
SHTG A 7 A_FireShotgun
|
||||
SHTG BC 5
|
||||
SHTG D 4
|
||||
SHTG CB 5
|
||||
SHTG A 3
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotReFire")
|
||||
SHTG A 7 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
SHTF A 4 Bright A_Light1
|
||||
SHTF B 3 Bright A_Light2
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
SHOT A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Shotgun
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotSuperShotgun : DoomWeapon replaces SuperShotgun
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 33
|
||||
Weapon.SlotNumber 3
|
||||
Weapon.SelectionOrder 400
|
||||
Weapon.AmmoUse 2
|
||||
Weapon.AmmoGive 8
|
||||
Weapon.AmmoType "Shell"
|
||||
Inventory.PickupMessage "$GOTSHOTGUN2"
|
||||
Obituary "$OB_MPSSHOTGUN"
|
||||
Tag "$TAG_SUPERSHOTGUN"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
SHT2 A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
SHT2 A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
SHT2 A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
SHT2 A 3
|
||||
SHT2 A 7 A_FireShotgun2
|
||||
SHT2 B 7
|
||||
SHT2 C 7 A_CheckReload
|
||||
SHT2 D 7 A_OpenShotgun2
|
||||
SHT2 E 7
|
||||
SHT2 F 7 A_LoadShotgun2
|
||||
SHT2 G 6
|
||||
SHT2 H 6 A_CloseShotgun2
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
SHT2 A 5 A_ReFire
|
||||
Goto Ready
|
||||
// unused states
|
||||
SHT2 B 7
|
||||
SHT2 A 3
|
||||
Goto Deselect
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
SHT2 I 4 Bright A_Light1
|
||||
SHT2 J 3 Bright A_Light2
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
SGN2 A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Chaingun
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotChaingun : DoomWeapon replaces Chaingun
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 28
|
||||
Weapon.SlotNumber 4
|
||||
Weapon.SelectionOrder 700
|
||||
Weapon.AmmoUse 1
|
||||
Weapon.AmmoGive 20
|
||||
Weapon.AmmoType "Clip"
|
||||
Inventory.PickupMessage "$GOTCHAINGUN"
|
||||
Obituary "$OB_MPCHAINGUN"
|
||||
Tag "$TAG_CHAINGUN"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CHGG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
CHGG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
CHGG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
CHGG AB 4 A_FireCGun
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
CHGG B 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
CHGF A 5 Bright A_Light1
|
||||
Goto LightDone
|
||||
CHGF B 5 Bright A_Light2
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
MGUN A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Rocket launcher
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotRocketLauncher : DoomWeapon replaces RocketLauncher
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 29
|
||||
Weapon.SlotNumber 5
|
||||
Weapon.SelectionOrder 2500
|
||||
Weapon.AmmoUse 1
|
||||
Weapon.AmmoGive 2
|
||||
Weapon.AmmoType "RocketAmmo"
|
||||
+WEAPON.NOAUTOFIRE
|
||||
Inventory.PickupMessage "$GOTLAUNCHER"
|
||||
Tag "$TAG_ROCKETLAUNCHER"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MISG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotExplosiveWeapon")
|
||||
MISG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotExplosiveWeapon")
|
||||
MISG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
MISG B 8 A_GunFlash
|
||||
MISG B 12 A_FireMissile
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
MISG B 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
MISF A 3 Bright A_Light1
|
||||
MISF B 4 Bright
|
||||
MISF CD 4 Bright A_Light2
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
LAUN A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Plasma rifle
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotPlasmaRifle : DoomWeapon replaces PlasmaRifle
|
||||
{
|
||||
Game Doom
|
||||
SpawnID 30
|
||||
Weapon.SlotNumber 6
|
||||
Weapon.SelectionOrder 100
|
||||
Weapon.AmmoUse 1
|
||||
Weapon.AmmoGive 40
|
||||
Weapon.AmmoType "Cell"
|
||||
Inventory.PickupMessage "$GOTPLASMA"
|
||||
Tag "$TAG_PLASMARIFLE"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
PLSG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
PLSG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
PLSG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
PLSG A 3 A_FirePlasma
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
PLSG B 20 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
PLSF A 4 Bright A_Light1
|
||||
Goto LightDone
|
||||
PLSF B 4 Bright A_Light1
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
PLAS A -1
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// BFG 9000
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotBFG9000 : DoomWeapon replaces BFG9000
|
||||
{
|
||||
Game Doom
|
||||
Height 20
|
||||
SpawnID 31
|
||||
Weapon.SlotNumber 7
|
||||
Weapon.SelectionOrder 2800
|
||||
Weapon.AmmoUse 40
|
||||
Weapon.AmmoGive 40
|
||||
Weapon.AmmoType "Cell"
|
||||
+WEAPON.NOAUTOFIRE
|
||||
Inventory.PickupMessage "$GOTBFG9000"
|
||||
Tag "$TAG_BFG9000"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
BFGG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
BFGG A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
BFGG A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
BFGG A 20 A_BFGsound
|
||||
BFGG B 10 A_GunFlash
|
||||
BFGG B 10 A_FireBFG
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
BFGG B 20 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
Flash:
|
||||
BFGF A 11 Bright A_Light1
|
||||
BFGF B 6 Bright A_Light2
|
||||
Goto LightDone
|
||||
Spawn:
|
||||
BFUG A -1
|
||||
Stop
|
||||
OldFire:
|
||||
BFGG A 10 A_BFGsound
|
||||
BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG
|
||||
BFGG B 0 A_Light0
|
||||
BFGG B 20 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
464
wadsrc_tdbots/static/tdbots/HEXNWEAPONS.dec
Normal file
464
wadsrc_tdbots/static/tdbots/HEXNWEAPONS.dec
Normal file
|
@ -0,0 +1,464 @@
|
|||
//==============================================================================
|
||||
//
|
||||
// The Cleric's Weapons
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
ACTOR BotCWeapMace : CWeapMace replaces CWeapMace
|
||||
{
|
||||
Weapon.Slotnumber 1
|
||||
States
|
||||
{
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
Goto Super::Select
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
Goto Super::Deselect
|
||||
Ready:
|
||||
CMCE A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
CMCE B 2 Offset (60, 20)
|
||||
CMCE B 1 Offset (30, 33)
|
||||
CMCE B 2 Offset (8, 45)
|
||||
CMCE C 1 Offset (8, 45)
|
||||
CMCE D 1 Offset (8, 45)
|
||||
CMCE E 1 Offset (8, 45)
|
||||
CMCE E 1 Offset (-11, 58) A_CMaceAttack
|
||||
CMCE F 1 Offset (8, 45)
|
||||
CMCE F 2 Offset (-8, 74)
|
||||
CMCE F 1 Offset (-20, 96)
|
||||
CMCE F 8 Offset (-33, 160)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CMCE A 2 Offset (8, 75) A_ReFire
|
||||
CMCE A 1 Offset (8, 65)
|
||||
CMCE A 2 Offset (8, 60)
|
||||
CMCE A 1 Offset (8, 55)
|
||||
CMCE A 2 Offset (8, 50)
|
||||
CMCE A 1 Offset (8, 45)
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotCWeapFlame : CWeapFlame replaces CWeapFlame
|
||||
{
|
||||
Weapon.Slotnumber 3
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CFLM A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CFLM C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
CFLM A 2 Offset (0, 40)
|
||||
CFLM D 2 Offset (0, 50)
|
||||
CFLM D 2 Offset (0, 36)
|
||||
CFLM E 4 Bright
|
||||
CFLM F 4 Bright A_CFlameAttack
|
||||
CFLM E 4 Bright
|
||||
CFLM G 2 Offset (0, 40)
|
||||
CFLM G 2
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
//Extremely unlikely the bot will ever get this, but for the sake of completion
|
||||
ACTOR BotCWeapWraithverge : CWeapWraithverge replaces CWeapWraithverge
|
||||
{
|
||||
Weapon.Slotnumber 4
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CHLY A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
CHLY AB 1 Bright Offset (0, 40)
|
||||
CHLY CD 2 Bright Offset (0, 43)
|
||||
CHLY E 2 Bright Offset (0, 45)
|
||||
CHLY F 6 Bright Offset (0, 48) A_CHolyAttack
|
||||
CHLY GG 2 Bright Offset (0, 40) A_CHolyPalette
|
||||
CHLY G 2 Offset (0, 36) A_CHolyPalette
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotCWeapStaff : CWeapStaff replaces CWeapStaff
|
||||
{
|
||||
Weapon.Slotnumber 2
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CSSF C 4
|
||||
CSSF B 3 A_CStaffInitBlink
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF A 1 A_CStaffCheckBlink
|
||||
Goto Ready + 2
|
||||
Fire:
|
||||
CSSF A 1 Offset (0, 45) A_CStaffCheck
|
||||
CSSF J 1 Offset (0, 50) A_CStaffAttack
|
||||
CSSF J 2 Offset (0, 50)
|
||||
CSSF J 2 Offset (0, 45)
|
||||
CSSF A 2 Offset (0, 40)
|
||||
CSSF A 2 Offset (0, 36)
|
||||
Goto Ready + 2
|
||||
Blink:
|
||||
CSSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CCSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CCSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CSSF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Goto Ready + 2
|
||||
Drain:
|
||||
CSSF K 10 Offset (0, 36)
|
||||
Goto Ready + 2
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
//The Fighter's weapons
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
ACTOR BotFWeapFist : FWeapFist replaces FWeapFist
|
||||
{
|
||||
Weapon.Slotnumber 1
|
||||
States
|
||||
{
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
Goto Super::Select
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
Goto Super::Deselect
|
||||
Ready:
|
||||
FPCH A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
FPCH B 5 Offset (5, 40)
|
||||
FPCH C 4 Offset (5, 40)
|
||||
FPCH D 4 Offset (5, 40) A_FPunchAttack
|
||||
FPCH C 4 Offset (5, 40)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FPCH B 5 Offset (5, 40) A_ReFire
|
||||
Goto Ready
|
||||
Fire2:
|
||||
FPCH DE 4 Offset (5, 40)
|
||||
FPCH E 1 Offset (15, 50)
|
||||
FPCH E 1 Offset (25, 60)
|
||||
FPCH E 1 Offset (35, 70)
|
||||
FPCH E 1 Offset (45, 80)
|
||||
FPCH E 1 Offset (55, 90)
|
||||
FPCH E 1 Offset (65, 90)
|
||||
FPCH E 10 Offset (0, 150)
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotFWeapHammer : FWeapHammer replaces FWeapHammer
|
||||
{
|
||||
Weapon.Slotnumber 3
|
||||
States
|
||||
{
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
FHMR A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
FHMR A 1 A_Raise
|
||||
Loop
|
||||
Ready:
|
||||
FHMR A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
FHMR B 6 Offset (5, 0)
|
||||
FHMR C 3 Offset (5, 0) A_FHammerAttack
|
||||
FHMR D 3 Offset (5, 0)
|
||||
FHMR E 2 Offset (5, 0)
|
||||
FHMR E 10 Offset (5, 150) A_FHammerThrow
|
||||
FHMR A 1 Offset (0, 60)
|
||||
FHMR A 1 Offset (0, 55)
|
||||
FHMR A 1 Offset (0, 50)
|
||||
FHMR A 1 Offset (0, 45)
|
||||
FHMR A 1 Offset (0, 40)
|
||||
FHMR A 1 Offset (0, 35)
|
||||
FHMR A 1
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotFWeapAxe : FWeapAxe replaces FWeapAxe
|
||||
{
|
||||
Weapon.Slotnumber 2
|
||||
States
|
||||
{
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
Goto Super::Select
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
Goto Super::Deselect
|
||||
Ready:
|
||||
FAXE A 1 A_FAxeCheckReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
FAXE B 4 Offset (15, 32) A_FAxeCheckAtk
|
||||
FAXE C 3 Offset (15, 32)
|
||||
FAXE D 2 Offset (15, 32)
|
||||
FAXE D 1 Offset (-5, 70) A_FAxeAttack
|
||||
FAXE D 2 Offset (-25, 90)
|
||||
FAXE E 1 Offset (15, 32)
|
||||
FAXE E 2 Offset (10, 54)
|
||||
FAXE E 7 Offset (10, 150)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FAXE A 1 Offset (0, 60) A_ReFire
|
||||
FAXE A 1 Offset (0, 52)
|
||||
FAXE A 1 Offset (0, 44)
|
||||
FAXE A 1 Offset (0, 36)
|
||||
FAXE A 1
|
||||
Goto Ready
|
||||
ReadyGlow:
|
||||
FAXE L 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE L 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE L 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE M 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE M 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE M 1 A_FAxeCheckReadyG TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
Loop
|
||||
FireGlow:
|
||||
FAXE N 4 Offset (15, 32)
|
||||
FAXE O 3 Offset (15, 32)
|
||||
FAXE P 2 Offset (15, 32)
|
||||
FAXE P 1 Offset (-5, 70) A_FAxeAttack
|
||||
FAXE P 2 Offset (-25, 90)
|
||||
FAXE Q 1 Offset (15, 32)
|
||||
FAXE Q 2 Offset (10, 54)
|
||||
FAXE Q 7 Offset (10, 150)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "FireGlow")
|
||||
FAXE A 1 Offset (0, 60) A_ReFire
|
||||
FAXE A 1 Offset (0, 52)
|
||||
FAXE A 1 Offset (0, 44)
|
||||
FAXE A 1 Offset (0, 36)
|
||||
FAXE A 1
|
||||
Goto ReadyGlow
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotFWeapQuietus : FWeapQuietus replaces FWeapQuietus
|
||||
{
|
||||
Weapon.Slotnumber 4
|
||||
States
|
||||
{
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
FSRD A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
FSRD A 1 A_Raise
|
||||
Loop
|
||||
Ready:
|
||||
FSRD A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FSRD C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
FSRD DE 3 Bright Offset (5, 36)
|
||||
FSRD F 2 Bright Offset (5, 36)
|
||||
FSRD G 3 Bright Offset (5, 36) A_FSwordAttack
|
||||
FSRD H 2 Bright Offset (5, 36)
|
||||
FSRD I 2 Bright Offset (5, 36)
|
||||
FSRD I 10 Bright Offset (5, 150)
|
||||
FSRD A 1 Bright Offset (5, 60)
|
||||
FSRD B 1 Bright Offset (5, 55)
|
||||
FSRD C 1 Bright Offset (5, 50)
|
||||
FSRD A 1 Bright Offset (5, 45)
|
||||
FSRD B 1 Bright Offset (5, 40)
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
//The Mage's weapons
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
ACTOR BotMWeapWand : MWeapWand replaces MWeapWand
|
||||
{
|
||||
Weapon.Slotnumber 1
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MWND A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
MWND A 6
|
||||
MWND B 6 Bright Offset (0, 48) A_FireCustomMissile ("MageWandMissile")
|
||||
MWND A 3 Offset (0, 40)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MWND A 3 Offset (0, 36) A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotMWeapFrost : MWeapFrost replaces MWeapFrost
|
||||
{
|
||||
Weapon.Slotnumber 2
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CONE A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
CONE B 3
|
||||
CONE C 4
|
||||
Hold:
|
||||
CONE D 3
|
||||
CONE E 5
|
||||
CONE F 3 A_FireConePL1
|
||||
CONE G 3
|
||||
CONE A 9
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Hold")
|
||||
CONE A 10 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotMWeapLightning : MWeapLightning replaces MWeapLightning
|
||||
{
|
||||
Weapon.Slotnumber 3
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MLNG A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG A 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG A 1 Bright A_LightningReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG C 1 Bright A_LightningReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MLNG B 1 Bright A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
MLNG DE 3 Bright
|
||||
MLNG F 4 Bright A_MLightningAttack
|
||||
MLNG G 4 Bright
|
||||
MLNG HI 3 Bright
|
||||
MLNG I 6 Bright Offset (0, 199)
|
||||
MLNG C 2 Bright Offset (0, 55)
|
||||
MLNG B 2 Bright Offset (0, 50)
|
||||
MLNG B 2 Bright Offset (0, 45)
|
||||
MLNG B 2 Bright Offset (0, 40)
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotMWeapBloodscourge : MWeapBloodscourge replaces MWeapBloodscourge
|
||||
{
|
||||
Weapon.Slotnumber 4
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF D 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF E 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF F 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF F 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF F 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF F 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MSTF F 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
MSTF G 4 Offset (0, 40)
|
||||
MSTF H 4 Bright Offset (0, 48) A_MStaffAttack
|
||||
MSTF H 2 Bright Offset (0, 48) A_MStaffPalette
|
||||
MSTF II 2 Offset (0, 48) A_MStaffPalette
|
||||
MSTF I 1 Offset (0, 40)
|
||||
MSTF J 5 Offset (0, 36)
|
||||
Goto Ready
|
||||
}
|
||||
}
|
564
wadsrc_tdbots/static/tdbots/HTICWEAPONS.dec
Normal file
564
wadsrc_tdbots/static/tdbots/HTICWEAPONS.dec
Normal file
|
@ -0,0 +1,564 @@
|
|||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Staff
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotStaff : Staff replaces Staff
|
||||
{
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.SisterWeapon "BotStaffPowered"
|
||||
States
|
||||
{
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
Goto Super::Select
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
Goto Super::Deselect
|
||||
Ready:
|
||||
STFF A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
STFF B 6
|
||||
STFF C 8 A_StaffAttack(random[StaffAttack](5, 20), "StaffPuff")
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
STFF B 8 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotStaffPowered : StaffPowered replaces StaffPowered
|
||||
{
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.sisterweapon "BotStaff"
|
||||
States
|
||||
{
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
Goto Super::Select
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
Goto Super::Deselect
|
||||
Ready:
|
||||
STFF D 4 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
STFF E 4 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
STFF F 4 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
STFF G 6
|
||||
STFF H 8 A_StaffAttack(random[StaffAttack](18, 81), "StaffPuff2")
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
STFF G 8 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Gold wand
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotGoldWand : GoldWand replaces GoldWand
|
||||
{
|
||||
Weapon.SlotNumber 2
|
||||
Weapon.AmmoGive 0
|
||||
Weapon.SisterWeapon "BotGoldWandPowered"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
GWND A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
GWND A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
GWND A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
GWND B 3
|
||||
GWND C 5 A_FireGoldWandPL1
|
||||
GWND D 3
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
GWND D 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotGoldWandPowered : GoldWandPowered replaces GoldWandPowered
|
||||
{
|
||||
Weapon.SlotNumber 2
|
||||
Weapon.SisterWeapon "BotGoldWand"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
GWND A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
GWND B 3
|
||||
GWND C 4 A_FireGoldWandPL2
|
||||
GWND D 3
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
GWND D 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Crossbow
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotCrossbow : Crossbow replaces Crossbow
|
||||
{
|
||||
Weapon.SlotNumber 3
|
||||
Weapon.SisterWeapon "BotCrossbowPowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WBOW A -1
|
||||
Stop
|
||||
Ready:
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
CRBW A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
CRBW A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
CRBW D 6 A_FireCrossbowPL1
|
||||
CRBW EFGH 3
|
||||
CRBW AB 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
CRBW C 5 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ACTOR BotCrossbowPowered : CrossbowPowered replaces CrossbowPowered
|
||||
{
|
||||
Weapon.SlotNumber 3
|
||||
Weapon.SisterWeapon "BotCrossbow"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW A 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW B 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
CRBW C 1 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
CRBW D 5 A_FireCrossbowPL2
|
||||
CRBW E 3
|
||||
CRBW F 2
|
||||
CRBW G 3
|
||||
CRBW H 2
|
||||
CRBW A 3
|
||||
CRBW B 3
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
CRBW C 4 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Gauntlets
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotGauntlets : Gauntlets replaces Gauntlets
|
||||
{
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.SisterWeapon "BotGauntletsPowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WGNT A -1
|
||||
Stop
|
||||
Ready:
|
||||
GAUN A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
GAUN A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
GAUN A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
GAUN B 4 A_PlayWeaponSound("weapons/gauntletsuse")
|
||||
GAUN C 4
|
||||
Hold:
|
||||
GAUN DEF 4 BRIGHT A_GauntletAttack(0)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
GAUN C 4 A_ReFire
|
||||
GAUN B 4 A_Light0
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ACTOR BotGauntletsPowered : GauntletsPowered replaces GauntletsPowered
|
||||
{
|
||||
Weapon.SlotNumber 1
|
||||
Weapon.SisterWeapon "BotGauntlets"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
GAUN G 4 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
GAUN H 4 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
GAUN I 4 A_WeaponReady TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
GAUN G 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
GAUN G 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
GAUN J 4 A_PlayWeaponSound("weapons/gauntletsuse")
|
||||
GAUN K 4
|
||||
Hold:
|
||||
GAUN LMN 4 BRIGHT A_GauntletAttack(1)
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
GAUN K 4 A_ReFire
|
||||
GAUN J 4 A_Light0
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// The mace itself
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotMace : Mace replaces Mace
|
||||
{
|
||||
Weapon.SlotNumber 7
|
||||
Weapon.SisterWeapon "BotMacePowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WMCE A -1
|
||||
Stop
|
||||
Ready:
|
||||
MACE A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
MACE A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
MACE A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
MACE B 4
|
||||
Hold:
|
||||
MACE CDEF 3 A_FireMacePL1
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
MACE C 4 A_ReFire
|
||||
MACE DEFB 4
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotMacePowered : MacePowered replaces MacePowered
|
||||
{
|
||||
Weapon.SlotNumber 7
|
||||
Weapon.SisterWeapon "BotMace"
|
||||
States
|
||||
{
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotCloseRange")
|
||||
MACE A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotCloseRange")
|
||||
MACE A 1 A_Raise
|
||||
Loop
|
||||
Ready:
|
||||
MACE A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
Hold:
|
||||
MACE B 4
|
||||
MACE D 4 A_FireMacePL2
|
||||
MACE B 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
MACE A 8 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Blaster
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotBlaster : Blaster replaces Blaster
|
||||
{
|
||||
Weapon.SlotNumber 4
|
||||
Weapon.SisterWeapon "BotBlasterPowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WBLS A -1
|
||||
Stop
|
||||
Ready:
|
||||
BLSR A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
BLSR A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
BLSR A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
BLSR BC 3
|
||||
Hold:
|
||||
BLSR D 2 A_FireBlasterPL1
|
||||
BLSR CB 2
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
BLSR A 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotBlasterPowered : BlasterPowered replaces BlasterPowered
|
||||
{
|
||||
Weapon.SlotNumber 4
|
||||
Weapon.SisterWeapon "BotBlaster"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
BLSR A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
BLSR BC 0
|
||||
Hold:
|
||||
BLSR D 3 A_FireCustomMissile("BlasterFX1")
|
||||
BLSR CB 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
BLSR A 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Skull (horn) rod
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotSkullRod : SkullRod replaces SkullRod
|
||||
{
|
||||
Weapon.SlotNumber 5
|
||||
Weapon.SisterWeapon "BotSkullRodPowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WSKL A -1
|
||||
Stop
|
||||
Ready:
|
||||
HROD A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotForceInacc")
|
||||
HROD A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotForceInacc")
|
||||
HROD A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
HROD AB 4 A_FireSkullRodPL1
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
HROD B 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotSkullRodPowered : SkullRodPowered replaces SkullRodPowered
|
||||
{
|
||||
Weapon.SlotNumber 5
|
||||
Weapon.SisterWeapon "BotSkullRod"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
HROD A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
HROD C 2
|
||||
HROD D 3
|
||||
HROD E 2
|
||||
HROD F 3
|
||||
HROD G 4 A_FireSkullRodPL2
|
||||
HROD F 2
|
||||
HROD E 3
|
||||
HROD D 2
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
HROD C 2 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Phoenix rod
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotPhoenixRod : PhoenixRod replaces PhoenixRod
|
||||
{
|
||||
Weapon.SlotNumber 6
|
||||
Weapon.Sisterweapon "BotPhoenixRodPowered"
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WPHX A -1
|
||||
Stop
|
||||
Ready:
|
||||
PHNX A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
PHNX A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
PHNX A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
PHNX B 5
|
||||
PHNX C 7 A_FirePhoenixPL1
|
||||
PHNX DB 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
PHNX B 0 A_ReFire
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Fire
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR BotPhoenixRodPowered : PhoenixRodPowered replaces PhoenixRodPowered
|
||||
{
|
||||
Weapon.SlotNumber 6
|
||||
Weapon.SisterWeapon "BotPhoenixRod"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
PHNX A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
PHNX B 3 A_InitPhoenixPL2
|
||||
Hold:
|
||||
PHNX C 1 A_FirePhoenixPL2
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "BotRefire")
|
||||
PHNX B 4 A_ReFire
|
||||
Powerdown:
|
||||
PHNX B 4 A_ShutdownPhoenixPL2
|
||||
Goto Ready
|
||||
BotRefire:
|
||||
TNT1 A 0 A_JumpIfNoAmmo("Deselect")
|
||||
Goto Hold
|
||||
}
|
||||
}
|
115
wadsrc_tdbots/static/tdbots/NODESTUDIO.dec
Normal file
115
wadsrc_tdbots/static/tdbots/NODESTUDIO.dec
Normal file
|
@ -0,0 +1,115 @@
|
|||
Actor TDBots_NodeStudio_Editor : Weapon
|
||||
{
|
||||
+WEAPON.NOAUTOFIRE
|
||||
+WEAPON.NOLMS
|
||||
+WEAPON.CHEATNOTWEAPON
|
||||
const int FLAGS = FBF_NORANDOMPUFFZ|FBF_NORANDOM|FBF_NOFLASH;
|
||||
states
|
||||
{
|
||||
Select:
|
||||
TNT1 AA 0 A_Raise
|
||||
TNT1 A 1 A_Raise
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 1 A_Lower
|
||||
Loop
|
||||
Ready:
|
||||
TNT1 A 1 A_FireBullets(0,0,1,0,"TDBots_NodeStudio_Marker",FLAGS)
|
||||
TNT1 A 0 A_WeaponReady(WRF_NOSWITCH)
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Reload",1,"Reload")
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Zoom",1,"Zoom")
|
||||
Loop
|
||||
Zoom:
|
||||
TNT1 A 1 ACS_NamedExecuteAlways("TDBots_NodeStudio_Save",0)
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Zoom",1,"ZR_Done")
|
||||
Goto Ready
|
||||
Reload:
|
||||
TNT1 A 1 ACS_NamedExecuteAlways("TDBots_NodeStudio_Help",0)
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Reload",1,"ZR_Done")
|
||||
Goto Ready
|
||||
Fire:
|
||||
TNT1 A 0
|
||||
TNT1 A 1 A_FireBullets(0,0,1,0,"TDBots_NodeStudio_Node",FLAGS)
|
||||
TNT1 A 0 A_Refire("Done")
|
||||
Goto Ready
|
||||
AltFire:
|
||||
TNT1 A 1 ACS_NamedExecuteAlways("TDBots_NodeStudio_Undo",0)
|
||||
TNT1 A 0 A_Refire("Done")
|
||||
Goto Ready
|
||||
Done:
|
||||
TNT1 A 1 A_FireBullets(0,0,1,0,"TDBots_NodeStudio_Marker",FLAGS)
|
||||
TNT1 A 0 A_Refire("Done")
|
||||
Goto Ready
|
||||
ZR_Done:
|
||||
TNT1 A 1 A_FireBullets(0,0,1,0,"TDBots_NodeStudio_Marker",FLAGS)
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Reload",1,"ZR_Done")
|
||||
TNT1 A 0 A_JumpIfInventory("TDB_NS_Zoom",1,"ZR_Done")
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
Actor TDB_NS_Reload : Inventory {}
|
||||
Actor TDB_NS_Zoom : Inventory {}
|
||||
|
||||
Actor TDBots_NodeStudio_Marker : BulletPuff
|
||||
{
|
||||
+FORCEXYBILLBOARD
|
||||
+CLIENTSIDEONLY
|
||||
+PUFFONACTORS
|
||||
-RANDOMIZE
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
Melee:
|
||||
TBND A 2 BRIGHT
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor TDBots_NodeStudio_Node : TDBots_NodeStudio_Marker
|
||||
{
|
||||
-CLIENTSIDEONLY
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
Melee:
|
||||
TNT1 A 0
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_NodeStudio_PlaceNode",0)
|
||||
TBND A 2 BRIGHT
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor TDBots_NodeStudio_FakeNode
|
||||
{
|
||||
Scale 3.0
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 AA 0 A_Stop
|
||||
TBND B -1 BRIGHT
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor TDBots_NodeStudio_FakeJumpNode : TDBots_NodeStudio_FakeNode
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 AA 0 A_Stop
|
||||
TBND C -1 BRIGHT
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
Actor TDBots_NodeStudio_FakePreciseNode : TDBots_NodeStudio_FakeNode
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 AA 0 A_Stop
|
||||
TBND D -1 BRIGHT
|
||||
Stop
|
||||
}
|
||||
}
|
177
wadsrc_tdbots/static/tdbots/PATHNODING.dec
Normal file
177
wadsrc_tdbots/static/tdbots/PATHNODING.dec
Normal file
|
@ -0,0 +1,177 @@
|
|||
ACTOR TDBots_IDoExist : Inventory {}
|
||||
|
||||
/*==============================================================================
|
||||
|
||||
Normal Path Node, does nothing special to the bot following it
|
||||
|
||||
==============================================================================*/
|
||||
ACTOR TDBots_PathNode : CustomInventory 2401
|
||||
{
|
||||
+INVISIBLE
|
||||
|
||||
+INVENTORY.NOSCREENFLASH
|
||||
+INVENTORY.NEVERRESPAWN
|
||||
Inventory.MaxAmount 99999
|
||||
Inventory.PickupMessage ""
|
||||
Inventory.PickupSound ""
|
||||
Scale 3.0
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
"####" "#" 0 NoDelay A_GiveInventory("TDBots_IDoExist")
|
||||
"####" "#" 0 A_SpawnItemEx("TDBots_NodeRespawn",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION,0,tid)
|
||||
TBND B -1
|
||||
Stop
|
||||
Pickup:
|
||||
TNT1 A 0 A_TakeInventory("BotPrecisionMode")
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IsBot", 1, "DoPickup")
|
||||
Fail
|
||||
DoPickup:
|
||||
TNT1 A 0 A_RailWait
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR TDBots_NodeRespawn
|
||||
{
|
||||
+INVISIBLE
|
||||
|
||||
Scale 4.0
|
||||
+NOBLOCKMAP
|
||||
+NOCLIP
|
||||
+ISMONSTER
|
||||
-SHOOTABLE
|
||||
-SOLID
|
||||
|
||||
var int user_ntid;
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 0 NoDelay A_SetUserVar("user_ntid", tid)
|
||||
TNT1 A 0 Thing_ChangeTID(0,0)
|
||||
TNT1 A 0 ACS_NamedExecuteWithResult("TDBots_SetTarget", user_ntid)
|
||||
Idle:
|
||||
TNT1 A 1
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IDoExist", 1, "Idle", AAPTR_TARGET)
|
||||
RespawnNode:
|
||||
TBND Z 0
|
||||
"####" "#####" 35
|
||||
TNT1 A 0 A_SpawnItemEx("TDBots_PathNode",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION,0,user_ntid)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
|
||||
Jump Node, makes the bot jump in the direction it was moving
|
||||
when touching it.
|
||||
|
||||
==============================================================================*/
|
||||
ACTOR TDBots_JumpNode : TDBots_PathNode 2402
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
"####" "#" 0 NoDelay A_GiveInventory("TDBots_IDoExist")
|
||||
"####" "#" 0 A_SpawnItemEx("TDBots_JNodeRespawn",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION,0,tid)
|
||||
TBND C -1
|
||||
Stop
|
||||
Pickup:
|
||||
TNT1 A 0 A_TakeInventory("BotPrecisionMode")
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IsBot", 1, "DoPickup")
|
||||
Fail
|
||||
DoPickup:
|
||||
TNT1 A 0 ACS_NamedExecuteAlways("TDBots_Jump")
|
||||
TNT1 A 0 A_Jump(256, "DoPickup2")
|
||||
Stop
|
||||
DoPickup2:
|
||||
TNT1 A 0 A_RailWait
|
||||
Stop
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR TDBots_JNodeRespawn : TDBots_NodeRespawn
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 0 NoDelay A_SetUserVar("user_ntid", tid)
|
||||
TNT1 A 0 Thing_ChangeTID(0,0)
|
||||
TNT1 A 0 ACS_NamedExecuteWithResult("TDBots_SetTarget", user_ntid)
|
||||
Idle:
|
||||
TNT1 A 1
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IDoExist", 1, "Idle", AAPTR_TARGET)
|
||||
RespawnNode:
|
||||
TBND Z 0
|
||||
"####" "#####" 35
|
||||
TNT1 A 0 A_SpawnItemEx("TDBots_JumpNode",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION,0,user_ntid)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
|
||||
Precision Node, once touched, makes the bot completely stop
|
||||
dodging attacks when in attacking state, to avoid falling down
|
||||
accidentally.
|
||||
|
||||
==============================================================================*/
|
||||
ACTOR TDBots_PrecisionNode : TDBots_PathNode
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
"####" "#" 0 NoDelay A_GiveInventory("TDBots_IDoExist")
|
||||
"####" "#" 0 A_SpawnItemEx("TDBots_PNodeRespawn",0,0,0,0,0,0,0,SXF_SETMASTER|SXF_NOCHECKPOSITION,0,tid)
|
||||
TBND D -1
|
||||
Stop
|
||||
Pickup:
|
||||
TNT1 A 0 A_GiveInventory("BotPrecisionMode")
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IsBot", 1, "DoPickup")
|
||||
Fail
|
||||
DoPickup:
|
||||
TNT1 A 0 A_RailWait
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR TDBots_PNodeRespawn : TDBots_NodeRespawn
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 0 NoDelay A_SetUserVar("user_ntid", tid)
|
||||
TNT1 A 0 Thing_ChangeTID(0,0)
|
||||
TNT1 A 0 ACS_NamedExecuteWithResult("TDBots_SetTarget", user_ntid)
|
||||
Idle:
|
||||
TNT1 A 1
|
||||
TNT1 A 0 A_JumpIfInventory("TDBots_IDoExist", 1, "Idle", AAPTR_TARGET)
|
||||
RespawnNode:
|
||||
TBND Z 0
|
||||
"####" "#####" 35
|
||||
TNT1 A 0 A_SpawnItemEx("TDBots_PrecisionNode",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION,0,user_ntid)
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR TDBots_TempNode : TDBots_PathNode
|
||||
{
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
TNT1 AAAAA 35
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
ACTOR TDBots_AutoNoder
|
||||
{
|
||||
+NOINTERACTION
|
||||
+INVISIBLE
|
||||
states
|
||||
{
|
||||
Spawn:
|
||||
Goto Null
|
||||
}
|
||||
}
|
327
wadsrc_tdbots/static/tdbots/STRFWEAPONS.dec
Normal file
327
wadsrc_tdbots/static/tdbots/STRFWEAPONS.dec
Normal file
|
@ -0,0 +1,327 @@
|
|||
//NOTE: The sigil weapon is not included, because it relies on hardcoded
|
||||
//behavior. To be more clear, hardcoded behavior i don't understand and thus
|
||||
//can't recreate reliably.
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Dagger
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotPunchDagger : PunchDagger replaces PunchDagger
|
||||
{
|
||||
Weapon.SlotNumber 1
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
PNCH A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotMeleeWeapon")
|
||||
PNCH A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotMeleeWeapon")
|
||||
PNCH A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
PNCH B 4
|
||||
PNCH C 4 A_JabDagger
|
||||
PNCH D 5
|
||||
PNCH C 4
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
PNCH B 5 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Strife's crossbow
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotStrifeCrossbow : StrifeCrossbow replaces StrifeCrossbow
|
||||
{
|
||||
Weapon.SlotNumber 2
|
||||
Weapon.SisterWeapon "BotStrifeCrossbow2"
|
||||
states
|
||||
{
|
||||
Ready:
|
||||
XBOW A 0 A_ShowElectricFlash
|
||||
Ready2:
|
||||
XBOW A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
XBOW A 3 A_ClearFlash
|
||||
XBOW B 6 A_FireArrow("ElectricBolt")
|
||||
XBOW C 4
|
||||
XBOW D 6
|
||||
XBOW E 3
|
||||
XBOW F 5
|
||||
XBOW G 0 A_ShowElectricFlash
|
||||
XBOW G 5 A_CheckReload
|
||||
Goto Ready+1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ACTOR BotStrifeCrossbow2 : StrifeCrossbow2 replaces StrifeCrossbow2
|
||||
{
|
||||
Weapon.SlotNumber 2
|
||||
Weapon.SisterWeapon "BotStrifeCrossbow"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
XBOW H 1 A_WeaponReady
|
||||
Loop
|
||||
Fire:
|
||||
XBOW H 3
|
||||
XBOW B 6 A_FireArrow("PoisonBolt")
|
||||
XBOW C 4
|
||||
XBOW D 6
|
||||
XBOW E 3
|
||||
XBOW I 5
|
||||
XBOW J 5 A_CheckReload
|
||||
Goto Ready
|
||||
Flash:
|
||||
Stop
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Assault gun
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
actor BotAssaultGun : AssaultGun replaces AssaultGun
|
||||
{
|
||||
Weapon.SlotNumber 3
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
RIFG A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
RIFF AB 3 A_FireAssaultGun
|
||||
RIFG D 3 A_FireAssaultGun
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
RIFG C 0 A_ReFire
|
||||
RIFG B 2 A_Light0
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Assault Gun (standing variant)
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotAssaultGunStanding : AssaultGunStanding replaces AssaultGunStanding {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Mini-Missile Launcher
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotMiniMissileLauncher : MiniMissileLauncher replaces MiniMissileLauncher
|
||||
{
|
||||
Weapon.SlotNumber 4
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MMIS A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotExplosiveWeapon")
|
||||
MMIS A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotExplosiveWeapon")
|
||||
MMIS A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
MMIS A 4 A_FireMiniMissile
|
||||
MMIS B 4 A_Light1
|
||||
MMIS C 5 Bright
|
||||
MMIS D 2 Bright A_Light2
|
||||
MMIS E 2 Bright
|
||||
MMIS F 2 Bright A_Light0
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MMIS F 0 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Flame thrower
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotFlameThrower : FlameThrower replaces FlameThrower
|
||||
{
|
||||
Weapon.SlotNumber 6
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
FLMT A 3 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FLMT B 3 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
FLMF A 2 A_FireFlamer
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
FLMF B 3 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
// Mauler -------------------------------------------------------------------
|
||||
// The scatter version
|
||||
|
||||
ACTOR BotMauler : Mauler replaces Mauler
|
||||
{
|
||||
Weapon.SlotNumber 7
|
||||
Weapon.SisterWeapon "BotMauler2"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MAUL F 6 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL G 6 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL H 6 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL A 6 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
BLSF A 5 Bright A_FireMauler1
|
||||
MAUL B 3 Bright A_Light1
|
||||
MAUL C 2 A_Light2
|
||||
MAUL DE 2
|
||||
MAUL A 7 A_Light0
|
||||
MAUL H 7
|
||||
MAUL G 7 A_CheckReload
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// Mauler (torpedo version)
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotMauler2 : Mauler2 replaces Mauler2
|
||||
{
|
||||
Weapon.SlotNumber 7
|
||||
Weapon.SisterWeapon "BotMauler"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
MAUL I 7 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL J 7 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL K 7 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL L 7 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Fire:
|
||||
MAUL I 20 A_FireMauler2Pre
|
||||
MAUL J 10 A_Light1
|
||||
BLSF A 10 Bright A_FireMauler2
|
||||
MAUL B 10 Bright A_Light2
|
||||
MAUL C 2
|
||||
MAUL D 2 A_Light0
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
MAUL E 2 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// HE-Grenade Launcher
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotStrifeGrenadeLauncher : StrifeGrenadeLauncher replaces StrifeGrenadeLauncher
|
||||
{
|
||||
Weapon.SlotNumber 5
|
||||
Weapon.SisterWeapon "BotStrifeGrenadeLauncher2"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
GREN A 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotExplosiveWeapon")
|
||||
GREN A 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotExplosiveWeapon")
|
||||
GREN A 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash")
|
||||
GREN B 10
|
||||
GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2")
|
||||
GREN C 10
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
GREN A 0 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// White phosphorus Grenade Launcher
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ACTOR BotStrifeGrenadeLauncher2 : StrifeGrenadeLauncher2 replaces StrifeGrenadeLauncher2
|
||||
{
|
||||
Weapon.SlotNumber 5
|
||||
Weapon.SisterWeapon "BotStrifeGrenadeLauncher"
|
||||
States
|
||||
{
|
||||
Ready:
|
||||
GREN D 1 A_WeaponReady
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
Loop
|
||||
Deselect:
|
||||
TNT1 A 0 A_TakeInventory("BotExplosiveWeapon")
|
||||
GREN D 1 A_Lower
|
||||
Loop
|
||||
Select:
|
||||
TNT1 A 0 A_GiveInventory("BotExplosiveWeapon")
|
||||
GREN D 1 A_Raise
|
||||
Loop
|
||||
Fire:
|
||||
GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash")
|
||||
GREN E 10
|
||||
GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2")
|
||||
GREN F 10
|
||||
TNT1 A 0 A_JumpIfInventory("BotAttack", 1, "Fire")
|
||||
GREN A 0 A_ReFire
|
||||
Goto Ready
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue