- 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)
This commit is contained in:
Christoph Oelckers 2009-02-20 22:28:48 +00:00
parent 125b0cefaf
commit 4b723beddd
13 changed files with 218 additions and 71 deletions

View File

@ -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

View File

@ -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<const char *> 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;
}

View File

@ -362,6 +362,8 @@ public:
fixed_t crouchoffset;
fixed_t crouchviewdelta;
FWeaponSlots weapons;
// [CW] I moved these here for multiplayer conversation support.
TObjPtr<AActor> ConversationNPC, ConversationPC;
angle_t ConversationNPCAngle;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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<const char *> 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 */

View File

@ -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<FString> 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<AWeapon *>(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<AWeapon *>(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<const char *> 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<const char *> 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;
}
//===========================================================================

View File

@ -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;

View File

@ -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;k<NUM_WEAPON_SLOTS;k++) for(j=0;j<LocalWeapons.Slots[k].Size();j++)
for (k = 0; k < NUM_WEAPON_SLOTS; k++) for(j = 0; j < CPlayer->weapons.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<AWeapon*>(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);

View File

@ -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))

View File

@ -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;
}

View File

@ -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.