- scriptified a large part of the weapon code.

This commit is contained in:
Christoph Oelckers 2017-01-19 17:40:34 +01:00
parent 3b55406302
commit 19b1c10ba8
22 changed files with 462 additions and 444 deletions

View file

@ -1749,7 +1749,7 @@ void C_MidPrintBold (FFont *font, const char *msg)
} }
} }
DEFINE_ACTION_FUNCTION(DObject, C_MidPrint) DEFINE_ACTION_FUNCTION(_Console, MidPrint)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_STRING(font); PARAM_STRING(font);

View file

@ -249,363 +249,6 @@ void AWeapon::MarkPrecacheSounds() const
ReadySound.MarkUsed(); ReadySound.MarkUsed();
} }
//===========================================================================
//
// AWeapon :: TryPickup
//
// If you can't see the weapon when it's active, then you can't pick it up.
//
//===========================================================================
bool AWeapon::TryPickupRestricted (AActor *&toucher)
{
// Wrong class, but try to pick up for ammo
if (CallShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//===========================================================================
//
// AWeapon :: TryPickup
//
//===========================================================================
bool AWeapon::TryPickup (AActor *&toucher)
{
FState * ReadyState = FindState(NAME_Ready);
if (ReadyState != NULL &&
ReadyState->GetFrame() < sprites[ReadyState->sprite].numframes)
{
return Super::TryPickup (toucher);
}
return false;
}
//===========================================================================
//
// AWeapon :: Use
//
// Make the player switch to this weapon.
//
//===========================================================================
bool AWeapon::Use (bool pickup)
{
AWeapon *useweap = this;
// Powered up weapons cannot be used directly.
if (WeaponFlags & WIF_POWERED_UP) return false;
// If the player is powered-up, use the alternate version of the
// weapon, if one exists.
if (SisterWeapon != NULL &&
SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
Owner->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true))
{
useweap = SisterWeapon;
}
if (Owner->player != NULL && Owner->player->ReadyWeapon != useweap)
{
Owner->player->PendingWeapon = useweap;
}
// Return false so that the weapon is not removed from the inventory.
return false;
}
//===========================================================================
//
// AWeapon :: Destroy
//
//===========================================================================
void AWeapon::OnDestroy()
{
AWeapon *sister = SisterWeapon;
if (sister != NULL)
{
// avoid recursion
sister->SisterWeapon = NULL;
if (sister != this)
{ // In case we are our own sister, don't crash.
sister->Destroy();
}
}
Super::OnDestroy();
}
//===========================================================================
//
// AWeapon :: HandlePickup
//
// Try to leach ammo from the weapon if you have it already.
//
//===========================================================================
bool AWeapon::HandlePickup (AInventory *item)
{
if (item->GetClass() == GetClass())
{
if (static_cast<AWeapon *>(item)->PickupForAmmo (this))
{
item->ItemFlags |= IF_PICKUPGOOD;
}
if (MaxAmount > 1) //[SP] If amount<maxamount do another pickup test of the weapon itself!
{
return Super::HandlePickup (item);
}
return true;
}
return false;
}
//===========================================================================
//
// AWeapon :: PickupForAmmo
//
// The player already has this weapon, so try to pick it up for ammo.
//
//===========================================================================
bool AWeapon::PickupForAmmo (AWeapon *ownedWeapon)
{
bool gotstuff = false;
// Don't take ammo if the weapon sticks around.
if (!CallShouldStay ())
{
int oldamount1 = 0;
int oldamount2 = 0;
if (ownedWeapon->Ammo1 != NULL) oldamount1 = ownedWeapon->Ammo1->Amount;
if (ownedWeapon->Ammo2 != NULL) oldamount2 = ownedWeapon->Ammo2->Amount;
if (AmmoGive1 > 0) gotstuff = AddExistingAmmo (ownedWeapon->Ammo1, AmmoGive1);
if (AmmoGive2 > 0) gotstuff |= AddExistingAmmo (ownedWeapon->Ammo2, AmmoGive2);
AActor *Owner = ownedWeapon->Owner;
if (gotstuff && Owner != NULL && Owner->player != NULL)
{
if (ownedWeapon->Ammo1 != NULL && oldamount1 == 0)
{
static_cast<APlayerPawn *>(Owner)->CheckWeaponSwitch(ownedWeapon->Ammo1->GetClass());
}
else if (ownedWeapon->Ammo2 != NULL && oldamount2 == 0)
{
static_cast<APlayerPawn *>(Owner)->CheckWeaponSwitch(ownedWeapon->Ammo2->GetClass());
}
}
}
return gotstuff;
}
//===========================================================================
//
// AWeapon :: CreateCopy
//
//===========================================================================
AInventory *AWeapon::CreateCopy (AActor *other)
{
AWeapon *copy = static_cast<AWeapon*>(Super::CreateCopy (other));
if (copy != this)
{
copy->AmmoGive1 = AmmoGive1;
copy->AmmoGive2 = AmmoGive2;
}
return copy;
}
//===========================================================================
//
// AWeapon :: CreateTossable
//
// A weapon that's tossed out should contain no ammo, so you can't cheat
// by dropping it and then picking it back up.
//
//===========================================================================
AInventory *AWeapon::CreateTossable ()
{
// Only drop the weapon that is meant to be placed in a level. That is,
// only drop the weapon that normally gives you ammo.
if (SisterWeapon != NULL &&
((AWeapon*)GetDefault())->AmmoGive1 == 0 &&
((AWeapon*)GetDefault())->AmmoGive2 == 0 &&
(((AWeapon*)SisterWeapon->GetDefault())->AmmoGive1 > 0 ||
((AWeapon*)SisterWeapon->GetDefault())->AmmoGive2 > 0))
{
return SisterWeapon->CallCreateTossable ();
}
AWeapon *copy = static_cast<AWeapon *> (Super::CreateTossable ());
if (copy != NULL)
{
// If this weapon has a sister, remove it from the inventory too.
if (SisterWeapon != NULL)
{
SisterWeapon->SisterWeapon = NULL;
SisterWeapon->Destroy ();
}
// To avoid exploits, the tossed weapon must not have any ammo.
copy->AmmoGive1 = 0;
copy->AmmoGive2 = 0;
}
return copy;
}
//===========================================================================
//
// AWeapon :: AttachToOwner
//
//===========================================================================
void AWeapon::AttachToOwner (AActor *other)
{
Super::AttachToOwner (other);
Ammo1 = AddAmmo (Owner, AmmoType1, AmmoGive1);
Ammo2 = AddAmmo (Owner, AmmoType2, AmmoGive2);
SisterWeapon = AddWeapon (SisterWeaponType);
if (Owner->player != NULL)
{
if (!Owner->player->userinfo.GetNeverSwitch() && !(WeaponFlags & WIF_NO_AUTO_SWITCH))
{
Owner->player->PendingWeapon = this;
}
if (Owner->player->mo == players[consoleplayer].camera)
{
StatusBar->ReceivedWeapon (this);
}
}
GivenAsMorphWeapon = false; // will be set explicitly by morphing code
}
//===========================================================================
//
// AWeapon :: AddAmmo
//
// Give some ammo to the owner, even if it's just 0.
//
//===========================================================================
AInventory *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount)
{
AInventory *ammo;
if (ammotype == NULL)
{
return NULL;
}
// [BC] This behavior is from the original Doom. Give 5/2 times as much ammo when
// we pick up a weapon in deathmatch.
if (( deathmatch ) && ( gameinfo.gametype & GAME_DoomChex ))
amount = amount * 5 / 2;
// extra ammo in baby mode and nightmare mode
if (!(this->ItemFlags&IF_IGNORESKILL))
{
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
}
ammo = other->FindInventory (ammotype);
if (ammo == NULL)
{
ammo = static_cast<AInventory *>(Spawn (ammotype));
ammo->Amount = MIN (amount, ammo->MaxAmount);
ammo->AttachToOwner (other);
}
else if (ammo->Amount < ammo->MaxAmount)
{
ammo->Amount += amount;
if (ammo->Amount > ammo->MaxAmount)
{
ammo->Amount = ammo->MaxAmount;
}
}
return ammo;
}
//===========================================================================
//
// AWeapon :: AddExistingAmmo
//
// Give the owner some more ammo he already has.
//
//===========================================================================
EXTERN_CVAR(Bool, sv_unlimited_pickup)
bool AWeapon::AddExistingAmmo (AInventory *ammo, int amount)
{
if (ammo != NULL && (ammo->Amount < ammo->MaxAmount || sv_unlimited_pickup))
{
// extra ammo in baby mode and nightmare mode
if (!(ItemFlags&IF_IGNORESKILL))
{
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
}
ammo->Amount += amount;
if (ammo->Amount > ammo->MaxAmount && !sv_unlimited_pickup)
{
ammo->Amount = ammo->MaxAmount;
}
return true;
}
return false;
}
//===========================================================================
//
// AWeapon :: AddWeapon
//
// Give the owner a weapon if they don't have it already.
//
//===========================================================================
AWeapon *AWeapon::AddWeapon (PClassWeapon *weapontype)
{
AWeapon *weap;
if (weapontype == NULL || !weapontype->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
{
return NULL;
}
weap = static_cast<AWeapon *>(Owner->FindInventory (weapontype));
if (weap == NULL)
{
weap = static_cast<AWeapon *>(Spawn (weapontype));
weap->AttachToOwner (Owner);
}
return weap;
}
//===========================================================================
//
// AWeapon :: ShouldStay
//
//===========================================================================
bool AWeapon::ShouldStay ()
{
if (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
!(flags & MF_DROPPED))
{
return true;
}
return false;
}
//=========================================================================== //===========================================================================
// //
// AWeapon :: CheckAmmo // AWeapon :: CheckAmmo
@ -781,49 +424,6 @@ void AWeapon::PostMorphWeapon ()
pspr->SetState(GetUpState()); pspr->SetState(GetUpState());
} }
//===========================================================================
//
// AWeapon :: EndPowerUp
//
// The Tome of Power just expired.
//
//===========================================================================
void AWeapon::EndPowerup ()
{
if (SisterWeapon != NULL && WeaponFlags&WIF_POWERED_UP)
{
if (GetReadyState() != SisterWeapon->GetReadyState())
{
if (Owner->player->PendingWeapon == NULL ||
Owner->player->PendingWeapon == WP_NOCHANGE)
Owner->player->PendingWeapon = SisterWeapon;
}
else
{
DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
{
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
psp->SetCaller(SisterWeapon);
Owner->player->ReadyWeapon = SisterWeapon;
}
else
{
// Something went wrong. Initiate a regular weapon change.
Owner->player->PendingWeapon = SisterWeapon;
}
}
}
}
DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup)
{
PARAM_SELF_PROLOGUE(AWeapon);
self->EndPowerup();
return 0;
}
//=========================================================================== //===========================================================================
// //
// AWeapon :: GetUpState // AWeapon :: GetUpState

