- Fixed: Player names and chat macros that end with incomplete \c escapes now

have those escapes stripped before printing so that they do not merge with
  subsequent text.
- Moved default weapon slot assignments into the player classes.
  Weapon.SlotNumber is now used solely for mods that want to add new weapons
  without completely redoing the player's arsenal. Restored some config-based
  weapon slot customization, though slots are no longer automatically saved
  to the config and section names have changed slightly. However, unlike
  before, config slots are now the definitive word on slot assignments and
  cannot be overridden by any other files loaded.
- Fixed: Several weapons were missing a game filter from their definitions.
- Removed storage of weapon slots in the config so that weapon slots can
  be setup in the weapons themselves. Slots are still configurable, since
  they need to be for KEYCONF to work; any changes simply won't be saved
  when you quit.
- Removed limit on weapon slot sizes.


SVN r1428 (trunk)
This commit is contained in:
Randy Heit 2009-02-20 00:53:25 +00:00
parent 491abe3a2c
commit a7e40b56f6
38 changed files with 824 additions and 391 deletions

View file

@ -1,8 +1,22 @@
February 15, 2009 (Changes by Graf Zahl)
February 17, 2009
- Fixed: Player names and chat macros that end with incomplete \c escapes now
have those escapes stripped before printing so that they do not merge with
subsequent text.
February 15, 2009 (Changes by Graf Zahl)
- Fixed: The CHARFORMAT structure that is used to set the color in a Windows
Rich Edit control was not fully initialized resulting in incorrect colors
being set.
Feburary 14, 2009
- Moved default weapon slot assignments into the player classes.
Weapon.SlotNumber is now used solely for mods that want to add new weapons
without completely redoing the player's arsenal. Restored some config-based
weapon slot customization, though slots are no longer automatically saved
to the config and section names have changed slightly. However, unlike
before, config slots are now the definitive word on slot assignments and
cannot be overridden by any other files loaded.
February 14, 2009 (Changes by Graf Zahl)
- Added MF5_CANTSEEK flag to prevent seeker missiles from homing in on
certain actors and added an option to APowerInvisibility to set this
@ -22,6 +36,14 @@ February 14, 2009 (Changes by Graf Zahl)
- Fixed: The MAPINFO parser ignored missing terminating braces of the last
block in the file.
February 11, 2009
- Fixed: Several weapons were missing a game filter from their definitions.
- Removed storage of weapon slots in the config so that weapon slots can
be setup in the weapons themselves. Slots are still configurable, since
they need to be for KEYCONF to work; any changes simply won't be saved
when you quit.
- Removed limit on weapon slot sizes.
February 10, 2009
- Fixed: DirectInput8Create() used the wrong calling convention.
- Moved the V_InitFontColors() call earlier in the startup sequence so that

View file

@ -10,6 +10,8 @@
#include "doomtype.h"
#include "cmdlib.h"
#include "i_system.h"
#include "v_text.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
@ -590,6 +592,35 @@ FString strbin1 (const char *start)
return result;
}
//==========================================================================
//
// CleanseString
//
// Does some mild sanity checking on a string: If it ends with an incomplete
// color escape, the escape is removed.
//
//==========================================================================
void CleanseString(char *str)
{
char *escape = strrchr(str, TEXTCOLOR_ESCAPE);
if (escape != NULL)
{
if (escape[1] == '\0')
{
*escape = '\0';
}
else if (escape[1] == '[')
{
char *close = strchr(escape + 2, ']');
if (close == NULL)
{
*escape = '\0';
}
}
}
}
//==========================================================================
//
// ExpandEnvVars

View file

@ -53,6 +53,7 @@ const char *myasctime ();
int strbin (char *str);
FString strbin1 (const char *start);
void CleanseString (char *str);
void CreatePath(const char * fn);

View file

@ -251,7 +251,8 @@ bool FConfigFile::SetSection (const char *name, bool allowCreate)
//
// FConfigFile :: SetFirstSection
//
// Sets the current section to the first one in the file.
// Sets the current section to the first one in the file. Returns
// false if there are no sections.
//
//====================================================================
@ -270,7 +271,8 @@ bool FConfigFile::SetFirstSection ()
//
// FConfigFile :: SetNextSection
//
// Advances the current section to the next one in the file.
// Advances the current section to the next one in the file. Returns
// false if there are no more sections.
//
//====================================================================
@ -332,6 +334,43 @@ void FConfigFile::ClearCurrentSection ()
}
}
//====================================================================
//
// FConfigFile :: DeleteCurrentSection
//
// Completely removes the current section. The current section is
// advanced to the next section. Returns true if there is still a
// current section.
//
//====================================================================
bool FConfigFile::DeleteCurrentSection()
{
if (CurrentSection != NULL)
{
FConfigSection *sec;
ClearCurrentSection();
// Find the preceding section.
for (sec = Sections; sec != NULL && sec->Next != CurrentSection; sec = sec->Next)
{ }
sec->Next = CurrentSection->Next;
if (LastSectionPtr == &CurrentSection->Next)
{
LastSectionPtr = &sec->Next;
}
CurrentSection->~FConfigSection();
delete[] (char *)CurrentSection;
CurrentSection = sec->Next;
return CurrentSection != NULL;
}
return false;
}
//====================================================================
//
// FConfigFile :: ClearKey

View file

@ -59,6 +59,7 @@ public:
bool SetNextSection ();
const char *GetCurrentSection () const;
void ClearCurrentSection ();
bool DeleteCurrentSection ();
void ClearKey (const char *key);
bool SectionIsEmpty ();

View file

@ -2525,9 +2525,6 @@ void D_DoomMain (void)
FActorInfo::StaticInit ();
// Now that all actors have been defined we can finally set up the weapon slots
GameConfig->DoWeaponSetup (GameNames[gameinfo.gametype]);
// [GRB] Initialize player class list
SetupPlayerClasses ();

View file

@ -1963,15 +1963,16 @@ void Net_DoCommand (int type, BYTE **stream, int player)
BYTE who = ReadByte (stream);
s = ReadString (stream);
CleanseString (s);
if (((who & 1) == 0) || players[player].userinfo.team == TEAM_NONE)
{ // Said to everyone
if (who & 2)
{
Printf (PRINT_CHAT, TEXTCOLOR_BOLD "* %s%s\n", name, s);
Printf (PRINT_CHAT, TEXTCOLOR_BOLD "* %s" TEXTCOLOR_BOLD "%s" TEXTCOLOR_BOLD "\n", name, s);
}
else
{
Printf (PRINT_CHAT, "%s: %s\n", name, s);
Printf (PRINT_CHAT, "%s" TEXTCOLOR_CHAT ": %s" TEXTCOLOR_CHAT "\n", name, s);
}
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE);
}
@ -1979,11 +1980,11 @@ void Net_DoCommand (int type, BYTE **stream, int player)
{ // Said only to members of the player's team
if (who & 2)
{
Printf (PRINT_TEAMCHAT, TEXTCOLOR_BOLD "* (%s)%s\n", name, s);
Printf (PRINT_TEAMCHAT, TEXTCOLOR_BOLD "* (%s" TEXTCOLOR_BOLD ")%s" TEXTCOLOR_BOLD "\n", name, s);
}
else
{
Printf (PRINT_TEAMCHAT, "(%s): %s\n", name, s);
Printf (PRINT_TEAMCHAT, "(%s" TEXTCOLOR_TEAMCHAT "): %s" TEXTCOLOR_TEAMCHAT "\n", name, s);
}
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE);
}

