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_bm )
|
||||||
add_subdirectory( wadsrc_lights )
|
add_subdirectory( wadsrc_lights )
|
||||||
add_subdirectory( wadsrc_extra )
|
add_subdirectory( wadsrc_extra )
|
||||||
|
add_subdirectory( wadsrc_tdbots )
|
||||||
add_subdirectory( wadsrc_widescreen )
|
add_subdirectory( wadsrc_widescreen )
|
||||||
add_subdirectory( src )
|
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_bot.cpp
|
||||||
playsim/bots/b_func.cpp
|
playsim/bots/b_func.cpp
|
||||||
playsim/bots/b_game.cpp
|
playsim/bots/b_game.cpp
|
||||||
playsim/bots/b_move.cpp
|
|
||||||
playsim/bots/b_think.cpp
|
|
||||||
bbannouncer.cpp
|
bbannouncer.cpp
|
||||||
console/c_cmds.cpp
|
console/c_cmds.cpp
|
||||||
console/c_notifybuffer.cpp
|
console/c_notifybuffer.cpp
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct FStartupInfo
|
||||||
int LoadLights = -1;
|
int LoadLights = -1;
|
||||||
int LoadBrightmaps = -1;
|
int LoadBrightmaps = -1;
|
||||||
int LoadWidescreen = -1;
|
int LoadWidescreen = -1;
|
||||||
|
int LoadBots = -1;
|
||||||
int modern = 0;
|
int modern = 0;
|
||||||
enum
|
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, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
|
||||||
CVAR (Bool, autoloadlights, 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, 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, r_debug_disable_vis_filter, false, 0)
|
||||||
CVAR(Bool, vid_fps, false, 0)
|
CVAR(Bool, vid_fps, false, 0)
|
||||||
CVAR(Int, vid_showpalette, 0, 0)
|
CVAR(Int, vid_showpalette, 0, 0)
|
||||||
|
@ -1945,6 +1946,11 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
|
||||||
sc.MustGetNumber();
|
sc.MustGetNumber();
|
||||||
GameStartupInfo.LoadWidescreen = !!sc.Number;
|
GameStartupInfo.LoadWidescreen = !!sc.Number;
|
||||||
}
|
}
|
||||||
|
else if (!nextKey.CompareNoCase("LOADBOTS"))
|
||||||
|
{
|
||||||
|
sc.MustGetNumber();
|
||||||
|
GameStartupInfo.LoadBots = !!sc.Number;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Silently ignore unknown properties
|
// Silently ignore unknown properties
|
||||||
|
@ -2085,6 +2091,12 @@ static void AddAutoloadFiles(const char *autoname)
|
||||||
if (wswad)
|
if (wswad)
|
||||||
D_AddFile (allwads, wswad, true, -1, GameConfig);
|
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)
|
if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload") && !disableautoload)
|
||||||
|
@ -3742,7 +3754,12 @@ void D_Cleanup()
|
||||||
// delete GameStartupInfo data
|
// delete GameStartupInfo data
|
||||||
GameStartupInfo.Name = "";
|
GameStartupInfo.Name = "";
|
||||||
GameStartupInfo.BkColor = GameStartupInfo.FgColor = GameStartupInfo.Type = 0;
|
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.
|
GC::FullGC(); // clean up before taking down the object list.
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@
|
||||||
#include "texturemanager.h"
|
#include "texturemanager.h"
|
||||||
|
|
||||||
extern void LoadActors ();
|
extern void LoadActors ();
|
||||||
extern void InitBotStuff();
|
|
||||||
extern void ClearStrifeTypes();
|
extern void ClearStrifeTypes();
|
||||||
|
|
||||||
TArray<PClassActor *> PClassActor::AllActorClasses;
|
TArray<PClassActor *> PClassActor::AllActorClasses;
|
||||||
|
@ -402,7 +401,6 @@ void PClassActor::StaticInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadAltHudStuff();
|
LoadAltHudStuff();
|
||||||
InitBotStuff();
|
|
||||||
|
|
||||||
// reinit GLOBAL static stuff from gameinfo, once classes are loaded.
|
// reinit GLOBAL static stuff from gameinfo, once classes are loaded.
|
||||||
staticEventManager.InitStaticHandlers(primaryLevel, false);
|
staticEventManager.InitStaticHandlers(primaryLevel, false);
|
||||||
|
|
|
@ -143,12 +143,6 @@ void DBot::Tick ()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BotThinkCycles.Clock();
|
|
||||||
Level->BotInfo.m_Thinking = true;
|
|
||||||
Think ();
|
|
||||||
Level->BotInfo.m_Thinking = false;
|
|
||||||
BotThinkCycles.Unclock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CVAR (Int, bot_next_color, 11, 0)
|
CVAR (Int, bot_next_color, 11, 0)
|
||||||
|
@ -245,70 +239,3 @@ CCMD (listbots)
|
||||||
Printf ("> %d bots\n", count);
|
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)
|
//(b_func.cpp)
|
||||||
void StartTravel ();
|
void StartTravel ();
|
||||||
void FinishTravel ();
|
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)
|
//(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.
|
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
|
||||||
|
|
||||||
|
@ -214,25 +207,6 @@ public:
|
||||||
DVector2 old;
|
DVector2 old;
|
||||||
|
|
||||||
private:
|
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 "doomtype.h"
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "p_local.h"
|
|
||||||
#include "p_maputl.h"
|
|
||||||
#include "b_bot.h"
|
#include "b_bot.h"
|
||||||
#include "g_game.h"
|
|
||||||
#include "d_event.h"
|
|
||||||
#include "d_player.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 ()
|
void FCajunMaster::StartTravel ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -476,11 +476,11 @@ void FCajunMaster::ForgetBots ()
|
||||||
|
|
||||||
#if defined _WIN32 || defined __APPLE__
|
#if defined _WIN32 || defined __APPLE__
|
||||||
|
|
||||||
FString M_GetCajunPath(const char* botfilename)
|
FString M_GetBotPath(const char* botfilename)
|
||||||
{
|
{
|
||||||
FString path;
|
FString path;
|
||||||
|
|
||||||
path << progdir << "zcajun/" << botfilename;
|
path << progdir << botfilename;
|
||||||
if (!FileExists(path))
|
if (!FileExists(path))
|
||||||
{
|
{
|
||||||
path = "";
|
path = "";
|
||||||
|
@ -490,7 +490,7 @@ FString M_GetCajunPath(const char* botfilename)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
FString M_GetCajunPath(const char* botfilename)
|
FString M_GetBotPath(const char* botfilename)
|
||||||
{
|
{
|
||||||
FString path;
|
FString path;
|
||||||
|
|
||||||
|
@ -519,7 +519,7 @@ bool FCajunMaster::LoadBots ()
|
||||||
int loaded_bots = 0;
|
int loaded_bots = 0;
|
||||||
|
|
||||||
ForgetBots ();
|
ForgetBots ();
|
||||||
tmp = M_GetCajunPath(BOTFILENAME);
|
tmp = M_GetBotPath(BOTFILENAME);
|
||||||
if (tmp.IsEmpty())
|
if (tmp.IsEmpty())
|
||||||
{
|
{
|
||||||
DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n");
|
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;
|
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||||
return false;
|
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
|
// [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
|
// [RH] Consider carrying sectors here
|
||||||
DVector2 cumm(0, 0);
|
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