View file

@ -136,17 +136,7 @@ public:
virtual void MarkPrecacheSounds() const; virtual void MarkPrecacheSounds() const;
virtual void Serialize(FSerializer &arc) override; virtual void Serialize(FSerializer &arc) override;
virtual bool ShouldStay () override;
virtual void AttachToOwner (AActor *other) override;
virtual bool HandlePickup (AInventory *item) override;
virtual AInventory *CreateCopy (AActor *other) override;
virtual AInventory *CreateTossable () override;
virtual bool TryPickup (AActor *&toucher) override;
virtual bool TryPickupRestricted (AActor *&toucher) override;
virtual bool Use (bool pickup) override;
virtual void OnDestroy() override;
bool PickupForAmmo(AWeapon *ownedWeapon);
void PostMorphWeapon(); void PostMorphWeapon();
// scripted virtuals. // scripted virtuals.
@ -158,9 +148,6 @@ public:
FState *GetStateForButtonName (FName button); FState *GetStateForButtonName (FName button);
virtual void EndPowerup ();
enum enum
{ {
PrimaryFire, PrimaryFire,
@ -180,10 +167,6 @@ public:
BobInverseSmooth BobInverseSmooth
}; };
protected:
AInventory *AddAmmo (AActor *other, PClassActor *ammotype, int amount);
bool AddExistingAmmo (AInventory *ammo, int amount);
AWeapon *AddWeapon (PClassWeapon *weapon);
}; };
enum enum