View file

@ -55,6 +55,7 @@
#include "teaminfo.h"
#include "r_translate.h"
#include "templates.h"
#include "cmdlib.h"
static FRandom pr_pickteam ("PickRandomTeam");
@ -698,10 +699,10 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
{
char oldname[MAXPLAYERNAME+1];
strncpy (oldname, info->netname, MAXPLAYERNAME);
oldname[MAXPLAYERNAME] = 0;
strcpy (oldname, info->netname);
strncpy (info->netname, value, MAXPLAYERNAME);
info->netname[MAXPLAYERNAME] = 0;
CleanseString(info->netname);
if (update && strcmp (oldname, info->netname) != 0)
{

View file

@ -59,6 +59,16 @@ enum
APMETA_Hexenarmor2,
APMETA_Hexenarmor3,
APMETA_Hexenarmor4,
APMETA_Slot0,
APMETA_Slot1,
APMETA_Slot2,
APMETA_Slot3,
APMETA_Slot4,
APMETA_Slot5,
APMETA_Slot6,
APMETA_Slot7,
APMETA_Slot8,
APMETA_Slot9,
};
class player_t;

View file

@ -296,12 +296,12 @@ CCMD (turn180)
CCMD (weapnext)
{
SendItemUse = PickNextWeapon (&players[consoleplayer]);
SendItemUse = LocalWeapons.PickNextWeapon (&players[consoleplayer]);
}
CCMD (weapprev)
{
SendItemUse = PickPrevWeapon (&players[consoleplayer]);
SendItemUse = LocalWeapons.PickPrevWeapon (&players[consoleplayer]);
}
CCMD (invnext)

View file

@ -7,7 +7,6 @@
#define MAX_MANA 200
#define MAX_WEAPONS_PER_SLOT 8
#define NUM_WEAPON_SLOTS 10
class player_t;
@ -17,30 +16,39 @@ class AWeapon;
class FWeaponSlot
{
public:
FWeaponSlot ();
void Clear ();
FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; }
void Clear() { Weapons.Clear(); }
bool AddWeapon (const char *type);
bool AddWeapon (const PClass *type);
void AddWeaponList (const char *list, bool clear);
AWeapon *PickWeapon (player_t *player);
int CountWeapons ();
int Size () { return (int)Weapons.Size(); }
int LocateWeapon (const PClass *type);
inline const PClass *GetWeapon (int index) const
{
return Weapons[index];
if ((unsigned)index < Weapons.Size())
{
return Weapons[index].Type;
}
else
{
return NULL;
}
}
friend AWeapon *PickNextWeapon (player_t *player);
friend AWeapon *PickPrevWeapon (player_t *player);
friend struct FWeaponSlots;
private:
const PClass *Weapons[MAX_WEAPONS_PER_SLOT];
struct WeaponInfo
{
const PClass *Type;
fixed_t Position;
};
void SetInitialPositions();
void Sort();
TArray<WeaponInfo> Weapons;
};
AWeapon *PickNextWeapon (player_t *player);
AWeapon *PickPrevWeapon (player_t *player);
// FWeaponSlots::AddDefaultWeapon return codes
enum ESlotDef
{
@ -53,13 +61,20 @@ struct FWeaponSlots
{
FWeaponSlot Slots[NUM_WEAPON_SLOTS];
AWeapon *PickNextWeapon (player_t *player);
AWeapon *PickPrevWeapon (player_t *player);
void Clear ();
bool LocateWeapon (const PClass *type, int *const slot, int *const index);
ESlotDef AddDefaultWeapon (int slot, const PClass *type);
int RestoreSlots (FConfigFile &config);
void SaveSlots (FConfigFile &config);
void AddExtraWeapons();
void SetFromPlayer(const PClass *type);
void CompleteSetup(const PClass *type);
int RestoreSlots (FConfigFile *config, const char *section);
};
void P_PlaybackKeyConfWeapons();
void P_SetLocalWeapons(AActor *player);
extern FWeaponSlots LocalWeapons;
/************************************************************************/
@ -202,6 +217,13 @@ public:
};
// A weapon is just that.
enum
{
AWMETA_BASE = 0x72000,
AWMETA_SlotNumber,
AWMETA_SlotPriority,
};
class AWeapon : public AInventory
{
DECLARE_CLASS (AWeapon, AInventory)

View file

@ -25,6 +25,9 @@ IMPLEMENT_POINTY_CLASS (AWeapon)
DECLARE_POINTER (SisterWeapon)
END_POINTERS
FString WeaponSection;
TArray<FString> KeyConfWeapons;
//===========================================================================
//
// AWeapon :: Serialize
@ -624,27 +627,22 @@ bool AWeaponGiver::TryPickup(AActor *&toucher)
FWeaponSlots LocalWeapons;
FWeaponSlot::FWeaponSlot ()
{
Clear ();
}
//===========================================================================
//
// FWeaponSlot :: AddWeapon
//
// Adds a weapon to the end of the slot if it isn't already in it.
//
//===========================================================================
void FWeaponSlot::Clear ()
{
for (int i = 0; i < MAX_WEAPONS_PER_SLOT; i++)
{
Weapons[i] = NULL;
}
}
bool FWeaponSlot::AddWeapon (const char *type)
bool FWeaponSlot::AddWeapon(const char *type)
{
return AddWeapon (PClass::FindClass (type));
}
bool FWeaponSlot::AddWeapon (const PClass *type)
bool FWeaponSlot::AddWeapon(const PClass *type)
{
int i;
unsigned int i;
if (type == NULL)
{
@ -657,41 +655,104 @@ bool FWeaponSlot::AddWeapon (const PClass *type)
return false;
}
for (i = 0; i < MAX_WEAPONS_PER_SLOT; i++)
for (i = 0; i < Weapons.Size(); i++)
{
if (Weapons[i] == type)
if (Weapons[i].Type == type)
return true; // Already present
if (Weapons[i] == NULL)
break;
}
if (i == MAX_WEAPONS_PER_SLOT)
{ // This slot is full
return false;
}
Weapons[i] = type;
WeaponInfo info = { type, -1 };
Weapons.Push(info);
return true;
}
AWeapon *FWeaponSlot::PickWeapon (player_t *player)
//===========================================================================
//
// FWeaponSlot :: AddWeaponList
//
// Appends all the weapons from the space-delimited list to this slot.
// Set clear to true to remove any weapons already in this slot first.
//
//===========================================================================
void FWeaponSlot :: AddWeaponList(const char *list, bool clear)
{
FString copy(list);
char *buff = copy.LockBuffer();
char *tok;
if (clear)
{
Clear();
}
tok = strtok(buff, " ");
while (tok != NULL)
{
AddWeapon(tok);
tok = strtok(NULL, " ");
}
}
//===========================================================================
//
// FWeaponSlot :: LocateWeapon
//
// Returns the index for the specified weapon in this slot, or -1 if it isn't
// in this slot.
//
//===========================================================================
int FWeaponSlot::LocateWeapon(const PClass *type)
{
unsigned int i;
for (i = 0; i < Weapons.Size(); ++i)
{
if (Weapons[i].Type == type)
{
return (int)i;
}
}
return -1;
}
//===========================================================================
//
// FWeaponSlot :: PickWeapon
//
// Picks a weapon from this slot. If no weapon is selected in this slot,
// or the first weapon in this slot is selected, returns the last weapon.
// Otherwise, returns the previous weapon in this slot. This means
// precedence is given to the last weapon in the slot, which by convention
// is probably the strongest. Does not return weapons you have no ammo
// for or which you do not possess.
//
//===========================================================================
AWeapon *FWeaponSlot::PickWeapon(player_t *player)
{
int i, j;
// Does this slot even have any weapons?
if (Weapons.Size() == 0)
{
return player->ReadyWeapon;
}
if (player->ReadyWeapon != NULL)
{
for (i = 0; i < MAX_WEAPONS_PER_SLOT; i++)
for (i = 0; i < Weapons.Size(); i++)
{
if (Weapons[i] == player->ReadyWeapon->GetClass() ||
if (Weapons[i].Type == player->ReadyWeapon->GetClass() ||
(player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP &&
player->ReadyWeapon->SisterWeapon != NULL &&
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i]))
player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type))
{
for (j = (unsigned)(i - 1) % MAX_WEAPONS_PER_SLOT;
for (j = (unsigned)(i - 1) % Weapons.Size();
j != i;
j = (unsigned)(j - 1) % MAX_WEAPONS_PER_SLOT)
j = (unsigned)(j - 1) % Weapons.Size())
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory (Weapons[j]));
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[j].Type));
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo (AWeapon::EitherFire, false))
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
@ -699,11 +760,11 @@ AWeapon *FWeaponSlot::PickWeapon (player_t *player)
}
}
}
for (i = MAX_WEAPONS_PER_SLOT - 1; i >= 0; i--)
for (i = Weapons.Size() - 1; i >= 0; i--)
{
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory (Weapons[i]));
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory(Weapons[i].Type));
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo (AWeapon::EitherFire, false))
if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
@ -711,17 +772,85 @@ AWeapon *FWeaponSlot::PickWeapon (player_t *player)
return player->ReadyWeapon;
}
void FWeaponSlots::Clear ()
//===========================================================================
//
// FWeaponSlot :: SetInitialPositions
//
// Fills in the position field for every weapon currently in the slot based
// on its position in the slot. These are not scaled to [0,1] so that extra
// weapons can use those values to go to the start or end of the slot.
//
//===========================================================================
void FWeaponSlot::SetInitialPositions()
{
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
unsigned int size = Weapons.Size(), i;
if (size == 1)
{
Slots[i].Clear ();
Weapons[0].Position = 0x8000;
}
else
{
for (i = 0; i < size; ++i)
{
Weapons[i].Position = i * 0xFF00 / (size - 1) + 0x80;
}
}
}
//===========================================================================
//
// FWeaponSlot :: Sort
//
// Rearranges the weapons by their position field.
//
//===========================================================================
void FWeaponSlot::Sort()
{
// This does not use qsort(), because the sort should be stable, and
// there is no guarantee that qsort() is stable. This insertion sort
// should be fine.
int i, j;
for (i = 1; i < (int)Weapons.Size(); ++i)
{
fixed_t pos = Weapons[i].Position;
const PClass *type = Weapons[i].Type;
for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j)
{
Weapons[j + 1] = Weapons[j];
}
Weapons[j + 1].Type = type;
Weapons[j + 1].Position = pos;
}
}
//===========================================================================
//
// FWeaponSlots :: Clear
//
// Removes all weapons from every slot.
//
//===========================================================================
void FWeaponSlots::Clear()
{
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
Slots[i].Clear();
}
}
//===========================================================================
//
// FWeaponSlots :: AddDefaultWeapon
//
// If the weapon already exists in a slot, don't add it. If it doesn't,
// then add it to the specified slot. False is returned if the weapon was
// not in a slot and could not be added. True is returned otherwise.
// then add it to the specified slot.
//
//===========================================================================
ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type)
{
@ -739,43 +868,59 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, const PClass *type)
return SLOTDEF_Exists;
}
//===========================================================================
//
// FWeaponSlots :: LocateWeapon
//
// Returns true if the weapon is in a slot, false otherwise. If the weapon
// is found, it can also optionally return the slot and index for it.
//
//===========================================================================
bool FWeaponSlots::LocateWeapon (const PClass *type, int *const slot, int *const index)
{
int i, j;
for (i = 0; i < NUM_WEAPON_SLOTS; i++)
{
for (j = 0; j < MAX_WEAPONS_PER_SLOT; j++)
j = Slots[i].LocateWeapon(type);
if (j >= 0)
{
if (Slots[i].Weapons[j] == type)
{
if (slot != NULL) *slot = i;
if (index != NULL) *index = j;
return true;
}
else if (Slots[i].Weapons[j] == NULL)
{ // No more weapons in this slot, so try the next
break;
}
if (slot != NULL) *slot = i;
if (index != NULL) *index = j;
return true;
}
}
return false;
}
static bool FindMostRecentWeapon (player_t *player, int *slot, int *index)
//===========================================================================
//
// FindMostRecentWeapon
//
// Locates the slot and index for the most recently selected weapon. If the
// player is in the process of switching to a new weapon, that is the most
// recently selected weapon. Otherwise, the current weapon is the most recent
// weapon.
//
//===========================================================================
static bool FindMostRecentWeapon(player_t *player, int *slot, int *index)
{
if (player->PendingWeapon != WP_NOCHANGE)
{
return LocalWeapons.LocateWeapon (player->PendingWeapon->GetClass(), slot, index);
return LocalWeapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index);
}
else if (player->ReadyWeapon != NULL)
{
AWeapon *weap = player->ReadyWeapon;
if (!LocalWeapons.LocateWeapon (weap->GetClass(), slot, index))
if (!LocalWeapons.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 LocalWeapons.LocateWeapon(weap->SisterWeaponType, slot, index);
}
return false;
}
@ -787,7 +932,17 @@ static bool FindMostRecentWeapon (player_t *player, int *slot, int *index)
}
}
AWeapon *PickNextWeapon (player_t *player)
//===========================================================================
//
// FWeaponSlots :: PickNextWeapon
//
// Returns the "next" weapon for this player. If the current weapon is not
// in a slot, then it just returns that weapon, since there's nothing to
// consider it relative to.
//
//===========================================================================
AWeapon *FWeaponSlots::PickNextWeapon(player_t *player)
{
int startslot, startindex;
@ -795,35 +950,52 @@ AWeapon *PickNextWeapon (player_t *player)
{
return NULL;
}
if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex))
if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex))
{
int start;
int i;
int slot;
int index;
if (player->ReadyWeapon == NULL)
{
startslot = NUM_WEAPON_SLOTS - 1;
startindex = MAX_WEAPONS_PER_SLOT - 1;
startindex = Slots[startslot].Size() - 1;
}
start = startslot * MAX_WEAPONS_PER_SLOT + startindex;
for (i = 1; i < NUM_WEAPON_SLOTS * MAX_WEAPONS_PER_SLOT + 1; i++)
slot = startslot;
index = startindex;
do
{
int slot = (unsigned)((start + i) / MAX_WEAPONS_PER_SLOT) % NUM_WEAPON_SLOTS;
int index = (unsigned)(start + i) % MAX_WEAPONS_PER_SLOT;
const PClass *type = LocalWeapons.Slots[slot].Weapons[index];
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory (type));
if (weap != NULL && weap->CheckAmmo (AWeapon::EitherFire, false))
if (++index >= Slots[slot].Size())
{
index = 0;
if (++slot >= NUM_WEAPON_SLOTS)
{
slot = 0;
}
}
const PClass *type = LocalWeapons.Slots[slot].GetWeapon(index);
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
}
while (slot != startslot || index != startindex);
}
return player->ReadyWeapon;
}
AWeapon *PickPrevWeapon (player_t *player)
//===========================================================================
//
// FWeaponSlots :: PickPrevWeapon
//
// Returns the "previous" weapon for this player. If the current weapon is
// not in a slot, then it just returns that weapon, since there's nothing to
// consider it relative to.
//
//===========================================================================
AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player)
{
int startslot, startindex;
@ -833,79 +1005,250 @@ AWeapon *PickPrevWeapon (player_t *player)
}
if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex))
{
int start;
int i;
int slot;
int index;
if (player->ReadyWeapon == NULL)
{
startslot = 0;
startindex = 0;
}
start = startslot * MAX_WEAPONS_PER_SLOT + startindex;
for (i = 1; i < NUM_WEAPON_SLOTS * MAX_WEAPONS_PER_SLOT + 1; i++)
slot = startslot;
index = startindex;
do
{
int slot = start - i;
if (slot < 0)
slot += NUM_WEAPON_SLOTS * MAX_WEAPONS_PER_SLOT;
int index = slot % MAX_WEAPONS_PER_SLOT;
slot /= MAX_WEAPONS_PER_SLOT;
const PClass *type = LocalWeapons.Slots[slot].Weapons[index];
AWeapon *weap = static_cast<AWeapon *> (player->mo->FindInventory (type));
if (weap != NULL && weap->CheckAmmo (AWeapon::EitherFire, false))
if (--index < 0)
{
if (--slot < 0)
{
slot = NUM_WEAPON_SLOTS - 1;
}
index = Slots[slot].Size() - 1;
}
const PClass *type = LocalWeapons.Slots[slot].GetWeapon(index);
AWeapon *weap = static_cast<AWeapon *>(player->mo->FindInventory(type));
if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false))
{
return weap;
}
}
while (slot != startslot || index != startindex);
}
return player->ReadyWeapon;
}
//===========================================================================
//
// FWeaponSlots :: AddExtraWeapons
//
// For every weapon class for the current game, add it to its desired slot
// and position within the slot. Does not first clear the slots.
//
//===========================================================================
void FWeaponSlots::AddExtraWeapons()
{
unsigned int i;
// Set fractional positions for current weapons.
for (i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
Slots[i].SetInitialPositions();
}
// Append extra weapons to the slots.
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
{
PClass *cls = PClass::m_Types[i];
if (cls->ActorInfo != NULL &&
(cls->ActorInfo->GameFilter == GAME_Any || (cls->ActorInfo->GameFilter & gameinfo.gametype)) &&
cls->ActorInfo->Replacement == NULL && // Replaced weapons don't get slotted.
cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)) &&
!LocateWeapon(cls, NULL, NULL) // Don't duplicate it if it's already present.
)
{
int slot = cls->Meta.GetMetaInt(AWMETA_SlotNumber, -1);
if ((unsigned)slot < NUM_WEAPON_SLOTS)
{
fixed_t position = cls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX);
FWeaponSlot::WeaponInfo info = { cls, position };
Slots[slot].Weapons.Push(info);
}
}
}
// Now resort every slot to put the new weapons in their proper places.
for (i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
Slots[i].Sort();
}
}
//===========================================================================
//
// FWeaponSlots :: CompleteSetup
//
// Sets up local weapon slots in this order:
// 1. Use slots from player class.
// 2. Add extra weapons that specify their own slot.
// 3. Run KEYCONF weapon commands, affecting slots accordingly.
// 4. Read config slots, overriding current slots. If WeaponSection is set,
// then [<WeaponSection>.<PlayerClass>.Weapons] is tried, followed by
// [<WeaponSection>.Weapons] if that did not exist. If WeaponSection is
// empty, then the slots are read from [<PlayerClass>.Weapons].
//
//===========================================================================
void FWeaponSlots::CompleteSetup(const PClass *type)
{
SetFromPlayer(type);
AddExtraWeapons();
P_PlaybackKeyConfWeapons();
if (WeaponSection.IsNotEmpty())
{
FString sectionclass(WeaponSection);
sectionclass << '.' << type->TypeName.GetChars();
if (RestoreSlots(GameConfig, sectionclass) == 0)
{
RestoreSlots(GameConfig, WeaponSection);
}
}
else
{
RestoreSlots(GameConfig, type->TypeName.GetChars());
}
}
//===========================================================================
//
// FWeaponSlots :: SetFromPlayer
//
// Sets all weapon slots according to the player class.
//
//===========================================================================
void FWeaponSlots::SetFromPlayer(const PClass *type)
{
Clear();
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
const char *str = type->Meta.GetMetaString(APMETA_Slot0 + i);
if (str != NULL)
{
Slots[i].AddWeaponList(str, false);
}
}
}
//===========================================================================
//
// FWeaponSlots :: RestoreSlots
//
// Reads slots from a config section. Any slots in the section override
// existing slot settings, while slots not present in the config are
// unaffected. Returns the number of slots read.
//
//===========================================================================
int FWeaponSlots::RestoreSlots(FConfigFile *config, const char *section)
{
FString section_name(section);
const char *key, *value;
int slotsread = 0;
section_name += ".Weapons";
if (!config->SetSection(section_name))
{
return 0;
}
while (config->NextInSection (key, value))
{
if (strnicmp (key, "Slot[", 5) != 0 ||
key[5] < '0' ||
key[5] > '0'+NUM_WEAPON_SLOTS ||
key[6] != ']' ||
key[7] != 0)
{
continue;
}
Slots[key[5] - '0'].AddWeaponList(value, true);
slotsread++;
}
return slotsread;
}
//===========================================================================
//
// CCMD setslot
//
//===========================================================================
CCMD (setslot)
{
int slot, i;
if (ParsingKeyConf && WeaponSection.IsEmpty())
{
Printf ("You need to use weaponsection before using setslot\n");
return;
}
int slot;
if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS)
{
Printf ("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n");
for (slot = 0; slot < NUM_WEAPON_SLOTS; ++slot)
Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n");
if (players[consoleplayer].mo != NULL)
{
Printf (" Slot %d:", slot);
for (i = 0;
i < MAX_WEAPONS_PER_SLOT && LocalWeapons.Slots[slot].GetWeapon(i) != NULL;
++i)
FString config(GameConfig->GetConfigPath(false));
Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE
" to retain these bindings:\n" TEXTCOLOR_NORMAL "[", config.GetChars());
if (WeaponSection.IsNotEmpty())
{
Printf (" %s", LocalWeapons.Slots[slot].GetWeapon(i)->TypeName.GetChars());
Printf("%s.", WeaponSection.GetChars());
}
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");
}
Printf ("\n");
}
return;
}
LocalWeapons.Slots[slot].Clear();
if (argv.argc() == 2)
if (ParsingKeyConf)
{
Printf ("Slot %d cleared\n", slot);
KeyConfWeapons.Push(argv.args());
}
else
{
for (i = 2; i < argv.argc(); ++i)
LocalWeapons.Slots[slot].Clear();
if (argv.argc() == 2)
{
if (!LocalWeapons.Slots[slot].AddWeapon (argv[i]))
Printf ("Slot %d cleared\n", slot);
}
else
{
for (int i = 2; i < argv.argc(); ++i)
{
Printf ("Could not add %s to slot %d\n", argv[i], slot);
if (!LocalWeapons.Slots[slot].AddWeapon (argv[i]))
{
Printf ("Could not add %s to slot %d\n", argv[i], slot);
}
}
}
}
}
//===========================================================================
//
// CCMD addslot
//
//===========================================================================
CCMD (addslot)
{
size_t slot;
@ -916,61 +1259,39 @@ CCMD (addslot)
return;
}
if (!LocalWeapons.Slots[slot].AddWeapon (argv[2]))
if (ParsingKeyConf)
{
Printf ("Could not add %s to slot %zu\n", argv[2], slot);
}
}
CCMD (weaponsection)
{
if (argv.argc() != 2)
{
Printf ("Usage: weaponsection <ini name>\n");
KeyConfWeapons.Push(argv.args());
}
else
{
// Limit the section name to 32 chars
if (strlen(argv[1]) > 32)
if (!LocalWeapons.Slots[slot].AddWeapon (argv[2]))
{
argv[1][32] = 0;
}
WeaponSection = argv[1];
// If the ini already has definitions for this section, load them
char fullSection[32*3];
char *tackOn;
if (gameinfo.gametype == GAME_Hexen)
{
strcpy (fullSection, "Hexen");
tackOn = fullSection + 5;
}
else if (gameinfo.gametype == GAME_Heretic)
{
strcpy (fullSection, "Heretic");
tackOn = fullSection + 7;
}
else if (gameinfo.gametype == GAME_Strife)
{
strcpy (fullSection, "Strife");
tackOn = fullSection + 6;
}
else
{
strcpy (fullSection, "Doom");
tackOn = fullSection + 4;
}
mysnprintf (tackOn, countof(fullSection) - (tackOn - fullSection),
".%s.WeaponSlots", WeaponSection.GetChars());
if (GameConfig->SetSection (fullSection))
{
LocalWeapons.RestoreSlots (*GameConfig);
Printf ("Could not add %s to slot %zu\n", argv[2], slot);
}
}
}
//===========================================================================
//
// CCMD weaponsection
//
//===========================================================================
CCMD (weaponsection)
{
if (argv.argc() > 1)
{
WeaponSection = argv[1];
}
}
//===========================================================================
//
// CCMD addslotdefault
//
//===========================================================================
CCMD (addslotdefault)
{
const PClass *type;
@ -982,113 +1303,58 @@ CCMD (addslotdefault)
return;
}
if (ParsingKeyConf && WeaponSection.IsEmpty())
{
Printf ("You need to use weaponsection before using addslotdefault\n");
return;
}
type = PClass::FindClass (argv[2]);
if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
{
Printf ("%s is not a weapon\n", argv[2]);
}
switch (LocalWeapons.AddDefaultWeapon (slot, type))
if (ParsingKeyConf)
{
case SLOTDEF_Full:
Printf ("Could not add %s to slot %d\n", argv[2], slot);
break;
case SLOTDEF_Added:
break;
case SLOTDEF_Exists:
break;
KeyConfWeapons.Push(argv.args());
}
}
int FWeaponSlots::RestoreSlots (FConfigFile &config)
{
char buff[MAX_WEAPONS_PER_SLOT*64];
const char *key, *value;
int slot;
int slotsread = 0;
buff[sizeof(buff)-1] = 0;
for (slot = 0; slot < NUM_WEAPON_SLOTS; ++slot)
else
{
Slots[slot].Clear ();
}
while (config.NextInSection (key, value))
{
if (strnicmp (key, "Slot[", 5) != 0 ||
key[5] < '0' ||
key[5] > '0'+NUM_WEAPON_SLOTS ||
key[6] != ']' ||
key[7] != 0)
switch (LocalWeapons.AddDefaultWeapon (slot, type))
{
continue;
}
slot = key[5] - '0';
strncpy (buff, value, sizeof(buff)-1);
char *tok;
case SLOTDEF_Full:
Printf ("Could not add %s to slot %d\n", argv[2], slot);
break;
Slots[slot].Clear ();
tok = strtok (buff, " ");
while (tok != NULL)
{
Slots[slot].AddWeapon (tok);
tok = strtok (NULL, " ");
}
slotsread++;
}
return slotsread;
}
case SLOTDEF_Added:
break;
void FWeaponSlots::SaveSlots (FConfigFile &config)
{
char buff[MAX_WEAPONS_PER_SLOT*64];
char keyname[16];
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
int index = 0;
for (int j = 0; j < MAX_WEAPONS_PER_SLOT; ++j)
{
if (Slots[i].Weapons[j] == NULL)
{
break;
}
if (index > 0)
{
buff[index++] = ' ';
}
const char *name = Slots[i].Weapons[j]->TypeName.GetChars();
strcpy (buff+index, name);
index += (int)strlen (name);
}
if (index > 0)
{
mysnprintf (keyname, countof(keyname), "Slot[%d]", i);
config.SetValueForKey (keyname, buff);
}
}
}
int FWeaponSlot::CountWeapons ()
{
int i;
for (i = 0; i < MAX_WEAPONS_PER_SLOT; ++i)
{
if (Weapons[i] == NULL)
{
case SLOTDEF_Exists:
break;
}
}
return i;
}
//===========================================================================
//
// P_PlaybackKeyConfWeapons
//
// Executes the weapon-related commands from a KEYCONF lump.
//
//===========================================================================
void P_PlaybackKeyConfWeapons()
{
for (unsigned int i = 0; i < KeyConfWeapons.Size(); ++i)
{
FString cmd(KeyConfWeapons[i]);
AddCommandString(cmd.LockBuffer());
}
}
//===========================================================================
//
// CCMD dumpslots
//
// Dumps a config-friendly listing of the current slot assignments.
//
//===========================================================================
CCMD (dumpslots)
{
}

