in doom_py/src/vizdoom/src/d_net.cpp [2137:2700]
void Net_DoCommand (int type, BYTE **stream, int player)
{
BYTE pos = 0;
char *s = NULL;
int i;
switch (type)
{
case DEM_SAY:
{
const char *name = players[player].userinfo.GetName();
BYTE who = ReadByte (stream);
s = ReadString (stream);
CleanseString (s);
if (((who & 1) == 0) || players[player].userinfo.GetTeam() == TEAM_NONE)
{ // Said to everyone
if (who & 2)
{
Printf (PRINT_CHAT, TEXTCOLOR_BOLD "* %s" TEXTCOLOR_BOLD "%s" TEXTCOLOR_BOLD "\n", name, s);
}
else
{
Printf (PRINT_CHAT, "%s" TEXTCOLOR_CHAT ": %s" TEXTCOLOR_CHAT "\n", name, s);
}
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE);
}
else if (players[player].userinfo.GetTeam() == players[consoleplayer].userinfo.GetTeam())
{ // Said only to members of the player's team
if (who & 2)
{
Printf (PRINT_TEAMCHAT, TEXTCOLOR_BOLD "* (%s" TEXTCOLOR_BOLD ")%s" TEXTCOLOR_BOLD "\n", name, s);
}
else
{
Printf (PRINT_TEAMCHAT, "(%s" TEXTCOLOR_TEAMCHAT "): %s" TEXTCOLOR_TEAMCHAT "\n", name, s);
}
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE);
}
}
break;
case DEM_MUSICCHANGE:
s = ReadString (stream);
S_ChangeMusic (s);
break;
case DEM_PRINT:
s = ReadString (stream);
Printf ("%s", s);
break;
case DEM_CENTERPRINT:
s = ReadString (stream);
C_MidPrint (SmallFont, s);
break;
case DEM_UINFCHANGED:
D_ReadUserInfoStrings (player, stream, true);
break;
case DEM_SINFCHANGED:
D_DoServerInfoChange (stream, false);
break;
case DEM_SINFCHANGEDXOR:
D_DoServerInfoChange (stream, true);
break;
case DEM_GIVECHEAT:
s = ReadString (stream);
cht_Give (&players[player], s, ReadWord (stream));
break;
case DEM_TAKECHEAT:
s = ReadString (stream);
cht_Take (&players[player], s, ReadWord (stream));
break;
case DEM_WARPCHEAT:
{
int x, y;
x = ReadWord (stream);
y = ReadWord (stream);
P_TeleportMove (players[player].mo, x * 65536, y * 65536, ONFLOORZ, true);
}
break;
case DEM_GENERICCHEAT:
cht_DoCheat (&players[player], ReadByte (stream));
break;
case DEM_CHANGEMAP2:
pos = ReadByte (stream);
/* intentional fall-through */
case DEM_CHANGEMAP:
// Change to another map without disconnecting other players
s = ReadString (stream);
// Using LEVEL_NOINTERMISSION tends to throw the game out of sync.
// That was a long time ago. Maybe it works now?
level.flags |= LEVEL_CHANGEMAPCHEAT;
G_ChangeLevel(s, pos, 0);
break;
case DEM_SUICIDE:
cht_Suicide (&players[player]);
break;
case DEM_ADDBOT:
bglobal.TryAddBot (stream, player);
break;
case DEM_KILLBOTS:
bglobal.RemoveAllBots (true);
Printf ("Removed all bots\n");
break;
case DEM_CENTERVIEW:
players[player].centering = true;
break;
case DEM_INVUSEALL:
if (gamestate == GS_LEVEL && !paused)
{
AInventory *item = players[player].mo->Inventory;
while (item != NULL)
{
AInventory *next = item->Inventory;
if (item->ItemFlags & IF_INVBAR && !(item->IsKindOf(RUNTIME_CLASS(APuzzleItem))))
{
players[player].mo->UseInventory (item);
}
item = next;
}
}
break;
case DEM_INVUSE:
case DEM_INVDROP:
{
DWORD which = ReadLong (stream);
if (gamestate == GS_LEVEL && !paused
&& players[player].playerstate != PST_DEAD)
{
AInventory *item = players[player].mo->Inventory;
while (item != NULL && item->InventoryID != which)
{
item = item->Inventory;
}
if (item != NULL)
{
if (type == DEM_INVUSE)
{
players[player].mo->UseInventory (item);
}
else
{
players[player].mo->DropInventory (item);
}
}
}
}
break;
case DEM_SUMMON:
case DEM_SUMMONFRIEND:
case DEM_SUMMONFOE:
case DEM_SUMMONMBF:
case DEM_SUMMON2:
case DEM_SUMMONFRIEND2:
case DEM_SUMMONFOE2:
{
const PClass *typeinfo;
int angle = 0;
SWORD tid = 0;
BYTE special = 0;
int args[5];
s = ReadString (stream);
if (type >= DEM_SUMMON2 && type <= DEM_SUMMONFOE2)
{
angle = ReadWord(stream);
tid = ReadWord(stream);
special = ReadByte(stream);
for(i = 0; i < 5; i++) args[i] = ReadLong(stream);
}
typeinfo = PClass::FindClass (s);
if (typeinfo != NULL && typeinfo->ActorInfo != NULL)
{
AActor *source = players[player].mo;
if (source != NULL)
{
if (GetDefaultByType (typeinfo)->flags & MF_MISSILE)
{
P_SpawnPlayerMissile (source, typeinfo);
}
else
{
const AActor *def = GetDefaultByType (typeinfo);
fixedvec3 spawnpos = source->Vec3Angle(def->radius * 2 + source->radius, source->angle, 8 * FRACUNIT);
AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE);
if (spawned != NULL)
{
if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF)
{
if (spawned->CountsAsKill())
{
level.total_monsters--;
}
spawned->FriendPlayer = player + 1;
spawned->flags |= MF_FRIENDLY;
spawned->LastHeard = players[player].mo;
spawned->health = spawned->SpawnHealth();
if (type == DEM_SUMMONMBF)
spawned->flags3 |= MF3_NOBLOCKMONST;
}
else if (type == DEM_SUMMONFOE || type == DEM_SUMMONFOE2)
{
spawned->FriendPlayer = 0;
spawned->flags &= ~MF_FRIENDLY;
spawned->health = spawned->SpawnHealth();
}
}
if (type >= DEM_SUMMON2 && type <= DEM_SUMMONFOE2)
{
spawned->angle = source->angle - (ANGLE_1 * angle);
spawned->tid = tid;
spawned->special = special;
for(i = 0; i < 5; i++) {
spawned->args[i] = args[i];
}
if(tid) spawned->AddToHash();
}
}
}
}
}
break;
case DEM_SPRAY:
{
FTraceResults trace;
angle_t ang = players[player].mo->angle >> ANGLETOFINESHIFT;
angle_t pitch = (angle_t)(players[player].mo->pitch) >> ANGLETOFINESHIFT;
fixed_t vx = FixedMul (finecosine[pitch], finecosine[ang]);
fixed_t vy = FixedMul (finecosine[pitch], finesine[ang]);
fixed_t vz = -finesine[pitch];
s = ReadString (stream);
if (Trace (players[player].mo->X(), players[player].mo->Y(),
players[player].mo->Top() - (players[player].mo->height>>2),
players[player].mo->Sector,
vx, vy, vz, 172*FRACUNIT, 0, ML_BLOCKEVERYTHING, players[player].mo,
trace, TRACE_NoSky))
{
if (trace.HitType == TRACE_HitWall)
{
DImpactDecal::StaticCreate (s,
trace.X, trace.Y, trace.Z,
trace.Line->sidedef[trace.Side], NULL);
}
}
}
break;
case DEM_PAUSE:
if (gamestate == GS_LEVEL)
{
if (paused)
{
paused = 0;
S_ResumeSound (false);
}
else
{
paused = player + 1;
S_PauseSound (false, false);
}
V_SetBorderNeedRefresh();
}
break;
case DEM_SAVEGAME:
if (gamestate == GS_LEVEL)
{
s = ReadString (stream);
savegamefile = s;
delete[] s;
s = ReadString (stream);
memset (savedescription, 0, sizeof(savedescription));
strncpy (savedescription, s, sizeof(savedescription));
if (player != consoleplayer)
{
// Paths sent over the network will be valid for the system that sent
// the save command. For other systems, the path needs to be changed.
const char *fileonly = savegamefile.GetChars();
const char *slash = strrchr (fileonly, '\\');
if (slash != NULL)
{
fileonly = slash + 1;
}
slash = strrchr (fileonly, '/');
if (slash != NULL)
{
fileonly = slash + 1;
}
if (fileonly != savegamefile.GetChars())
{
savegamefile = G_BuildSaveName (fileonly, -1);
}
}
}
gameaction = ga_savegame;
break;
case DEM_CHECKAUTOSAVE:
// Do not autosave in multiplayer games or when dead.
// For demo playback, DEM_DOAUTOSAVE already exists in the demo if the
// autosave happened. And if it doesn't, we must not generate it.
if (multiplayer ||
demoplayback ||
players[consoleplayer].playerstate != PST_LIVE ||
disableautosave >= 2 ||
autosavecount == 0)
{
break;
}
Net_WriteByte (DEM_DOAUTOSAVE);
break;
case DEM_DOAUTOSAVE:
gameaction = ga_autosave;
break;
case DEM_FOV:
{
float newfov = (float)ReadByte (stream);
if (newfov != players[consoleplayer].DesiredFOV)
{
Printf ("FOV%s set to %g\n",
consoleplayer == Net_Arbitrator ? " for everyone" : "",
newfov);
}
for (i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i])
{
players[i].DesiredFOV = newfov;
}
}
}
break;
case DEM_MYFOV:
players[player].DesiredFOV = (float)ReadByte (stream);
break;
case DEM_RUNSCRIPT:
case DEM_RUNSCRIPT2:
{
int snum = ReadWord (stream);
int argn = ReadByte (stream);
RunScript(stream, players[player].mo, snum, argn, (type == DEM_RUNSCRIPT2) ? ACS_ALWAYS : 0);
}
break;
case DEM_RUNNAMEDSCRIPT:
{
char *sname = ReadString(stream);
int argn = ReadByte(stream);
RunScript(stream, players[player].mo, -FName(sname), argn & 127, (argn & 128) ? ACS_ALWAYS : 0);
}
break;
case DEM_RUNSPECIAL:
{
int snum = ReadByte(stream);
int argn = ReadByte(stream);
int arg[5] = { 0, 0, 0, 0, 0 };
for (i = 0; i < argn; ++i)
{
int argval = ReadLong(stream);
if ((unsigned)i < countof(arg))
{
arg[i] = argval;
}
}
if (!CheckCheatmode(player == consoleplayer))
{
P_ExecuteSpecial(snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
}
}
break;
case DEM_CROUCH:
if (gamestate == GS_LEVEL && players[player].mo != NULL &&
players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP) &&
!P_IsPlayerTotallyFrozen(&players[player]))
{
players[player].crouching = players[player].crouchdir < 0 ? 1 : -1;
}
break;
case DEM_MORPHEX:
{
s = ReadString (stream);
const char *msg = cht_Morph (players + player, PClass::FindClass (s), false);
if (player == consoleplayer)
{
Printf ("%s\n", *msg != '\0' ? msg : "Morph failed.");
}
}
break;
case DEM_ADDCONTROLLER:
{
BYTE playernum = ReadByte (stream);
players[playernum].settings_controller = true;
if (consoleplayer == playernum || consoleplayer == Net_Arbitrator)
Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.GetName());
}
break;
case DEM_DELCONTROLLER:
{
BYTE playernum = ReadByte (stream);
players[playernum].settings_controller = false;
if (consoleplayer == playernum || consoleplayer == Net_Arbitrator)
Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.GetName());
}
break;
case DEM_KILLCLASSCHEAT:
{
char *classname = ReadString (stream);
int killcount = 0;
const PClass *cls = PClass::FindClass(classname);
if (cls != NULL && cls->ActorInfo != NULL)
{
killcount = KillAll(cls);
const PClass *cls_rep = cls->GetReplacement();
if (cls != cls_rep)
{
killcount += KillAll(cls_rep);
}
Printf ("Killed %d monsters of type %s.\n",killcount, classname);
}
else
{
Printf ("%s is not an actor class.\n", classname);
}
}
break;
case DEM_REMOVE:
{
char *classname = ReadString(stream);
int removecount = 0;
const PClass *cls = PClass::FindClass(classname);
if (cls != NULL && cls->ActorInfo != NULL)
{
removecount = RemoveClass(cls);
const PClass *cls_rep = cls->GetReplacement();
if (cls != cls_rep)
{
removecount += RemoveClass(cls_rep);
}
Printf("Removed %d actors of type %s.\n", removecount, classname);
}
else
{
Printf("%s is not an actor class.\n", classname);
}
}
break;
case DEM_CONVREPLY:
case DEM_CONVCLOSE:
case DEM_CONVNULL:
P_ConversationCommand (type, player, stream);
break;
case DEM_SETSLOT:
case DEM_SETSLOTPNUM:
{
int pnum;
if (type == DEM_SETSLOTPNUM)
{
pnum = ReadByte(stream);
}
else
{
pnum = player;
}
unsigned int slot = ReadByte(stream);
int count = ReadByte(stream);
if (slot < NUM_WEAPON_SLOTS)
{
players[pnum].weapons.Slots[slot].Clear();
}
for(i = 0; i < count; ++i)
{
const PClass *wpn = Net_ReadWeapon(stream);
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
}
}
break;
case DEM_ADDSLOT:
{
int slot = ReadByte(stream);
const PClass *wpn = Net_ReadWeapon(stream);
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
}
break;
case DEM_ADDSLOTDEFAULT:
{
int slot = ReadByte(stream);
const PClass *wpn = Net_ReadWeapon(stream);
players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer);
}
break;
case DEM_SETPITCHLIMIT:
players[player].MinPitch = ReadByte(stream) * -ANGLE_1; // up
players[player].MaxPitch = ReadByte(stream) * ANGLE_1; // down
break;
case DEM_ADVANCEINTER:
F_AdvanceIntermission();
break;
case DEM_REVERTCAMERA:
players[player].camera = players[player].mo;
break;
case DEM_FINISHGAME:
// Simulate an end-of-game action
G_ChangeLevel(NULL, 0, 0);
break;
default:
I_Error ("Unknown net command: %d", type);
break;
}
if (s)
delete[] s;
}