View file

@ -1673,6 +1673,15 @@ void DBaseStatusBar::ReceivedWeapon (AWeapon *weapon)
{ {
} }
DEFINE_ACTION_FUNCTION(_StatusBar, ReceivedWeapon)
{
PARAM_PROLOGUE;
PARAM_POINTER(w, AWeapon);
StatusBar->ReceivedWeapon(w);
return 0;
}
void DBaseStatusBar::SerializeMessages(FSerializer &arc) void DBaseStatusBar::SerializeMessages(FSerializer &arc)
{ {
arc.Array("hudmessages", Messages, 3, true); arc.Array("hudmessages", Messages, 3, true);

View file

@ -49,6 +49,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype)
const char *GameNames[17] = const char *GameNames[17] =

View file

@ -209,6 +209,7 @@ void ADynamicLight::Activate(AActor *activator)
m_cycler.SetCycleType(CYCLE_Sin); m_cycler.SetCycleType(CYCLE_Sin);
m_currentRadius = m_cycler.GetVal(); m_currentRadius = m_cycler.GetVal();
} }
assert(m_currentRadius > 0);
} }

View file

@ -137,7 +137,7 @@ public:
void SetHalo(bool halo) { m_halo = halo; } void SetHalo(bool halo) { m_halo = halo; }
protected: protected:
FName m_Name; FName m_Name;
unsigned char m_Args[5]; int m_Args[5];
double m_Param; double m_Param;
DVector3 m_Pos; DVector3 m_Pos;
ELightType m_type; ELightType m_type;
@ -159,7 +159,7 @@ FLightDefaults::FLightDefaults(FName name, ELightType type)
m_type = type; m_type = type;
m_Pos.Zero(); m_Pos.Zero();
memset(m_Args, 0, 5); memset(m_Args, 0, sizeof(m_Args));
m_Param = 0; m_Param = 0;
m_subtractive = false; m_subtractive = false;
@ -1195,8 +1195,8 @@ void gl_SetActorLights(AActor *actor)
for(;count<actor->dynamiclights.Size();count++) for(;count<actor->dynamiclights.Size();count++)
{ {
actor->dynamiclights[count]->flags2|=MF2_DORMANT; actor->dynamiclights[count]->flags2 |= MF2_DORMANT;
memset(actor->dynamiclights[count]->args, 0, sizeof(actor->args)); memset(actor->dynamiclights[count]->args, 0, 3*sizeof(actor->args[0]));
} }
All.Unclock(); All.Unclock();
} }