View file

@ -414,7 +414,7 @@ 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 < MAX_WEAPONS_PER_SLOT; i++)
for (int i = 0; i < LocalWeapons.Slots[cmd.value].Size(); i++)
{
const PClass *weap = LocalWeapons.Slots[cmd.value].GetWeapon(i);
if(weap == NULL)

View file

@ -506,7 +506,7 @@ 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<MAX_WEAPONS_PER_SLOT;j++)
for (k=0;k<NUM_WEAPON_SLOTS;k++) for(j=0;j<LocalWeapons.Slots[k].Size();j++)
{
const PClass * weap = LocalWeapons.Slots[k].GetWeapon(j);
@ -636,7 +636,7 @@ static void DrawWeapons(player_t * CPlayer, int x, int y)
}
// And now everything in the weapon slots back to front
for (k=NUM_WEAPON_SLOTS-1;k>=0;k--) for(j=MAX_WEAPONS_PER_SLOT-1;j>=0;j--)
for (k=NUM_WEAPON_SLOTS-1;k>=0;k--) for(j=LocalWeapons.Slots[k].Size()-1;j>=0;j--)
{
const PClass * weap = LocalWeapons.Slots[k].GetWeapon(j);
if (weap)

View file

@ -73,8 +73,6 @@ EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, wi_percents)
FString WeaponSection;
FGameConfigFile::FGameConfigFile ()
{
FString pathname;
@ -222,16 +220,6 @@ void FGameConfigFile::DoGlobalSetup ()
noblitter->ResetToDefault ();
}
}
if (last < 201)
{
// Be sure the Hexen fourth weapons are assigned to slot 4
// If this section does not already exist, then they will be
// assigned by SetupWeaponList().
if (SetSection ("Hexen.WeaponSlots"))
{
SetValueForKey ("Slot[4]", "FWeapQuietus CWeapWraithverge MWeapBloodscourge");
}
}
if (last < 202)
{
// Make sure the Hexen hotkeys are accessible by default.
@ -271,6 +259,28 @@ void FGameConfigFile::DoGlobalSetup ()
precache->ResetToDefault();
}
}
if (last < 208)
{ // Weapon sections are no longer used, so tidy up the config by deleting them.
const char *name;
size_t namelen;
bool more;
more = SetFirstSection();
while (more)
{
name = GetCurrentSection();
if (name != NULL &&
(namelen = strlen(name)) > 12 &&
strcmp(name + namelen - 12, ".WeaponSlots") == 0)
{
more = DeleteCurrentSection();
}
else
{
more = SetNextSection();
}
}
}
}
}
}
@ -376,17 +386,6 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
}
}
// Separated from DoGameSetup because it needs all the weapons properly defined
void FGameConfigFile::DoWeaponSetup (const char *gamename)
{
strncpy (subsection, "WeaponSlots", sublen);
if (!SetSection (section) || !LocalWeapons.RestoreSlots (*this))
{
SetupWeaponList (gamename);
}
}
void FGameConfigFile::ReadNetVars ()
{
strncpy (subsection, "NetServerInfo", sublen);
@ -460,18 +459,6 @@ void FGameConfigFile::ArchiveGameData (const char *gamename)
strncpy (subsection, "DoubleBindings", sublen);
SetSection (section, true);
C_ArchiveBindings (this, true);
if (WeaponSection.IsEmpty())
{
strncpy (subsection, "WeaponSlots", sublen);
}
else
{
mysnprintf (subsection, sublen, "%s.WeaponSlots", WeaponSection.GetChars());
}
SetSection (section, true);
ClearCurrentSection ();
LocalWeapons.SaveSlots (*this);
}
void FGameConfigFile::ArchiveGlobalData ()
@ -676,79 +663,6 @@ void FGameConfigFile::SetRavenDefaults (bool isHexen)
}
}
void FGameConfigFile::SetupWeaponList (const char *gamename)
{
for (int i = 0; i < NUM_WEAPON_SLOTS; ++i)
{
LocalWeapons.Slots[i].Clear ();
}
if (strcmp (gamename, "Heretic") == 0)
{
LocalWeapons.Slots[1].AddWeapon ("Staff");
LocalWeapons.Slots[1].AddWeapon ("Gauntlets");
LocalWeapons.Slots[2].AddWeapon ("GoldWand");
LocalWeapons.Slots[3].AddWeapon ("Crossbow");
LocalWeapons.Slots[4].AddWeapon ("Blaster");
LocalWeapons.Slots[5].AddWeapon ("SkullRod");
LocalWeapons.Slots[6].AddWeapon ("PhoenixRod");
LocalWeapons.Slots[7].AddWeapon ("Mace");
}
else if (strcmp (gamename, "Hexen") == 0)
{
LocalWeapons.Slots[1].AddWeapon ("FWeapFist");
LocalWeapons.Slots[2].AddWeapon ("FWeapAxe");
LocalWeapons.Slots[3].AddWeapon ("FWeapHammer");
LocalWeapons.Slots[4].AddWeapon ("FWeapQuietus");
LocalWeapons.Slots[1].AddWeapon ("CWeapMace");
LocalWeapons.Slots[2].AddWeapon ("CWeapStaff");
LocalWeapons.Slots[3].AddWeapon ("CWeapFlame");
LocalWeapons.Slots[4].AddWeapon ("CWeapWraithverge");
LocalWeapons.Slots[1].AddWeapon ("MWeapWand");
LocalWeapons.Slots[2].AddWeapon ("MWeapFrost");
LocalWeapons.Slots[3].AddWeapon ("MWeapLightning");
LocalWeapons.Slots[4].AddWeapon ("MWeapBloodscourge");
}
else if (strcmp (gamename, "Strife") == 0)
{
LocalWeapons.Slots[1].AddWeapon ("PunchDagger");
LocalWeapons.Slots[2].AddWeapon ("StrifeCrossbow2");
LocalWeapons.Slots[2].AddWeapon ("StrifeCrossbow");
LocalWeapons.Slots[3].AddWeapon ("AssaultGun");
LocalWeapons.Slots[4].AddWeapon ("MiniMissileLauncher");
LocalWeapons.Slots[5].AddWeapon ("StrifeGrenadeLauncher2");
LocalWeapons.Slots[5].AddWeapon ("StrifeGrenadeLauncher");
LocalWeapons.Slots[6].AddWeapon ("FlameThrower");
LocalWeapons.Slots[7].AddWeapon ("Mauler2");
LocalWeapons.Slots[7].AddWeapon ("Mauler");
LocalWeapons.Slots[8].AddWeapon ("Sigil");
}
else if (strcmp (gamename, "Chex") == 0)
{
LocalWeapons.Slots[1].AddWeapon ("Bootspoon");
LocalWeapons.Slots[1].AddWeapon ("SuperBootspork");
LocalWeapons.Slots[2].AddWeapon ("MiniZorcher");
LocalWeapons.Slots[3].AddWeapon ("LargeZorcher");
LocalWeapons.Slots[3].AddWeapon ("SuperLargeZorcher");
LocalWeapons.Slots[4].AddWeapon ("RapidZorcher");
LocalWeapons.Slots[5].AddWeapon ("ZorchPropulsor");
LocalWeapons.Slots[6].AddWeapon ("PhasingZorcher");
LocalWeapons.Slots[7].AddWeapon ("LAZDevice");
}
else // Doom
{
LocalWeapons.Slots[1].AddWeapon ("Fist");
LocalWeapons.Slots[1].AddWeapon ("Chainsaw");
LocalWeapons.Slots[2].AddWeapon ("Pistol");
LocalWeapons.Slots[3].AddWeapon ("Shotgun");
LocalWeapons.Slots[3].AddWeapon ("SuperShotgun");
LocalWeapons.Slots[4].AddWeapon ("Chaingun");
LocalWeapons.Slots[5].AddWeapon ("RocketLauncher");
LocalWeapons.Slots[6].AddWeapon ("PlasmaRifle");
LocalWeapons.Slots[7].AddWeapon ("BFG9000");
}
}
CCMD (whereisini)
{
FString path = GameConfig->GetConfigPath (false);

View file

@ -47,7 +47,6 @@ public:
void DoGlobalSetup ();
void DoGameSetup (const char *gamename);
void DoWeaponSetup (const char *gamename);
void ArchiveGlobalData ();
void ArchiveGameData (const char *gamename);
void AddAutoexec (DArgs *list, const char *gamename);
@ -64,7 +63,6 @@ private:
void MigrateOldConfig ();
void SetRavenDefaults (bool isHexen);
void ReadCVars (DWORD flags);
void SetupWeaponList (const char *gamename);
bool bMigrating;
@ -73,7 +71,6 @@ private:
size_t sublen;
};
extern FString WeaponSection;
extern FGameConfigFile *GameConfig;
#endif //__GAMECONFIGFILE_H__

