From 4b723bedddbb1a614d1c82d172643b482b08fc6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 20 Feb 2009 22:28:48 +0000 Subject: [PATCH] - Bumped netgame, demo and min demo version for the weapon slot changes. - changed weapon slots to be stored per player. Information is now transmitted across the network so that all machines know each player's current weapon configuration so that it can be used by cheats or HUD display routines. SVN r1430 (trunk) --- docs/rh-log.txt | 4 + src/d_net.cpp | 50 +++++++++ src/d_player.h | 2 + src/d_protocol.cpp | 7 ++ src/d_protocol.h | 4 + src/g_game.cpp | 6 +- src/g_shared/a_pickups.h | 9 +- src/g_shared/a_weapons.cpp | 167 ++++++++++++++++++++++-------- src/g_shared/sbarinfo_display.cpp | 4 +- src/g_shared/shared_hud.cpp | 18 ++-- src/m_cheat.cpp | 10 +- src/p_mobj.cpp | 2 +- src/version.h | 6 +- 13 files changed, 218 insertions(+), 71 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 83c59e364..f44d50aad 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,8 @@ February 20, 2009 (Changes by Graf Zahl) +- Bumped netgame, demo and min demo version for the weapon slot changes. +- changed weapon slots to be stored per player. Information is now transmitted + across the network so that all machines know each player's current weapon + configuration so that it can be used by cheats or HUD display routines. - fixed: level_info_t::mapbg was not initialized February 17, 2009 diff --git a/src/d_net.cpp b/src/d_net.cpp index fd092b49e..3400e45da 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2378,6 +2378,40 @@ void Net_DoCommand (int type, BYTE **stream, int player) P_ConversationCommand (player, stream); break; + case DEM_SETSLOT: + { + BYTE playernum = ReadByte(stream); + BYTE slot = ReadByte(stream); + BYTE count = ReadByte(stream); + TArray weapons; + + weapons.Resize(count); + for(int i = 0; i < count; i++) + { + weapons[i] = ReadStringConst(stream); + } + players[playernum].weapons.SetSlot(slot, weapons); + } + break; + + case DEM_ADDSLOT: + { + BYTE playernum = ReadByte(stream); + BYTE slot = ReadByte(stream); + const char *weap = ReadStringConst(stream); + players[playernum].weapons.AddSlot(slot, weap); + } + break; + + case DEM_ADDSLOTDEFAULT: + { + BYTE playernum = ReadByte(stream); + BYTE slot = ReadByte(stream); + const char *weap = ReadStringConst(stream); + players[playernum].weapons.AddSlotDefault(slot, weap); + } + break; + default: I_Error ("Unknown net command: %d", type); break; @@ -2496,6 +2530,22 @@ void Net_SkipCommand (int type, BYTE **stream) } break; + case DEM_SETSLOT: + { + skip = 3; + for(int numweapons = *(*stream + 2); numweapons > 0; numweapons--) + { + skip += strlen ((char *)(*stream + skip)) + 1; + } + } + break; + + case DEM_ADDSLOT: + case DEM_ADDSLOTDEFAULT: + skip = strlen ((char *)(*stream + 2)) + 3; + break; + + default: return; } diff --git a/src/d_player.h b/src/d_player.h index b78ae5a30..709257860 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -362,6 +362,8 @@ public: fixed_t crouchoffset; fixed_t crouchviewdelta; + FWeaponSlots weapons; + // [CW] I moved these here for multiplayer conversation support. TObjPtr ConversationNPC, ConversationPC; angle_t ConversationNPCAngle; diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 0508157c1..25008ca1e 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -49,6 +49,13 @@ char *ReadString (BYTE **stream) return copystring (string); } +const char *ReadStringConst(BYTE **stream) +{ + const char *string = *((const char **)stream); + *stream += strlen (string) + 1; + return string; +} + int ReadByte (BYTE **stream) { BYTE v = **stream; diff --git a/src/d_protocol.h b/src/d_protocol.h index cf268c746..9812ca3f2 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -151,6 +151,9 @@ enum EDemoCommand DEM_SUMMON2, // 52 String: Thing to fabricate, WORD: angle offset DEM_SUMMONFRIEND2, // 53 DEM_SUMMONFOE2, // 54 + DEM_ADDSLOTDEFAULT, // 55 + DEM_ADDSLOT, // 56 + DEM_SETSLOT, // 57 }; // The following are implemented by cht_DoCheat in m_cheat.cpp @@ -226,6 +229,7 @@ int ReadWord (BYTE **stream); int ReadLong (BYTE **stream); float ReadFloat (BYTE **stream); char *ReadString (BYTE **stream); +const char *ReadStringConst(BYTE **stream); void WriteByte (BYTE val, BYTE **stream); void WriteWord (short val, BYTE **stream); void WriteLong (int val, BYTE **stream); diff --git a/src/g_game.cpp b/src/g_game.cpp index e5b3ce8df..d78aba115 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -264,7 +264,7 @@ CCMD (slot) if (slot < NUM_WEAPON_SLOTS) { - SendItemUse = LocalWeapons.Slots[slot].PickWeapon (&players[consoleplayer]); + SendItemUse = players[consoleplayer].weapons.Slots[slot].PickWeapon (&players[consoleplayer]); } } } @@ -296,12 +296,12 @@ CCMD (turn180) CCMD (weapnext) { - SendItemUse = LocalWeapons.PickNextWeapon (&players[consoleplayer]); + SendItemUse = players[consoleplayer].weapons.PickNextWeapon (&players[consoleplayer]); } CCMD (weapprev) { - SendItemUse = LocalWeapons.PickPrevWeapon (&players[consoleplayer]); + SendItemUse = players[consoleplayer].weapons.PickPrevWeapon (&players[consoleplayer]); } CCMD (invnext) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index f98518686..50c65a6bc 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -71,11 +71,16 @@ struct FWeaponSlots void SetFromPlayer(const PClass *type); void CompleteSetup(const PClass *type); int RestoreSlots (FConfigFile *config, const char *section); + void PrintSettings(); + + void SetSlot(int slot, TArray argv); + void AddSlot(int slot, const char *name); + void AddSlotDefault(int slot, const char *name); + }; void P_PlaybackKeyConfWeapons(); -void P_SetLocalWeapons(AActor *player); -extern FWeaponSlots LocalWeapons; +void P_CompleteWeaponSetup(int playernum, const PClass *type); /************************************************************************/ /* Class definitions */ diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 22fa776d2..400106ef3 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -16,6 +16,7 @@ #include "thingdef/thingdef.h" #include "doomstat.h" #include "g_level.h" +#include "d_net.h" #define BONUSADD 6 @@ -27,6 +28,7 @@ END_POINTERS FString WeaponSection; TArray KeyConfWeapons; +bool PlayingKeyConf; //=========================================================================== // @@ -909,18 +911,18 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index) { if (player->PendingWeapon != WP_NOCHANGE) { - return LocalWeapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); + return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); } else if (player->ReadyWeapon != NULL) { AWeapon *weap = player->ReadyWeapon; - if (!LocalWeapons.LocateWeapon(weap->GetClass(), slot, index)) + if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index)) { // If the current weapon wasn't found and is powered up, // look for its non-powered up version. if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL) { - return LocalWeapons.LocateWeapon(weap->SisterWeaponType, slot, index); + return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index); } return false; } @@ -973,7 +975,7 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - const PClass *type = LocalWeapons.Slots[slot].GetWeapon(index); + const PClass *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1026,7 +1028,7 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - const PClass *type = LocalWeapons.Slots[slot].GetWeapon(index); + const PClass *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -1121,6 +1123,25 @@ void FWeaponSlots::CompleteSetup(const PClass *type) } } +void P_CompleteWeaponSetup(int playernum, const PClass *type) +{ + // Set up the weapon slots locally + LocalWeapons.CompleteSetup(type); + // Now transmit them across the network + for (int i = 0; i < NUM_WEAPON_SLOTS; ++i) + { + Net_WriteByte(DEM_SETSLOT); + Net_WriteByte(playernum); + Net_WriteByte(i); + Net_WriteByte(LocalWeapons.Slots[i].Size()); + for(int j = 0; j < LocalWeapons.Slots[i].Size(); j++) + { + const PClass *cls = LocalWeapons.Slots[i].GetWeapon(j); + if (cls != NULL) Net_WriteString(cls->TypeName.GetChars()); + } + } +} + //=========================================================================== // // FWeaponSlots :: SetFromPlayer @@ -1184,6 +1205,35 @@ int FWeaponSlots::RestoreSlots(FConfigFile *config, const char *section) // CCMD setslot // //=========================================================================== +void FWeaponSlots::SetSlot(int slot, TArray argv) +{ + Slots[slot].Clear(); + for (int i = 0; i < argv.Size(); ++i) + { + if (!Slots[slot].AddWeapon (argv[i])) + { + Printf ("Could not add %s to slot %d\n", argv[i], slot); + } + } +} + + +void FWeaponSlots::PrintSettings() +{ + for (int i = 1; i <= NUM_WEAPON_SLOTS; ++i) + { + int slot = i % NUM_WEAPON_SLOTS; + if (Slots[slot].Size() > 0) + { + Printf("Slot[%d]=", slot); + for (int j = 0; j < Slots[slot].Size(); ++j) + { + Printf("%s ", Slots[slot].GetWeapon(j)->TypeName.GetChars()); + } + Printf("\n"); + } + } +} CCMD (setslot) { @@ -1203,19 +1253,7 @@ CCMD (setslot) } Printf("%s.Weapons]\n", players[consoleplayer].mo->GetClass()->TypeName.GetChars()); } - for (int i = 1; i <= NUM_WEAPON_SLOTS; ++i) - { - int slot = i % NUM_WEAPON_SLOTS; - if (LocalWeapons.Slots[slot].Size() > 0) - { - Printf("Slot[%d]=", slot); - for (int j = 0; j < LocalWeapons.Slots[slot].Size(); ++j) - { - Printf("%s ", LocalWeapons.Slots[slot].GetWeapon(j)->TypeName.GetChars()); - } - Printf("\n"); - } - } + players[consoleplayer].weapons.PrintSettings(); return; } @@ -1223,22 +1261,32 @@ CCMD (setslot) { KeyConfWeapons.Push(argv.args()); } + else if (PlayingKeyConf) + { + BYTE count = argv.argc()-2; + TArray weapons; + + weapons.Resize(count); + for(int i = 0; i < count; i++) + { + weapons[i] = argv[i+2]; + } + LocalWeapons.SetSlot(slot, weapons); + } else { - LocalWeapons.Slots[slot].Clear(); if (argv.argc() == 2) { Printf ("Slot %d cleared\n", slot); } - else + + Net_WriteByte(DEM_SETSLOT); + Net_WriteByte(consoleplayer); + Net_WriteByte(slot); + Net_WriteByte(argv.argc()-2); + for (int i = 2; i < argv.argc(); i++) { - for (int i = 2; i < argv.argc(); ++i) - { - if (!LocalWeapons.Slots[slot].AddWeapon (argv[i])) - { - Printf ("Could not add %s to slot %d\n", argv[i], slot); - } - } + Net_WriteString(argv[i]); } } } @@ -1249,9 +1297,17 @@ CCMD (setslot) // //=========================================================================== +void FWeaponSlots::AddSlot(int slot, const char *name) +{ + if (!Slots[slot].AddWeapon (name)) + { + Printf ("Could not add %s to slot %zu\n", name, slot); + } +} + CCMD (addslot) { - size_t slot; + unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) { @@ -1263,12 +1319,16 @@ CCMD (addslot) { KeyConfWeapons.Push(argv.args()); } + else if (PlayingKeyConf) + { + LocalWeapons.AddSlot(int(slot), argv[2]); + } else { - if (!LocalWeapons.Slots[slot].AddWeapon (argv[2])) - { - Printf ("Could not add %s to slot %zu\n", argv[2], slot); - } + Net_WriteByte(DEM_ADDSLOT); + Net_WriteByte(consoleplayer); + Net_WriteByte(slot); + Net_WriteString(argv[2]); } } @@ -1291,6 +1351,26 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== +void FWeaponSlots::AddSlotDefault(int slot, const char *name) +{ + const PClass *type = PClass::FindClass (name); + if (type != NULL && type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + { + switch (AddDefaultWeapon (slot, type)) + { + case SLOTDEF_Full: + Printf ("Could not add %s to slot %d\n", name, slot); + break; + + default: + case SLOTDEF_Added: + break; + + case SLOTDEF_Exists: + break; + } + } +} CCMD (addslotdefault) { @@ -1307,26 +1387,23 @@ CCMD (addslotdefault) if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) { Printf ("%s is not a weapon\n", argv[2]); + return; } if (ParsingKeyConf) { KeyConfWeapons.Push(argv.args()); } + else if (PlayingKeyConf) + { + LocalWeapons.AddSlotDefault(int(slot), argv[2]); + } else { - switch (LocalWeapons.AddDefaultWeapon (slot, type)) - { - case SLOTDEF_Full: - Printf ("Could not add %s to slot %d\n", argv[2], slot); - break; - - case SLOTDEF_Added: - break; - - case SLOTDEF_Exists: - break; - } + Net_WriteByte(DEM_ADDSLOTDEFAULT); + Net_WriteByte(consoleplayer); + Net_WriteByte(slot); + Net_WriteString(argv[2]); } } @@ -1340,11 +1417,13 @@ CCMD (addslotdefault) void P_PlaybackKeyConfWeapons() { + PlayingKeyConf = true; for (unsigned int i = 0; i < KeyConfWeapons.Size(); ++i) { FString cmd(KeyConfWeapons[i]); AddCommandString(cmd.LockBuffer()); } + PlayingKeyConf = false; } //=========================================================================== diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp index 28a1363bb..702e38682 100644 --- a/src/g_shared/sbarinfo_display.cpp +++ b/src/g_shared/sbarinfo_display.cpp @@ -414,9 +414,9 @@ void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int a if((cmd.flags & DRAWIMAGE_WEAPONSLOT)) //weaponslots { drawAlt = 1; //draw off state until we know we have something. - for (int i = 0; i < LocalWeapons.Slots[cmd.value].Size(); i++) + for (int i = 0; i < CPlayer->weapons.Slots[cmd.value].Size(); i++) { - const PClass *weap = LocalWeapons.Slots[cmd.value].GetWeapon(i); + const PClass *weap = CPlayer->weapons.Slots[cmd.value].GetWeapon(i); if(weap == NULL) { continue; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 3a6271fa0..a1905aff9 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -491,14 +491,14 @@ static void AddAmmoToList(AWeapon * weapdef) } } -static int DrawAmmo(player_t * CPlayer, int x, int y) +static int DrawAmmo(player_t *CPlayer, int x, int y) { int i,j,k; char buf[256]; - AInventory * inv; + AInventory *inv; - AWeapon * wi=CPlayer->ReadyWeapon; + AWeapon *wi=CPlayer->ReadyWeapon; orderedammos.Clear(); @@ -506,9 +506,9 @@ static int DrawAmmo(player_t * CPlayer, int x, int y) // Do not check for actual presence in the inventory! // We want to show all ammo types that can be used by // the weapons in the weapon slots. - for (k=0;kweapons.Slots[k].Size(); j++) { - const PClass * weap = LocalWeapons.Slots[k].GetWeapon(j); + const PClass *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) AddAmmoToList((AWeapon*)GetDefaultByType(weap)); } @@ -628,17 +628,17 @@ static void DrawWeapons(player_t * CPlayer, int x, int y) // First draw all weapons in the inventory that are not assigned to a weapon slot for(inv=CPlayer->mo->Inventory;inv;inv=inv->Inventory) { - int slot, index; - if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && !LocalWeapons.LocateWeapon(RUNTIME_TYPE(inv), &slot, &index)) + if (inv->IsKindOf(RUNTIME_CLASS(AWeapon)) && + !CPlayer->weapons.LocateWeapon(RUNTIME_TYPE(inv), NULL, NULL)) { DrawOneWeapon(CPlayer, x, y, static_cast(inv)); } } // And now everything in the weapon slots back to front - for (k=NUM_WEAPON_SLOTS-1;k>=0;k--) for(j=LocalWeapons.Slots[k].Size()-1;j>=0;j--) + for (k = NUM_WEAPON_SLOTS - 1; k >= 0; k--) for(j = CPlayer->weapons.Slots[k].Size() - 1; j >= 0; j--) { - const PClass * weap = LocalWeapons.Slots[k].GetWeapon(j); + const PClass *weap = CPlayer->weapons.Slots[k].GetWeapon(j); if (weap) { inv=CPlayer->mo->FindInventory(weap); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index f8141e1a1..1401cd338 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -735,14 +735,10 @@ void cht_Give (player_t *player, const char *name, int amount) { // Give the weapon only if it belongs to the current game or - // is in a weapon slot. Unfortunately this check only works in - // singleplayer games because the weapon slots are stored locally. - // In multiplayer games or demos all weapons must be given because the state of - // the weapon slots is not guaranteed to be the same when recording or playing back. - if (multiplayer || demorecording || demoplayback || - type->ActorInfo->GameFilter == GAME_Any || + // is in a weapon slot. + if (type->ActorInfo->GameFilter == GAME_Any || (type->ActorInfo->GameFilter & gameinfo.gametype) || - LocalWeapons.LocateWeapon(type, NULL, NULL)) + player->weapons.LocateWeapon(type, NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 1370cd9b7..a4b22b175 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3771,7 +3771,7 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer) } if (playernum == consoleplayer) { - LocalWeapons.CompleteSetup(mobj->GetClass()); + P_CompleteWeaponSetup(consoleplayer, mobj->GetClass()); } return mobj; } diff --git a/src/version.h b/src/version.h index 10591266d..b8ff05a07 100644 --- a/src/version.h +++ b/src/version.h @@ -54,7 +54,7 @@ // Version identifier for network games. // Bump it every time you do a release unless you're certain you // didn't change anything that will affect sync. -#define NETGAMEVERSION 218 +#define NETGAMEVERSION 219 // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to @@ -64,11 +64,11 @@ // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. // Otherwise, it should be safe to leave it alone. -#define DEMOGAMEVERSION 0x20E +#define DEMOGAMEVERSION 0x20F // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. -#define MINDEMOVERSION 0x207 +#define MINDEMOVERSION 0x20F // SAVEVER is the version of the information stored in level snapshots. // Note that SAVEVER is not directly comparable to VERSION.