View file

@ -40,6 +40,8 @@
#include "c_dispatch.h" #include "c_dispatch.h"
#include "v_text.h" #include "v_text.h"
#include "thingdef.h" #include "thingdef.h"
#include "r_state.h"
// stores indices for symbolic state labels for some old-style DECORATE functions. // stores indices for symbolic state labels for some old-style DECORATE functions.
FStateLabelStorage StateLabels; FStateLabelStorage StateLabels;
@ -1092,3 +1094,9 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo)
} }
ACTION_RETURN_INT(retv); ACTION_RETURN_INT(retv);
} }
DEFINE_ACTION_FUNCTION(FState, ValidateSpriteFrame)
{
PARAM_SELF_STRUCT_PROLOGUE(FState);
ACTION_RETURN_BOOL(self->Frame < sprites[self->sprite].numframes);
}

View file

@ -643,6 +643,11 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetUserName)
ACTION_RETURN_STRING(self->userinfo.GetName()); ACTION_RETURN_STRING(self->userinfo.GetName());
} }
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetNeverSwitch)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
ACTION_RETURN_BOOL(self->userinfo.GetNeverSwitch());
}
//=========================================================================== //===========================================================================
// //

View file

@ -2359,7 +2359,6 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
ExpEmit FxAssign::Emit(VMFunctionBuilder *build) ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
{ {
static const BYTE loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; static const BYTE loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
assert(ValueType == Base->ValueType);
assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); assert(ValueType->GetRegType() == Right->ValueType->GetRegType());
ExpEmit pointer = Base->Emit(build); ExpEmit pointer = Base->Emit(build);

View file

@ -40,6 +40,7 @@ struct Screen native
struct Console native struct Console native
{ {
native static void HideConsole(); native static void HideConsole();
native static void MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable.
} }
struct DamageTypeDefinition native struct DamageTypeDefinition native
@ -54,6 +55,7 @@ struct GameInfoStruct native
native double Armor2Percent; native double Armor2Percent;
native String ArmorIcon1; native String ArmorIcon1;
native String ArmorIcon2; native String ArmorIcon2;
native int gametype;
} }
class Object native class Object native
@ -65,12 +67,10 @@ class Object native
native static double G_SkillPropertyFloat(int p); native static double G_SkillPropertyFloat(int p);
native static vector3, int G_PickDeathmatchStart(); native static vector3, int G_PickDeathmatchStart();
native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); native static vector3, int G_PickPlayerStart(int pnum, int flags = 0);
native static int GameType();
native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM);
native static void S_PauseSound (bool notmusic, bool notsfx); native static void S_PauseSound (bool notmusic, bool notsfx);
native static void S_ResumeSound (bool notsfx); native static void S_ResumeSound (bool notsfx);
native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false); native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false);
native static void C_MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable.
native static uint BAM(double angle); native static uint BAM(double angle);
native static void SetMusicVolume(float vol); native static void SetMusicVolume(float vol);
@ -241,6 +241,7 @@ struct State native
native bool bDehacked; native bool bDehacked;
native int DistanceTo(state other); native int DistanceTo(state other);
native bool ValidateSpriteFrame();
} }
struct F3DFloor native struct F3DFloor native