View file

@ -737,7 +737,7 @@ 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 demors all weapons must be given because the state of
// 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 ||

View file

@ -3769,6 +3769,10 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer)
FBehavior::StaticStartTypedScripts (SCRIPT_Respawn, p->mo, true);
}
}
if (playernum == consoleplayer)
{
LocalWeapons.CompleteSetup(mobj->GetClass());
}
return mobj;
}

View file

@ -1405,6 +1405,24 @@ DEFINE_CLASS_PROPERTY(yadjust, F, Weapon)
defaults->YAdjust = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon)
{
PROP_INT_PARM(i, 0);
info->Class->Meta.SetMetaInt(AWMETA_SlotNumber, i);
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon)
{
PROP_FIXED_PARM(i, 0);
info->Class->Meta.SetMetaFixed(AWMETA_SlotPriority, i);
}
//==========================================================================
//
//==========================================================================
@ -1823,6 +1841,30 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
}
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, weaponslot, ISsssssssssssssssssssssssssssssssssssssssssss, PlayerPawn)
{
PROP_INT_PARM(slot, 0);
if (slot < 0 || slot > 9)
{
I_Error("Slot must be between 0 and 9.");
}
else
{
FString weapons;
for(int i = 1; i < PROP_PARM_COUNT; ++i)
{
PROP_STRING_PARM(str, i);
weapons << ' ' << str;
}
info->Class->Meta.SetMetaString(APMETA_Slot0 + slot, &weapons[1]);
}
}
//==========================================================================
//
//==========================================================================

