mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-14 00:21:34 +00:00
66d28a24b8
Needless to say, this is simply too volatile and would require constant active maintenance, not to mention a huge amount of work up front to get going. It also hid a nasty problem with the Destroy method. Due to the way the garbage collector works, Destroy cannot be exposed to scripts as-is. It may be called from scripts but it may not be overridden from scripts because the garbage collector can call this function after all data needed for calling a scripted override has already been destroyed because if that data is also being collected there is no guarantee that proper order of destruction is observed. So for now Destroy is just a normal native method to scripted classes
285 lines
6.7 KiB
C++
285 lines
6.7 KiB
C++
// Cajun bot
|
|
//
|
|
// [RH] Moved console commands out of d_netcmd.c (in Cajun source), because
|
|
// they don't really belong there.
|
|
|
|
#include "c_cvars.h"
|
|
#include "c_dispatch.h"
|
|
#include "b_bot.h"
|
|
#include "m_argv.h"
|
|
#include "doomstat.h"
|
|
#include "p_local.h"
|
|
#include "cmdlib.h"
|
|
#include "teaminfo.h"
|
|
#include "d_net.h"
|
|
#include "serializer.h"
|
|
#include "d_player.h"
|
|
|
|
IMPLEMENT_CLASS(DBot, false, true)
|
|
|
|
IMPLEMENT_POINTERS_START(DBot)
|
|
IMPLEMENT_POINTER(dest)
|
|
IMPLEMENT_POINTER(prev)
|
|
IMPLEMENT_POINTER(enemy)
|
|
IMPLEMENT_POINTER(missile)
|
|
IMPLEMENT_POINTER(mate)
|
|
IMPLEMENT_POINTER(last_mate)
|
|
IMPLEMENT_POINTERS_END
|
|
|
|
DBot::DBot ()
|
|
: DThinker(STAT_BOT)
|
|
{
|
|
Clear ();
|
|
}
|
|
|
|
void DBot::Clear ()
|
|
{
|
|
player = NULL;
|
|
Angle = 0.;
|
|
dest = NULL;
|
|
prev = NULL;
|
|
enemy = NULL;
|
|
missile = NULL;
|
|
mate = NULL;
|
|
last_mate = NULL;
|
|
memset(&skill, 0, sizeof(skill));
|
|
t_active = 0;
|
|
t_respawn = 0;
|
|
t_strafe = 0;
|
|
t_react = 0;
|
|
t_fight = 0;
|
|
t_roam = 0;
|
|
t_rocket = 0;
|
|
first_shot = true;
|
|
sleft = false;
|
|
allround = false;
|
|
increase = false;
|
|
old = { 0, 0 };
|
|
}
|
|
|
|
FSerializer &Serialize(FSerializer &arc, const char *key, botskill_t &skill, botskill_t *def)
|
|
{
|
|
if (arc.BeginObject(key))
|
|
{
|
|
arc("aiming", skill.aiming)
|
|
("perfection", skill.perfection)
|
|
("reaction", skill.reaction)
|
|
("isp", skill.isp)
|
|
.EndObject();
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
void DBot::Serialize(FSerializer &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
|
|
arc("player", player)
|
|
("angle", Angle)
|
|
("dest", dest)
|
|
("prev", prev)
|
|
("enemy", enemy)
|
|
("missile", missile)
|
|
("mate", mate)
|
|
("lastmate", last_mate)
|
|
("skill", skill)
|
|
("active", t_active)
|
|
("respawn", t_respawn)
|
|
("strafe", t_strafe)
|
|
("react", t_react)
|
|
("fight", t_fight)
|
|
("roam", t_roam)
|
|
("rocket", t_rocket)
|
|
("firstshot", first_shot)
|
|
("sleft", sleft)
|
|
("allround", allround)
|
|
("increase", increase)
|
|
("old", old);
|
|
}
|
|
|
|
void DBot::Tick ()
|
|
{
|
|
Super::Tick ();
|
|
|
|
if (player->mo == NULL || bglobal.freeze)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BotThinkCycles.Clock();
|
|
bglobal.m_Thinking = true;
|
|
Think ();
|
|
bglobal.m_Thinking = false;
|
|
BotThinkCycles.Unclock();
|
|
}
|
|
|
|
CVAR (Int, bot_next_color, 11, 0)
|
|
CVAR (Bool, bot_observer, false, 0)
|
|
|
|
CCMD (addbot)
|
|
{
|
|
if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION)
|
|
{
|
|
Printf ("Bots cannot be added when not in a game!\n");
|
|
return;
|
|
}
|
|
|
|
if (!players[consoleplayer].settings_controller)
|
|
{
|
|
Printf ("Only setting controllers can add bots\n");
|
|
return;
|
|
}
|
|
|
|
if (argv.argc() > 2)
|
|
{
|
|
Printf ("addbot [botname] : add a bot to the game\n");
|
|
return;
|
|
}
|
|
|
|
if (argv.argc() > 1)
|
|
bglobal.SpawnBot (argv[1]);
|
|
else
|
|
bglobal.SpawnBot (NULL);
|
|
}
|
|
|
|
void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
|
{
|
|
if (players[i].mo)
|
|
{
|
|
players[i].mo->Destroy ();
|
|
players[i].mo = NULL;
|
|
}
|
|
botinfo_t *bot = botinfo;
|
|
while (bot && stricmp (players[i].userinfo.GetName(), bot->name))
|
|
bot = bot->next;
|
|
if (bot)
|
|
{
|
|
bot->inuse = BOTINUSE_No;
|
|
bot->lastteam = keepTeam ? players[i].userinfo.GetTeam() : TEAM_NONE;
|
|
}
|
|
if (players[i].Bot != NULL)
|
|
{
|
|
players[i].Bot->Destroy ();
|
|
players[i].Bot = NULL;
|
|
}
|
|
players[i].~player_t();
|
|
::new(&players[i]) player_t;
|
|
players[i].userinfo.Reset();
|
|
playeringame[i] = false;
|
|
}
|
|
|
|
CCMD (removebots)
|
|
{
|
|
if (!players[consoleplayer].settings_controller)
|
|
{
|
|
Printf ("Only setting controllers can remove bots\n");
|
|
return;
|
|
}
|
|
|
|
Net_WriteByte (DEM_KILLBOTS);
|
|
}
|
|
|
|
CCMD (freeze)
|
|
{
|
|
if (CheckCheatmode ())
|
|
return;
|
|
|
|
if (netgame && !players[consoleplayer].settings_controller)
|
|
{
|
|
Printf ("Only setting controllers can use freeze mode\n");
|
|
return;
|
|
}
|
|
|
|
Net_WriteByte (DEM_GENERICCHEAT);
|
|
Net_WriteByte (CHT_FREEZE);
|
|
}
|
|
|
|
CCMD (listbots)
|
|
{
|
|
botinfo_t *thebot = bglobal.botinfo;
|
|
int count = 0;
|
|
|
|
while (thebot)
|
|
{
|
|
Printf ("%s%s\n", thebot->name, thebot->inuse == BOTINUSE_Yes ? " (active)" : "");
|
|
thebot = thebot->next;
|
|
count++;
|
|
}
|
|
Printf ("> %d bots\n", count);
|
|
}
|
|
|
|
// set the bot specific weapon information
|
|
// This is intentionally not in the weapon definition anymore.
|
|
void InitBotStuff()
|
|
{
|
|
static struct BotInit
|
|
{
|
|
const char *type;
|
|
int movecombatdist;
|
|
int weaponflags;
|
|
const char *projectile;
|
|
} botinits[] = {
|
|
|
|
{ "Pistol", 25000000, 0, NULL },
|
|
{ "Shotgun", 24000000, 0, NULL },
|
|
{ "SuperShotgun", 15000000, 0, NULL },
|
|
{ "Chaingun", 27000000, 0, NULL },
|
|
{ "RocketLauncher", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "Rocket" },
|
|
{ "PlasmaRifle", 27000000, 0, "PlasmaBall" },
|
|
{ "BFG9000", 10000000, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_BFG, "BFGBall" },
|
|
{ "GoldWand", 25000000, 0, NULL },
|
|
{ "GoldWandPowered", 25000000, 0, NULL },
|
|
{ "Crossbow", 24000000, 0, "CrossbowFX1" },
|
|
{ "CrossbowPowered", 24000000, 0, "CrossbowFX2" },
|
|
{ "Blaster", 27000000, 0, NULL },
|
|
{ "BlasterPowered", 27000000, 0, "BlasterFX1" },
|
|
{ "SkullRod", 27000000, 0, "HornRodFX1" },
|
|
{ "SkullRodPowered", 27000000, 0, "HornRodFX2" },
|
|
{ "PhoenixRod", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "PhoenixFX1" },
|
|
{ "Mace", 27000000, WIF_BOT_REACTION_SKILL_THING, "MaceFX2" },
|
|
{ "MacePowered", 27000000, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "MaceFX4" },
|
|
{ "FWeapHammer", 22000000, 0, "HammerMissile" },
|
|
{ "FWeapQuietus", 20000000, 0, "FSwordMissile" },
|
|
{ "CWeapStaff", 25000000, 0, "CStaffMissile" },
|
|
{ "CWeapFlane", 27000000, 0, "CFlameMissile" },
|
|
{ "MWeapWand", 25000000, 0, "MageWandMissile" },
|
|
{ "CWeapWraithverge", 22000000, 0, "HolyMissile" },
|
|
{ "MWeapFrost", 19000000, 0, "FrostMissile" },
|
|
{ "MWeapLightning", 23000000, 0, "LightningFloor" },
|
|
{ "MWeapBloodscourge", 20000000, 0, "MageStaffFX2" },
|
|
{ "StrifeCrossbow", 24000000, 0, "ElectricBolt" },
|
|
{ "StrifeCrossbow2", 24000000, 0, "PoisonBolt" },
|
|
{ "AssaultGun", 27000000, 0, NULL },
|
|
{ "MiniMissileLauncher", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "MiniMissile" },
|
|
{ "FlameThrower", 24000000, 0, "FlameMissile" },
|
|
{ "Mauler", 15000000, 0, NULL },
|
|
{ "Mauler2", 10000000, 0, "MaulerTorpedo" },
|
|
{ "StrifeGrenadeLauncher", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "HEGrenade" },
|
|
{ "StrifeGrenadeLauncher2", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "PhosphorousGrenade" },
|
|
};
|
|
|
|
for(unsigned i=0;i<sizeof(botinits)/sizeof(botinits[0]);i++)
|
|
{
|
|
const PClass *cls = PClass::FindClass(botinits[i].type);
|
|
if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
|
{
|
|
AWeapon *w = (AWeapon*)GetDefaultByType(cls);
|
|
if (w != NULL)
|
|
{
|
|
w->MoveCombatDist = botinits[i].movecombatdist/65536.;
|
|
w->WeaponFlags |= botinits[i].weaponflags;
|
|
w->ProjectileType = PClass::FindActor(botinits[i].projectile);
|
|
}
|
|
}
|
|
}
|
|
|
|
static const char *warnbotmissiles[] = { "PlasmaBall", "Ripper", "HornRodFX1" };
|
|
for(unsigned i=0;i<countof(warnbotmissiles);i++)
|
|
{
|
|
AActor *a = GetDefaultByName (warnbotmissiles[i]);
|
|
if (a != NULL)
|
|
{
|
|
a->flags3|=MF3_WARNBOT;
|
|
}
|
|
}
|
|
}
|