View file

@ -1,4 +1,18 @@
// This file contains compatibility wrappers for DECORATE functions with bad parameters. // This file contains compatibility wrappers for DECORATE functions with bad parameters or other things that were refactored since the first release.
extend class Object
{
deprecated static int GameType() // deprecated for 2.4.x
{
return gameinfo.gametype;
}
deprecated static void C_MidPrint(string fontname, string textlabel, bool bold = false) // deprecated for 2.4.x
{
return Console.MidPrint(fontname, textlabel, bold);
}
}
extend class Actor extend class Actor
{ {
@ -16,3 +30,9 @@ extend class StateProvider
} }
} }
// this is just a placeholder until the statusbar gets properly exported.
struct StatusBar native
{
native static void ReceivedWeapon(Weapon weap);
}

View file

@ -26,7 +26,7 @@ class ArtiBoostArmor : Inventory
{ {
int count = 0; int count = 0;
if (gametype() == GAME_Hexen) if (gameinfo.gametype == GAME_Hexen)
{ {
HexenArmor armor; HexenArmor armor;

View file

@ -124,7 +124,7 @@ class PuzzleItem : Inventory
Owner.A_PlaySound ("*puzzfail", CHAN_VOICE); Owner.A_PlaySound ("*puzzfail", CHAN_VOICE);
if (Owner.CheckLocalView (consoleplayer)) if (Owner.CheckLocalView (consoleplayer))
{ {
C_MidPrint ("SmallFont", PuzzFailMessage, true); Console.MidPrint ("SmallFont", PuzzFailMessage, true);
} }
return false; return false;
} }

View file

@ -11,14 +11,14 @@ class Weapon : StateProvider native
const ZOOM_NOSCALETURNING = 2; const ZOOM_NOSCALETURNING = 2;
native uint WeaponFlags; native uint WeaponFlags;
native class<Ammo> AmmoType1, AmmoType2; // Types of ammo used by this weapon native class<Ammo> AmmoType1, AmmoType2; // Types of ammo used by self weapon
native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to self weapon
native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
native int Kickback; native int Kickback;
native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double)
native sound UpSound, ReadySound; // Sounds when coming up and idle native sound UpSound, ReadySound; // Sounds when coming up and idle
native class<Weapon> SisterWeaponType; // Another weapon to pick up with this one native class<Weapon> SisterWeaponType; // Another weapon to pick up with self one
native class<Actor> ProjectileType; // Projectile used by primary attack native class<Actor> ProjectileType; // Projectile used by primary attack
native class<Actor> AltProjectileType; // Projectile used by alternate attack native class<Actor> AltProjectileType; // Projectile used by alternate attack
native int SelectionOrder; // Lower-numbered weapons get picked first native int SelectionOrder; // Lower-numbered weapons get picked first
@ -33,7 +33,7 @@ class Weapon : StateProvider native
native float FOVScale; native float FOVScale;
native int Crosshair; // 0 to use player's crosshair native int Crosshair; // 0 to use player's crosshair
native bool GivenAsMorphWeapon; native bool GivenAsMorphWeapon;
native bool bAltFire; // Set when this weapon's alternate fire is used. native bool bAltFire; // Set when self weapon's alternate fire is used.
native readonly bool bDehAmmo; native readonly bool bDehAmmo;
Default Default
@ -55,7 +55,6 @@ class Weapon : StateProvider native
native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1); native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1);
native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1);
native virtual void EndPowerup();
virtual State GetReadyState () virtual State GetReadyState ()
{ {
@ -248,6 +247,398 @@ class Weapon : StateProvider native
player.ReadyWeapon.Crosshair = xhair; player.ReadyWeapon.Crosshair = xhair;
} }
} }
//===========================================================================
//
// AWeapon :: TryPickup
//
// If you can't see the weapon when it's active, then you can't pick it up.
//
//===========================================================================
override bool TryPickupRestricted (in out Actor toucher)
{
// Wrong class, but try to pick up for ammo
if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//===========================================================================
//
// AWeapon :: TryPickup
//
//===========================================================================
override bool TryPickup (in out Actor toucher)
{
State ReadyState = FindState('Ready');
if (ReadyState != NULL && ReadyState.ValidateSpriteFrame())
{
return Super.TryPickup (toucher);
}
return false;
}
//===========================================================================
//
// AWeapon :: Use
//
// Make the player switch to self weapon.
//
//===========================================================================
override bool Use (bool pickup)
{
Weapon useweap = self;
// Powered up weapons cannot be used directly.
if (bPowered_Up) return false;
// If the player is powered-up, use the alternate version of the
// weapon, if one exists.
if (SisterWeapon != NULL &&
SisterWeapon.bPowered_Up &&
Owner.FindInventory ("PowerWeaponLevel2", true))
{
useweap = SisterWeapon;
}
if (Owner.player != NULL && Owner.player.ReadyWeapon != useweap)
{
Owner.player.PendingWeapon = useweap;
}
// Return false so that the weapon is not removed from the inventory.
return false;
}
//===========================================================================
//
// AWeapon :: Destroy
//
//===========================================================================
override void OnDestroy()
{
let sister = SisterWeapon;
if (sister != NULL)
{
// avoid recursion
sister.SisterWeapon = NULL;
if (sister != self)
{ // In case we are our own sister, don't crash.
sister.Destroy();
}
}
Super.OnDestroy();
}
//===========================================================================
//
// AWeapon :: HandlePickup
//
// Try to leach ammo from the weapon if you have it already.
//
//===========================================================================
override bool HandlePickup (Inventory item)
{
if (item.GetClass() == GetClass())
{
if (Weapon(item).PickupForAmmo (self))
{
item.bPickupGood = true;
}
if (MaxAmount > 1) //[SP] If amount<maxamount do another pickup test of the weapon itself!
{
return Super.HandlePickup (item);
}
return true;
}
return false;
}
//===========================================================================
//
// AWeapon :: PickupForAmmo
//
// The player already has self weapon, so try to pick it up for ammo.
//
//===========================================================================
protected bool PickupForAmmo (Weapon ownedWeapon)
{
bool gotstuff = false;
// Don't take ammo if the weapon sticks around.
if (!ShouldStay ())
{
int oldamount1 = 0;
int oldamount2 = 0;
if (ownedWeapon.Ammo1 != NULL) oldamount1 = ownedWeapon.Ammo1.Amount;
if (ownedWeapon.Ammo2 != NULL) oldamount2 = ownedWeapon.Ammo2.Amount;
if (AmmoGive1 > 0) gotstuff = AddExistingAmmo (ownedWeapon.Ammo1, AmmoGive1);
if (AmmoGive2 > 0) gotstuff |= AddExistingAmmo (ownedWeapon.Ammo2, AmmoGive2);
let Owner = ownedWeapon.Owner;
if (gotstuff && Owner != NULL && Owner.player != NULL)
{
if (ownedWeapon.Ammo1 != NULL && oldamount1 == 0)
{
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo1.GetClass());
}
else if (ownedWeapon.Ammo2 != NULL && oldamount2 == 0)
{
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo2.GetClass());
}
}
}
return gotstuff;
}
//===========================================================================
//
// AWeapon :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{
let copy = Weapon(Super.CreateCopy (other));
if (copy != self && copy != null)
{
copy.AmmoGive1 = AmmoGive1;
copy.AmmoGive2 = AmmoGive2;
}
return copy;
}
//===========================================================================
//
// AWeapon :: CreateTossable
//
// A weapon that's tossed out should contain no ammo, so you can't cheat
// by dropping it and then picking it back up.
//
//===========================================================================
override Inventory CreateTossable ()
{
// Only drop the weapon that is meant to be placed in a level. That is,
// only drop the weapon that normally gives you ammo.
if (SisterWeapon != NULL &&
Default.AmmoGive1 == 0 && Default.AmmoGive2 == 0 &&
(SisterWeapon.Default.AmmoGive1 > 0 || SisterWeapon.Default.AmmoGive2 > 0))
{
return SisterWeapon.CreateTossable ();
}
let copy = Weapon(Super.CreateTossable ());
if (copy != NULL)
{
// If self weapon has a sister, remove it from the inventory too.
if (SisterWeapon != NULL)
{
SisterWeapon.SisterWeapon = NULL;
SisterWeapon.Destroy ();
}
// To avoid exploits, the tossed weapon must not have any ammo.
copy.AmmoGive1 = 0;
copy.AmmoGive2 = 0;
}
return copy;
}
//===========================================================================
//
// AWeapon :: AttachToOwner
//
//===========================================================================
override void AttachToOwner (Actor other)
{
Super.AttachToOwner (other);
Ammo1 = AddAmmo (Owner, AmmoType1, AmmoGive1);
Ammo2 = AddAmmo (Owner, AmmoType2, AmmoGive2);
SisterWeapon = AddWeapon (SisterWeaponType);
if (Owner.player != NULL)
{
if (!Owner.player.GetNeverSwitch() && !bNo_Auto_Switch)
{
Owner.player.PendingWeapon = self;
}
if (Owner.player.mo == players[consoleplayer].camera)
{
StatusBar.ReceivedWeapon (self);
}
}
GivenAsMorphWeapon = false; // will be set explicitly by morphing code
}
//===========================================================================
//
// AWeapon :: AddAmmo
//
// Give some ammo to the owner, even if it's just 0.
//
//===========================================================================
protected Ammo AddAmmo (Actor other, Class<Ammo> ammotype, int amount)
{
Ammo ammoitem;
if (ammotype == NULL)
{
return NULL;
}
// [BC] This behavior is from the original Doom. Give 5/2 times as much ammoitem when
// we pick up a weapon in deathmatch.
if (( deathmatch ) && ( gameinfo.gametype & GAME_DoomChex ))
amount = amount * 5 / 2;
// extra ammoitem in baby mode and nightmare mode
if (!bIgnoreSkill)
{
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
}
ammoitem = Ammo(other.FindInventory (ammotype));
if (ammoitem == NULL)
{
ammoitem = Ammo(Spawn (ammotype));
ammoitem.Amount = MIN (amount, ammoitem.MaxAmount);
ammoitem.AttachToOwner (other);
}
else if (ammoitem.Amount < ammoitem.MaxAmount)
{
ammoitem.Amount += amount;
if (ammoitem.Amount > ammoitem.MaxAmount)
{
ammoitem.Amount = ammoitem.MaxAmount;
}
}
return ammoitem;
}
//===========================================================================
//
// AWeapon :: AddExistingAmmo
//
// Give the owner some more ammo he already has.
//
//===========================================================================
protected bool AddExistingAmmo (Inventory ammo, int amount)
{
if (ammo != NULL && (ammo.Amount < ammo.MaxAmount || sv_unlimited_pickup))
{
// extra ammo in baby mode and nightmare mode
if (!bIgnoreSkill)
{
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
}
ammo.Amount += amount;
if (ammo.Amount > ammo.MaxAmount && !sv_unlimited_pickup)
{
ammo.Amount = ammo.MaxAmount;
}
return true;
}
return false;
}
//===========================================================================
//
// AWeapon :: AddWeapon
//
// Give the owner a weapon if they don't have it already.
//
//===========================================================================
protected Weapon AddWeapon (Class<Weapon> weapontype)
{
Weapon weap;
if (weapontype == NULL)
{
return NULL;
}
weap = Weapon(Owner.FindInventory (weapontype));
if (weap == NULL)
{
weap = Weapon(Spawn (weapontype));
weap.AttachToOwner (Owner);
}
return weap;
}
//===========================================================================
//
// AWeapon :: ShouldStay
//
//===========================================================================
override bool ShouldStay ()
{
if (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || sv_weaponstay) &&
!bDropped)
{
return true;
}
return false;
}
//===========================================================================
//
// AWeapon :: EndPowerUp
//
// The Tome of Power just expired.
//
//===========================================================================
virtual void EndPowerup ()
{
let player = Owner.player;
if (SisterWeapon != NULL && bPowered_Up)
{
if (GetReadyState() != SisterWeapon.GetReadyState())
{
if (player.PendingWeapon == NULL || player.PendingWeapon == WP_NOCHANGE)
player.PendingWeapon = SisterWeapon;
}
else
{
let psp = player.FindPSprite(PSP_WEAPON);
if (psp != null && psp.Caller == player.ReadyWeapon)
{
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
psp.Caller = SisterWeapon;
player.ReadyWeapon = SisterWeapon;
}
else
{
// Something went wrong. Initiate a regular weapon change.
player.PendingWeapon = SisterWeapon;
}
}
}
}
} }
class WeaponGiver : Weapon class WeaponGiver : Weapon
@ -276,7 +667,7 @@ class WeaponGiver : Weapon
master = weap = Weapon(Spawn(di.Name)); master = weap = Weapon(Spawn(di.Name));
if (weap != NULL) if (weap != NULL)
{ {
weap.bAlwaysPickup = false; // use the flag of this item only. weap.bAlwaysPickup = false; // use the flag of self item only.
weap.bDropped = bDropped; weap.bDropped = bDropped;
// If our ammo gives are non-negative, transfer them to the real weapon. // If our ammo gives are non-negative, transfer them to the real weapon.

View file

@ -252,8 +252,7 @@ class Minotaur : Actor
{ {
Class<Actor> type; Class<Actor> type;
//if (gameinfo.gametype == GAME_Heretic) if (gameinfo.gametype == GAME_Heretic)
if (gametype() == GAME_Heretic)
{ {
type = "PhoenixPuff"; type = "PhoenixPuff";
} }

View file

@ -308,6 +308,7 @@ userinfo_t userinfo;
native void SetLogNumber (int text); native void SetLogNumber (int text);
native void SetLogText (String text); native void SetLogText (String text);
native String GetUserName(); native String GetUserName();
native bool GetNeverSwitch();
native void DropWeapon(); native void DropWeapon();
native void BringUpWeapon(); native void BringUpWeapon();

View file

@ -123,7 +123,7 @@ extend class PlayerPawn
if (giveall || name ~== "armor") if (giveall || name ~== "armor")
{ {
if (GameType() != GAME_Hexen) if (gameinfo.gametype != GAME_Hexen)
{ {
let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup")); let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup"));
armoritem.SaveAmount = 100*deh.BlueAC; armoritem.SaveAmount = 100*deh.BlueAC;

View file

@ -27,7 +27,7 @@ class TeleportFog : Actor
{ {
Super.PostBeginPlay (); Super.PostBeginPlay ();
A_PlaySound ("misc/teleport", CHAN_BODY); A_PlaySound ("misc/teleport", CHAN_BODY);
switch (gametype()) switch (gameinfo.gametype)
{ {
case GAME_Hexen: case GAME_Hexen:
case GAME_Heretic: case GAME_Heretic:

View file

@ -108,13 +108,13 @@ class AlienSpectre1 : SpectralMonster
} }
else if (cls == "AlienSpectre2") else if (cls == "AlienSpectre2")
{ {
C_MidPrint("SmallFont", "$TXT_KILLED_BISHOP"); Console.MidPrint("SmallFont", "$TXT_KILLED_BISHOP");
log = 74; log = 74;
player.GiveInventoryType ("QuestItem21"); player.GiveInventoryType ("QuestItem21");
} }
else if (cls == "AlienSpectre3") else if (cls == "AlienSpectre3")
{ {
C_MidPrint("SmallFont", "$TXT_KILLED_ORACLE"); Console.MidPrint("SmallFont", "$TXT_KILLED_ORACLE");
// If there are any Oracles still alive, kill them. // If there are any Oracles still alive, kill them.
ThinkerIterator it = ThinkerIterator.Create("Oracle"); ThinkerIterator it = ThinkerIterator.Create("Oracle");
Actor oracle; Actor oracle;
@ -144,7 +144,7 @@ class AlienSpectre1 : SpectralMonster
} }
else if (cls == "AlienSpectre4") else if (cls == "AlienSpectre4")
{ {
C_MidPrint("SmallFont", "$TXT_KILLED_MACIL"); Console.MidPrint("SmallFont", "$TXT_KILLED_MACIL");
player.GiveInventoryType ("QuestItem24"); player.GiveInventoryType ("QuestItem24");
if (player.FindInventory ("QuestItem25") == null) if (player.FindInventory ("QuestItem25") == null)
{ // Richter has taken over. Macil is a snake. { // Richter has taken over. Macil is a snake.
@ -157,7 +157,7 @@ class AlienSpectre1 : SpectralMonster
} }
else if (cls == "AlienSpectre5") else if (cls == "AlienSpectre5")
{ {
C_MidPrint("SmallFont", "$TXT_KILLED_LOREMASTER"); Console.MidPrint("SmallFont", "$TXT_KILLED_LOREMASTER");
player.GiveInventoryType ("QuestItem26"); player.GiveInventoryType ("QuestItem26");
if (!multiplayer) if (!multiplayer)

View file

@ -531,7 +531,7 @@ class Scanner : PowerupGiver
{ {
if (Owner.CheckLocalView (consoleplayer)) if (Owner.CheckLocalView (consoleplayer))
{ {
C_MidPrint("SmallFont", "$TXT_NEEDMAP"); Console.MidPrint("SmallFont", "$TXT_NEEDMAP");
} }
return false; return false;
} }

View file

@ -32,7 +32,7 @@ extend class Actor
if (msg != msgid) // if both are identical there was no message of this name in the stringtable. if (msg != msgid) // if both are identical there was no message of this name in the stringtable.
{ {
C_MidPrint ("SmallFont", msg); Console.MidPrint ("SmallFont", msg);
} }
} }