View file

@ -215,6 +215,8 @@ static int STACK_ARGS TranslationMapCompare (const void *a, const void *b);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern int PrintColors[];
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FFont *FFont::FirstFont = NULL;
@ -2057,7 +2059,7 @@ EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int bol
const BYTE *ch = color_value;
int newcolor = *ch++;
if (newcolor == '-') // Normal
if (newcolor == '-') // Normal
{
newcolor = normalcolor;
}
@ -2065,6 +2067,14 @@ EColorRange V_ParseFontColor (const BYTE *&color_value, int normalcolor, int bol
{
newcolor = boldcolor;
}
else if (newcolor == '!') // Team chat
{
newcolor = PrintColors[PRINT_TEAMCHAT];
}
else if (newcolor == '*') // Chat
{
newcolor = PrintColors[PRINT_CHAT];
}
else if (newcolor == '[') // Named
{
const BYTE *namestart = ch;

View file

@ -71,6 +71,9 @@ struct FBrokenLines
#define TEXTCOLOR_NORMAL "\034-"
#define TEXTCOLOR_BOLD "\034+"
#define TEXTCOLOR_CHAT "\034*"
#define TEXTCOLOR_TEAMCHAT "\034!"
FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str);
void V_FreeBrokenLines (FBrokenLines *lines);
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str)

