- 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:
parent
491abe3a2c
commit
a7e40b56f6
38 changed files with 811 additions and 378 deletions
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue