- Update scripting branch to trunk.

SVN r3758 (scripting)
This commit is contained in:
Randy Heit 2012-07-14 03:04:41 +00:00
commit 562cf04db2
614 changed files with 63691 additions and 31256 deletions

View file

@ -30,7 +30,6 @@
#include "doomstat.h"
#include "s_sound.h"
#include "i_system.h"
#include "r_draw.h"
#include "gi.h"
#include "m_random.h"
#include "p_pspr.h"
@ -44,7 +43,7 @@
#include "w_wad.h"
#include "cmdlib.h"
#include "sbar.h"
#include "f_finale.h"
#include "intermission/intermission.h"
#include "c_console.h"
#include "doomdef.h"
#include "c_dispatch.h"
@ -52,6 +51,9 @@
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "d_net.h"
#include "gstrings.h"
#include "farchive.h"
#include "r_renderer.h"
static FRandom pr_skullpop ("SkullPop");
@ -95,40 +97,57 @@ bool FPlayerClass::CheckSkin (int skin)
return false;
}
//===========================================================================
//
// GetDisplayName
//
//===========================================================================
FString GetPrintableDisplayName(PClassPlayerPawn *cls)
{
// Fixme; This needs a decent way to access the string table without creating a mess.
// [RH] ????
return cls->DisplayName;
}
bool ValidatePlayerClass(PClassActor *ti, const char *name)
{
if (ti == NULL)
{
Printf("Unknown player class '%s'\n", name);
return false;
}
else if (!ti->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)))
{
Printf("Invalid player class '%s'\n", name);
return false;
}
else if (static_cast<PClassPlayerPawn *>(ti)->DisplayName.IsEmpty())
{
Printf ("Missing displayname for player class '%s'\n", name);
return false;
}
return true;
}
void SetupPlayerClasses ()
{
FPlayerClass newclass;
newclass.Flags = 0;
if (gameinfo.gametype == GAME_Doom)
PlayerClasses.Clear();
for (unsigned i = 0; i < gameinfo.PlayerClasses.Size(); i++)
{
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_DoomPlayer));
PlayerClasses.Push(newclass);
}
else if (gameinfo.gametype == GAME_Heretic)
{
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_HereticPlayer));
PlayerClasses.Push(newclass);
}
else if (gameinfo.gametype == GAME_Hexen)
{
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_FighterPlayer));
PlayerClasses.Push(newclass);
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_ClericPlayer));
PlayerClasses.Push(newclass);
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_MagePlayer));
PlayerClasses.Push(newclass);
}
else if (gameinfo.gametype == GAME_Strife)
{
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_StrifePlayer));
PlayerClasses.Push(newclass);
}
else if (gameinfo.gametype == GAME_Chex)
{
newclass.Type = static_cast<PClassPlayerPawn *>(PClass::FindClass(NAME_ChexPlayer));
PlayerClasses.Push(newclass);
PClassActor *cls = PClass::FindActor(gameinfo.PlayerClasses[i]);;
if (ValidatePlayerClass(cls, gameinfo.PlayerClasses[i]))
{
newclass.Flags = 0;
newclass.Type = static_cast<PClassPlayerPawn *>(cls);
if ((GetDefaultByType(cls)->flags6 & MF6_NOMENU))
{
newclass.Flags |= PCF_NOMENU;
}
PlayerClasses.Push(newclass);
}
}
}
@ -144,25 +163,17 @@ CCMD (addplayerclass)
{
if (ParsingKeyConf && argv.argc () > 1)
{
PClassPlayerPawn *ti = dyn_cast<PClassPlayerPawn>(PClass::FindClass(argv[1]));
PClassActor *ti = PClass::FindActor(argv[1]);
if (ti == NULL)
{
Printf ("Unknown player class '%s'\n", argv[1]);
}
else if (ti->DisplayName.IsEmpty())
{
Printf ("Missing displayname for player class '%s'\n", argv[1]);
}
else
if (ValidatePlayerClass(ti, argv[1]))
{
FPlayerClass newclass;
newclass.Type = ti;
newclass.Type = static_cast<PClassPlayerPawn *>(ti);
newclass.Flags = 0;
int arg = 2;
while (arg < argv.argc ())
while (arg < argv.argc())
{
if (!stricmp (argv[arg], "nomenu"))
{
@ -184,7 +195,9 @@ CCMD (playerclasses)
{
for (unsigned int i = 0; i < PlayerClasses.Size (); i++)
{
Printf("% 3d %s\n", i, PlayerClasses[i].Type->DisplayName.GetChars());
Printf ("%3d: Class = %s, Name = %s\n", i,
PlayerClasses[i].Type->TypeName.GetChars(),
PlayerClasses[i].Type->DisplayName.GetChars());
}
}
@ -198,6 +211,11 @@ CCMD (playerclasses)
bool onground;
FArchive &operator<< (FArchive &arc, player_t *&p)
{
return arc.SerializePointer (players, (BYTE **)&p, sizeof(*players));
}
// The player_t constructor. Since LogText is not a POD, we cannot just
// memset it all to 0.
player_t::player_t()
@ -228,6 +246,7 @@ player_t::player_t()
ReadyWeapon(0),
PendingWeapon(0),
cheats(0),
timefreezer(0),
refire(0),
inconsistant(0),
killcount(0),
@ -250,8 +269,6 @@ player_t::player_t()
respawn_time(0),
camera(0),
air_finished(0),
accuracy(0),
stamina(0),
savedyaw(0),
savedpitch(0),
angle(0),
@ -309,21 +326,25 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep)
{
APlayerPawn *replacement = static_cast<APlayerPawn *>(rep);
size_t changed = 0;
if (mo == old) mo = replacement, changed++;
if (poisoner == old) poisoner = replacement, changed++;
if (attacker == old) attacker = replacement, changed++;
if (camera == old) camera = replacement, changed++;
if (dest == old) dest = replacement, changed++;
if (prev == old) prev = replacement, changed++;
if (enemy == old) enemy = replacement, changed++;
if (missile == old) missile = replacement, changed++;
if (mate == old) mate = replacement, changed++;
if (last_mate == old) last_mate = replacement, changed++;
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
if (PremorphWeapon == old) PremorphWeapon = static_cast<AWeapon *>(rep), changed++;
if (ConversationNPC == old) ConversationNPC = replacement, changed++;
if (ConversationPC == old) ConversationPC = replacement, changed++;
// The construct *& is used in several of these to avoid the read barriers
// that would turn the pointer we want to check to NULL if the old object
// is pending deletion.
if (mo == old) mo = replacement, changed++;
if (*&poisoner == old) poisoner = replacement, changed++;
if (*&attacker == old) attacker = replacement, changed++;
if (*&camera == old) camera = replacement, changed++;
if (*&dest == old) dest = replacement, changed++;
if (*&prev == old) prev = replacement, changed++;
if (*&enemy == old) enemy = replacement, changed++;
if (*&missile == old) missile = replacement, changed++;
if (*&mate == old) mate = replacement, changed++;
if (*&last_mate == old) last_mate = replacement, changed++;
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
if (*&PremorphWeapon == old) PremorphWeapon = static_cast<AWeapon *>(rep), changed++;
if (*&ConversationNPC == old) ConversationNPC = replacement, changed++;
if (*&ConversationPC == old) ConversationPC = replacement, changed++;
return changed;
}
@ -450,6 +471,25 @@ void PClassPlayerPawn::EnumColorSets(TArray<int> *out)
qsort(&(*out)[0], out->Size(), sizeof(int), intcmp);
}
//===========================================================================
//
// player_t :: SendPitchLimits
//
// Ask the local player's renderer what pitch restrictions should be imposed
// and let everybody know. Only sends data for the consoleplayer, since the
// local player is the only one our data is valid for.
//
//===========================================================================
void player_t::SendPitchLimits() const
{
if (this - players == consoleplayer)
{
Net_WriteByte(DEM_SETPITCHLIMIT);
Net_WriteByte(Renderer->GetMaxViewPitch(false)); // up
Net_WriteByte(Renderer->GetMaxViewPitch(true)); // down
}
}
//===========================================================================
//
@ -481,11 +521,8 @@ void APlayerPawn::Serialize (FArchive &arc)
<< InvSel
<< MorphWeapon
<< DamageFade
<< PlayerFlags;
if (SaveVersion < 2435)
{
DamageFade.a = 255;
}
<< PlayerFlags
<< FlechetteType;
}
//===========================================================================
@ -558,6 +595,7 @@ void APlayerPawn::Tick()
void APlayerPawn::PostBeginPlay()
{
Super::PostBeginPlay();
SetupWeaponSlots();
// Voodoo dolls: restore original floorz/ceilingz logic
@ -565,9 +603,13 @@ void APlayerPawn::PostBeginPlay()
{
dropoffz = floorz = Sector->floorplane.ZatPoint(x, y);
ceilingz = Sector->ceilingplane.ZatPoint(x, y);
P_FindFloorCeiling(this, true);
P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS);
z = floorz;
}
else
{
player->SendPitchLimits();
}
}
//===========================================================================
@ -585,11 +627,21 @@ void APlayerPawn::SetupWeaponSlots()
if (player != NULL && player->mo == this)
{
player->weapons.StandardSetup(GetClass());
if (player - players == consoleplayer)
{ // If we're the local player, then there's a bit more work to do.
// If we're the local player, then there's a bit more work to do.
// This also applies if we're a bot and this is the net arbitrator.
if (player - players == consoleplayer ||
(player->isbot && consoleplayer == Net_Arbitrator))
{
FWeaponSlots local_slots(player->weapons);
local_slots.LocalSetup(GetClass());
local_slots.SendDifferences(player->weapons);
if (player->isbot)
{ // Bots only need weapons from KEYCONF, not INI modifications.
P_PlaybackKeyConfWeapons(&local_slots);
}
else
{
local_slots.LocalSetup(GetClass());
}
local_slots.SendDifferences(int(player - players), player->weapons);
}
}
}
@ -683,7 +735,7 @@ bool APlayerPawn::UseInventory (AInventory *item)
{ // You can't use items if you're totally frozen
return false;
}
if (( level.flags2 & LEVEL2_FROZEN ) && ( player == NULL || !( player->cheats & CF_TIMEFREEZE )))
if ((level.flags2 & LEVEL2_FROZEN) && (player == NULL || player->timefreezer == 0))
{
// Time frozen
return false;
@ -712,13 +764,13 @@ bool APlayerPawn::UseInventory (AInventory *item)
//
//===========================================================================
AWeapon *APlayerPawn::BestWeapon (const PClass *ammotype)
AWeapon *APlayerPawn::BestWeapon(PClassAmmo *ammotype)
{
AWeapon *bestMatch = NULL;
int bestOrder = INT_MAX;
AInventory *item;
AWeapon *weap;
bool tomed = NULL != FindInventory (RUNTIME_CLASS(APowerWeaponLevel2));
bool tomed = NULL != FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
// Find the best weapon the player has.
for (item = Inventory; item != NULL; item = item->Inventory)
@ -768,7 +820,7 @@ AWeapon *APlayerPawn::BestWeapon (const PClass *ammotype)
//
//===========================================================================
AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype)
AWeapon *APlayerPawn::PickNewWeapon(PClassAmmo *ammotype)
{
AWeapon *best = BestWeapon (ammotype);
@ -796,7 +848,7 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype)
//
//===========================================================================
void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype)
void APlayerPawn::CheckWeaponSwitch(PClassAmmo *ammotype)
{
if (!player->userinfo.neverswitch &&
player->PendingWeapon == WP_NOCHANGE &&
@ -969,6 +1021,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
const char *APlayerPawn::GetSoundClass ()
{
if (player != NULL &&
(player->mo == NULL || !(player->mo->flags4 &MF4_NOSKIN)) &&
(unsigned int)player->userinfo.skin >= PlayerClasses.Size () &&
(size_t)player->userinfo.skin < numskins)
{
@ -1208,15 +1261,15 @@ void APlayerPawn::ActivateMorphWeapon ()
//
//===========================================================================
void APlayerPawn::Die (AActor *source, AActor *inflictor)
void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags)
{
Super::Die (source, inflictor);
Super::Die (source, inflictor, dmgflags);
if (player != NULL && player->mo == this) player->bonuscount = 0;
if (player != NULL && player->mo != this)
{ // Make the real player die, too
player->mo->Die (source, inflictor);
player->mo->Die (source, inflictor, dmgflags);
}
else
{
@ -1227,6 +1280,22 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor)
{
AInventory *item;
// kgDROP - start - modified copy from a_action.cpp
DDropItem *di = weap->GetDropItems();
if (di != NULL)
{
while (di != NULL)
{
if (di->Name != NAME_None)
{
PClassActor *ti = PClass::FindActor(di->Name);
if (ti) P_DropItem (player->mo, ti, di->Amount, di->Probability);
}
di = di->Next;
}
} else
// kgDROP - end
if (weap->SpawnState != NULL &&
weap->SpawnState != ::GetDefault<AActor>()->SpawnState)
{
@ -1261,9 +1330,9 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor)
}
}
}
if (!multiplayer && (level.flags2 & LEVEL2_DEATHSLIDESHOW))
if (!multiplayer && level.info->deathsequence != NAME_None)
{
F_StartSlideshow ();
F_StartIntermission(level.info->deathsequence, FSTATE_EndingGame);
}
}
}
@ -1483,7 +1552,6 @@ void P_CheckPlayerSprites()
// Set the crouch sprite
if (player->crouchfactor < FRACUNIT*3/4)
{
if (mo->sprite == mo->SpawnState->sprite || mo->sprite == mo->crouchsprite)
{
crouchspriteno = mo->crouchsprite;
@ -1512,13 +1580,16 @@ void P_CheckPlayerSprites()
}
else // Set the normal sprite
{
if (mo->sprite == mo->crouchsprite)
if (mo->sprite != 0)
{
mo->sprite = mo->SpawnState->sprite;
}
else if (mo->sprite == skins[player->userinfo.skin].crouchsprite)
{
mo->sprite = skins[player->userinfo.skin].sprite;
if (mo->sprite == mo->crouchsprite)
{
mo->sprite = mo->SpawnState->sprite;
}
else if (mo->sprite != 0 && mo->sprite == skins[player->userinfo.skin].crouchsprite)
{
mo->sprite = skins[player->userinfo.skin].sprite;
}
}
mo->scaleY = defscaleY;
}
@ -2136,9 +2207,7 @@ void P_PlayerThink (player_t *player)
player->mo->flags &= ~MF_JUSTATTACKED;
}
bool totallyfrozen = (player->cheats & CF_TOTALLYFROZEN || gamestate == GS_TITLELEVEL ||
(( level.flags2 & LEVEL2_FROZEN ) && ( player == NULL || !( player->cheats & CF_TIMEFREEZE )))
);
bool totallyfrozen = P_IsPlayerTotallyFrozen(player);
// [RH] Being totally frozen zeros out most input parameters.
if (totallyfrozen)
@ -2210,9 +2279,13 @@ void P_PlayerThink (player_t *player)
P_DeathThink (player);
return;
}
if (player->jumpTics)
if (player->jumpTics != 0)
{
player->jumpTics--;
if (onground && player->jumpTics < -18)
{
player->jumpTics = 0;
}
}
if (player->morphTics && !(player->cheats & CF_PREDICTING))
{
@ -2236,22 +2309,47 @@ void P_PlayerThink (player_t *player)
{
if (look == -32768 << 16)
{ // center view
player->mo->pitch = 0;
player->centering = true;
}
else
else if (!player->centering)
{
fixed_t oldpitch = player->mo->pitch;
player->mo->pitch -= look;
if (look > 0)
{ // look up
player->mo->pitch = MAX(player->mo->pitch, screen->GetMaxViewPitch(false));
player->mo->pitch = MAX(player->mo->pitch, player->MinPitch);
if (player->mo->pitch > oldpitch)
{
player->mo->pitch = player->MinPitch;
}
}
else
{ // look down
player->mo->pitch = MIN(player->mo->pitch, screen->GetMaxViewPitch(true));
player->mo->pitch = MIN(player->mo->pitch, player->MaxPitch);
if (player->mo->pitch < oldpitch)
{
player->mo->pitch = player->MaxPitch;
}
}
}
}
}
if (player->centering)
{
if (abs(player->mo->pitch) > 2*ANGLE_1)
{
player->mo->pitch = FixedMul(player->mo->pitch, FRACUNIT*2/3);
}
else
{
player->mo->pitch = 0;
player->centering = false;
if (player - players == consoleplayer)
{
LocalViewPitch = 0;
}
}
}
// [RH] Check for fast turn around
if (cmd->ucmd.buttons & BT_TURN180 && !(player->oldbuttons & BT_TURN180))
@ -2271,7 +2369,7 @@ void P_PlayerThink (player_t *player)
// [RH] check for jump
if (cmd->ucmd.buttons & BT_JUMP)
{
if (player->crouchoffset!=0)
if (player->crouchoffset != 0)
{
// Jumping while crouching will force an un-crouch but not jump
player->crouching = 1;
@ -2285,7 +2383,7 @@ void P_PlayerThink (player_t *player)
{
player->mo->velz = 3*FRACUNIT;
}
else if (level.IsJumpingAllowed() && onground && !player->jumpTics)
else if (level.IsJumpingAllowed() && onground && player->jumpTics == 0)
{
fixed_t jumpvelz = player->mo->JumpZ * 35 / TICRATE;
@ -2295,7 +2393,7 @@ void P_PlayerThink (player_t *player)
player->mo->velz += jumpvelz;
S_Sound (player->mo, CHAN_BODY, "*jump", 1, ATTN_NORM);
player->mo->flags2 &= ~MF2_ONMOBJ;
player->jumpTics = 18*TICRATE/35;
player->jumpTics = -1;
}
}
@ -2414,15 +2512,6 @@ void P_PlayerThink (player_t *player)
P_PoisonDamage (player, player->poisoner, 1, true);
}
// [BC] Apply regeneration.
if (( level.time & 31 ) == 0 && ( player->cheats & CF_REGENERATION ) && ( player->health ))
{
if ( P_GiveBody( player->mo, 5 ))
{
S_Sound(player->mo, CHAN_ITEM, "*regenerate", 1, ATTN_NORM );
}
}
// Apply degeneration.
if (dmflags2 & DF2_YES_DEGENERATION)
{
@ -2604,33 +2693,9 @@ void player_t::Serialize (FArchive &arc)
<< poisoncount
<< poisoner
<< attacker
<< extralight;
if (SaveVersion < 1858)
{
int fixedmap;
arc << fixedmap;
fixedcolormap = NOFIXEDCOLORMAP;
fixedlightlevel = -1;
if (fixedmap >= NUMCOLORMAPS)
{
fixedcolormap = fixedmap - NUMCOLORMAPS;
}
else if (fixedmap > 0)
{
fixedlightlevel = fixedmap;
}
}
else if (SaveVersion < 1893)
{
int ll;
arc << fixedcolormap << ll;
fixedlightlevel = ll;
}
else
{
arc << fixedcolormap << fixedlightlevel;
}
arc << morphTics
<< extralight
<< fixedcolormap << fixedlightlevel
<< morphTics
<< MorphedPlayerClass
<< MorphStyle
<< MorphExitFlash
@ -2645,9 +2710,18 @@ void player_t::Serialize (FArchive &arc)
<< BlendR
<< BlendG
<< BlendB
<< BlendA
<< accuracy << stamina
<< LogText
<< BlendA;
if (SaveVersion < 3427)
{
WORD oldaccuracy, oldstamina;
arc << oldaccuracy << oldstamina;
if (mo != NULL)
{
mo->accuracy = oldaccuracy;
mo->stamina = oldstamina;
}
}
arc << LogText
<< ConversationNPC
<< ConversationPC
<< ConversationNPCAngle
@ -2667,6 +2741,29 @@ void player_t::Serialize (FArchive &arc)
<< original_cmd
<< original_oldbuttons;
if (SaveVersion >= 3475)
{
arc << poisontype << poisonpaintype;
}
else if (poisoner != NULL)
{
poisontype = poisoner->DamageType;
poisonpaintype = poisoner->PainType != NAME_None ? poisoner->PainType : poisoner->DamageType;
}
if (SaveVersion >= 3599)
{
arc << timefreezer;
}
else
{
cheats &= ~(1 << 15); // make sure old CF_TIMEFREEZE bit is cleared
}
if (SaveVersion < 3640)
{
cheats &= ~(1 << 17); // make sure old CF_REGENERATION bit is cleared
}
if (isbot)
{
arc << angle
@ -2702,3 +2799,11 @@ void player_t::Serialize (FArchive &arc)
original_oldbuttons = ~0;
}
}
bool P_IsPlayerTotallyFrozen(const player_t *player)
{
return
gamestate == GS_TITLELEVEL ||
player->cheats & CF_TOTALLYFROZEN ||
((level.flags2 & LEVEL2_FROZEN) && player->timefreezer == 0);
}