mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
- Generalized Hexen's class-based spawning to be a property of the player class
so now it is available in all games. - Replaced the call to A_FlameSnd in the HereticPlayer's burn death sequence with A_FireScream and defined *burndeath for Heretic. - Added Grubber's custom player class support. SVN r250 (trunk)
This commit is contained in:
parent
38a073626f
commit
31c749058b
45 changed files with 1762 additions and 853 deletions
|
@ -1,3 +1,10 @@
|
|||
July 13, 2006 (Changes by Graf Zahl)
|
||||
- Generalized Hexen's class-based spawning to be a property of the player class
|
||||
so now it is available in all games.
|
||||
- Replaced the call to A_FlameSnd in the HereticPlayer's burn death sequence
|
||||
with A_FireScream and defined *burndeath for Heretic.
|
||||
- Added Grubber's custom player class support.
|
||||
|
||||
July 12, 2006
|
||||
- Changed decorate replacement to be opt-in instead of opt-out. This allows for
|
||||
greater flexibility in what can be replaced (replaced actors need not be ancestors
|
||||
|
|
|
@ -61,7 +61,9 @@ static const char *KeyConfCommands[] =
|
|||
"addmenukey",
|
||||
"addslotdefault",
|
||||
"weaponsection",
|
||||
"setslot"
|
||||
"setslot",
|
||||
"addplayerclass",
|
||||
"clearplayerclasses"
|
||||
};
|
||||
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv);
|
||||
|
|
|
@ -1661,6 +1661,12 @@ static int PatchMisc (int dummy)
|
|||
health->MaxAmount = deh.MaxSoulsphere;
|
||||
}
|
||||
|
||||
APlayerPawn *player = static_cast<APlayerPawn *> (GetDefaultByName ("DoomPlayer"));
|
||||
if (player != NULL)
|
||||
{
|
||||
player->health = deh.StartHealth;
|
||||
}
|
||||
|
||||
// 0xDD means "enable infighting"
|
||||
if (infighting == 0xDD)
|
||||
{
|
||||
|
|
|
@ -97,6 +97,7 @@ extern void M_RestoreMode ();
|
|||
extern void M_SetDefaultMode ();
|
||||
extern void R_ExecuteSetViewSize ();
|
||||
extern void G_NewInit ();
|
||||
extern void SetupPlayerClasses ();
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
|
@ -2017,9 +2018,18 @@ void D_DoomMain (void)
|
|||
|
||||
FActorInfo::StaticInit ();
|
||||
|
||||
// [GRB] Initialize player class list
|
||||
SetupPlayerClasses ();
|
||||
|
||||
// [RH] Load custom key and weapon settings from WADs
|
||||
D_LoadWadSettings ();
|
||||
|
||||
// [GRB] Check if someone used clearplayerclasses but not addplayerclass
|
||||
if (PlayerClasses.Size () == 0)
|
||||
{
|
||||
I_FatalError ("No player classes defined");
|
||||
}
|
||||
|
||||
FActorInfo::StaticGameSet ();
|
||||
|
||||
Printf ("Init DOOM refresh subsystem.\n");
|
||||
|
|
|
@ -47,18 +47,11 @@ enum
|
|||
GENDER_NEUTER
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYERCLASS_Random = -1,
|
||||
PLAYERCLASS_Fighter,
|
||||
PLAYERCLASS_Cleric,
|
||||
PALYERCLASS_Mage
|
||||
};
|
||||
extern const char *PlayerClassNames[4];
|
||||
|
||||
int D_GenderToInt (const char *gender);
|
||||
extern const char *GenderNames[3];
|
||||
|
||||
int D_PlayerClassToInt (const char *classname);
|
||||
|
||||
struct userinfo_s
|
||||
{
|
||||
char netname[MAXPLAYERNAME+1];
|
||||
|
|
|
@ -83,11 +83,6 @@ enum
|
|||
INFO_PlayerClass,
|
||||
};
|
||||
|
||||
const char *PlayerClassNames[4] =
|
||||
{
|
||||
"Random", "Fighter", "Cleric", "Mage"
|
||||
};
|
||||
|
||||
const char *TeamNames[NUM_TEAMS] =
|
||||
{
|
||||
"Red", "Blue", "Green", "Gold"
|
||||
|
@ -125,16 +120,25 @@ int D_GenderToInt (const char *gender)
|
|||
return GENDER_MALE;
|
||||
}
|
||||
|
||||
static int D_PlayerClassToInt (const char *classname)
|
||||
int D_PlayerClassToInt (const char *classname)
|
||||
{
|
||||
for (int i = 1; i <= 3; ++i)
|
||||
if (PlayerClasses.Size () > 1)
|
||||
{
|
||||
if (stricmp (PlayerClassNames[i], classname) == 0)
|
||||
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i)
|
||||
{
|
||||
return i-1;
|
||||
const PClass *type = PlayerClasses[i].Type;
|
||||
|
||||
if (stricmp (type->Meta.GetMetaString (APMETA_DisplayName), classname) == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void D_GetPlayerColor (int player, float *h, float *s, float *v)
|
||||
|
@ -319,7 +323,7 @@ void D_SetupUserInfo ()
|
|||
coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1));
|
||||
}
|
||||
coninfo->color = color;
|
||||
coninfo->skin = R_FindSkin (skin);
|
||||
coninfo->skin = R_FindSkin (skin, 0);
|
||||
coninfo->gender = D_GenderToInt (gender);
|
||||
coninfo->neverswitch = neverswitchonpickup;
|
||||
coninfo->MoveBob = (fixed_t)(65536.f * movebob);
|
||||
|
@ -494,6 +498,8 @@ void D_WriteUserInfoStrings (int i, byte **stream, bool compact)
|
|||
{
|
||||
userinfo_t *info = &players[i].userinfo;
|
||||
|
||||
const PClass *type = PlayerClasses[info->PlayerClass].Type;
|
||||
|
||||
if (!compact)
|
||||
{
|
||||
sprintf (*((char **)stream),
|
||||
|
@ -517,7 +523,8 @@ void D_WriteUserInfoStrings (int i, byte **stream, bool compact)
|
|||
info->neverswitch,
|
||||
(float)(info->MoveBob) / 65536.f,
|
||||
(float)(info->StillBob) / 65536.f,
|
||||
PlayerClassNames[info->PlayerClass+1]
|
||||
info->PlayerClass == -1 ? "Random" :
|
||||
type->Meta.GetMetaString (APMETA_DisplayName)
|
||||
);
|
||||
}
|
||||
else
|
||||
|
@ -545,7 +552,8 @@ void D_WriteUserInfoStrings (int i, byte **stream, bool compact)
|
|||
info->neverswitch,
|
||||
(float)(info->MoveBob) / 65536.f,
|
||||
(float)(info->StillBob) / 65536.f,
|
||||
PlayerClassNames[info->PlayerClass+1]
|
||||
info->PlayerClass == -1 ? "Random" :
|
||||
type->Meta.GetMetaString (APMETA_DisplayName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -647,24 +655,20 @@ void D_ReadUserInfoStrings (int i, byte **stream, bool update)
|
|||
break;
|
||||
|
||||
case INFO_Skin:
|
||||
info->skin = R_FindSkin (value);
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
info->skin = R_FindSkin (value, players[i].CurrentPlayerClass);
|
||||
if (players[i].mo != NULL)
|
||||
{
|
||||
if (players[i].mo != NULL && gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
if (players[i].cls != NULL &&
|
||||
players[i].mo->state->sprite.index ==
|
||||
GetDefaultByType (players[i].cls)->SpawnState->sprite.index)
|
||||
{ // Only change the sprite if the player is using a standard one
|
||||
players[i].mo->sprite = skins[info->skin].sprite;
|
||||
players[i].mo->xscale = players[i].mo->yscale = skins[info->skin].scale;
|
||||
}
|
||||
if (players[i].cls != NULL &&
|
||||
players[i].mo->state->sprite.index ==
|
||||
GetDefaultByType (players[i].cls)->SpawnState->sprite.index)
|
||||
{ // Only change the sprite if the player is using a standard one
|
||||
players[i].mo->sprite = skins[info->skin].sprite;
|
||||
players[i].mo->xscale = players[i].mo->yscale = skins[info->skin].scale;
|
||||
}
|
||||
players[i].skin = &skins[info->skin];
|
||||
// Rebuild translation in case the new skin uses a different range
|
||||
// than the old one.
|
||||
R_BuildPlayerTranslation (i);
|
||||
}
|
||||
// Rebuild translation in case the new skin uses a different range
|
||||
// than the old one.
|
||||
R_BuildPlayerTranslation (i);
|
||||
if (StatusBar != NULL && i == StatusBar->GetPlayer())
|
||||
{
|
||||
StatusBar->SetFace (&skins[info->skin]);
|
||||
|
|
|
@ -45,6 +45,15 @@
|
|||
//Added by MC:
|
||||
#include "b_bot.h"
|
||||
|
||||
enum
|
||||
{
|
||||
APMETA_BASE = 0x95000,
|
||||
|
||||
APMETA_DisplayName, // display name (used in menus etc.)
|
||||
APMETA_SoundClass, // sound class
|
||||
APMETA_ColorRange, // skin color range
|
||||
};
|
||||
|
||||
class player_s;
|
||||
|
||||
class APlayerPawn : public AActor
|
||||
|
@ -64,8 +73,6 @@ public:
|
|||
virtual void PlayAttacking2 ();
|
||||
virtual void ThrowPoisonBag ();
|
||||
virtual void GiveDefaultInventory ();
|
||||
virtual const char *GetSoundClass ();
|
||||
virtual fixed_t GetJumpZ ();
|
||||
virtual void TweakSpeeds (int &forwardmove, int &sidemove);
|
||||
virtual bool DoHealingRadius (APlayerPawn *other);
|
||||
virtual void MorphPlayerThink ();
|
||||
|
@ -75,6 +82,8 @@ public:
|
|||
virtual void GiveDeathmatchInventory ();
|
||||
virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
|
||||
|
||||
const char *GetSoundClass ();
|
||||
|
||||
enum EInvulState
|
||||
{
|
||||
INVUL_Start,
|
||||
|
@ -88,8 +97,18 @@ public:
|
|||
void BeginPlay ();
|
||||
void Die (AActor *source, AActor *inflictor);
|
||||
|
||||
fixed_t JumpZ; // [GRB] Variable JumpZ
|
||||
int crouchsprite;
|
||||
int MaxHealth;
|
||||
|
||||
// [GRB] Player class properties
|
||||
fixed_t JumpZ;
|
||||
fixed_t ViewHeight;
|
||||
fixed_t ForwardMove1, ForwardMove2;
|
||||
fixed_t SideMove1, SideMove2;
|
||||
int ScoreIcon;
|
||||
int SpawnMask;
|
||||
|
||||
int GetMaxHealth() const;
|
||||
};
|
||||
|
||||
class APlayerChunk : public APlayerPawn
|
||||
|
@ -177,7 +196,6 @@ public:
|
|||
float FOV; // current field of vision
|
||||
fixed_t viewz; // focal origin above r.z
|
||||
fixed_t viewheight; // base height above floor for viewz
|
||||
fixed_t defaultviewheight; // The normal view height when standing
|
||||
fixed_t deltaviewheight; // squat speed.
|
||||
fixed_t bob; // bounded/scaled total momentum
|
||||
|
||||
|
@ -275,7 +293,6 @@ public:
|
|||
fixed_t oldx;
|
||||
fixed_t oldy;
|
||||
|
||||
FPlayerSkin *skin; // [RH] Sprite override
|
||||
float BlendR; // [RH] Final blending values
|
||||
float BlendG;
|
||||
float BlendB;
|
||||
|
@ -291,7 +308,7 @@ public:
|
|||
|
||||
fixed_t GetDeltaViewHeight() const
|
||||
{
|
||||
return (defaultviewheight + crouchviewdelta - viewheight) >> 3;
|
||||
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
||||
}
|
||||
|
||||
void Uncrouch()
|
||||
|
@ -302,6 +319,8 @@ public:
|
|||
crouching = 0;
|
||||
crouchviewdelta = 0;
|
||||
}
|
||||
|
||||
int GetSpawnClass();
|
||||
};
|
||||
|
||||
typedef player_s player_t;
|
||||
|
@ -321,4 +340,27 @@ void P_CheckPlayerSprites();
|
|||
#define MAX_DN_ANGLE 56 // Max looking down angle
|
||||
#define MAX_UP_ANGLE 32 // Max looking up angle
|
||||
|
||||
|
||||
// [GRB] Custom player classes
|
||||
enum
|
||||
{
|
||||
PCF_NOMENU = 1, // Hide in new game menu
|
||||
};
|
||||
|
||||
class FPlayerClass
|
||||
{
|
||||
public:
|
||||
FPlayerClass ();
|
||||
FPlayerClass (const FPlayerClass &other);
|
||||
~FPlayerClass ();
|
||||
|
||||
bool CheckSkin (int skin);
|
||||
|
||||
const PClass *Type;
|
||||
DWORD Flags;
|
||||
TArray<int> Skins;
|
||||
};
|
||||
|
||||
extern TArray<FPlayerClass> PlayerClasses;
|
||||
|
||||
#endif // __D_PLAYER_H__
|
||||
|
|
|
@ -75,9 +75,6 @@ FState ADoomPlayer::States[] =
|
|||
S_NORMAL (PLAY, 'W', 5, NULL , &States[S_HTIC_XDIE+8]),
|
||||
S_NORMAL (PLAY, 'X', 5, NULL , &States[S_HTIC_XDIE+9]),
|
||||
S_NORMAL (PLAY, 'Y', -1, NULL , NULL),
|
||||
|
||||
#define S_CROUCH (S_HTIC_XDIE+10) // only here so that the crouching sprite is entered into the sprite table.
|
||||
S_NORMAL (PLYC, 'A', -1, NULL , NULL),
|
||||
};
|
||||
|
||||
IMPLEMENT_ACTOR (ADoomPlayer, Doom, -1, 0)
|
||||
|
@ -97,24 +94,32 @@ IMPLEMENT_ACTOR (ADoomPlayer, Doom, -1, 0)
|
|||
PROP_MissileState (S_PLAY_ATK)
|
||||
PROP_DeathState (S_PLAY_DIE)
|
||||
PROP_XDeathState (S_PLAY_XDIE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_ColorRange (112, 127)
|
||||
PROP_PlayerPawn_DisplayName ("Marine")
|
||||
PROP_PlayerPawn_CrouchSprite ("PLYC")
|
||||
END_DEFAULTS
|
||||
|
||||
void ADoomPlayer::GiveDefaultInventory ()
|
||||
{
|
||||
AInventory *fist, *pistol, *bullets;
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
player->health = deh.StartHealth; // [RH] Used to be MAXHEALTH
|
||||
health = deh.StartHealth;
|
||||
fist = player->mo->GiveInventoryType (PClass::FindClass ("Fist"));
|
||||
pistol = player->mo->GiveInventoryType (PClass::FindClass ("Pistol"));
|
||||
// Adding the pistol automatically adds bullets
|
||||
bullets = player->mo->FindInventory (PClass::FindClass ("Clip"));
|
||||
if (bullets != NULL)
|
||||
if (!Inventory)
|
||||
{
|
||||
bullets->Amount = deh.StartBullets; // [RH] Used to be 50
|
||||
AInventory *fist, *pistol, *bullets;
|
||||
|
||||
fist = player->mo->GiveInventoryType (PClass::FindClass ("Fist"));
|
||||
pistol = player->mo->GiveInventoryType (PClass::FindClass ("Pistol"));
|
||||
// Adding the pistol automatically adds bullets
|
||||
bullets = player->mo->FindInventory (PClass::FindClass ("Clip"));
|
||||
if (bullets != NULL)
|
||||
{
|
||||
bullets->Amount = deh.StartBullets; // [RH] Used to be 50
|
||||
}
|
||||
player->ReadyWeapon = player->PendingWeapon =
|
||||
static_cast<AWeapon *> (deh.StartBullets > 0 ? pistol : fist);
|
||||
}
|
||||
player->ReadyWeapon = player->PendingWeapon =
|
||||
static_cast<AWeapon *> (deh.StartBullets > 0 ? pistol : fist);
|
||||
}
|
||||
|
||||
void A_FireScream (AActor *self)
|
||||
|
@ -182,57 +187,33 @@ void A_PlayerScream (AActor *self)
|
|||
S_SoundID (self, chan, sound, 1, ATTN_NORM);
|
||||
}
|
||||
|
||||
AT_GAME_SET(DoomPlayer)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_DoomSkinCheck1
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void A_DoomSkinCheck1 (AActor *actor)
|
||||
{
|
||||
// Sets the crouching sprite.
|
||||
// Exception: If the normal sprite is from a PWAD and the crouching sprite from ZDoom.pk3
|
||||
// it is assumed that they don't match and the crouching sprite is disabled.
|
||||
// This code is not executed when the player already has a crouch sprite (set by DECORATE.)
|
||||
if (gameinfo.gametype == GAME_Doom && GetDefault<ADoomPlayer>()->crouchsprite == 0)
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].othergame)
|
||||
{
|
||||
int spritenorm = Wads.CheckNumForName("PLAYA1", ns_sprites);
|
||||
int spritecrouch = Wads.CheckNumForName("PLYCA1", ns_sprites);
|
||||
|
||||
if (spritenorm==-1 || spritecrouch ==-1) return;
|
||||
|
||||
int wadnorm = Wads.GetLumpFile(spritenorm);
|
||||
int wadcrouch = Wads.GetLumpFile(spritenorm);
|
||||
|
||||
if (wadnorm > FWadCollection::IWAD_FILENUM && wadcrouch <= FWadCollection::IWAD_FILENUM)
|
||||
{
|
||||
// Question: Add an option / disable crouching or do what?
|
||||
return;
|
||||
}
|
||||
actor->SetState (&ADoomPlayer::States[S_HTIC_DIE]);
|
||||
}
|
||||
GetDefault<ADoomPlayer>()->crouchsprite = ADoomPlayer::States[S_CROUCH].sprite.index;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_DoomSkinCheck1
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void A_DoomSkinCheck1 (AActor *actor)
|
||||
{
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].game != GAME_Doom)
|
||||
{
|
||||
actor->SetState (&ADoomPlayer::States[S_HTIC_DIE]);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_DoomSkinCheck2
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void A_DoomSkinCheck2 (AActor *actor)
|
||||
{
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].game != GAME_Doom)
|
||||
{
|
||||
actor->SetState (&ADoomPlayer::States[S_HTIC_XDIE]);
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
// A_DoomSkinCheck2
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void A_DoomSkinCheck2 (AActor *actor)
|
||||
{
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].othergame)
|
||||
{
|
||||
actor->SetState (&ADoomPlayer::States[S_HTIC_XDIE]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "p_local.h"
|
||||
#include "a_doomglobal.h"
|
||||
#include "a_action.h"
|
||||
#include "thingdef.h"
|
||||
|
||||
void A_PainAttack (AActor *);
|
||||
void A_PainDie (AActor *);
|
||||
|
|
|
@ -408,7 +408,12 @@ CCMD (useflechette)
|
|||
if (m_Instigator == NULL)
|
||||
return;
|
||||
|
||||
i = (m_Instigator->player->CurrentPlayerClass + 2) % 3;
|
||||
if (m_Instigator->IsKindOf (PClass::FindClass (NAME_ClericPlayer)))
|
||||
i = 0;
|
||||
else if (m_Instigator->IsKindOf (PClass::FindClass (NAME_MagePlayer)))
|
||||
i = 1;
|
||||
else
|
||||
i = 2;
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
|
|
|
@ -108,10 +108,8 @@ class AChickenPlayer : public APlayerPawn
|
|||
{
|
||||
DECLARE_ACTOR (AChickenPlayer, APlayerPawn)
|
||||
public:
|
||||
fixed_t GetJumpZ () { return FRACUNIT; }
|
||||
void MorphPlayerThink ();
|
||||
void ActivateMorphWeapon ();
|
||||
void TweakSpeeds (int &forward, int &side);
|
||||
};
|
||||
|
||||
FState AChickenPlayer::States[] =
|
||||
|
@ -160,6 +158,14 @@ IMPLEMENT_ACTOR (AChickenPlayer, Heretic, -1, 0)
|
|||
PROP_MissileState (S_CHICPLAY_ATK)
|
||||
PROP_DeathState (S_CHICPLAY_DIE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (FRACUNIT)
|
||||
PROP_PlayerPawn_ViewHeight (21*FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove1 (FRACUNIT * 2500 / 2048)
|
||||
PROP_PlayerPawn_ForwardMove2 (FRACUNIT * 2500 / 2048)
|
||||
PROP_PlayerPawn_SideMove1 (FRACUNIT * 2500 / 2048)
|
||||
PROP_PlayerPawn_SideMove2 (FRACUNIT * 2500 / 2048)
|
||||
|
||||
PROP_PainSound ("chicken/pain")
|
||||
PROP_DeathSound ("chicken/death")
|
||||
END_DEFAULTS
|
||||
|
@ -180,7 +186,7 @@ void AChickenPlayer::MorphPlayerThink ()
|
|||
}
|
||||
if ((z <= floorz) && (pr_chickenplayerthink() < 32))
|
||||
{ // Jump and noise
|
||||
momz += GetJumpZ ();
|
||||
momz += JumpZ;
|
||||
if (PainState != NULL)
|
||||
{
|
||||
SetState (PainState);
|
||||
|
@ -207,12 +213,6 @@ void AChickenPlayer::ActivateMorphWeapon ()
|
|||
}
|
||||
}
|
||||
|
||||
void AChickenPlayer::TweakSpeeds (int &forward, int &side)
|
||||
{
|
||||
forward = forward * 2500 / 2048;
|
||||
side = side * 2500 / 2048;
|
||||
}
|
||||
|
||||
// Chicken (non-player) -----------------------------------------------------
|
||||
|
||||
class AChicken : public AActor
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "d_player.h"
|
||||
#include "a_action.h"
|
||||
#include "p_local.h"
|
||||
#include "thingdef.h"
|
||||
|
||||
static FRandom pr_skullpop ("SkullPop");
|
||||
|
||||
|
@ -12,7 +13,7 @@ void A_Pain (AActor *);
|
|||
void A_PlayerScream (AActor *);
|
||||
void A_CheckSkullFloor (AActor *);
|
||||
void A_CheckSkullDone (AActor *);
|
||||
void A_FlameSnd (AActor *);
|
||||
void A_FireScream (AActor *);
|
||||
void A_HereticSkinCheck1 (AActor *);
|
||||
void A_HereticSkinCheck2 (AActor *);
|
||||
void A_XScream (AActor *);
|
||||
|
@ -69,13 +70,13 @@ FState AHereticPlayer::States[] =
|
|||
S_NORMAL (PLAY, 'Y', -1, NULL , NULL),
|
||||
|
||||
#define S_PLAY_FDTH (S_PLAY_XDIE+10)
|
||||
S_BRIGHT (FDTH, 'A', 5, A_FlameSnd , &States[S_PLAY_FDTH+1]),
|
||||
S_BRIGHT (FDTH, 'A', 5, A_FireScream , &States[S_PLAY_FDTH+1]),
|
||||
S_BRIGHT (FDTH, 'B', 4, NULL , &States[S_PLAY_FDTH+2]),
|
||||
S_BRIGHT (FDTH, 'C', 5, NULL , &States[S_PLAY_FDTH+3]),
|
||||
S_BRIGHT (FDTH, 'D', 4, A_PlayerScream , &States[S_PLAY_FDTH+4]),
|
||||
S_BRIGHT (FDTH, 'E', 5, NULL , &States[S_PLAY_FDTH+5]),
|
||||
S_BRIGHT (FDTH, 'F', 4, NULL , &States[S_PLAY_FDTH+6]),
|
||||
S_BRIGHT (FDTH, 'G', 5, A_FlameSnd , &States[S_PLAY_FDTH+7]),
|
||||
S_BRIGHT (FDTH, 'G', 5, A_FireScream , &States[S_PLAY_FDTH+7]),
|
||||
S_BRIGHT (FDTH, 'H', 4, NULL , &States[S_PLAY_FDTH+8]),
|
||||
S_BRIGHT (FDTH, 'I', 5, NULL , &States[S_PLAY_FDTH+9]),
|
||||
S_BRIGHT (FDTH, 'J', 4, NULL , &States[S_PLAY_FDTH+10]),
|
||||
|
@ -128,19 +129,27 @@ IMPLEMENT_ACTOR (AHereticPlayer, Heretic, -1, 0)
|
|||
PROP_DeathState (S_PLAY_DIE)
|
||||
PROP_XDeathState (S_PLAY_XDIE)
|
||||
PROP_BDeathState (S_PLAY_FDTH)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_ColorRange (225, 240)
|
||||
PROP_PlayerPawn_DisplayName ("Corvus")
|
||||
END_DEFAULTS
|
||||
|
||||
void AHereticPlayer::GiveDefaultInventory ()
|
||||
{
|
||||
AInventory *wand, *ammo;
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
player->health = GetDefault()->health;
|
||||
player->mo->GiveInventoryType (PClass::FindClass ("Staff"));
|
||||
wand = player->mo->GiveInventoryType (PClass::FindClass ("GoldWand"));
|
||||
// Adding the gold wand automatically adds its ammo
|
||||
ammo = player->mo->FindInventory (PClass::FindClass ("GoldWandAmmo"));
|
||||
ammo->Amount = 50;
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (wand);
|
||||
if (!Inventory)
|
||||
{
|
||||
AInventory *wand, *ammo;
|
||||
|
||||
player->mo->GiveInventoryType (PClass::FindClass ("Staff"));
|
||||
wand = player->mo->GiveInventoryType (PClass::FindClass ("GoldWand"));
|
||||
// Adding the gold wand automatically adds its ammo
|
||||
ammo = player->mo->FindInventory (PClass::FindClass ("GoldWandAmmo"));
|
||||
ammo->Amount = 50;
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (wand);
|
||||
}
|
||||
}
|
||||
|
||||
// The player's skull -------------------------------------------------------
|
||||
|
@ -185,8 +194,16 @@ void A_SkullPop (AActor *actor)
|
|||
APlayerPawn *mo;
|
||||
player_t *player;
|
||||
|
||||
// [GRB] Parameterized version
|
||||
const PClass *spawntype = NULL;
|
||||
int index = CheckIndex (1, NULL);
|
||||
if (index >= 0)
|
||||
spawntype = PClass::FindClass((ENamedName)StateParameters[index]);
|
||||
if (!spawntype || !spawntype->IsDescendantOf (RUNTIME_CLASS (APlayerChunk)))
|
||||
spawntype = RUNTIME_CLASS (ABloodySkull);
|
||||
|
||||
actor->flags &= ~MF_SOLID;
|
||||
mo = Spawn<ABloodySkull> (actor->x, actor->y, actor->z + 48*FRACUNIT);
|
||||
mo = (APlayerPawn *)Spawn (spawntype, actor->x, actor->y, actor->z + 48*FRACUNIT);
|
||||
//mo->target = actor;
|
||||
mo->momx = pr_skullpop.Random2() << 9;
|
||||
mo->momy = pr_skullpop.Random2() << 9;
|
||||
|
@ -236,17 +253,6 @@ void A_CheckSkullDone (AActor *actor)
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// PROC A_FlameSnd
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void A_FlameSnd (AActor *actor)
|
||||
{
|
||||
S_Sound (actor, CHAN_BODY, "misc/burn", 1, ATTN_NORM); // Burn sound
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_HereticSkinCheck1
|
||||
|
@ -256,7 +262,7 @@ void A_FlameSnd (AActor *actor)
|
|||
void A_HereticSkinCheck1 (AActor *actor)
|
||||
{
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].game == GAME_Doom)
|
||||
skins[actor->player->userinfo.skin].othergame)
|
||||
{
|
||||
actor->SetState (&AHereticPlayer::States[S_DOOM_DIE]);
|
||||
}
|
||||
|
@ -271,7 +277,7 @@ void A_HereticSkinCheck1 (AActor *actor)
|
|||
void A_HereticSkinCheck2 (AActor *actor)
|
||||
{
|
||||
if (actor->player != NULL &&
|
||||
skins[actor->player->userinfo.skin].game == GAME_Doom)
|
||||
skins[actor->player->userinfo.skin].othergame)
|
||||
{
|
||||
actor->SetState (&AHereticPlayer::States[S_DOOM_XDIE]);
|
||||
}
|
||||
|
|
|
@ -106,17 +106,18 @@ IMPLEMENT_ACTOR (AClericPlayer, Hexen, -1, 0)
|
|||
PROP_BDeathState (S_PLAY_C_FDTH)
|
||||
PROP_IDeathState (S_CPLAY_ICE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (FRACUNIT*39/4) // ~9.75
|
||||
PROP_PlayerPawn_ViewHeight (48*FRACUNIT)
|
||||
PROP_PlayerPawn_ColorRange (146, 163)
|
||||
PROP_PlayerPawn_SpawnMask (MTF_CLERIC)
|
||||
|
||||
PROP_PlayerPawn_DisplayName ("Cleric")
|
||||
PROP_PlayerPawn_SoundClass ("cleric")
|
||||
PROP_PlayerPawn_ScoreIcon ("CLERFACE")
|
||||
PROP_PainSound ("PlayerClericPain")
|
||||
END_DEFAULTS
|
||||
|
||||
const char *AClericPlayer::GetSoundClass ()
|
||||
{
|
||||
if (player == NULL || player->userinfo.skin == 0)
|
||||
{
|
||||
return "cleric";
|
||||
}
|
||||
return Super::GetSoundClass ();
|
||||
}
|
||||
void AClericPlayer::PlayAttacking2 ()
|
||||
{
|
||||
SetState (MissileState);
|
||||
|
@ -124,9 +125,13 @@ void AClericPlayer::PlayAttacking2 ()
|
|||
|
||||
void AClericPlayer::GiveDefaultInventory ()
|
||||
{
|
||||
player->health = GetDefault()->health;
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("CWeapMace")));
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
if (!Inventory)
|
||||
{
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("CWeapMace")));
|
||||
}
|
||||
|
||||
GiveInventoryType (RUNTIME_CLASS(AHexenArmor));
|
||||
AHexenArmor *armor = FindInventory<AHexenArmor>();
|
||||
|
@ -137,11 +142,6 @@ void AClericPlayer::GiveDefaultInventory ()
|
|||
armor->SlotsIncrement[3] = 20*FRACUNIT;
|
||||
}
|
||||
|
||||
fixed_t AClericPlayer::GetJumpZ ()
|
||||
{
|
||||
return FRACUNIT*39/4; // ~9.75
|
||||
}
|
||||
|
||||
void AClericPlayer::SpecialInvulnerabilityHandling (EInvulState state, fixed_t * pAlpha)
|
||||
{
|
||||
if (state == INVUL_Active)
|
||||
|
|
|
@ -104,17 +104,22 @@ IMPLEMENT_ACTOR (AFighterPlayer, Hexen, -1, 0)
|
|||
PROP_BDeathState (S_PLAY_F_FDTH)
|
||||
PROP_IDeathState (S_FPLAY_ICE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (FRACUNIT*39/4) // ~9.75
|
||||
PROP_PlayerPawn_ViewHeight (48*FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove1 (FRACUNIT * 0x1d / 0x19)
|
||||
PROP_PlayerPawn_ForwardMove2 (FRACUNIT * 0x3c / 0x32)
|
||||
PROP_PlayerPawn_SideMove1 (FRACUNIT * 0x1b / 0x18)
|
||||
PROP_PlayerPawn_SideMove2 (FRACUNIT * 0x3b / 0x28) // The fighter is a very fast strafer when running!
|
||||
PROP_PlayerPawn_ColorRange (246, 254)
|
||||
PROP_PlayerPawn_SpawnMask (MTF_FIGHTER)
|
||||
PROP_PlayerPawn_DisplayName ("Fighter")
|
||||
PROP_PlayerPawn_SoundClass ("fighter")
|
||||
PROP_PlayerPawn_ScoreIcon ("FITEFACE")
|
||||
|
||||
PROP_PainSound ("PlayerFighterPain")
|
||||
END_DEFAULTS
|
||||
|
||||
const char *AFighterPlayer::GetSoundClass ()
|
||||
{
|
||||
if (player == NULL || player->userinfo.skin == 0)
|
||||
{
|
||||
return "fighter";
|
||||
}
|
||||
return Super::GetSoundClass ();
|
||||
}
|
||||
void AFighterPlayer::PlayAttacking2 ()
|
||||
{
|
||||
SetState (MissileState);
|
||||
|
@ -122,9 +127,13 @@ void AFighterPlayer::PlayAttacking2 ()
|
|||
|
||||
void AFighterPlayer::GiveDefaultInventory ()
|
||||
{
|
||||
player->health = GetDefault()->health;
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("FWeapFist")));
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
if (!Inventory)
|
||||
{
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("FWeapFist")));
|
||||
}
|
||||
|
||||
GiveInventoryType (RUNTIME_CLASS(AHexenArmor));
|
||||
AHexenArmor *armor = FindInventory<AHexenArmor>();
|
||||
|
@ -340,32 +349,6 @@ punchdone:
|
|||
return;
|
||||
}
|
||||
|
||||
void AFighterPlayer::TweakSpeeds (int &forward, int &side)
|
||||
{
|
||||
if ((unsigned int)(forward + 0x31ff) < 0x63ff)
|
||||
{
|
||||
forward = forward * 0x1d / 0x19;
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = forward * 0x3c / 0x32;
|
||||
}
|
||||
if ((unsigned int)(side + 0x27ff) < 0x4fff)
|
||||
{
|
||||
side = side * 0x1b / 0x18;
|
||||
}
|
||||
else
|
||||
{ // The fighter is a very fast strafer when running!
|
||||
side = side * 0x3b / 0x28;
|
||||
}
|
||||
Super::TweakSpeeds (forward, side);
|
||||
}
|
||||
|
||||
fixed_t AFighterPlayer::GetJumpZ ()
|
||||
{
|
||||
return FRACUNIT*39/4; // ~9.75
|
||||
}
|
||||
|
||||
// Radius armor boost
|
||||
bool AFighterPlayer::DoHealingRadius (APlayerPawn *other)
|
||||
{
|
||||
|
|
|
@ -83,9 +83,6 @@ class AFighterPlayer : public APlayerPawn
|
|||
public:
|
||||
void PlayAttacking2 ();
|
||||
void GiveDefaultInventory ();
|
||||
void TweakSpeeds (int &forward, int &side);
|
||||
const char *GetSoundClass ();
|
||||
fixed_t GetJumpZ ();
|
||||
bool DoHealingRadius (APlayerPawn *other);
|
||||
};
|
||||
|
||||
|
@ -102,8 +99,6 @@ class AClericPlayer : public APlayerPawn
|
|||
public:
|
||||
void PlayAttacking2 ();
|
||||
void GiveDefaultInventory ();
|
||||
const char *GetSoundClass ();
|
||||
fixed_t GetJumpZ ();
|
||||
void SpecialInvulnerabilityHandling (EInvulState state, fixed_t * pAlpha);
|
||||
};
|
||||
|
||||
|
@ -120,9 +115,6 @@ class AMagePlayer : public APlayerPawn
|
|||
public:
|
||||
void PlayAttacking2 ();
|
||||
void GiveDefaultInventory ();
|
||||
void TweakSpeeds (int &forward, int &side);
|
||||
const char *GetSoundClass ();
|
||||
fixed_t GetJumpZ ();
|
||||
bool DoHealingRadius (APlayerPawn *other);
|
||||
void SpecialInvulnerabilityHandling (EInvulState state, fixed_t * pAlpha);
|
||||
};
|
||||
|
|
|
@ -103,17 +103,22 @@ IMPLEMENT_ACTOR (AMagePlayer, Hexen, -1, 0)
|
|||
PROP_BDeathState (S_PLAY_M_FDTH)
|
||||
PROP_IDeathState (S_MPLAY_ICE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (FRACUNIT*39/4) // ~9.75
|
||||
PROP_PlayerPawn_ViewHeight (48*FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove1 (FRACUNIT * 0x16 / 0x19)
|
||||
PROP_PlayerPawn_ForwardMove2 (FRACUNIT * 0x2e / 0x32)
|
||||
PROP_PlayerPawn_SideMove1 (FRACUNIT * 0x15 / 0x18)
|
||||
PROP_PlayerPawn_SideMove2 (FRACUNIT * 0x25 / 0x28)
|
||||
PROP_PlayerPawn_ColorRange (146, 163)
|
||||
PROP_PlayerPawn_SpawnMask (MTF_MAGE)
|
||||
|
||||
PROP_PlayerPawn_DisplayName ("Mage")
|
||||
PROP_PlayerPawn_SoundClass ("mage")
|
||||
PROP_PlayerPawn_ScoreIcon ("MAGEFACE")
|
||||
PROP_PainSound ("PlayerMagePain")
|
||||
END_DEFAULTS
|
||||
|
||||
const char *AMagePlayer::GetSoundClass ()
|
||||
{
|
||||
if (player == NULL || player->userinfo.skin == 0)
|
||||
{
|
||||
return "mage";
|
||||
}
|
||||
return Super::GetSoundClass ();
|
||||
}
|
||||
void AMagePlayer::PlayAttacking2 ()
|
||||
{
|
||||
SetState (MissileState);
|
||||
|
@ -121,9 +126,13 @@ void AMagePlayer::PlayAttacking2 ()
|
|||
|
||||
void AMagePlayer::GiveDefaultInventory ()
|
||||
{
|
||||
player->health = GetDefault()->health;
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("MWeapWand")));
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
if (!Inventory)
|
||||
{
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *>
|
||||
(GiveInventoryType (PClass::FindClass ("MWeapWand")));
|
||||
}
|
||||
|
||||
GiveInventoryType (RUNTIME_CLASS(AHexenArmor));
|
||||
AHexenArmor *armor = FindInventory<AHexenArmor>();
|
||||
|
@ -134,32 +143,6 @@ void AMagePlayer::GiveDefaultInventory ()
|
|||
armor->SlotsIncrement[3] = 25*FRACUNIT;
|
||||
}
|
||||
|
||||
void AMagePlayer::TweakSpeeds (int &forward, int &side)
|
||||
{
|
||||
if ((unsigned int)(forward + 0x31ff) < 0x63ff)
|
||||
{
|
||||
forward = forward * 0x16 / 0x19;
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = forward * 0x2e / 0x32;
|
||||
}
|
||||
if ((unsigned int)(side + 0x27ff) < 0x4fff)
|
||||
{
|
||||
side = side * 0x15 / 0x18;
|
||||
}
|
||||
else
|
||||
{
|
||||
side = side * 0x25 / 0x28;
|
||||
}
|
||||
Super::TweakSpeeds (forward, side);
|
||||
}
|
||||
|
||||
fixed_t AMagePlayer::GetJumpZ ()
|
||||
{
|
||||
return FRACUNIT*39/4; // ~9.75
|
||||
}
|
||||
|
||||
// Radius mana boost
|
||||
bool AMagePlayer::DoHealingRadius (APlayerPawn *other)
|
||||
{
|
||||
|
|
|
@ -90,8 +90,6 @@ class APigPlayer : public APlayerPawn
|
|||
{
|
||||
DECLARE_ACTOR (APigPlayer, APlayerPawn)
|
||||
public:
|
||||
fixed_t GetJumpZ () { return 6*FRACUNIT; }
|
||||
void TweakSpeeds (int &forward, int &side);
|
||||
void MorphPlayerThink ();
|
||||
void ActivateMorphWeapon ();
|
||||
};
|
||||
|
@ -148,31 +146,18 @@ IMPLEMENT_ACTOR (APigPlayer, Hexen, -1, 0)
|
|||
PROP_DeathState (S_PIGPLAY_DIE1)
|
||||
PROP_IDeathState (S_PIGPLAY_ICE)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (6*FRACUNIT)
|
||||
PROP_PlayerPawn_ViewHeight (28*FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove1 (FRACUNIT * 0x18 / 0x19) // Yes, the pig is faster than a mage.
|
||||
PROP_PlayerPawn_ForwardMove2 (FRACUNIT * 0x31 / 0x32)
|
||||
PROP_PlayerPawn_SideMove1 (FRACUNIT * 0x17 / 0x18)
|
||||
PROP_PlayerPawn_SideMove2 (FRACUNIT * 0x27 / 0x28)
|
||||
|
||||
PROP_PainSound ("PigPain")
|
||||
PROP_DeathSound ("PigDeath")
|
||||
END_DEFAULTS
|
||||
|
||||
void APigPlayer::TweakSpeeds (int &forward, int &side)
|
||||
{
|
||||
// Yes, the pig is faster than a mage.
|
||||
if ((unsigned int)(forward + 0x31ff) < 0x63ff)
|
||||
{
|
||||
forward = forward * 0x18 / 0x19;
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = forward * 0x31 / 0x32;
|
||||
}
|
||||
if ((unsigned int)(side + 0x27ff) < 0x4fff)
|
||||
{
|
||||
side = side * 0x17 / 0x18;
|
||||
}
|
||||
else
|
||||
{
|
||||
side = side * 0x27 / 0x28;
|
||||
}
|
||||
}
|
||||
|
||||
void APigPlayer::MorphPlayerThink ()
|
||||
{
|
||||
if (player->morphTics&15)
|
||||
|
|
|
@ -2923,7 +2923,7 @@ static void InitPlayerClasses ()
|
|||
SinglePlayerClass[i] = players[i].userinfo.PlayerClass;
|
||||
if (SinglePlayerClass[i] < 0 || !playeringame[i])
|
||||
{
|
||||
SinglePlayerClass[i] = (pr_classchoice() >> 6) % 3;
|
||||
SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size ();
|
||||
}
|
||||
players[i].cls = NULL;
|
||||
players[i].CurrentPlayerClass = SinglePlayerClass[i];
|
||||
|
|
|
@ -76,7 +76,7 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
|
|||
actor->renderflags |= RF_INVISIBLE;
|
||||
p->morphTics = MORPHTICS;
|
||||
p->health = morphed->health;
|
||||
p->mo = static_cast<APlayerPawn *>(morphed);
|
||||
p->mo = morphed;
|
||||
p->momx = p->momy = 0;
|
||||
morphed->ObtainInventory (actor);
|
||||
// Remove all armor
|
||||
|
@ -94,6 +94,7 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
|
|||
{
|
||||
p->camera = morphed;
|
||||
}
|
||||
morphed->ScoreIcon = actor->ScoreIcon; // [GRB]
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -148,6 +149,7 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
|
|||
mo->flags3 = (mo->flags3 & ~MF3_GHOST) | (pmo->flags3 & MF3_GHOST);
|
||||
|
||||
player->morphTics = 0;
|
||||
player->viewheight = mo->ViewHeight;
|
||||
AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2));
|
||||
if (level2 != NULL)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "thingdef.h"
|
||||
#include "p_conversation.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_action.h"
|
||||
#include "m_random.h"
|
||||
|
@ -66,6 +67,55 @@ IMPLEMENT_ACTOR (AIceChunkHead, Any, -1, 0)
|
|||
PROP_SpawnState (0)
|
||||
END_DEFAULTS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// PROC A_NoBlocking
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void A_NoBlocking (AActor *actor)
|
||||
{
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (actor->flags & MF_STEALTH)
|
||||
{
|
||||
actor->alpha = OPAQUE;
|
||||
actor->visdir = 0;
|
||||
}
|
||||
|
||||
actor->flags &= ~MF_SOLID;
|
||||
|
||||
// If the actor has a conversation that sets an item to drop, drop that.
|
||||
if (actor->Conversation != NULL && actor->Conversation->DropType != NULL)
|
||||
{
|
||||
P_DropItem (actor, actor->Conversation->DropType, -1, 256);
|
||||
actor->Conversation = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
actor->Conversation = NULL;
|
||||
|
||||
// If the actor has attached metadata for items to drop, drop those.
|
||||
// Otherwise, call NoBlockingSet() and let it decide what to drop.
|
||||
if (!actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
|
||||
{
|
||||
FDropItem *di = GetDropItems(actor);
|
||||
|
||||
while (di != NULL)
|
||||
{
|
||||
if (di->Name != NAME_None)
|
||||
{
|
||||
const PClass *ti = PClass::FindClass(di->Name);
|
||||
if (ti) P_DropItem (actor, ti, di->amount, di->probability);
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->NoBlockingSet ();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_SetFloorClip
|
||||
|
@ -224,7 +274,7 @@ void A_FreezeDeathChunks (AActor *actor)
|
|||
}
|
||||
if (actor->player)
|
||||
{ // attach the player's view to a chunk of ice
|
||||
AIceChunkHead *head = Spawn<AIceChunkHead> (actor->x, actor->y, actor->z + actor->player->defaultviewheight);
|
||||
AIceChunkHead *head = Spawn<AIceChunkHead> (actor->x, actor->y, actor->z + actor->player->mo->ViewHeight);
|
||||
head->momz = FixedDiv(head->z-actor->z, actor->height)<<2;
|
||||
head->momx = pr_freeze.Random2 () << (FRACBITS-7);
|
||||
head->momy = pr_freeze.Random2 () << (FRACBITS-7);
|
||||
|
|
|
@ -186,7 +186,7 @@ bool P_GiveBody (AActor *actor, int num)
|
|||
|
||||
if (player != NULL)
|
||||
{
|
||||
max = ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina;
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->stamina;
|
||||
if (player->morphTics)
|
||||
{
|
||||
max = MAXMORPHHEALTH;
|
||||
|
@ -820,6 +820,7 @@ void AInventory::Hide ()
|
|||
{
|
||||
SetState (&States[S_HIDESPECIAL]);
|
||||
tics = 1400;
|
||||
if (ItemFlags & IF_PICKUPFLASH) tics += 30;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1091,16 +1092,6 @@ IMPLEMENT_STATELESS_ACTOR (APowerupGiver, Any, -1, 0)
|
|||
PROP_Inventory_PickupSound ("misc/p_pkup")
|
||||
END_DEFAULTS
|
||||
|
||||
AT_GAME_SET(PowerupGiver)
|
||||
{
|
||||
APowerupGiver * giver = GetDefault<APowerupGiver>();
|
||||
|
||||
if (gameinfo.gametype & GAME_Raven)
|
||||
{
|
||||
giver->RespawnTics = 1400+30;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AInventory :: DoRespawn
|
||||
|
@ -1816,7 +1807,7 @@ bool AHealth::TryPickup (AActor *other)
|
|||
PrevHealth = other->player->health;
|
||||
if (max == 0)
|
||||
{
|
||||
max = ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina;
|
||||
max = static_cast<APlayerPawn*>(other)->GetMaxHealth() + player->stamina;
|
||||
if (player->morphTics)
|
||||
{
|
||||
max = MAXMORPHHEALTH;
|
||||
|
|
|
@ -130,15 +130,24 @@ IMPLEMENT_ACTOR (AStrifePlayer, Strife, -1, 0)
|
|||
PROP_XDeathState (S_PLAY_XDIE)
|
||||
PROP_BDeathState (S_PLAY_BURNDEATH)
|
||||
PROP_EDeathState (S_PLAY_ZAPDEATH)
|
||||
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_ColorRange (96, 111)
|
||||
PROP_PlayerPawn_DisplayName ("Rebel")
|
||||
END_DEFAULTS
|
||||
|
||||
void AStrifePlayer::GiveDefaultInventory ()
|
||||
{
|
||||
AWeapon *weapon;
|
||||
Super::GiveDefaultInventory ();
|
||||
|
||||
player->health = GetDefault()->health;
|
||||
weapon = static_cast<AWeapon *>(player->mo->GiveInventoryType (PClass::FindClass ("PunchDagger")));
|
||||
player->ReadyWeapon = player->PendingWeapon = weapon;
|
||||
if (!Inventory)
|
||||
{
|
||||
AWeapon *weapon;
|
||||
|
||||
player->health = GetDefault()->health;
|
||||
weapon = static_cast<AWeapon *>(player->mo->GiveInventoryType (PClass::FindClass ("PunchDagger")));
|
||||
player->ReadyWeapon = player->PendingWeapon = weapon;
|
||||
}
|
||||
}
|
||||
|
||||
void AStrifePlayer::TweakSpeeds (int &forward, int &side)
|
||||
|
|
|
@ -51,8 +51,6 @@
|
|||
#include "i_input.h"
|
||||
#include "templates.h"
|
||||
|
||||
static const char *FaceNames[3] = { "FITEFACE", "CLERFACE", "MAGEFACE" };
|
||||
|
||||
static void HU_DrawTeamScores (player_t *, player_t *[MAXPLAYERS]);
|
||||
static void HU_DrawSingleScores (player_t *, player_t *[MAXPLAYERS]);
|
||||
static void HU_DrawTimeRemaining (int y);
|
||||
|
@ -244,10 +242,9 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int x, int y, int h
|
|||
|
||||
screen->Clear (x, y, x + 24*CleanXfac, y + height, color);
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen &&
|
||||
player->CurrentPlayerClass < 3)
|
||||
if (player->mo->ScoreIcon > 0)
|
||||
{
|
||||
screen->DrawTexture (TexMan[FaceNames[player->CurrentPlayerClass]], x+(pack?20:32)*CleanXfac, y,
|
||||
screen->DrawTexture (TexMan[player->mo->ScoreIcon], x+(pack?20:32)*CleanXfac, y,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
|
||||
|
|
39
src/info.cpp
39
src/info.cpp
|
@ -169,6 +169,24 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int GetSpriteIndex(const char * spritename)
|
||||
{
|
||||
for (unsigned i = 0; i < sprites.Size (); ++i)
|
||||
{
|
||||
if (strncmp (sprites[i].name, spritename, 4) == 0)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
spritedef_t temp;
|
||||
strncpy (temp.name, spritename, 4);
|
||||
temp.name[4] = 0;
|
||||
temp.numframes = 0;
|
||||
temp.spriteframes = 0;
|
||||
return (int)sprites.Push (temp);
|
||||
}
|
||||
|
||||
|
||||
// Change sprite names to indices
|
||||
static void ProcessStates (FState *states, int numstates)
|
||||
{
|
||||
|
@ -180,26 +198,7 @@ static void ProcessStates (FState *states, int numstates)
|
|||
{
|
||||
if (sprite == -1 || strncmp (sprites[sprite].name, states->sprite.name, 4) != 0)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
sprite = -1;
|
||||
for (i = 0; i < sprites.Size (); ++i)
|
||||
{
|
||||
if (strncmp (sprites[i].name, states->sprite.name, 4) == 0)
|
||||
{
|
||||
sprite = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sprite == -1)
|
||||
{
|
||||
spritedef_t temp;
|
||||
strncpy (temp.name, states->sprite.name, 4);
|
||||
temp.name[4] = 0;
|
||||
temp.numframes = 0;
|
||||
temp.spriteframes = 0;
|
||||
sprite = (int)sprites.Push (temp);
|
||||
}
|
||||
sprite = GetSpriteIndex(states->sprite.name);
|
||||
}
|
||||
states->sprite.index = sprite;
|
||||
states++;
|
||||
|
|
24
src/info.h
24
src/info.h
|
@ -166,11 +166,6 @@ struct FState
|
|||
static const PClass *StaticFindStateOwner (const FState *state, const FActorInfo *info);
|
||||
};
|
||||
|
||||
// A truly awful hack to get to the state that called an action function
|
||||
// without knowing whether it has been called from a weapon or actor.
|
||||
extern FState * CallingState;
|
||||
int CheckIndex(int paramsize, FState ** pcallstate=NULL);
|
||||
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FState *&state);
|
||||
|
||||
|
@ -245,7 +240,12 @@ enum
|
|||
ADEF_Obituary,
|
||||
ADEF_HitObituary,
|
||||
ADEF_Inventory_PickupMsg,
|
||||
ADEF_LastString = ADEF_Inventory_PickupMsg,
|
||||
// [GRB] Player class properties
|
||||
ADEF_PlayerPawn_CrouchSprite,
|
||||
ADEF_PlayerPawn_DisplayName,
|
||||
ADEF_PlayerPawn_SoundClass,
|
||||
ADEF_PlayerPawn_ScoreIcon,
|
||||
ADEF_LastString = ADEF_PlayerPawn_ScoreIcon,
|
||||
|
||||
// The rest of the properties use their type field (upper 2 bits)
|
||||
ADEF_XScale,
|
||||
|
@ -352,6 +352,16 @@ enum
|
|||
ADEF_Weapon_FlashState,
|
||||
ADEF_Sigil_NumPieces,
|
||||
|
||||
// [GRB] Player class properties
|
||||
ADEF_PlayerPawn_JumpZ,
|
||||
ADEF_PlayerPawn_ViewHeight,
|
||||
ADEF_PlayerPawn_ForwardMove1,
|
||||
ADEF_PlayerPawn_ForwardMove2,
|
||||
ADEF_PlayerPawn_SideMove1,
|
||||
ADEF_PlayerPawn_SideMove2,
|
||||
ADEF_PlayerPawn_ColorRange,
|
||||
ADEF_PlayerPawn_SpawnMask,
|
||||
|
||||
// The following are not properties but affect how the list is parsed
|
||||
ADEF_FirstCommand,
|
||||
ADEF_SkipSuper = ADEF_FirstCommand, // Take defaults from AActor instead of superclass(es)
|
||||
|
@ -424,6 +434,8 @@ private:
|
|||
|
||||
extern FDoomEdMap DoomEdMap;
|
||||
|
||||
int GetSpriteIndex(const char * spritename);
|
||||
|
||||
#include "infomacros.h"
|
||||
|
||||
#endif // __INFO_H__
|
||||
|
|
|
@ -128,6 +128,7 @@ static void ApplyActorDefault (int defnum, const char *datastr, int dataint)
|
|||
AWeapon *const weapon = (AWeapon *)sgDefaults;
|
||||
ASigil *const sigil = (ASigil *)sgDefaults;
|
||||
AAmmo *const ammo = (AAmmo *)sgDefaults;
|
||||
APlayerPawn *const player = (APlayerPawn *)sgDefaults;
|
||||
|
||||
switch (defnum)
|
||||
{
|
||||
|
@ -313,6 +314,32 @@ static void ApplyActorDefault (int defnum, const char *datastr, int dataint)
|
|||
case ADEF_Weapon_AltHoldAtkState:weapon->AltHoldAtkState = datastate; break;
|
||||
case ADEF_Weapon_FlashState: weapon->FlashState = datastate; break;
|
||||
case ADEF_Sigil_NumPieces: sigil->NumPieces = dataint; break;
|
||||
|
||||
// [GRB] Player class properties
|
||||
case ADEF_PlayerPawn_JumpZ: player->JumpZ = dataint; break;
|
||||
case ADEF_PlayerPawn_ViewHeight: player->ViewHeight = dataint; break;
|
||||
case ADEF_PlayerPawn_ForwardMove1: player->ForwardMove1 = dataint; break;
|
||||
case ADEF_PlayerPawn_ForwardMove2: player->ForwardMove2 = dataint; break;
|
||||
case ADEF_PlayerPawn_SideMove1: player->SideMove1 = dataint; break;
|
||||
case ADEF_PlayerPawn_SideMove2: player->SideMove2 = dataint; break;
|
||||
case ADEF_PlayerPawn_ColorRange: sgClass->Meta.SetMetaInt (APMETA_ColorRange, dataint); break;
|
||||
case ADEF_PlayerPawn_CrouchSprite: player->crouchsprite = GetSpriteIndex(datastr); break;
|
||||
case ADEF_PlayerPawn_SpawnMask: player->SpawnMask = dataint; break;
|
||||
|
||||
case ADEF_PlayerPawn_DisplayName:
|
||||
sgClass->Meta.SetMetaString (APMETA_DisplayName, datastr);
|
||||
break;
|
||||
case ADEF_PlayerPawn_SoundClass:
|
||||
sgClass->Meta.SetMetaString (APMETA_SoundClass, datastr);
|
||||
break;
|
||||
case ADEF_PlayerPawn_ScoreIcon:
|
||||
player->ScoreIcon = TexMan.AddPatch (datastr);
|
||||
if (player->ScoreIcon <= 0)
|
||||
{
|
||||
player->ScoreIcon = TexMan.AddPatch (datastr, ns_sprites);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,6 +210,11 @@ public:
|
|||
#define PROP_Obituary(x) ADD_STRING_PROP(ADEF_Obituary,"\21",x)
|
||||
#define PROP_HitObituary(x) ADD_STRING_PROP(ADEF_HitObituary,"\22",x)
|
||||
#define PROP_Inventory_PickupMessage(x) ADD_STRING_PROP(ADEF_Inventory_PickupMsg,"\23",x)
|
||||
// [GRB] Player class properties
|
||||
#define PROP_PlayerPawn_CrouchSprite(x) ADD_STRING_PROP(ADEF_PlayerPawn_CrouchSprite,"\24",x)
|
||||
#define PROP_PlayerPawn_DisplayName(x) ADD_STRING_PROP(ADEF_PlayerPawn_DisplayName,"\25",x)
|
||||
#define PROP_PlayerPawn_SoundClass(x) ADD_STRING_PROP(ADEF_PlayerPawn_SoundClass,"\26",x)
|
||||
#define PROP_PlayerPawn_ScoreIcon(x) ADD_STRING_PROP(ADEF_PlayerPawn_ScoreIcon,"\27",x)
|
||||
|
||||
#define PROP_XScale(x) ADD_BYTE_PROP(ADEF_XScale,x)
|
||||
#define PROP_YScale(x) ADD_BYTE_PROP(ADEF_YScale,x)
|
||||
|
@ -324,4 +329,14 @@ public:
|
|||
#define PROP_Weapon_FlashState(x) ADD_BYTE_PROP(ADEF_Weapon_FlashState,x)
|
||||
#define PROP_Sigil_NumPieces(x) ADD_BYTE_PROP(ADEF_Sigil_NumPieces,x)
|
||||
|
||||
// [GRB] Player class properties
|
||||
#define PROP_PlayerPawn_JumpZ(x) ADD_LONG_PROP(ADEF_PlayerPawn_JumpZ,x)
|
||||
#define PROP_PlayerPawn_ViewHeight(x) ADD_LONG_PROP(ADEF_PlayerPawn_ViewHeight,x)
|
||||
#define PROP_PlayerPawn_ForwardMove1(x) ADD_LONG_PROP(ADEF_PlayerPawn_ForwardMove1,x)
|
||||
#define PROP_PlayerPawn_ForwardMove2(x) ADD_LONG_PROP(ADEF_PlayerPawn_ForwardMove2,x)
|
||||
#define PROP_PlayerPawn_SideMove1(x) ADD_LONG_PROP(ADEF_PlayerPawn_SideMove1,x)
|
||||
#define PROP_PlayerPawn_SideMove2(x) ADD_LONG_PROP(ADEF_PlayerPawn_SideMove2,x)
|
||||
#define PROP_PlayerPawn_ColorRange(x,y) ADD_LONG_PROP(ADEF_PlayerPawn_ColorRange,x|(y<<8))
|
||||
#define PROP_PlayerPawn_SpawnMask(x) ADD_BYTE_PROP(ADEF_PlayerPawn_SpawnMask, x)
|
||||
|
||||
#endif //__INFOMACROS_H__
|
||||
|
|
|
@ -289,7 +289,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
player->morphTics = 0;
|
||||
}
|
||||
player->health = player->mo->health = player->mo->GetDefault()->health;
|
||||
player->viewheight = player->defaultviewheight;
|
||||
player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight;
|
||||
player->mo->flags = player->mo->GetDefault()->flags;
|
||||
player->mo->height = player->mo->GetDefault()->height;
|
||||
player->mo->SetState (player->mo->SpawnState);
|
||||
|
|
527
src/m_menu.cpp
527
src/m_menu.cpp
|
@ -84,6 +84,7 @@ struct FSaveGameNode : public Node
|
|||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
void M_DrawSlider (int x, int y, float min, float max, float cur);
|
||||
void R_GetPlayerTranslation (int color, FPlayerSkin *skin, BYTE *table);
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
|
@ -106,6 +107,7 @@ static void M_GameFiles (int choice);
|
|||
static void M_ClearSaveStuff ();
|
||||
|
||||
static void SCClass (int choice);
|
||||
static void M_ChooseClass (int choice);
|
||||
|
||||
static void M_FinishReadThis (int choice);
|
||||
static void M_QuickSave ();
|
||||
|
@ -129,6 +131,7 @@ static void M_DrawLoad ();
|
|||
static void M_DrawSave ();
|
||||
static void DrawClassMenu ();
|
||||
static void DrawHexenSkillMenu ();
|
||||
static void M_DrawClassMenu ();
|
||||
|
||||
static void M_DrawHereticMainMenu ();
|
||||
static void M_DrawFiles ();
|
||||
|
@ -151,6 +154,7 @@ static void M_PlayerNameChanged (FSaveGameNode *dummy);
|
|||
static void M_SlidePlayerRed (int choice);
|
||||
static void M_SlidePlayerGreen (int choice);
|
||||
static void M_SlidePlayerBlue (int choice);
|
||||
static void M_ChangeClass (int choice);
|
||||
static void M_ChangeGender (int choice);
|
||||
static void M_ChangeSkin (int choice);
|
||||
static void M_ChangeAutoAim (int choice);
|
||||
|
@ -179,7 +183,6 @@ bool OptionsActive;
|
|||
|
||||
static char tempstring[80];
|
||||
static char underscore[2];
|
||||
static int MenuPClass;
|
||||
|
||||
static FSaveGameNode *quickSaveSlot; // NULL = no quicksave slot picked!
|
||||
static FSaveGameNode *lastSaveSlot; // Used for highlighting the most recently used slot in the menu
|
||||
|
@ -219,11 +222,13 @@ static oldmenu_t *TopLevelMenu; // The main menu everything hangs off of
|
|||
static DCanvas *FireScreen;
|
||||
static byte FireRemap[256];
|
||||
|
||||
static char *genders[3] = { "male", "female", "other" };
|
||||
static const PClass *PlayerClass;
|
||||
static FState *PlayerState;
|
||||
static int PlayerTics;
|
||||
static int PlayerRotation;
|
||||
static char *genders[3] = { "male", "female", "other" };
|
||||
static FPlayerClass *PlayerClass;
|
||||
static int PlayerSkin;
|
||||
static FState *PlayerState;
|
||||
static int PlayerTics;
|
||||
static int PlayerRotation;
|
||||
static BYTE PlayerTranslation[256];
|
||||
|
||||
static DCanvas *SavePic;
|
||||
static brokenlines_t *SaveComment;
|
||||
|
@ -298,6 +303,30 @@ static oldmenu_t ClassMenu =
|
|||
0
|
||||
};
|
||||
|
||||
//
|
||||
// [GRB] CLASS SELECT
|
||||
//
|
||||
oldmenuitem_t ClassMenuItems[8] =
|
||||
{
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
{1,1,0, NULL, M_ChooseClass },
|
||||
};
|
||||
|
||||
oldmenu_t ClassMenuDef =
|
||||
{
|
||||
0,
|
||||
ClassMenuItems,
|
||||
M_DrawClassMenu,
|
||||
48,63,
|
||||
0
|
||||
};
|
||||
|
||||
//
|
||||
// EPISODE SELECT
|
||||
//
|
||||
|
@ -416,8 +445,9 @@ static oldmenuitem_t PlayerSetupMenu[] =
|
|||
{ 2,0,'r',NULL,M_SlidePlayerRed},
|
||||
{ 2,0,'g',NULL,M_SlidePlayerGreen},
|
||||
{ 2,0,'b',NULL,M_SlidePlayerBlue},
|
||||
{ 2,0,'e',NULL,M_ChangeGender},
|
||||
{ 2,0,'c',NULL,M_ChangeClass},
|
||||
{ 2,0,'s',NULL,M_ChangeSkin},
|
||||
{ 2,0,'e',NULL,M_ChangeGender},
|
||||
{ 2,0,'a',NULL,M_ChangeAutoAim}
|
||||
};
|
||||
|
||||
|
@ -1492,7 +1522,7 @@ void M_NewGame(int choice)
|
|||
}
|
||||
epi = 0;
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
if (gameinfo.gametype == GAME_Hexen && ClassMenuDef.numitems == 0)
|
||||
{ // [RH] Make the default entry the last class the player used.
|
||||
ClassMenu.lastOn = players[consoleplayer].userinfo.PlayerClass;
|
||||
if (ClassMenu.lastOn < 0)
|
||||
|
@ -1501,28 +1531,55 @@ void M_NewGame(int choice)
|
|||
}
|
||||
M_SetupNextMenu (&ClassMenu);
|
||||
}
|
||||
else
|
||||
// [GRB] Class select
|
||||
else if (ClassMenuDef.numitems > 1)
|
||||
{
|
||||
if (EpiDef.numitems <= 1)
|
||||
ClassMenuDef.lastOn = ClassMenuDef.numitems - 1;
|
||||
if (players[consoleplayer].userinfo.PlayerClass >= 0)
|
||||
{
|
||||
if (EpisodeNoSkill[0])
|
||||
int n = 0;
|
||||
for (int i = 0; i < PlayerClasses.Size () && n < 7; i++)
|
||||
{
|
||||
M_ChooseSkill(2);
|
||||
}
|
||||
else if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
||||
{
|
||||
M_SetupNextMenu (&NewDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_SetupNextMenu (&HereticSkillMenu);
|
||||
if (!(PlayerClasses[i].Flags & PCF_NOMENU))
|
||||
{
|
||||
if (i == players[consoleplayer].userinfo.PlayerClass)
|
||||
{
|
||||
ClassMenuDef.lastOn = n;
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PickPlayerClass ();
|
||||
|
||||
PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState;
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
|
||||
if (FireScreen == NULL)
|
||||
FireScreen = new DSimpleCanvas (144, 160);
|
||||
M_SetupNextMenu (&ClassMenuDef);
|
||||
}
|
||||
else if (EpiDef.numitems <= 1)
|
||||
{
|
||||
if (EpisodeNoSkill[0])
|
||||
{
|
||||
M_ChooseSkill(2);
|
||||
}
|
||||
else if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
||||
{
|
||||
M_SetupNextMenu (&NewDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_SetupNextMenu (&EpiDef);
|
||||
M_SetupNextMenu (&HereticSkillMenu);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
M_SetupNextMenu (&EpiDef);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1561,6 +1618,53 @@ static void DrawClassMenu(void)
|
|||
screen->DrawTexture (TexMan[name], 174+24, 8+12, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
|
||||
// [GRB] Class select drawer
|
||||
static void M_DrawClassMenu ()
|
||||
{
|
||||
int tit_y = 15;
|
||||
|
||||
if (ClassMenuDef.numitems > 4 && gameinfo.gametype & GAME_Raven)
|
||||
tit_y = 2;
|
||||
|
||||
screen->DrawText (gameinfo.gametype == GAME_Doom ? CR_RED : CR_UNTRANSLATED,
|
||||
160 - BigFont->StringWidth ("CHOOSE CLASS:")/2,
|
||||
tit_y,
|
||||
"CHOOSE CLASS:", DTA_Clean, true, TAG_DONE);
|
||||
|
||||
int x = (200-160)*CleanXfac+(SCREENWIDTH>>1);
|
||||
int y = (ClassMenuDef.y-100)*CleanYfac+(SCREENHEIGHT>>1);
|
||||
|
||||
if (!FireScreen)
|
||||
{
|
||||
screen->Clear (x, y, x + 72 * CleanXfac, y + 80 * CleanYfac-1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
FireScreen->Lock ();
|
||||
M_RenderPlayerBackdrop ();
|
||||
M_DrawPlayerBackdrop (x, y - 1);
|
||||
FireScreen->Unlock ();
|
||||
}
|
||||
|
||||
M_DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1);
|
||||
|
||||
spriteframe_t *sprframe = &SpriteFrames[sprites[PlayerState->sprite.index].spriteframes + PlayerState->GetFrame()];
|
||||
int scale = GetDefaultByType (PlayerClass->Type)->xscale + 1;
|
||||
|
||||
if (sprframe != NULL)
|
||||
{
|
||||
FTexture *tex = TexMan(sprframe->Texture[0]);
|
||||
if (tex != NULL && tex->UseType != FTexture::TEX_Null)
|
||||
{
|
||||
screen->DrawTexture (tex,
|
||||
x + 36*CleanXfac, y + 71*CleanYfac,
|
||||
DTA_DestWidth, MulScale6 (tex->GetWidth() * CleanXfac, scale),
|
||||
DTA_DestHeight, MulScale6 (tex->GetHeight() * CleanYfac, scale),
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawSkillMenu
|
||||
|
@ -1605,10 +1709,6 @@ void M_ChooseSkill (int choice)
|
|||
|
||||
gameskill = choice;
|
||||
gamestate = gamestate == GS_FULLCONSOLE ? GS_HIDECONSOLE : gamestate;
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
playerclass = PlayerClassNames[MenuPClass+1];
|
||||
}
|
||||
G_DeferedInitNew (EpisodeMaps[epi]);
|
||||
gamestate = gamestate == GS_FULLCONSOLE ? GS_HIDECONSOLE : gamestate;
|
||||
M_ClearMenus ();
|
||||
|
@ -1645,6 +1745,53 @@ void M_Episode (int choice)
|
|||
M_SetupNextMenu (&HereticSkillMenu);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets Hexen's skill menu according to player class
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SetHexenSkillMenu (const char * pclass)
|
||||
{
|
||||
if (!stricmp(pclass, "fighter"))
|
||||
{
|
||||
HexenSkillMenu.x = 120;
|
||||
HexenSkillItems[0].name = "SQUIRE";
|
||||
HexenSkillItems[1].name = "KNIGHT";
|
||||
HexenSkillItems[2].name = "WARRIOR";
|
||||
HexenSkillItems[3].name = "BERSERKER";
|
||||
HexenSkillItems[4].name = "TITAN";
|
||||
}
|
||||
else if (!stricmp(pclass, "cleric"))
|
||||
{
|
||||
HexenSkillMenu.x = 116;
|
||||
HexenSkillItems[0].name = "ALTAR BOY";
|
||||
HexenSkillItems[1].name = "ACOLYTE";
|
||||
HexenSkillItems[2].name = "PRIEST";
|
||||
HexenSkillItems[3].name = "CARDINAL";
|
||||
HexenSkillItems[4].name = "POPE";
|
||||
}
|
||||
else if (!stricmp(pclass, "mage"))
|
||||
{
|
||||
HexenSkillMenu.x = 112;
|
||||
HexenSkillItems[0].name = "APPRENTICE";
|
||||
HexenSkillItems[1].name = "ENCHANTER";
|
||||
HexenSkillItems[2].name = "SORCERER";
|
||||
HexenSkillItems[3].name = "WARLOCK";
|
||||
HexenSkillItems[4].name = "ARCHMAGE";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use Heretic's menu titles as default
|
||||
HexenSkillMenu.x = HereticSkillMenu.x;
|
||||
HexenSkillItems[0].name = HereticSkillItems[0].name;
|
||||
HexenSkillItems[1].name = HereticSkillItems[1].name;
|
||||
HexenSkillItems[2].name = HereticSkillItems[2].name;
|
||||
HexenSkillItems[3].name = HereticSkillItems[3].name;
|
||||
HexenSkillItems[4].name = HereticSkillItems[4].name;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SCClass
|
||||
|
@ -1658,44 +1805,14 @@ static void SCClass (int option)
|
|||
M_StartMessage (GStrings("NEWGAME"), NULL, false);
|
||||
return;
|
||||
}
|
||||
MenuPClass = option < 3 ? option : -1;
|
||||
switch (MenuPClass)
|
||||
{
|
||||
case 0/*PCLASS_FIGHTER*/:
|
||||
HexenSkillMenu.x = 120;
|
||||
HexenSkillItems[0].name = "SQUIRE";
|
||||
HexenSkillItems[1].name = "KNIGHT";
|
||||
HexenSkillItems[2].name = "WARRIOR";
|
||||
HexenSkillItems[3].name = "BERSERKER";
|
||||
HexenSkillItems[4].name = "TITAN";
|
||||
break;
|
||||
case 1/*PCLASS_CLERIC*/:
|
||||
HexenSkillMenu.x = 116;
|
||||
HexenSkillItems[0].name = "ALTAR BOY";
|
||||
HexenSkillItems[1].name = "ACOLYTE";
|
||||
HexenSkillItems[2].name = "PRIEST";
|
||||
HexenSkillItems[3].name = "CARDINAL";
|
||||
HexenSkillItems[4].name = "POPE";
|
||||
break;
|
||||
case 2/*PCLASS_MAGE*/:
|
||||
HexenSkillMenu.x = 112;
|
||||
HexenSkillItems[0].name = "APPRENTICE";
|
||||
HexenSkillItems[1].name = "ENCHANTER";
|
||||
HexenSkillItems[2].name = "SORCERER";
|
||||
HexenSkillItems[3].name = "WARLOCK";
|
||||
HexenSkillItems[4].name = "ARCHMAGE";
|
||||
break;
|
||||
case -1/*random*/: // [RH]
|
||||
// Since Hexen is "Heretic 2", use the Heretic skill
|
||||
// names when not playing as a specific class.
|
||||
HexenSkillMenu.x = HereticSkillMenu.x;
|
||||
HexenSkillItems[0].name = HereticSkillItems[0].name;
|
||||
HexenSkillItems[1].name = HereticSkillItems[1].name;
|
||||
HexenSkillItems[2].name = HereticSkillItems[2].name;
|
||||
HexenSkillItems[3].name = HereticSkillItems[3].name;
|
||||
HexenSkillItems[4].name = HereticSkillItems[4].name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (option == 3)
|
||||
playerclass = "Random";
|
||||
else
|
||||
playerclass = PlayerClasses[option].Type->Meta.GetMetaString (APMETA_DisplayName);
|
||||
|
||||
SetHexenSkillMenu(playerclass);
|
||||
|
||||
if (EpiDef.numitems > 1)
|
||||
{
|
||||
M_SetupNextMenu (&EpiDef);
|
||||
|
@ -1710,6 +1827,40 @@ static void SCClass (int option)
|
|||
}
|
||||
}
|
||||
|
||||
// [GRB]
|
||||
static void M_ChooseClass (int choice)
|
||||
{
|
||||
if (netgame)
|
||||
{
|
||||
M_StartMessage (GStrings("NEWGAME"), NULL, false);
|
||||
return;
|
||||
}
|
||||
|
||||
playerclass = (choice < ClassMenuDef.numitems-1) ? ClassMenuItems[choice].name : "Random";
|
||||
SetHexenSkillMenu(playerclass);
|
||||
|
||||
if (EpiDef.numitems > 1)
|
||||
{
|
||||
M_SetupNextMenu (&EpiDef);
|
||||
}
|
||||
else if (!EpisodeNoSkill[0])
|
||||
{
|
||||
M_SetupNextMenu (&HexenSkillMenu);
|
||||
}
|
||||
else if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
||||
{
|
||||
M_SetupNextMenu (&NewDef);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
M_SetupNextMenu (&HexenSkillMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_SetupNextMenu (&HereticSkillMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_Options (int choice)
|
||||
{
|
||||
|
@ -1847,9 +1998,11 @@ void M_PlayerSetup (void)
|
|||
M_SetupNextMenu (&PSetupDef);
|
||||
if (players[consoleplayer].mo != NULL)
|
||||
{
|
||||
PlayerClass = RUNTIME_TYPE(players[consoleplayer].mo);
|
||||
PlayerClass = &PlayerClasses[players[consoleplayer].CurrentPlayerClass];
|
||||
}
|
||||
PlayerState = GetDefaultByType (PlayerClass)->SpawnState;
|
||||
PlayerSkin = players[consoleplayer].userinfo.skin;
|
||||
R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], PlayerTranslation);
|
||||
PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState;
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
if (FireScreen == NULL)
|
||||
FireScreen = new DSimpleCanvas (144, 160);
|
||||
|
@ -1858,30 +2011,42 @@ void M_PlayerSetup (void)
|
|||
static void M_PlayerSetupTicker (void)
|
||||
{
|
||||
// Based on code in f_finale.c
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
FPlayerClass *oldclass = PlayerClass;
|
||||
|
||||
if (currentMenu == &ClassMenuDef)
|
||||
{
|
||||
const PClass *oldclass = PlayerClass;
|
||||
int item;
|
||||
|
||||
PickPlayerClass ();
|
||||
if (PlayerClass != oldclass)
|
||||
{
|
||||
PlayerState = GetDefaultByType (PlayerClass)->SpawnState;
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
}
|
||||
}
|
||||
if (itemOn < ClassMenuDef.numitems-1)
|
||||
item = itemOn;
|
||||
else
|
||||
item = (MenuTime>>2) % (ClassMenuDef.numitems-1);
|
||||
|
||||
if (--PlayerTics > 0)
|
||||
return;
|
||||
|
||||
if (PlayerState->GetTics() == -1 || PlayerState->GetNextState() == NULL)
|
||||
{
|
||||
PlayerState = GetDefaultByType (PlayerClass)->SeeState;
|
||||
PlayerClass = &PlayerClasses[D_PlayerClassToInt (ClassMenuItems[item].name)];
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerState = PlayerState->GetNextState();
|
||||
PickPlayerClass ();
|
||||
}
|
||||
|
||||
if (PlayerClass != oldclass)
|
||||
{
|
||||
PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState;
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
|
||||
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, PlayerClass - &PlayerClasses[0]);
|
||||
R_GetPlayerTranslation (players[consoleplayer].userinfo.color,
|
||||
&skins[PlayerSkin], PlayerTranslation);
|
||||
}
|
||||
|
||||
if (PlayerState->GetTics () != -1 && PlayerState->GetNextState () != NULL)
|
||||
{
|
||||
if (--PlayerTics > 0)
|
||||
return;
|
||||
|
||||
PlayerState = PlayerState->GetNextState();
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
}
|
||||
PlayerTics = PlayerState->GetTics();
|
||||
}
|
||||
|
||||
static void M_PlayerSetupDrawer ()
|
||||
|
@ -1956,17 +2121,18 @@ static void M_PlayerSetupDrawer ()
|
|||
{
|
||||
spriteframe_t *sprframe;
|
||||
int scale;
|
||||
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
|
||||
if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN ||
|
||||
players[consoleplayer].userinfo.PlayerClass == -1 ||
|
||||
PlayerState->sprite.index != GetDefaultByType (PlayerClass->Type)->SpawnState->sprite.index)
|
||||
{
|
||||
sprframe =
|
||||
&SpriteFrames[sprites[skins[players[consoleplayer].userinfo.skin].sprite].spriteframes + PlayerState->GetFrame()];
|
||||
scale = skins[players[consoleplayer].userinfo.skin].scale + 1;
|
||||
sprframe = &SpriteFrames[sprites[PlayerState->sprite.index].spriteframes + PlayerState->GetFrame()];
|
||||
scale = GetDefaultByType (PlayerClass->Type)->xscale + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprframe = &SpriteFrames[sprites[PlayerState->sprite.index].spriteframes + PlayerState->GetFrame()];
|
||||
scale = GetDefault<APlayerPawn>()->xscale + 1;
|
||||
sprframe = &SpriteFrames[sprites[skins[PlayerSkin].sprite].spriteframes + PlayerState->GetFrame()];
|
||||
scale = skins[PlayerSkin].scale + 1;
|
||||
}
|
||||
|
||||
if (sprframe != NULL)
|
||||
|
@ -1983,7 +2149,7 @@ static void M_PlayerSetupDrawer ()
|
|||
(PSetupDef.y + LINEHEIGHT*3 + 57 - 104)*CleanYfac + (SCREENHEIGHT/2),
|
||||
DTA_DestWidth, MulScale6 (tex->GetWidth() * CleanXfac, scale),
|
||||
DTA_DestHeight, MulScale6 (tex->GetHeight() * CleanYfac, scale),
|
||||
DTA_Translation, translationtables[TRANSLATION_Players] + consoleplayer*256,
|
||||
DTA_Translation, PlayerTranslation,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
@ -2014,33 +2180,38 @@ static void M_PlayerSetupDrawer ()
|
|||
M_DrawSlider (x, PSetupDef.y + LINEHEIGHT*3+yo, 0.0f, 255.0f, GPART(color));
|
||||
M_DrawSlider (x, PSetupDef.y + LINEHEIGHT*4+yo, 0.0f, 255.0f, BPART(color));
|
||||
|
||||
// Draw gender setting
|
||||
x = SmallFont->StringWidth ("Gender") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*5+yo, "Gender", DTA_Clean, true, TAG_DONE);
|
||||
// [GRB] Draw class setting
|
||||
int pclass = players[consoleplayer].userinfo.PlayerClass;
|
||||
x = SmallFont->StringWidth ("Class") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*5+yo, "Class", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*5+yo,
|
||||
genders[players[consoleplayer].userinfo.gender], DTA_Clean, true, TAG_DONE);
|
||||
pclass == -1 ? "Random" : PlayerClasses[pclass].Type->Meta.GetMetaString (APMETA_DisplayName),
|
||||
DTA_Clean, true, TAG_DONE);
|
||||
|
||||
// Draw skin setting
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
x = SmallFont->StringWidth ("Skin") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*6+yo, "Skin", DTA_Clean, true, TAG_DONE);
|
||||
if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN ||
|
||||
players[consoleplayer].userinfo.PlayerClass == -1)
|
||||
{
|
||||
x = SmallFont->StringWidth ("Skin") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*6+yo, "Skin", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*6+yo,
|
||||
skins[players[consoleplayer].userinfo.skin].name, DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*6+yo, "Base", DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = SmallFont->StringWidth ("Class") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*6+yo, "Class", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*6+yo,
|
||||
PlayerClassNames[players[consoleplayer].userinfo.PlayerClass+1], DTA_Clean, true, TAG_DONE);
|
||||
skins[PlayerSkin].name, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
|
||||
// Draw gender setting
|
||||
x = SmallFont->StringWidth ("Gender") + 8 + PSetupDef.x;
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*7+yo, "Gender", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*7+yo,
|
||||
genders[players[consoleplayer].userinfo.gender], DTA_Clean, true, TAG_DONE);
|
||||
|
||||
// Draw autoaim setting
|
||||
x = SmallFont->StringWidth ("Autoaim") + 8 + PSetupDef.x;
|
||||
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*7+yo, "Autoaim", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*7+yo,
|
||||
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*8+yo, "Autoaim", DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT*8+yo,
|
||||
autoaim == 0 ? "Never" :
|
||||
autoaim <= 0.25 ? "Very Low" :
|
||||
autoaim <= 0.5 ? "Low" :
|
||||
|
@ -2261,6 +2432,45 @@ static void M_DrawPlayerBackdrop (int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_ChangeClass (int choice)
|
||||
{
|
||||
if (PlayerClasses.Size () == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int type = players[consoleplayer].userinfo.PlayerClass;
|
||||
|
||||
if (!choice)
|
||||
type = (type < 0) ? (int)PlayerClasses.Size () - 1 : type - 1;
|
||||
else
|
||||
type = (type < (int)PlayerClasses.Size () - 1) ? type + 1 : -1;
|
||||
|
||||
cvar_set ("playerclass", type < 0 ? "Random" :
|
||||
PlayerClasses[type].Type->Meta.GetMetaString (APMETA_DisplayName));
|
||||
}
|
||||
|
||||
static void M_ChangeSkin (int choice)
|
||||
{
|
||||
if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN ||
|
||||
players[consoleplayer].userinfo.PlayerClass == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (!choice)
|
||||
PlayerSkin = (PlayerSkin == 0) ? (int)numskins - 1 : PlayerSkin - 1;
|
||||
else
|
||||
PlayerSkin = (PlayerSkin < (int)numskins - 1) ? PlayerSkin + 1 : 0;
|
||||
} while (!PlayerClass->CheckSkin (PlayerSkin));
|
||||
|
||||
R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], PlayerTranslation);
|
||||
|
||||
cvar_set ("skin", skins[PlayerSkin].name);
|
||||
}
|
||||
|
||||
static void M_ChangeGender (int choice)
|
||||
{
|
||||
int gender = players[consoleplayer].userinfo.gender;
|
||||
|
@ -2273,32 +2483,6 @@ static void M_ChangeGender (int choice)
|
|||
cvar_set ("gender", genders[gender]);
|
||||
}
|
||||
|
||||
static void M_ChangeSkin (int choice)
|
||||
{
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
size_t skin = players[consoleplayer].userinfo.skin;
|
||||
|
||||
if (!choice)
|
||||
skin = (skin == 0) ? numskins - 1 : skin - 1;
|
||||
else
|
||||
skin = (skin < numskins - 1) ? skin + 1 : 0;
|
||||
|
||||
cvar_set ("skin", skins[skin].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
int type = players[consoleplayer].userinfo.PlayerClass;
|
||||
|
||||
if (!choice)
|
||||
type = (type < 0) ? 2 : type - 1;
|
||||
else
|
||||
type = (type < 2) ? type + 1 : -1;
|
||||
|
||||
cvar_set ("playerclass", PlayerClassNames[type+1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_ChangeAutoAim (int choice)
|
||||
{
|
||||
static const float ranges[] = { 0, 0.25, 0.5, 1, 2, 3, 5000 };
|
||||
|
@ -2393,6 +2577,8 @@ static void SendNewColor (int red, int green, int blue)
|
|||
|
||||
sprintf (command, "color \"%02x %02x %02x\"", red, green, blue);
|
||||
C_DoCommand (command);
|
||||
|
||||
R_GetPlayerTranslation (MAKERGB (red, green, blue), &skins[PlayerSkin], PlayerTranslation);
|
||||
}
|
||||
|
||||
static void M_SlidePlayerRed (int choice)
|
||||
|
@ -2966,7 +3152,8 @@ void M_Drawer ()
|
|||
if (currentMenu->menuitems[i].fulltext)
|
||||
{
|
||||
int color = CR_UNTRANSLATED;
|
||||
if (currentMenu == &EpiDef && gameinfo.gametype == GAME_Doom)
|
||||
if ((currentMenu == &EpiDef || currentMenu == &ClassMenuDef) &&
|
||||
gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
color = CR_RED;
|
||||
}
|
||||
|
@ -3136,7 +3323,7 @@ void M_Ticker (void)
|
|||
whichSkull ^= 1;
|
||||
skullAnimCounter = 8;
|
||||
}
|
||||
if (currentMenu == &PSetupDef)
|
||||
if (currentMenu == &PSetupDef || currentMenu == &ClassMenuDef)
|
||||
M_PlayerSetupTicker ();
|
||||
}
|
||||
|
||||
|
@ -3215,6 +3402,55 @@ void M_Init (void)
|
|||
}
|
||||
M_OptInit ();
|
||||
|
||||
// [GRB] Set up player class menu
|
||||
if (!(gameinfo.gametype == GAME_Hexen && PlayerClasses.Size () == 3 &&
|
||||
PlayerClasses[0].Type->IsDescendantOf (PClass::FindClass (NAME_FighterPlayer)) &&
|
||||
PlayerClasses[1].Type->IsDescendantOf (PClass::FindClass (NAME_ClericPlayer)) &&
|
||||
PlayerClasses[2].Type->IsDescendantOf (PClass::FindClass (NAME_MagePlayer))))
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (i = 0; i < PlayerClasses.Size () && n < 7; i++)
|
||||
{
|
||||
if (!(PlayerClasses[i].Flags & PCF_NOMENU))
|
||||
{
|
||||
ClassMenuItems[n].name =
|
||||
PlayerClasses[i].Type->Meta.GetMetaString (APMETA_DisplayName);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
ClassMenuItems[n].name = "Random";
|
||||
ClassMenuDef.numitems = n+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
ClassMenuItems[0].name =
|
||||
PlayerClasses[0].Type->Meta.GetMetaString (APMETA_DisplayName);
|
||||
}
|
||||
ClassMenuDef.numitems = 1;
|
||||
}
|
||||
|
||||
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
||||
{
|
||||
ClassMenuDef.x = 48;
|
||||
ClassMenuDef.y = 63;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassMenuDef.x = 80;
|
||||
ClassMenuDef.y = 50;
|
||||
}
|
||||
if (ClassMenuDef.numitems > 4)
|
||||
{
|
||||
ClassMenuDef.y -= LINEHEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Build a palette translation table for the player setup effect
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
|
@ -3235,25 +3471,18 @@ void M_Init (void)
|
|||
|
||||
static void PickPlayerClass ()
|
||||
{
|
||||
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
||||
{
|
||||
PlayerClass = PClass::FindClass (NAME_DoomPlayer);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
PlayerClass = PClass::FindClass (NAME_HereticPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const ENamedName classnames[3] = { NAME_FighterPlayer, NAME_ClericPlayer, NAME_MagePlayer };
|
||||
int pclass = 0;
|
||||
|
||||
int nowtype = players[consoleplayer].userinfo.PlayerClass;
|
||||
// [GRB] Pick a class from player class list
|
||||
if (PlayerClasses.Size () > 1)
|
||||
{
|
||||
pclass = players[consoleplayer].userinfo.PlayerClass;
|
||||
|
||||
if (nowtype < 0)
|
||||
if (pclass < 0)
|
||||
{
|
||||
nowtype = (MenuTime>>7) % 3;
|
||||
pclass = (MenuTime>>7) % PlayerClasses.Size ();
|
||||
}
|
||||
|
||||
PlayerClass = PClass::FindClass (classnames[nowtype]);
|
||||
}
|
||||
|
||||
PlayerClass = &PlayerClasses[pclass];
|
||||
}
|
||||
|
|
|
@ -4606,6 +4606,17 @@ int DLevelScript::RunScript ()
|
|||
}
|
||||
sp -= 2;
|
||||
break;
|
||||
|
||||
case PCD_PLAYERCLASS: // [GRB]
|
||||
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !playeringame[STACK(1)])
|
||||
{
|
||||
STACK(1) = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = players[STACK(1)].CurrentPlayerClass;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -493,6 +493,7 @@ public:
|
|||
PCD_CHECKACTORINVENTORY,
|
||||
PCD_THINGCOUNTNAME,
|
||||
PCD_SPAWNSPOTFACING,
|
||||
PCD_PLAYERCLASS, // [GRB]
|
||||
|
||||
PCODE_COMMAND_COUNT
|
||||
};
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "a_action.h"
|
||||
#include "a_keys.h"
|
||||
#include "p_conversation.h"
|
||||
#include "thingdef.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -394,9 +395,13 @@ void AActor::Serialize (FArchive &arc)
|
|||
SetShade (alphacolor);
|
||||
if (player)
|
||||
{
|
||||
if (playeringame[player - players])
|
||||
if (playeringame[player - players] &&
|
||||
player->cls != NULL &&
|
||||
state->sprite.index ==
|
||||
GetDefaultByType (player->cls)->SpawnState->sprite.index)
|
||||
{ // Give player back the skin
|
||||
player->skin = &skins[player->userinfo.skin];
|
||||
sprite = skins[player->userinfo.skin].sprite;
|
||||
xscale = yscale = skins[player->userinfo.skin].scale;
|
||||
}
|
||||
if (Speed == 0)
|
||||
{
|
||||
|
@ -3327,22 +3332,9 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
|
|||
|
||||
if (p->cls == NULL)
|
||||
{
|
||||
p->CurrentPlayerClass = 0;
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
// [GRB] Pick a class from player class list
|
||||
if (PlayerClasses.Size () > 1)
|
||||
{
|
||||
p->cls = PClass::FindClass (NAME_DoomPlayer);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
p->cls = PClass::FindClass (NAME_HereticPlayer);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
p->cls = PClass::FindClass (NAME_StrifePlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const ENamedName classes[3] = { NAME_FighterPlayer, NAME_ClericPlayer, NAME_MagePlayer };
|
||||
int type;
|
||||
|
||||
if (!deathmatch || !multiplayer)
|
||||
|
@ -3354,12 +3346,16 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
|
|||
type = p->userinfo.PlayerClass;
|
||||
if (type < 0)
|
||||
{
|
||||
type = pr_multiclasschoice() % 3;
|
||||
type = pr_multiclasschoice() % PlayerClasses.Size ();
|
||||
}
|
||||
}
|
||||
p->CurrentPlayerClass = type;
|
||||
p->cls = PClass::FindClass (classes[type]);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->CurrentPlayerClass = 0;
|
||||
}
|
||||
p->cls = PlayerClasses[p->CurrentPlayerClass].Type;
|
||||
}
|
||||
|
||||
mobj = static_cast<APlayerPawn *>
|
||||
|
@ -3380,6 +3376,10 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
|
|||
mobj->ObtainInventory (oldactor);
|
||||
}
|
||||
|
||||
// [GRB] Reset skin
|
||||
p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass);
|
||||
StatusBar->SetFace (&skins[p->userinfo.skin]);
|
||||
|
||||
// [RH] Be sure the player has the right translation
|
||||
R_BuildPlayerTranslation (playernum);
|
||||
|
||||
|
@ -3394,12 +3394,8 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
|
|||
mobj->id = playernum;
|
||||
|
||||
// [RH] Set player sprite based on skin
|
||||
p->skin = &skins[p->userinfo.skin];
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
mobj->sprite = p->skin->sprite;
|
||||
mobj->xscale = mobj->yscale = p->skin->scale;
|
||||
}
|
||||
mobj->sprite = skins[p->userinfo.skin].sprite;
|
||||
mobj->xscale = mobj->yscale = skins[p->userinfo.skin].scale;
|
||||
|
||||
p->DesiredFOV = p->FOV = 90.f;
|
||||
p->camera = p->mo;
|
||||
|
@ -3410,7 +3406,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
|
|||
p->morphTics = 0;
|
||||
p->extralight = 0;
|
||||
p->fixedcolormap = 0;
|
||||
p->viewheight = p->defaultviewheight = gameinfo.gametype == GAME_Hexen? 48*FRACUNIT : 41*FRACUNIT;
|
||||
p->viewheight = mobj->ViewHeight;
|
||||
p->inconsistant = 0;
|
||||
p->attacker = NULL;
|
||||
p->spreecount = 0;
|
||||
|
@ -3505,7 +3501,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
|
|||
{
|
||||
MTF_FIGHTER,
|
||||
MTF_CLERIC,
|
||||
MTF_MAGE
|
||||
MTF_MAGE,
|
||||
};
|
||||
|
||||
if (mthing->type == 0 || mthing->type == -1)
|
||||
|
@ -3615,30 +3611,33 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
|
|||
return;
|
||||
}
|
||||
|
||||
// Check current character classes with spawn flags
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
if (!multiplayer)
|
||||
{ // Single player
|
||||
if ((mthing->flags & classFlags[players[consoleplayer].CurrentPlayerClass]) == 0)
|
||||
{ // Not for current class
|
||||
return;
|
||||
// Check class spawn masks. Now with player classes available
|
||||
// this is enabled for all games.
|
||||
if (!multiplayer)
|
||||
{ // Single player
|
||||
int spawnmask = players[consoleplayer].GetSpawnClass();
|
||||
if (spawnmask != 0 && (mthing->flags & spawnmask) == 0)
|
||||
{ // Not for current class
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!deathmatch)
|
||||
{ // Cooperative
|
||||
mask = 0;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
int spawnmask = players[i].GetSpawnClass();
|
||||
if (spawnmask != 0)
|
||||
mask |= spawnmask;
|
||||
else
|
||||
mask = -1;
|
||||
}
|
||||
}
|
||||
else if (!deathmatch)
|
||||
{ // Cooperative
|
||||
mask = 0;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
mask |= classFlags[players[i].CurrentPlayerClass];
|
||||
}
|
||||
}
|
||||
if ((mthing->flags & mask) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (mask != -1 && (mthing->flags & mask) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
351
src/p_user.cpp
351
src/p_user.cpp
|
@ -48,6 +48,9 @@
|
|||
#include "f_finale.h"
|
||||
#include "c_console.h"
|
||||
#include "doomdef.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "tarray.h"
|
||||
#include "thingdef.h"
|
||||
|
||||
static FRandom pr_healradius ("HealRadius");
|
||||
|
||||
|
@ -60,6 +63,133 @@ static player_t PredictionPlayerBackup;
|
|||
static BYTE PredictionActorBackup[sizeof(AActor)];
|
||||
static TArray<sector_t *> PredictionTouchingSectorsBackup;
|
||||
|
||||
// [GRB] Custom player classes
|
||||
TArray<FPlayerClass> PlayerClasses;
|
||||
|
||||
FPlayerClass::FPlayerClass ()
|
||||
{
|
||||
Type = NULL;
|
||||
Flags = 0;
|
||||
}
|
||||
|
||||
FPlayerClass::FPlayerClass (const FPlayerClass &other)
|
||||
{
|
||||
Type = other.Type;
|
||||
Flags = other.Flags;
|
||||
Skins = other.Skins;
|
||||
}
|
||||
|
||||
FPlayerClass::~FPlayerClass ()
|
||||
{
|
||||
}
|
||||
|
||||
bool FPlayerClass::CheckSkin (int skin)
|
||||
{
|
||||
for (int i = 0; i < Skins.Size (); i++)
|
||||
{
|
||||
if (Skins[i] == skin)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetupPlayerClasses ()
|
||||
{
|
||||
FPlayerClass newclass;
|
||||
|
||||
newclass.Flags = 0;
|
||||
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
newclass.Type = PClass::FindClass (NAME_DoomPlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
newclass.Type = PClass::FindClass (NAME_HereticPlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
newclass.Type = PClass::FindClass (NAME_FighterPlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
newclass.Type = PClass::FindClass (NAME_ClericPlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
newclass.Type = PClass::FindClass (NAME_MagePlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
newclass.Type = PClass::FindClass (NAME_StrifePlayer);
|
||||
PlayerClasses.Push (newclass);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (clearplayerclasses)
|
||||
{
|
||||
if (ParsingKeyConf)
|
||||
{
|
||||
PlayerClasses.Clear ();
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (addplayerclass)
|
||||
{
|
||||
if (ParsingKeyConf && argv.argc () > 1)
|
||||
{
|
||||
const PClass *ti = PClass::FindClass (argv[1]);
|
||||
|
||||
if (!ti)
|
||||
{
|
||||
I_FatalError ("Unknown player class '%s'", argv[1]);
|
||||
}
|
||||
else if (!ti->IsDescendantOf (RUNTIME_CLASS (APlayerPawn)))
|
||||
{
|
||||
I_FatalError ("Invalid player class '%s'", argv[1]);
|
||||
}
|
||||
else if (ti->Meta.GetMetaString (APMETA_DisplayName) == NULL)
|
||||
{
|
||||
I_FatalError ("Missing displayname for player class '%s'", argv[1]);
|
||||
}
|
||||
else if (ti->ActorInfo->GameFilter == GAME_Any ||
|
||||
gameinfo.gametype & ti->ActorInfo->GameFilter)
|
||||
{
|
||||
FPlayerClass newclass;
|
||||
|
||||
newclass.Type = ti;
|
||||
newclass.Flags = 0;
|
||||
|
||||
int arg = 2;
|
||||
while (arg < argv.argc ())
|
||||
{
|
||||
if (!stricmp (argv[arg], "nomenu"))
|
||||
{
|
||||
newclass.Flags |= PCF_NOMENU;
|
||||
}
|
||||
else
|
||||
{
|
||||
I_FatalError ("Unknown flag '%s' for player class '%s'", argv[arg], argv[1]);
|
||||
}
|
||||
|
||||
arg++;
|
||||
}
|
||||
|
||||
PlayerClasses.Push (newclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (playerclasses)
|
||||
{
|
||||
for (int i = 0; i < PlayerClasses.Size (); i++)
|
||||
{
|
||||
Printf ("% 3d %s\n", i,
|
||||
PlayerClasses[i].Type->Meta.GetMetaString (APMETA_DisplayName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Movement.
|
||||
//
|
||||
|
@ -79,7 +209,6 @@ player_s::player_s()
|
|||
FOV(0),
|
||||
viewz(0),
|
||||
viewheight(0),
|
||||
defaultviewheight(0),
|
||||
deltaviewheight(0),
|
||||
bob(0),
|
||||
momx(0),
|
||||
|
@ -146,7 +275,6 @@ player_s::player_s()
|
|||
allround(0),
|
||||
oldx(0),
|
||||
oldy(0),
|
||||
skin(0),
|
||||
BlendR(0),
|
||||
BlendG(0),
|
||||
BlendB(0),
|
||||
|
@ -224,28 +352,94 @@ void player_s::SetLogText (const char *text)
|
|||
LogText = text;
|
||||
}
|
||||
|
||||
int player_t::GetSpawnClass()
|
||||
{
|
||||
const PClass * type = PlayerClasses[players[consoleplayer].CurrentPlayerClass].Type;
|
||||
return static_cast<APlayerPawn*>(GetDefaultByType(type))->SpawnMask;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
IMPLEMENT_ABSTRACT_ACTOR (APlayerPawn)
|
||||
IMPLEMENT_STATELESS_ACTOR (APlayerPawn, Any, -1, 0)
|
||||
PROP_SpawnHealth (100)
|
||||
PROP_RadiusFixed (16)
|
||||
PROP_HeightFixed (56)
|
||||
PROP_Mass (100)
|
||||
PROP_PainChance (255)
|
||||
PROP_SpeedFixed (1)
|
||||
// [GRB]
|
||||
PROP_PlayerPawn_JumpZ (8*FRACUNIT)
|
||||
PROP_PlayerPawn_ViewHeight (41*FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove1 (FRACUNIT)
|
||||
PROP_PlayerPawn_ForwardMove2 (FRACUNIT)
|
||||
PROP_PlayerPawn_SideMove1 (FRACUNIT)
|
||||
PROP_PlayerPawn_SideMove2 (FRACUNIT)
|
||||
PROP_PlayerPawn_ColorRange (0, 0)
|
||||
PROP_PlayerPawn_SoundClass ("player")
|
||||
END_DEFAULTS
|
||||
|
||||
IMPLEMENT_ABSTRACT_ACTOR (APlayerChunk)
|
||||
|
||||
void APlayerPawn::Serialize (FArchive &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
|
||||
arc << JumpZ;
|
||||
arc << JumpZ
|
||||
<< MaxHealth
|
||||
<< SpawnMask
|
||||
<< ForwardMove1
|
||||
<< ForwardMove2
|
||||
<< SideMove1
|
||||
<< SideMove2
|
||||
<< ScoreIcon;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: BeginPlay
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APlayerPawn::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
ChangeStatNum (STAT_PLAYER);
|
||||
}
|
||||
|
||||
// Check whether a PWADs normal sprite is to be combined with the base WADs
|
||||
// crouch sprite. In such a case the sprites normally don't match and it is
|
||||
// best to disable the crouch sprite.
|
||||
if (crouchsprite > 0)
|
||||
{
|
||||
// This assumes that player sprites always exist in rotated form and
|
||||
// that the front view is always a separate sprite. So far this is
|
||||
// true for anything that exists.
|
||||
FString normspritename = sprites[SpawnState->sprite.index].name;
|
||||
FString crouchspritename = sprites[crouchsprite].name;
|
||||
|
||||
int spritenorm = Wads.CheckNumForName(normspritename + "A1", ns_sprites);
|
||||
int spritecrouch = Wads.CheckNumForName(crouchspritename + "A1", ns_sprites);
|
||||
|
||||
if (spritenorm==-1 || spritecrouch ==-1)
|
||||
{
|
||||
// Sprites do not exist so it is best to disable the crouch sprite.
|
||||
crouchsprite = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int wadnorm = Wads.GetLumpFile(spritenorm);
|
||||
int wadcrouch = Wads.GetLumpFile(spritenorm);
|
||||
|
||||
if (wadnorm > FWadCollection::IWAD_FILENUM && wadcrouch <= FWadCollection::IWAD_FILENUM)
|
||||
{
|
||||
// Question: Add an option / disable crouching or do what?
|
||||
crouchsprite = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -591,20 +785,48 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
|
|||
PickNewWeapon (NULL);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: GetSoundClass
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
const char *APlayerPawn::GetSoundClass ()
|
||||
{
|
||||
if (player != NULL &&
|
||||
player->userinfo.skin != 0 &&
|
||||
player->userinfo.skin >= PlayerClasses.Size () &&
|
||||
(unsigned)player->userinfo.skin < numskins)
|
||||
{
|
||||
return skins[player->userinfo.skin].name;
|
||||
}
|
||||
return "player";
|
||||
|
||||
// [GRB]
|
||||
const char *sclass = GetClass ()->Meta.GetMetaString (APMETA_SoundClass);
|
||||
return sclass != NULL ? sclass : "player";
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: GetMaxHealth
|
||||
//
|
||||
// only needed because Boom screwed up Dehacked.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int APlayerPawn::GetMaxHealth() const
|
||||
{
|
||||
return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Animations
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APlayerPawn::PlayIdle ()
|
||||
{
|
||||
if (state >= SeeState && state < MissileState)
|
||||
if (InStateSequence(state, SeeState))
|
||||
SetState (SpawnState);
|
||||
}
|
||||
|
||||
|
@ -628,8 +850,55 @@ void APlayerPawn::ThrowPoisonBag ()
|
|||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: GiveDefaultInventory
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APlayerPawn::GiveDefaultInventory ()
|
||||
{
|
||||
// [GRB] Give inventory specified in DECORATE
|
||||
player->health = GetDefault ()->health;
|
||||
|
||||
FDropItem *di = GetDropItems(this);
|
||||
|
||||
while (di)
|
||||
{
|
||||
const PClass *ti = PClass::FindClass (di->Name);
|
||||
if (ti)
|
||||
{
|
||||
AInventory *item = FindInventory (ti);
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Amount = clamp<int>(
|
||||
item->Amount + (di->amount ? di->amount : ((AInventory *)item->GetDefault ())->Amount),
|
||||
0, item->MaxAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
AInventory *item = static_cast<AInventory *>(Spawn (ti, 0,0,0));
|
||||
item->Amount = di->amount;
|
||||
if (item->IsKindOf (RUNTIME_CLASS (AWeapon)))
|
||||
{
|
||||
// To allow better control any weapon is emptied of
|
||||
// ammo before being given to the player.
|
||||
static_cast<AWeapon*>(item)->AmmoGive1 =
|
||||
static_cast<AWeapon*>(item)->AmmoGive2 = 0;
|
||||
}
|
||||
if (!item->TryPickup(this))
|
||||
{
|
||||
item->Destroy ();
|
||||
item = NULL;
|
||||
}
|
||||
}
|
||||
if (item != NULL && item->IsKindOf (RUNTIME_CLASS (AWeapon)))
|
||||
{
|
||||
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (item);
|
||||
}
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
|
||||
void APlayerPawn::MorphPlayerThink ()
|
||||
|
@ -640,10 +909,11 @@ void APlayerPawn::ActivateMorphWeapon ()
|
|||
{
|
||||
}
|
||||
|
||||
fixed_t APlayerPawn::GetJumpZ ()
|
||||
{
|
||||
return 8*FRACUNIT;
|
||||
}
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: Die
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APlayerPawn::Die (AActor *source, AActor *inflictor)
|
||||
{
|
||||
|
@ -700,8 +970,32 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor)
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn :: TweakSpeeds
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APlayerPawn::TweakSpeeds (int &forward, int &side)
|
||||
{
|
||||
// [GRB]
|
||||
if ((unsigned int)(forward + 0x31ff) < 0x63ff)
|
||||
{
|
||||
forward = FixedMul (forward, ForwardMove1);
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = FixedMul (forward, ForwardMove2);
|
||||
}
|
||||
if ((unsigned int)(side + 0x27ff) < 0x4fff)
|
||||
{
|
||||
side = FixedMul (side, SideMove1);
|
||||
}
|
||||
else
|
||||
{
|
||||
side = FixedMul (side, SideMove2);
|
||||
}
|
||||
|
||||
if ((player->Powers & PW_SPEED) && !player->morphTics)
|
||||
{ // Adjust for a player with a speed artifact
|
||||
forward = (3*forward)>>1;
|
||||
|
@ -753,8 +1047,7 @@ void P_CheckPlayerSprites()
|
|||
defyscale = skins[player->userinfo.skin].scale;
|
||||
}
|
||||
|
||||
// FIXME: Handle skins
|
||||
|
||||
// Set the crouch sprite
|
||||
if (player->crouchfactor < FRACUNIT*3/4)
|
||||
{
|
||||
|
||||
|
@ -783,7 +1076,7 @@ void P_CheckPlayerSprites()
|
|||
mo->yscale = player->crouchfactor < FRACUNIT*3/4 ? defyscale/2 : defyscale;
|
||||
}
|
||||
}
|
||||
else
|
||||
else // Set the normal sprite
|
||||
{
|
||||
if (mo->sprite == mo->crouchsprite)
|
||||
{
|
||||
|
@ -901,7 +1194,7 @@ void P_CalcHeight (player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
fixed_t defaultviewheight = player->defaultviewheight + player->crouchviewdelta;
|
||||
fixed_t defaultviewheight = player->mo->ViewHeight + player->crouchviewdelta;
|
||||
|
||||
if (player->cheats & CF_NOMOMENTUM)
|
||||
{
|
||||
|
@ -959,12 +1252,9 @@ void P_CalcHeight (player_t *player)
|
|||
|
||||
if (player->morphTics)
|
||||
{
|
||||
player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->viewz = player->mo->z + player->viewheight + bob;
|
||||
bob = 0;
|
||||
}
|
||||
player->viewz = player->mo->z + player->viewheight + bob;
|
||||
if (player->mo->floorclip && player->playerstate != PST_DEAD
|
||||
&& player->mo->z <= player->mo->floorz)
|
||||
{
|
||||
|
@ -1320,8 +1610,8 @@ void P_CrouchMove(player_t * player, int direction)
|
|||
player->mo->height = savedheight;
|
||||
|
||||
player->crouchfactor = clamp<fixed_t>(player->crouchfactor, FRACUNIT/2, FRACUNIT);
|
||||
player->viewheight = FixedMul(player->defaultviewheight, player->crouchfactor);
|
||||
player->crouchviewdelta = player->viewheight - player->defaultviewheight;
|
||||
player->viewheight = FixedMul(player->mo->ViewHeight, player->crouchfactor);
|
||||
player->crouchviewdelta = player->viewheight - player->mo->ViewHeight;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -1448,7 +1738,7 @@ void P_PlayerThink (player_t *player)
|
|||
player->Uncrouch();
|
||||
}
|
||||
|
||||
player->crouchoffset = -FixedMul(player->defaultviewheight, (FRACUNIT - player->crouchfactor));
|
||||
player->crouchoffset = -FixedMul(player->mo->ViewHeight, (FRACUNIT - player->crouchfactor));
|
||||
|
||||
|
||||
if (player->playerstate == PST_DEAD)
|
||||
|
@ -1536,8 +1826,7 @@ void P_PlayerThink (player_t *player)
|
|||
}
|
||||
else if (!(dmflags & DF_NO_JUMP) && onground && !player->jumpTics)
|
||||
{
|
||||
fixed_t JumpZ = (player->mo->JumpZ > 0 ? player->mo->JumpZ : player->mo->GetJumpZ ()); // [GRB]
|
||||
player->mo->momz += JumpZ*35/TICRATE;
|
||||
player->mo->momz += player->mo->JumpZ * 35 / TICRATE;
|
||||
S_Sound (player->mo, CHAN_BODY, "*jump", 1, ATTN_NORM);
|
||||
player->mo->flags2 &= ~MF2_ONMOBJ;
|
||||
player->jumpTics = 18*TICRATE/35;
|
||||
|
@ -1792,7 +2081,6 @@ void player_s::Serialize (FArchive &arc)
|
|||
<< DesiredFOV << FOV
|
||||
<< viewz
|
||||
<< viewheight
|
||||
<< defaultviewheight
|
||||
<< deltaviewheight
|
||||
<< bob
|
||||
<< momx
|
||||
|
@ -1821,13 +2109,8 @@ void player_s::Serialize (FArchive &arc)
|
|||
<< poisoner
|
||||
<< attacker
|
||||
<< extralight
|
||||
<< fixedcolormap;
|
||||
if (SaveVersion < 233)
|
||||
{
|
||||
int xviewshift;
|
||||
arc << xviewshift;
|
||||
}
|
||||
arc << morphTics
|
||||
<< fixedcolormap
|
||||
<< morphTics
|
||||
<< PremorphWeapon
|
||||
<< chickenPeck
|
||||
<< jumpTics
|
||||
|
|
|
@ -303,6 +303,6 @@ DWORD R_BlendForColormap (DWORD map); // [RH] return calculated blend for a col
|
|||
extern byte *realcolormaps; // [RH] make the colormaps externally visible
|
||||
extern size_t numfakecmaps;
|
||||
|
||||
int R_FindSkin (const char *name); // [RH] Find a skin
|
||||
int R_FindSkin (const char *name, int pclass); // [RH] Find a skin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -840,7 +840,7 @@ public:
|
|||
byte range0start;
|
||||
byte range0end;
|
||||
byte scale;
|
||||
byte game;
|
||||
bool othergame; // [GRB]
|
||||
int sprite;
|
||||
int crouchsprite;
|
||||
int namespc; // namespace for this skin
|
||||
|
|
168
src/r_draw.cpp
168
src/r_draw.cpp
|
@ -1599,16 +1599,13 @@ void R_InitTranslationTables ()
|
|||
}
|
||||
|
||||
// [RH] Create a player's translation table based on a given mid-range color.
|
||||
void R_BuildPlayerTranslation (int player)
|
||||
// [GRB] Split to 2 functions (because of player setup menu)
|
||||
static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, BYTE *table, BYTE *alttable)
|
||||
{
|
||||
byte *table = &translationtables[TRANSLATION_Players][player*256];
|
||||
FPlayerSkin *skin = &skins[players[player].userinfo.skin];
|
||||
|
||||
int i;
|
||||
byte start = skin->range0start;
|
||||
byte end = skin->range0end;
|
||||
float r, g, b;
|
||||
float h, s, v;
|
||||
float bases, basev;
|
||||
float sdelta, vdelta;
|
||||
float range;
|
||||
|
@ -1617,67 +1614,68 @@ void R_BuildPlayerTranslation (int player)
|
|||
// for the current game, then this is just an identity translation.
|
||||
// Otherwise, it remaps the colors from the skin's original palette to
|
||||
// the current one.
|
||||
if (skin->game & gameinfo.gametype)
|
||||
if (skin->othergame)
|
||||
{
|
||||
memcpy (table, OtherGameSkinRemap, 256);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
table[i] = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (table, OtherGameSkinRemap, 256);
|
||||
}
|
||||
|
||||
// [GRB] Don't translate skins with color range 0-0 (APlayerPawn default)
|
||||
if (start == 0 && end == 0)
|
||||
return;
|
||||
|
||||
range = (float)(end-start+1);
|
||||
|
||||
D_GetPlayerColor (player, &h, &s, &v);
|
||||
|
||||
bases = s;
|
||||
basev = v;
|
||||
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
if (gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
if (skin->game == GAME_Doom)
|
||||
// Build player sprite translation
|
||||
s -= 0.23f;
|
||||
v += 0.1f;
|
||||
sdelta = 0.23f / range;
|
||||
vdelta = -0.94112f / range;
|
||||
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
// Build player sprite translation
|
||||
s -= 0.23f;
|
||||
v += 0.1f;
|
||||
sdelta = 0.23f / range;
|
||||
vdelta = -0.94112f / range;
|
||||
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
float uses, usev;
|
||||
uses = clamp (s, 0.f, 1.f);
|
||||
usev = clamp (v, 0.f, 1.f);
|
||||
HSVtoRGB (&r, &g, &b, h, uses, usev);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
s += sdelta;
|
||||
v += vdelta;
|
||||
}
|
||||
float uses, usev;
|
||||
uses = clamp (s, 0.f, 1.f);
|
||||
usev = clamp (v, 0.f, 1.f);
|
||||
HSVtoRGB (&r, &g, &b, h, uses, usev);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
s += sdelta;
|
||||
v += vdelta;
|
||||
}
|
||||
else
|
||||
{ // This is not Doom, so it must be Heretic
|
||||
float vdelta = 0.418916f / range;
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
float vdelta = 0.418916f / range;
|
||||
|
||||
// Build player sprite translation
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
v = vdelta * (float)(i - start) + basev - 0.2352937f;
|
||||
v = clamp (v, 0.f, 1.f);
|
||||
HSVtoRGB (&r, &g, &b, h, s, v);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
}
|
||||
// Build player sprite translation
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
v = vdelta * (float)(i - start) + basev - 0.2352937f;
|
||||
v = clamp (v, 0.f, 1.f);
|
||||
HSVtoRGB (&r, &g, &b, h, s, v);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
}
|
||||
|
||||
// Build rain/lifegem translation
|
||||
table = &translationtables[TRANSLATION_PlayersExtra][player*256];
|
||||
// Build rain/lifegem translation
|
||||
if (alttable)
|
||||
{
|
||||
bases = MIN (bases*1.3f, 1.f);
|
||||
basev = MIN (basev*1.3f, 1.f);
|
||||
for (i = 145; i <= 168; i++)
|
||||
|
@ -1685,31 +1683,19 @@ void R_BuildPlayerTranslation (int player)
|
|||
s = MIN (bases, 0.8965f - 0.0962f*(float)(i - 161));
|
||||
v = MIN (1.f, (0.2102f + 0.0489f*(float)(i - 144)) * basev);
|
||||
HSVtoRGB (&r, &g, &b, h, s, v);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
alttable[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // This is Hexen we are playing
|
||||
bool fighter;
|
||||
|
||||
if (players[player].mo != NULL)
|
||||
{
|
||||
fighter = players[player].mo->IsKindOf (RUNTIME_CLASS(AFighterPlayer));
|
||||
}
|
||||
else
|
||||
{
|
||||
fighter = players[player].userinfo.PlayerClass == 0;
|
||||
}
|
||||
if (fighter)
|
||||
else if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
if (memcmp (sprites[skin->sprite].name, "PLAY", 4) == 0)
|
||||
{ // The fighter is different! He gets a brown hairy loincloth, but the other
|
||||
// two have blue capes.
|
||||
float vs[9] = { .28f, .32f, .38f, .42f, .47f, .5f, .58f, .71f, .83f };
|
||||
start = 0xf6;
|
||||
end = 0xfe;
|
||||
|
||||
// Build player sprite translation
|
||||
//h = 45.f;
|
||||
|
@ -1717,7 +1703,7 @@ void R_BuildPlayerTranslation (int player)
|
|||
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
HSVtoRGB (&r, &g, &b, h, s, vs[i-start]*basev);
|
||||
HSVtoRGB (&r, &g, &b, h, s, vs[(i-start)*9/(int)range]*basev);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
|
@ -1728,15 +1714,13 @@ void R_BuildPlayerTranslation (int player)
|
|||
{
|
||||
float ms[18] = { .95f, .96f, .89f, .97f, .97f, 1.f, 1.f, 1.f, .97f, .99f, .87f, .77f, .69f, .62f, .57f, .47f, .43f };
|
||||
float mv[18] = { .16f, .19f, .22f, .25f, .31f, .35f, .38f, .41f, .47f, .54f, .60f, .65f, .71f, .77f, .83f, .89f, .94f, 1.f };
|
||||
start = 0x92;
|
||||
end = 0xa3;
|
||||
|
||||
// Build player sprite translation
|
||||
v = MAX (0.1f, v);
|
||||
|
||||
for (i = start; i <= end; i++)
|
||||
{
|
||||
HSVtoRGB (&r, &g, &b, h, ms[i-start]*bases, mv[i-start]*basev);
|
||||
HSVtoRGB (&r, &g, &b, h, ms[(i-start)*18/(int)range]*bases, mv[(i-start)*18/(int)range]*basev);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
|
@ -1745,24 +1729,46 @@ void R_BuildPlayerTranslation (int player)
|
|||
}
|
||||
|
||||
// Build lifegem translation
|
||||
table = &translationtables[TRANSLATION_PlayersExtra][player*256];
|
||||
start = 0xa4;
|
||||
end = 0xb9;
|
||||
for (i = start; i <= end; ++i)
|
||||
if (alttable)
|
||||
{
|
||||
const PalEntry *base = &GPalette.BaseColors[i];
|
||||
float dummy;
|
||||
for (i = 164; i <= 185; ++i)
|
||||
{
|
||||
const PalEntry *base = &GPalette.BaseColors[i];
|
||||
float dummy;
|
||||
|
||||
RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v);
|
||||
HSVtoRGB (&r, &g, &b, h, s*bases, v*basev);
|
||||
table[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v);
|
||||
HSVtoRGB (&r, &g, &b, h, s*bases, v*basev);
|
||||
alttable[i] = ColorMatcher.Pick (
|
||||
clamp ((int)(r * 255.f), 0, 255),
|
||||
clamp ((int)(g * 255.f), 0, 255),
|
||||
clamp ((int)(b * 255.f), 0, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R_BuildPlayerTranslation (int player)
|
||||
{
|
||||
float h, s, v;
|
||||
|
||||
D_GetPlayerColor (player, &h, &s, &v);
|
||||
|
||||
R_CreatePlayerTranslation (h, s, v,
|
||||
&skins[players[player].userinfo.skin],
|
||||
&translationtables[TRANSLATION_Players][player*256],
|
||||
&translationtables[TRANSLATION_PlayersExtra][player*256]);
|
||||
}
|
||||
|
||||
void R_GetPlayerTranslation (int color, FPlayerSkin *skin, BYTE *table)
|
||||
{
|
||||
float h, s, v;
|
||||
|
||||
RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f,
|
||||
&h, &s, &v);
|
||||
|
||||
R_CreatePlayerTranslation (h, s, v, skin, table, NULL);
|
||||
}
|
||||
|
||||
void R_DrawBorder (int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int picnum;
|
||||
|
|
324
src/r_things.cpp
324
src/r_things.cpp
|
@ -423,9 +423,11 @@ void R_InitSkins (void)
|
|||
int j, k, base;
|
||||
int lastlump;
|
||||
int aliasid;
|
||||
bool remove;
|
||||
const PClass *basetype, *transtype;
|
||||
|
||||
key[sizeof(key)-1] = 0;
|
||||
i = 0;
|
||||
i = PlayerClasses.Size () - 1;
|
||||
lastlump = 0;
|
||||
|
||||
for (j = 0; j < NUMSKINSOUNDS; ++j)
|
||||
|
@ -449,6 +451,9 @@ void R_InitSkins (void)
|
|||
intname = 0;
|
||||
crouchname = 0;
|
||||
|
||||
remove = false;
|
||||
basetype = NULL;
|
||||
|
||||
// Data is stored as "key = data".
|
||||
while (SC_GetString ())
|
||||
{
|
||||
|
@ -500,12 +505,61 @@ void R_InitSkins (void)
|
|||
}
|
||||
else if (0 == stricmp (key, "game"))
|
||||
{
|
||||
if (stricmp (sc_String, "heretic"))
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
basetype = PClass::FindClass (NAME_HereticPlayer);
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
basetype = PClass::FindClass (NAME_StrifePlayer);
|
||||
else
|
||||
basetype = PClass::FindClass (NAME_DoomPlayer);
|
||||
|
||||
transtype = basetype;
|
||||
|
||||
if (stricmp (sc_String, "heretic") == 0)
|
||||
{
|
||||
skins[i].game = GAME_Heretic;
|
||||
skins[i].range0start = 225;
|
||||
skins[i].range0end = 240;
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
transtype = PClass::FindClass (NAME_HereticPlayer);
|
||||
skins[i].othergame = true;
|
||||
}
|
||||
else if (gameinfo.gametype != GAME_Heretic)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
else if (stricmp (sc_String, "strife") == 0)
|
||||
{
|
||||
if (gameinfo.gametype != GAME_Strife)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
transtype = PClass::FindClass (NAME_DoomPlayer);
|
||||
skins[i].othergame = true;
|
||||
}
|
||||
else if (gameinfo.gametype != GAME_Doom)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove)
|
||||
break;
|
||||
}
|
||||
else if (0 == stricmp (key, "class"))
|
||||
{ // [GRB] Define the skin for a specific player class
|
||||
int pclass = D_PlayerClassToInt (sc_String);
|
||||
|
||||
if (pclass < 0)
|
||||
{
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
|
||||
basetype = transtype = PlayerClasses[pclass].Type;
|
||||
}
|
||||
else if (key[0] == '*')
|
||||
{ // Player sound replacment (ZDoom extension)
|
||||
|
@ -554,71 +608,119 @@ void R_InitSkins (void)
|
|||
}
|
||||
}
|
||||
|
||||
if (skins[i].name[0] == 0)
|
||||
sprintf (skins[i].name, "skin%d", i);
|
||||
|
||||
// Now collect the sprite frames for this skin. If the sprite name was not
|
||||
// specified, use whatever immediately follows the specifier lump.
|
||||
if (intname == 0)
|
||||
// [GRB] Assume Doom skin by default
|
||||
if (!remove && basetype == NULL)
|
||||
{
|
||||
char name[9];
|
||||
Wads.GetLumpName (name, base+1);
|
||||
intname = *(DWORD *)name;
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
basetype = transtype = PClass::FindClass (NAME_DoomPlayer);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
basetype = PClass::FindClass (NAME_HereticPlayer);
|
||||
transtype = PClass::FindClass (NAME_DoomPlayer);
|
||||
skins[i].othergame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
int basens = Wads.GetLumpNamespace(base);
|
||||
|
||||
for(int spr = 0; spr<2; spr++)
|
||||
if (!remove)
|
||||
{
|
||||
memset (sprtemp, 0xFFFF, sizeof(sprtemp));
|
||||
for (k = 0; k < MAX_SPRITE_FRAMES; ++k)
|
||||
{
|
||||
sprtemp[k].Flip = 0;
|
||||
}
|
||||
maxframe = -1;
|
||||
skins[i].range0start = transtype->Meta.GetMetaInt (APMETA_ColorRange) & 0xff;
|
||||
skins[i].range0end = transtype->Meta.GetMetaInt (APMETA_ColorRange) >> 8;
|
||||
|
||||
if (spr == 1)
|
||||
remove = true;
|
||||
for (j = 0; j < PlayerClasses.Size (); j++)
|
||||
{
|
||||
if (crouchname !=0 && crouchname != intname)
|
||||
const PClass *type = PlayerClasses[j].Type;
|
||||
|
||||
if (type->IsDescendantOf (basetype) &&
|
||||
GetDefaultByType (type)->SpawnState->sprite.index == GetDefaultByType (basetype)->SpawnState->sprite.index &&
|
||||
type->Meta.GetMetaInt (APMETA_ColorRange) == basetype->Meta.GetMetaInt (APMETA_ColorRange))
|
||||
{
|
||||
intname = crouchname;
|
||||
PlayerClasses[j].Skins.Push ((int)i);
|
||||
remove = false;
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
|
||||
if (!remove)
|
||||
{
|
||||
if (skins[i].name[0] == 0)
|
||||
sprintf (skins[i].name, "skin%d", i);
|
||||
|
||||
// Now collect the sprite frames for this skin. If the sprite name was not
|
||||
// specified, use whatever immediately follows the specifier lump.
|
||||
if (intname == 0)
|
||||
{
|
||||
char name[9];
|
||||
Wads.GetLumpName (name, base+1);
|
||||
intname = *(DWORD *)name;
|
||||
}
|
||||
|
||||
int basens = Wads.GetLumpNamespace(base);
|
||||
|
||||
for(int spr = 0; spr<2; spr++)
|
||||
{
|
||||
memset (sprtemp, 0xFFFF, sizeof(sprtemp));
|
||||
for (k = 0; k < MAX_SPRITE_FRAMES; ++k)
|
||||
{
|
||||
skins[i].crouchsprite = -1;
|
||||
sprtemp[k].Flip = 0;
|
||||
}
|
||||
maxframe = -1;
|
||||
|
||||
if (spr == 1)
|
||||
{
|
||||
if (crouchname !=0 && crouchname != intname)
|
||||
{
|
||||
intname = crouchname;
|
||||
}
|
||||
else
|
||||
{
|
||||
skins[i].crouchsprite = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (k = base + 1; Wads.GetLumpNamespace(k) == basens; k++)
|
||||
{
|
||||
char lname[9];
|
||||
Wads.GetLumpName (lname, k);
|
||||
if (*(DWORD *)lname == intname)
|
||||
{
|
||||
int picnum = TexMan.CreateTexture(k, FTexture::TEX_SkinSprite);
|
||||
R_InstallSpriteLump (picnum, lname[4] - 'A', lname[5], false);
|
||||
|
||||
if (lname[6])
|
||||
R_InstallSpriteLump (picnum, lname[6] - 'A', lname[7], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (spr == 0 && maxframe <= 0)
|
||||
{
|
||||
Printf (PRINT_BOLD, "Skin %s (#%d) has no frames. Removing.\n", skins[i].name, i);
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Wads.GetLumpName (temp.name, base+1);
|
||||
temp.name[4] = 0;
|
||||
int sprno = (int)sprites.Push (temp);
|
||||
if (spr==0) skins[i].sprite = sprno;
|
||||
else skins[i].crouchsprite = sprno;
|
||||
R_InstallSprite (sprno);
|
||||
}
|
||||
}
|
||||
|
||||
for (k = base + 1; Wads.GetLumpNamespace(k) == basens; k++)
|
||||
{
|
||||
char lname[9];
|
||||
Wads.GetLumpName (lname, k);
|
||||
if (*(DWORD *)lname == intname)
|
||||
{
|
||||
int picnum = TexMan.CreateTexture(k, FTexture::TEX_SkinSprite);
|
||||
R_InstallSpriteLump (picnum, lname[4] - 'A', lname[5], false);
|
||||
|
||||
if (lname[6])
|
||||
R_InstallSpriteLump (picnum, lname[6] - 'A', lname[7], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (spr == 0 && maxframe <= 0)
|
||||
{
|
||||
Printf (PRINT_BOLD, "Skin %s (#%d) has no frames. Removing.\n", skins[i].name, i);
|
||||
if (i < numskins-1)
|
||||
memmove (&skins[i], &skins[i+1], sizeof(skins[0])*(numskins-i-1));
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
Wads.GetLumpName (temp.name, base+1);
|
||||
temp.name[4] = 0;
|
||||
int sprno = (int)sprites.Push (temp);
|
||||
if (spr==0) skins[i].sprite = sprno;
|
||||
else skins[i].crouchsprite = sprno;
|
||||
R_InstallSprite (sprno);
|
||||
if (remove)
|
||||
{
|
||||
if (i < numskins-1)
|
||||
memmove (&skins[i], &skins[i+1], sizeof(skins[0])*(numskins-i-1));
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register any sounds this skin provides
|
||||
|
@ -649,7 +751,7 @@ void R_InitSkins (void)
|
|||
}
|
||||
}
|
||||
|
||||
if (numskins > 1)
|
||||
if (numskins > PlayerClasses.Size ())
|
||||
{ // The sound table may have changed, so rehash it.
|
||||
S_HashSounds ();
|
||||
S_ShrinkPlayerSoundLists ();
|
||||
|
@ -657,17 +759,17 @@ void R_InitSkins (void)
|
|||
}
|
||||
|
||||
// [RH] Find a skin by name
|
||||
int R_FindSkin (const char *name)
|
||||
int R_FindSkin (const char *name, int pclass)
|
||||
{
|
||||
int min, max, mid;
|
||||
int lexx;
|
||||
|
||||
if (stricmp ("base", name) == 0)
|
||||
{
|
||||
return 0;
|
||||
return pclass;
|
||||
}
|
||||
|
||||
min = 1;
|
||||
min = PlayerClasses.Size ();
|
||||
max = (int)numskins-1;
|
||||
|
||||
while (min <= max)
|
||||
|
@ -675,13 +777,22 @@ int R_FindSkin (const char *name)
|
|||
mid = (min + max)/2;
|
||||
lexx = strnicmp (skins[mid].name, name, 16);
|
||||
if (lexx == 0)
|
||||
return mid;
|
||||
{
|
||||
if (PlayerClasses[pclass].CheckSkin (mid))
|
||||
return mid;
|
||||
else
|
||||
return pclass;
|
||||
}
|
||||
else if (lexx < 0)
|
||||
{
|
||||
min = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return pclass;
|
||||
}
|
||||
|
||||
// [RH] List the names of all installed skins
|
||||
|
@ -689,8 +800,8 @@ CCMD (skins)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)numskins; i++)
|
||||
Printf ("% 3d %s\n", i, skins[i].name);
|
||||
for (i = PlayerClasses.Size ()-1; i < (int)numskins; i++)
|
||||
Printf ("% 3d %s\n", i-PlayerClasses.Size ()+1, skins[i].name);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -726,28 +837,11 @@ static void R_CreateSkinTranslation (const char *palname)
|
|||
//
|
||||
void R_InitSprites ()
|
||||
{
|
||||
byte rangestart, rangeend;
|
||||
int lump, lastlump;
|
||||
unsigned int i;
|
||||
unsigned int i, j;
|
||||
|
||||
clearbufshort (zeroarray, MAXWIDTH, 0);
|
||||
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
rangestart = 112;
|
||||
rangeend = 127;
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
rangestart = 225;
|
||||
rangeend = 240;
|
||||
}
|
||||
else // Hexen - Not used, because we don't do skins with Hexen
|
||||
{
|
||||
rangestart = 146;
|
||||
rangeend = 163;
|
||||
}
|
||||
|
||||
// [RH] Create a standard translation to map skins between Heretic and Doom
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
|
@ -759,14 +853,11 @@ void R_InitSprites ()
|
|||
}
|
||||
|
||||
// [RH] Count the number of skins.
|
||||
numskins = 1;
|
||||
numskins = PlayerClasses.Size ();
|
||||
lastlump = 0;
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
while ((lump = Wads.FindLump ("S_SKIN", &lastlump, true)) != -1)
|
||||
{
|
||||
while ((lump = Wads.FindLump ("S_SKIN", &lastlump, true)) != -1)
|
||||
{
|
||||
numskins++;
|
||||
}
|
||||
numskins++;
|
||||
}
|
||||
|
||||
// [RH] Do some preliminary setup
|
||||
|
@ -774,44 +865,49 @@ void R_InitSprites ()
|
|||
memset (skins, 0, sizeof(*skins) * numskins);
|
||||
for (i = 0; i < numskins; i++)
|
||||
{ // Assume Doom skin by default
|
||||
skins[i].range0start = 112;
|
||||
skins[i].range0end = 127;
|
||||
skins[i].scale = 63;
|
||||
skins[i].game = GAME_Doom;
|
||||
const PClass *type = PlayerClasses[0].Type;
|
||||
skins[i].range0start = type->Meta.GetMetaInt (APMETA_ColorRange) & 255;
|
||||
skins[i].range0end = type->Meta.GetMetaInt (APMETA_ColorRange) >> 8;
|
||||
skins[i].scale = GetDefaultByType (type)->xscale;
|
||||
}
|
||||
|
||||
R_InitSpriteDefs ();
|
||||
NumStdSprites = sprites.Size();
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
R_InitSkins (); // [RH] Finish loading skin data
|
||||
}
|
||||
R_InitSkins (); // [RH] Finish loading skin data
|
||||
|
||||
// [RH] Set up base skin
|
||||
strcpy (skins[0].name, "Base");
|
||||
skins[0].face[0] = 'S';
|
||||
skins[0].face[1] = 'T';
|
||||
skins[0].face[2] = 'F';
|
||||
skins[0].namespc = ns_global;
|
||||
skins[0].scale = GetDefaultByName ("DoomPlayer")->xscale;
|
||||
skins[0].game = gameinfo.gametype;
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
// [GRB] Each player class has its own base skin
|
||||
for (i = 0; i < PlayerClasses.Size (); i++)
|
||||
{
|
||||
skins[0].range0start = 225;
|
||||
skins[0].range0end = 240;
|
||||
}
|
||||
const PClass *basetype = PlayerClasses[i].Type;
|
||||
|
||||
for (i = 0; i < sprites.Size (); i++)
|
||||
{
|
||||
if (memcmp (sprites[i].name, deh.PlayerSprite, 4) == 0)
|
||||
strcpy (skins[i].name, "Base");
|
||||
skins[i].face[0] = 'S';
|
||||
skins[i].face[1] = 'T';
|
||||
skins[i].face[2] = 'F';
|
||||
skins[i].range0start = basetype->Meta.GetMetaInt (APMETA_ColorRange) & 255;
|
||||
skins[i].range0end = basetype->Meta.GetMetaInt (APMETA_ColorRange) >> 8;
|
||||
skins[i].scale = GetDefaultByType (basetype)->xscale;
|
||||
skins[i].sprite = GetDefaultByType (basetype)->SpawnState->sprite.index;
|
||||
skins[i].namespc = ns_global;
|
||||
|
||||
PlayerClasses[i].Skins.Push (i);
|
||||
|
||||
if (memcmp (sprites[skins[i].sprite].name, "PLAY", 4) == 0)
|
||||
{
|
||||
skins[0].sprite = (int)i;
|
||||
break;
|
||||
for (j = 0; j < sprites.Size (); j++)
|
||||
{
|
||||
if (memcmp (sprites[j].name, deh.PlayerSprite, 4) == 0)
|
||||
{
|
||||
skins[i].sprite = (int)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Sort the skins, but leave base as skin 0
|
||||
qsort (&skins[1], numskins-1, sizeof(FPlayerSkin), skinsorter);
|
||||
qsort (&skins[PlayerClasses.Size ()], numskins-PlayerClasses.Size (), sizeof(FPlayerSkin), skinsorter);
|
||||
}
|
||||
|
||||
void R_DeinitSprites()
|
||||
|
|
|
@ -221,7 +221,7 @@ static int NumPlayerReserves;
|
|||
static bool DoneReserving;
|
||||
static bool PlayerClassesIsSorted;
|
||||
|
||||
static TArray<FPlayerClassLookup> PlayerClasses;
|
||||
static TArray<FPlayerClassLookup> PlayerClassLookups;
|
||||
static TArray<WORD> PlayerSounds;
|
||||
|
||||
static char DefPlayerClassName[MAX_SNDNAME+1];
|
||||
|
@ -1121,7 +1121,7 @@ static int S_AddPlayerClass (const char *name)
|
|||
|
||||
memcpy (lookup.Name, name, namelen);
|
||||
lookup.ListIndex[2] = lookup.ListIndex[1] = lookup.ListIndex[0] = 0xffff;
|
||||
cnum = (int)PlayerClasses.Push (lookup);
|
||||
cnum = (int)PlayerClassLookups.Push (lookup);
|
||||
PlayerClassesIsSorted = false;
|
||||
|
||||
// The default player class is the first one added
|
||||
|
@ -1147,9 +1147,9 @@ static int S_FindPlayerClass (const char *name)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < PlayerClasses.Size(); ++i)
|
||||
for (i = 0; i < PlayerClassLookups.Size(); ++i)
|
||||
{
|
||||
if (stricmp (name, PlayerClasses[i].Name) == 0)
|
||||
if (stricmp (name, PlayerClassLookups[i].Name) == 0)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
|
@ -1158,12 +1158,12 @@ static int S_FindPlayerClass (const char *name)
|
|||
else
|
||||
{
|
||||
int min = 0;
|
||||
int max = (int)(PlayerClasses.Size() - 1);
|
||||
int max = (int)(PlayerClassLookups.Size() - 1);
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int lexx = stricmp (PlayerClasses[mid].Name, name);
|
||||
int lexx = stricmp (PlayerClassLookups[mid].Name, name);
|
||||
if (lexx == 0)
|
||||
{
|
||||
return mid;
|
||||
|
@ -1193,13 +1193,13 @@ static int S_AddPlayerGender (int classnum, int gender)
|
|||
{
|
||||
int index;
|
||||
|
||||
index = PlayerClasses[classnum].ListIndex[gender];
|
||||
index = PlayerClassLookups[classnum].ListIndex[gender];
|
||||
if (index == 0xffff)
|
||||
{
|
||||
WORD pushee = 0;
|
||||
|
||||
index = (int)PlayerSounds.Size ();
|
||||
PlayerClasses[classnum].ListIndex[gender] = (WORD)index;
|
||||
PlayerClassLookups[classnum].ListIndex[gender] = (WORD)index;
|
||||
for (int i = NumPlayerReserves; i != 0; --i)
|
||||
{
|
||||
PlayerSounds.Push (pushee);
|
||||
|
@ -1213,15 +1213,15 @@ static int S_AddPlayerGender (int classnum, int gender)
|
|||
// S_ShrinkPlayerSoundLists
|
||||
//
|
||||
// Shrinks the arrays used by the player sounds to be just large enough
|
||||
// and also sorts the PlayerClasses array.
|
||||
// and also sorts the PlayerClassLookups array.
|
||||
//==========================================================================
|
||||
|
||||
void S_ShrinkPlayerSoundLists ()
|
||||
{
|
||||
PlayerSounds.ShrinkToFit ();
|
||||
PlayerClasses.ShrinkToFit ();
|
||||
PlayerClassLookups.ShrinkToFit ();
|
||||
|
||||
qsort (&PlayerClasses[0], PlayerClasses.Size(),
|
||||
qsort (&PlayerClassLookups[0], PlayerClassLookups.Size(),
|
||||
sizeof(FPlayerClassLookup), SortPlayerClasses);
|
||||
PlayerClassesIsSorted = true;
|
||||
DefPlayerClass = S_FindPlayerClass (DefPlayerClassName);
|
||||
|
@ -1269,14 +1269,14 @@ static int S_LookupPlayerSound (int classidx, int gender, int refid)
|
|||
classidx = DefPlayerClass;
|
||||
}
|
||||
|
||||
int listidx = PlayerClasses[classidx].ListIndex[gender];
|
||||
int listidx = PlayerClassLookups[classidx].ListIndex[gender];
|
||||
if (listidx == 0xffff)
|
||||
{
|
||||
int g;
|
||||
|
||||
for (g = 0; g < 3 && listidx == 0xffff; ++g)
|
||||
{
|
||||
listidx = PlayerClasses[classidx].ListIndex[g];
|
||||
listidx = PlayerClassLookups[classidx].ListIndex[g];
|
||||
}
|
||||
if (g == 3)
|
||||
{ // No sounds defined at all for this class (can this happen?)
|
||||
|
@ -1428,8 +1428,8 @@ int S_FindSkinnedSound (AActor *actor, int refid)
|
|||
}
|
||||
else
|
||||
{
|
||||
pclass = gameinfo.gametype != GAME_Hexen
|
||||
? "player" : "fighter";
|
||||
pclass =
|
||||
((APlayerPawn *)GetDefaultByType (PlayerClasses[0].Type))->GetSoundClass ();
|
||||
gender = GENDER_MALE;
|
||||
}
|
||||
|
||||
|
@ -1527,13 +1527,13 @@ CCMD (playersounds)
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < PlayerClasses.Size(); ++i)
|
||||
for (i = 0; i < PlayerClassLookups.Size(); ++i)
|
||||
{
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
if ((l = PlayerClasses[i].ListIndex[j]) != 0xffff)
|
||||
if ((l = PlayerClassLookups[i].ListIndex[j]) != 0xffff)
|
||||
{
|
||||
Printf ("\n%s, %s:\n", PlayerClasses[i].Name, GenderNames[j]);
|
||||
Printf ("\n%s, %s:\n", PlayerClassLookups[i].Name, GenderNames[j]);
|
||||
for (k = 0; k < NumPlayerReserves; ++l, ++k)
|
||||
{
|
||||
Printf (" %-16s%s\n", reserveNames[k], S_sfx[PlayerSounds[l]].name);
|
||||
|
|
260
src/thingdef.cpp
260
src/thingdef.cpp
|
@ -208,6 +208,7 @@ static flagdef ActorFlags[]=
|
|||
DEFINE_FLAG(MF4, NOEXTREMEDEATH, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, FRIGHTENED, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, NOBOUNCESOUND, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, NOSKIN, AActor, flags4),
|
||||
|
||||
DEFINE_FLAG(MF5, FASTER, AActor, flags5),
|
||||
DEFINE_FLAG(MF5, FASTMELEE, AActor, flags5),
|
||||
|
@ -500,6 +501,9 @@ ACTOR(CountdownArg)
|
|||
ACTOR(CustomMeleeAttack)
|
||||
ACTOR(Light)
|
||||
ACTOR(Burst)
|
||||
ACTOR(SkullPop)
|
||||
ACTOR(CheckFloor)
|
||||
ACTOR(CheckSkullDone)
|
||||
ACTOR(RadiusThrust)
|
||||
|
||||
|
||||
|
@ -606,6 +610,8 @@ AFuncDesc AFTable[]=
|
|||
FUNC(A_CentaurDefend, NULL)
|
||||
FUNC(A_BishopMissileWeave, NULL)
|
||||
FUNC(A_CStaffMissileSlither, NULL)
|
||||
FUNC(A_SkullPop, "m")
|
||||
{"A_CheckPlayerDone", A_CheckSkullDone, NULL },
|
||||
|
||||
// useful functions from Strife
|
||||
FUNC(A_Wander, NULL)
|
||||
|
@ -675,6 +681,7 @@ AFuncDesc AFTable[]=
|
|||
FUNC(A_JumpIf, "XL")
|
||||
FUNC(A_KillMaster, NULL)
|
||||
FUNC(A_KillChildren, NULL)
|
||||
FUNC(A_CheckFloor, "L")
|
||||
{"A_BasicAttack", A_ComboAttack, "ISMF" },
|
||||
|
||||
// Weapon only functions
|
||||
|
@ -949,14 +956,6 @@ enum
|
|||
};
|
||||
|
||||
|
||||
struct FDropItem
|
||||
{
|
||||
FName Name;
|
||||
int probability;
|
||||
int amount;
|
||||
FDropItem * Next;
|
||||
};
|
||||
|
||||
static void FreeDropItemChain(FDropItem *chain)
|
||||
{
|
||||
while (chain != NULL)
|
||||
|
@ -979,59 +978,17 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
FDropItemPtrArray DropItemList;
|
||||
static FDropItemPtrArray DropItemList;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// PROC A_NoBlocking
|
||||
//
|
||||
// (moved here so that it has access to FDropItemList's definition)
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void A_NoBlocking (AActor *actor)
|
||||
FDropItem *GetDropItems(AActor * actor)
|
||||
{
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (actor->flags & MF_STEALTH)
|
||||
{
|
||||
actor->alpha = OPAQUE;
|
||||
actor->visdir = 0;
|
||||
}
|
||||
unsigned int index = actor->GetClass ()->Meta.GetMetaInt (ACMETA_DropItems) - 1;
|
||||
|
||||
actor->flags &= ~MF_SOLID;
|
||||
|
||||
unsigned int index = actor->GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1;
|
||||
|
||||
// If the actor has a conversation that sets an item to drop, drop that.
|
||||
if (actor->Conversation != NULL && actor->Conversation->DropType != NULL)
|
||||
{
|
||||
P_DropItem (actor, actor->Conversation->DropType, -1, 256);
|
||||
actor->Conversation = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
actor->Conversation = NULL;
|
||||
|
||||
// If the actor has attached metadata for items to drop, drop those.
|
||||
// Otherwise, call NoBlockingSet() and let it decide what to drop.
|
||||
if (index >= 0 && index < DropItemList.Size())
|
||||
{
|
||||
FDropItem *di = DropItemList[index];
|
||||
|
||||
while (di != NULL)
|
||||
{
|
||||
if (di->Name != NAME_None)
|
||||
{
|
||||
const PClass *ti = PClass::FindClass(di->Name);
|
||||
if (ti) P_DropItem (actor, ti, di->amount, di->probability);
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->NoBlockingSet ();
|
||||
return DropItemList[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1165,7 +1122,7 @@ FState ** FindState(AActor * actor, const PClass * type, const char * name)
|
|||
}
|
||||
else if (type->IsDescendantOf (RUNTIME_CLASS(ASwitchableDecoration)))
|
||||
{
|
||||
// These are the names that 2.1.0 will use
|
||||
// These are the names that the code will use when custom labels are working.
|
||||
if (!stricmp(name, "ACTIVE")) return &actor->SeeState;
|
||||
if (!stricmp(name, "INACTIVE")) return &actor->MeleeState;
|
||||
}
|
||||
|
@ -2838,8 +2795,8 @@ static void ActorMeleeDamage (AActor *defaults, Baggage &bag)
|
|||
//==========================================================================
|
||||
static void ActorMeleeRange (AActor *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetNumber();
|
||||
defaults->meleerange = sc_Number;
|
||||
SC_MustGetFloat();
|
||||
defaults->meleerange = fixed_t(sc_Float*FRACUNIT);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3524,6 +3481,181 @@ static void PowerupType (APowerupGiver *defaults, Baggage &bag)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// [GRB] Special player properties
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerDisplayName (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetString ();
|
||||
bag.Info->Class->Meta.SetMetaString (APMETA_DisplayName, sc_String);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerSoundClass (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
SC_MustGetString ();
|
||||
sprintf (tmp, sc_String);
|
||||
|
||||
for (int i = 0; i < strlen (tmp); i++)
|
||||
if (tmp[i] == ' ')
|
||||
tmp[i] = '_';
|
||||
|
||||
bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerColorRange (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
int start, end;
|
||||
|
||||
SC_MustGetNumber ();
|
||||
start = sc_Number;
|
||||
SC_MustGetNumber ();
|
||||
end = sc_Number;
|
||||
|
||||
if (start > end)
|
||||
swap (start, end);
|
||||
|
||||
bag.Info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerJumpZ (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetFloat ();
|
||||
defaults->JumpZ = FLOAT2FIXED (sc_Float);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerSpawnClass (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetString ();
|
||||
if (SC_Compare ("Any"))
|
||||
defaults->SpawnMask = 0;
|
||||
else if (SC_Compare ("Fighter"))
|
||||
defaults->SpawnMask |= MTF_FIGHTER;
|
||||
else if (SC_Compare ("Cleric"))
|
||||
defaults->SpawnMask |= MTF_CLERIC;
|
||||
else if (SC_Compare ("Mage"))
|
||||
defaults->SpawnMask |= MTF_MAGE;
|
||||
else if (IsNum(sc_String))
|
||||
{
|
||||
int val = strtol(sc_String, NULL, 0);
|
||||
defaults->SpawnMask = (val*MTF_FIGHTER) & (MTF_FIGHTER|MTF_CLERIC|MTF_MAGE);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerViewHeight (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetFloat ();
|
||||
defaults->ViewHeight = FLOAT2FIXED (sc_Float);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerForwardMove (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetFloat ();
|
||||
defaults->ForwardMove1 = defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
|
||||
if (SC_CheckFloat ())
|
||||
defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerSideMove (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetFloat ();
|
||||
defaults->SideMove1 = defaults->SideMove2 = FLOAT2FIXED (sc_Float);
|
||||
if (SC_CheckFloat ())
|
||||
defaults->SideMove2 = FLOAT2FIXED (sc_Float);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerMaxHealth (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetNumber ();
|
||||
defaults->MaxHealth = sc_Number;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerScoreIcon (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetString ();
|
||||
defaults->ScoreIcon = TexMan.AddPatch (sc_String);
|
||||
if (defaults->ScoreIcon <= 0)
|
||||
{
|
||||
defaults->ScoreIcon = TexMan.AddPatch (sc_String, ns_sprites);
|
||||
if (defaults->ScoreIcon <= 0)
|
||||
{
|
||||
Printf("Icon '%s' for '%s' not found\n", sc_String, bag.Info->Class->TypeName.GetChars ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerCrouchSprite (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
SC_MustGetString ();
|
||||
for (int i = 0; i < sc_StringLen; i++) sc_String[i] = toupper (sc_String[i]);
|
||||
defaults->crouchsprite = GetSpriteIndex (sc_String);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// [GRB] Store start items in drop item list
|
||||
//
|
||||
//==========================================================================
|
||||
static void PlayerStartItem (APlayerPawn *defaults, Baggage &bag)
|
||||
{
|
||||
// create a linked list of dropitems
|
||||
if (!bag.DropItemSet)
|
||||
{
|
||||
bag.DropItemSet = true;
|
||||
bag.DropItemList = NULL;
|
||||
}
|
||||
|
||||
FDropItem * di=new FDropItem;
|
||||
|
||||
SC_MustGetString();
|
||||
di->Name=strdup(sc_String);
|
||||
di->probability=255;
|
||||
di->amount=0;
|
||||
if (SC_CheckNumber())
|
||||
{
|
||||
di->amount=sc_Number;
|
||||
}
|
||||
di->Next = bag.DropItemList;
|
||||
bag.DropItemList = di;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -3625,6 +3757,18 @@ static const ActorProps props[] =
|
|||
{ "pain", ActorPainState, RUNTIME_CLASS(AActor) },
|
||||
{ "painchance", ActorPainChance, RUNTIME_CLASS(AActor) },
|
||||
{ "painsound", ActorPainSound, RUNTIME_CLASS(AActor) },
|
||||
{ "player.colorrange", (apf)PlayerColorRange, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.crouchsprite", (apf)PlayerCrouchSprite, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.displayname", (apf)PlayerDisplayName, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.forwardmove", (apf)PlayerForwardMove, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.jumpz", (apf)PlayerJumpZ, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.maxhealth", (apf)PlayerMaxHealth, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.scoreicon", (apf)PlayerScoreIcon, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.sidemove", (apf)PlayerSideMove, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.soundclass", (apf)PlayerSoundClass, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.spawnclass", (apf)PlayerSpawnClass, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.startitem", (apf)PlayerStartItem, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "player.viewheight", (apf)PlayerViewHeight, RUNTIME_CLASS(APlayerPawn) },
|
||||
{ "poisondamage", ActorPoisonDamage, RUNTIME_CLASS(AActor) },
|
||||
{ "powerup.color", (apf)PowerupColor, RUNTIME_CLASS(APowerupGiver) },
|
||||
{ "powerup.duration", (apf)PowerupDuration, RUNTIME_CLASS(APowerupGiver) },
|
||||
|
|
|
@ -21,10 +21,31 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
int ParseExpression (bool _not);
|
||||
|
||||
int EvalExpressionI (int id, AActor *self);
|
||||
float EvalExpressionF (int id, AActor *self);
|
||||
bool EvalExpressionN (int id, AActor *self);
|
||||
|
||||
|
||||
struct FDropItem
|
||||
{
|
||||
FName Name;
|
||||
int probability;
|
||||
int amount;
|
||||
FDropItem * Next;
|
||||
};
|
||||
|
||||
FDropItem *GetDropItems(AActor * actor);
|
||||
|
||||
|
||||
// A truly awful hack to get to the state that called an action function
|
||||
// without knowing whether it has been called from a weapon or actor.
|
||||
extern FState * CallingState;
|
||||
int CheckIndex(int paramsize, FState ** pcallstate=NULL);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1658,3 +1658,19 @@ void A_Burst (AActor *actor)
|
|||
actor->Destroy ();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_CheckFloor
|
||||
// [GRB] Jumps if actor is standing on floor
|
||||
//
|
||||
//===========================================================================
|
||||
void A_CheckFloor (AActor *self)
|
||||
{
|
||||
FState *CallingState;
|
||||
int index = CheckIndex (1, &CallingState);
|
||||
|
||||
if (self->z <= self->floorz && index >= 0)
|
||||
{
|
||||
DoJump (self, CallingState, StateParameters[index]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 207
|
||||
#define NETGAMEVERSION 208
|
||||
|
||||
// Version stored in the ini's [LastRun] section.
|
||||
// Bump it if you made some configuration change that you want to
|
||||
|
@ -73,8 +73,8 @@
|
|||
// SAVEVER is the version of the information stored in level snapshots.
|
||||
// Note that SAVEVER is not directly comparable to VERSION.
|
||||
// SAVESIG should match SAVEVER.
|
||||
#define SAVEVER 233
|
||||
#define SAVESIG "ZDOOMSAVE233"
|
||||
#define SAVEVER 234
|
||||
#define SAVESIG "ZDOOMSAVE234"
|
||||
|
||||
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
||||
#define GAMESIG "ZDOOM"
|
||||
|
@ -89,7 +89,7 @@
|
|||
#endif
|
||||
|
||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||
#define MINSAVEVER 232 // Used by 2.1.0
|
||||
#define MINSAVEVER 234 // Used by 2.1.2
|
||||
|
||||
// The maximum length of one save game description for the menus.
|
||||
#define SAVESTRINGSIZE 24
|
||||
|
|
|
@ -1636,6 +1636,31 @@ FMemLump FWadCollection::ReadLump (int lump)
|
|||
return FMemLump (dest);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SetLumpAddress
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FWadCollection::SetLumpAddress(LumpRecord *l)
|
||||
{
|
||||
// This file is inside a zip and has not been opened before.
|
||||
// Position points to the start of the local file header, which we must
|
||||
// read and skip so that we can get to the actual file data.
|
||||
FZipLocalHeader localHeader;
|
||||
int skiplen;
|
||||
int address;
|
||||
|
||||
WadFileRecord *wad = Wads[l->wadnum];
|
||||
|
||||
address = wad->Tell();
|
||||
wad->Seek (l->position, SEEK_SET);
|
||||
wad->Read (&localHeader, sizeof(localHeader));
|
||||
skiplen = LittleShort(localHeader.wFileNameSize) + LittleShort(localHeader.wExtraSize);
|
||||
l->position += sizeof(localHeader) + skiplen;
|
||||
l->flags &= ~LUMPF_NEEDFILESTART;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OpenLumpNum
|
||||
|
@ -1660,23 +1685,10 @@ FWadLump FWadCollection::OpenLumpNum (int lump)
|
|||
|
||||
if (l->flags & LUMPF_NEEDFILESTART)
|
||||
{
|
||||
// This file is inside a zip and has not been opened before.
|
||||
// Position points to the start of the local file header, which we must
|
||||
// read and skip so that we can get to the actual file data.
|
||||
FZipLocalHeader localHeader;
|
||||
int skiplen;
|
||||
SetLumpAddress(l);
|
||||
}
|
||||
|
||||
wad->Seek (l->position, SEEK_SET);
|
||||
wad->Read (&localHeader, sizeof(localHeader));
|
||||
skiplen = LittleShort(localHeader.wFileNameSize) + LittleShort(localHeader.wExtraSize);
|
||||
l->position += sizeof(localHeader) + skiplen;
|
||||
wad->Seek (skiplen, SEEK_CUR);
|
||||
l->flags &= ~LUMPF_NEEDFILESTART;
|
||||
}
|
||||
else
|
||||
{
|
||||
wad->Seek (l->position, SEEK_SET);
|
||||
}
|
||||
wad->Seek (l->position, SEEK_SET);
|
||||
|
||||
if (l->flags & LUMPF_COMPRESSED)
|
||||
{
|
||||
|
@ -1728,20 +1740,7 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
|
|||
|
||||
if (l->flags & LUMPF_NEEDFILESTART)
|
||||
{
|
||||
// This file is inside a zip and has not been opened before.
|
||||
// Position points to the start of the local file header, which we must
|
||||
// read and skip so that we can get to the actual file data.
|
||||
FZipLocalHeader localHeader;
|
||||
int skiplen;
|
||||
int address;
|
||||
|
||||
address = wad->Tell();
|
||||
wad->Seek (l->position, SEEK_SET);
|
||||
wad->Read (&localHeader, sizeof(localHeader));
|
||||
skiplen = LittleShort(localHeader.wFileNameSize) + LittleShort(localHeader.wExtraSize);
|
||||
l->position += sizeof(localHeader) + skiplen;
|
||||
l->flags &= ~LUMPF_NEEDFILESTART;
|
||||
wad->Seek (address, SEEK_SET);
|
||||
SetLumpAddress(l);
|
||||
}
|
||||
|
||||
if (l->flags & LUMPF_COMPRESSED)
|
||||
|
|
|
@ -237,6 +237,7 @@ private:
|
|||
static int STACK_ARGS lumpcmp(const void * a, const void * b);
|
||||
void ScanForFlatHack (int startlump);
|
||||
void RenameSprites (int startlump);
|
||||
void SetLumpAddress(LumpRecord *l);
|
||||
};
|
||||
|
||||
extern FWadCollection Wads;
|
||||
|
|
|
@ -529,6 +529,7 @@ $playersound player male *grunt plroof
|
|||
$playersounddup player male *usefail *grunt
|
||||
$playersounddup player male *land *grunt
|
||||
$playersound player male *jump plrjmp
|
||||
$playersound player male *burndeath hedat1
|
||||
|
||||
chicken/sight chicpai
|
||||
chicken/pain chicpai
|
||||
|
|
Loading…
Reference in a new issue