View file

@ -59,7 +59,7 @@
// Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to
// be able to migrate in FGameConfigFile::DoGlobalSetup().
#define LASTRUNVERSION "207"
#define LASTRUNVERSION "208"
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.

View file

@ -9,4 +9,11 @@ actor ChexPlayer : DoomPlayer
player.startitem "Bootspoon"
player.startitem "MiniZorchRecharge", 50
player.damagescreencolor "60 b0 58"
player.WeaponSlot 1, Bootspoon, SuperBootspork
player.WeaponSlot 2, MiniZorcher
player.WeaponSlot 3, LargeZorcher, SuperLargeZorcher
player.WeaponSlot 4, RapidZorcher
player.WeaponSlot 5, ZorchPropulsor
player.WeaponSlot 6, PhasingZorcher
player.WeaponSlot 7, LAZDevice
}

View file

@ -17,7 +17,14 @@ ACTOR DoomPlayer : PlayerPawn
Player.StartItem "Pistol"
Player.StartItem "Fist"
Player.StartItem "Clip", 50
Player.WeaponSlot 1, Fist, Chainsaw
Player.WeaponSlot 2, Pistol
Player.WeaponSlot 3, Shotgun, SuperShotgun
Player.WeaponSlot 4, Chaingun
Player.WeaponSlot 5, RocketLauncher
Player.WeaponSlot 6, PlasmaRifle
Player.WeaponSlot 7, BFG9000
States
{
Spawn:

View file

@ -17,6 +17,7 @@ ACTOR DoomWeapon : Weapon
ACTOR Fist : Weapon
{
Game Doom
Weapon.SelectionOrder 3700
Weapon.Kickback 100
Obituary "$OB_MPFIST"
@ -52,6 +53,7 @@ ACTOR Fist : Weapon
ACTOR Pistol : DoomWeapon 5010
{
Game Doom
Weapon.SelectionOrder 1900
Weapon.AmmoUse 1
Weapon.AmmoGive 20

View file

@ -11,6 +11,14 @@ ACTOR HereticPlayer : PlayerPawn
Player.StartItem "GoldWand"
Player.StartItem "Staff"
Player.StartItem "GoldWandAmmo", 50
Player.WeaponSlot 1, Staff, Gauntlets
Player.WeaponSlot 2, GoldWand
Player.WeaponSlot 3, Crossbow
Player.WeaponSlot 4, Blaster
Player.WeaponSlot 5, SkullRod
Player.WeaponSlot 6, PhoenixRod
Player.WeaponSlot 7, Mace
States
{
Spawn:

View file

@ -9,6 +9,7 @@ ACTOR HereticWeapon : Weapon
ACTOR Staff : HereticWeapon
{
Game Heretic
Weapon.SelectionOrder 3800
+THRUGHOST
+WIMPY_WEAPON
@ -38,6 +39,7 @@ ACTOR Staff : HereticWeapon
ACTOR StaffPowered : Staff
{
Game Heretic
Weapon.sisterweapon "Staff"
Weapon.ReadySound "weapons/staffcrackle"
+WEAPON.POWERED_UP
@ -106,6 +108,7 @@ ACTOR StaffPuff2
ACTOR GoldWand : HereticWeapon
{
Game Heretic
+BLOODSPLATTER
Weapon.SelectionOrder 2000
Weapon.AmmoGive 25
@ -138,6 +141,7 @@ ACTOR GoldWand : HereticWeapon
ACTOR GoldWandPowered : GoldWand
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.AmmoGive 0
Weapon.SisterWeapon "GoldWand"
@ -269,6 +273,7 @@ ACTOR Crossbow : HereticWeapon 2001
ACTOR CrossbowPowered : Crossbow
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.AmmoGive 0
Weapon.SisterWeapon "Crossbow"
@ -388,7 +393,7 @@ ACTOR Gauntlets : Weapon 2005
Weapon.YAdjust 15
Weapon.UpSound "weapons/gauntletsactivate"
Weapon.SisterWeapon "GauntletsPowered"
Inventory.PickupMessage "$TxT_WPNGAUNTLETS"
Inventory.PickupMessage "$TXT_WPNGAUNTLETS"
action native A_GauntletAttack (int power);
@ -420,6 +425,7 @@ ACTOR Gauntlets : Weapon 2005
ACTOR GauntletsPowered : Gauntlets
{
Game Heretic
+POWERED_UP
Weapon.SisterWeapon "Gauntlets"
States
@ -518,6 +524,7 @@ ACTOR Mace : HereticWeapon
ACTOR MacePowered : Mace
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.AmmoUse 5
Weapon.AmmoGive 0
@ -704,6 +711,7 @@ ACTOR Blaster : HereticWeapon 53
ACTOR BlasterPowered : Blaster
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.AmmoUse 5
Weapon.AmmoGive 0
@ -850,6 +858,7 @@ ACTOR SkullRod : HereticWeapon 2004
ACTOR SkullRodPowered : SkullRod
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.AmmoUse1 5
Weapon.AmmoGive1 0
@ -1022,6 +1031,7 @@ ACTOR PhoenixRod : Weapon 2003 native
ACTOR PhoenixRodPowered : PhoenixRod native
{
Game Heretic
+WEAPON.POWERED_UP
Weapon.SisterWeapon "PhoenixRod"
Weapon.AmmoGive 0

View file

@ -71,6 +71,7 @@ ACTOR WraithvergeDrop
ACTOR CWeapWraithverge : ClericWeapon native
{
Game Hexen
Health 3
Weapon.SelectionOrder 3000
+WEAPON.PRIMARY_USES_BOTH

View file

@ -3,6 +3,7 @@
ACTOR CWeapMace : ClericWeapon
{
Game Hexen
Weapon.SelectionOrder 3500
Weapon.KickBack 150
Weapon.YAdjust -8

View file

@ -22,6 +22,11 @@ ACTOR ClericPlayer : PlayerPawn
Player.HealRadiusType "Health"
Player.Hexenarmor 10, 10, 25, 5, 20
Player.StartItem "CWeapMace"
Player.WeaponSlot 1, CWeapMace
Player.WeaponSlot 2, CWeapStaff
Player.WeaponSlot 3, CWeapFlame
Player.WeaponSlot 4, CWeapWraithverge
States
{
Spawn:

View file

@ -3,6 +3,7 @@
ACTOR FWeapFist : FighterWeapon
{
Game Hexen
+BLOODSPLATTER
Weapon.SelectionOrder 3400
+WEAPON.MELEEWEAPON

View file

@ -22,6 +22,11 @@ ACTOR FighterPlayer : PlayerPawn
Player.StartItem "FWeapFist"
Player.ForwardMove 1.08, 1.2
Player.SideMove 1.125, 1.475
Player.WeaponSlot 1, FWeapFist
Player.WeaponSlot 2, FWeapAxe
Player.WeaponSlot 3, FWeapHammer
Player.WeaponSlot 4, FWeapQuietus
States
{
Spawn:

View file

@ -71,6 +71,7 @@ ACTOR QuietusDrop
ACTOR FWeapQuietus : FighterWeapon
{
Game Hexen
Health 3
Weapon.SelectionOrder 2900
+WEAPON.PRIMARY_USES_BOTH

View file

@ -24,6 +24,11 @@ ACTOR MagePlayer : PlayerPawn
Player.StartItem "MWeapWand"
Player.ForwardMove 0.88, 0.92
Player.SideMove 0.875, 0.925
Player.WeaponSlot 1, MWeapWand
Player.WeaponSlot 2, MWeapFrost
Player.WeaponSlot 3, MWeapLightning
Player.WeaponSlot 4, MWeapBloodscourge
States
{
Spawn:

View file

@ -71,6 +71,7 @@ ACTOR BloodscourgeDrop
ACTOR MWeapBloodscourge : MageWeapon native
{
Game Hexen
Health 3
Weapon.SelectionOrder 3100
Weapon.AmmoUse1 15

View file

@ -3,9 +3,11 @@
ACTOR MWeapWand : MageWeapon
{
Game Hexen
Weapon.SelectionOrder 3600
Weapon.KickBack 0
Weapon.YAdjust 9
States
{
Select:

View file

@ -12,6 +12,14 @@ ACTOR StrifePlayer : PlayerPawn
Player.ColorRange 128, 143
Player.DisplayName "Rebel"
Player.StartItem "PunchDagger"
Player.WeaponSlot 1, PunchDagger
Player.WeaponSlot 2, StrifeCrossbow2, StrifeCrossbow
Player.WeaponSlot 3, AssaultGun
Player.WeaponSlot 4, MiniMissileLauncher
Player.WeaponSlot 5, StrifeGrenadeLauncher2, StrifeGrenadeLauncher
Player.WeaponSlot 6, FlameThrower
Player.WeaponSlot 7, Mauler2, Mauler
Player.WeaponSlot 8, Sigil
action native A_ItBurnsItBurns();
action native A_CrispyPlayer();

View file

@ -45,6 +45,7 @@ ACTOR StrifeSpark : StrifePuff
ACTOR PunchDagger : StrifeWeapon
{
Game Strife
Weapon.SelectionOrder 3900
+WEAPON.NOALERT
@ -198,11 +199,13 @@ ACTOR StrifeCrossbow : StrifeWeapon 2001
ACTOR StrifeCrossbow2 : StrifeCrossbow
{
Game Strife
Weapon.SelectionOrder 2700
Weapon.AmmoUse1 1
Weapon.AmmoGive1 0
Weapon.AmmoType1 "PoisonBolts"
Weapon.SisterWeapon "StrifeCrossbow"
States
{
Ready:
@ -362,6 +365,7 @@ ACTOR MiniMissilePuff : StrifePuff
ACTOR MiniMissile
{
Game Strife
ConversationID 99,-1,-1
Speed 20
Radius 10
@ -515,6 +519,7 @@ ACTOR Mauler : StrifeWeapon 2004
ACTOR Mauler2 : Mauler
{
Game Strife
Weapon.SelectionOrder 3300
Weapon.AmmoUse1 30
Weapon.AmmoGive1 0
@ -626,6 +631,7 @@ ACTOR MaulerTorpedoWave
ACTOR HEGrenade
{
Game Strife
ConversationID 106,-1,-1
Speed 15
Radius 13
@ -663,6 +669,7 @@ ACTOR HEGrenade
ACTOR PhosphorousGrenade
{
Game Strife
ConversationID 107,-1,-1
Speed 15
Radius 13
@ -782,6 +789,7 @@ ACTOR StrifeGrenadeLauncher : StrifeWeapon 154
ACTOR StrifeGrenadeLauncher2 : StrifeGrenadeLauncher
{
Game Strife
Weapon.SelectionOrder 3200
Weapon.AmmoUse1 1
Weapon.AmmoGive1 0