mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 15:02:01 +00:00
- scriptified PowerFlight and PowerWeaponLevel2.
This commit is contained in:
parent
4837e1e770
commit
d2d6e5d486
25 changed files with 369 additions and 306 deletions
|
@ -186,6 +186,13 @@ private:
|
|||
int texnum;
|
||||
};
|
||||
|
||||
// This is for the script interface which needs to do casts from int to texture.
|
||||
class FSetTextureID : public FTextureID
|
||||
{
|
||||
public:
|
||||
FSetTextureID(int v) : FTextureID(v) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Screenshot buffer image data types
|
||||
|
|
|
@ -1008,230 +1008,6 @@ void APowerTorch::DoEffect ()
|
|||
}
|
||||
}
|
||||
|
||||
// Flight (aka Wings of Wrath) powerup ---------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(APowerFlight, false, false)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerFlight::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("hitcenterframe", HitCenterFrame);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerFlight::InitEffect ()
|
||||
{
|
||||
Super::InitEffect();
|
||||
Owner->flags2 |= MF2_FLY;
|
||||
Owner->flags |= MF_NOGRAVITY;
|
||||
if (Owner->Z() <= Owner->floorz)
|
||||
{
|
||||
Owner->Vel.Z = 4;; // thrust the player in the air a bit
|
||||
}
|
||||
if (Owner->Vel.Z <= -35)
|
||||
{ // stop falling scream
|
||||
S_StopSound (Owner, CHAN_VOICE);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: DoEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerFlight::Tick ()
|
||||
{
|
||||
// The Wings of Wrath only expire in multiplayer and non-hub games
|
||||
if (!multiplayer && (level.flags2 & LEVEL2_INFINITE_FLIGHT))
|
||||
{
|
||||
assert(EffectTics < INT_MAX); // I can't see a game lasting nearly two years, but...
|
||||
EffectTics++;
|
||||
}
|
||||
|
||||
Super::Tick ();
|
||||
|
||||
// Owner->flags |= MF_NOGRAVITY;
|
||||
// Owner->flags2 |= MF2_FLY;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerFlight::EndEffect ()
|
||||
{
|
||||
Super::EndEffect();
|
||||
if (Owner == NULL || Owner->player == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(Owner->flags7 & MF7_FLYCHEAT))
|
||||
{
|
||||
if (Owner->Z() != Owner->floorz)
|
||||
{
|
||||
Owner->player->centering = true;
|
||||
}
|
||||
Owner->flags2 &= ~MF2_FLY;
|
||||
Owner->flags &= ~MF_NOGRAVITY;
|
||||
}
|
||||
// BorderTopRefresh = screen->GetPageCount (); //make sure the sprite's cleared out
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: DrawPowerup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool APowerFlight::DrawPowerup (int x, int y)
|
||||
{
|
||||
// If this item got a valid icon use that instead of the default spinning wings.
|
||||
if (Icon.isValid())
|
||||
{
|
||||
return Super::DrawPowerup(x, y);
|
||||
}
|
||||
|
||||
if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
|
||||
{
|
||||
FTextureID picnum = TexMan.CheckForTexture ("SPFLY0", FTexture::TEX_MiscPatch);
|
||||
int frame = (level.time/3) & 15;
|
||||
|
||||
if (!picnum.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Owner->flags & MF_NOGRAVITY)
|
||||
{
|
||||
if (HitCenterFrame && (frame != 15 && frame != 0))
|
||||
{
|
||||
screen->DrawTexture (TexMan[picnum+15], x, y,
|
||||
DTA_HUDRules, HUD_Normal, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->DrawTexture (TexMan[picnum+frame], x, y,
|
||||
DTA_HUDRules, HUD_Normal, TAG_DONE);
|
||||
HitCenterFrame = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!HitCenterFrame && (frame != 15 && frame != 0))
|
||||
{
|
||||
screen->DrawTexture (TexMan[picnum+frame], x, y,
|
||||
DTA_HUDRules, HUD_Normal, TAG_DONE);
|
||||
HitCenterFrame = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->DrawTexture (TexMan[picnum+15], x, y,
|
||||
DTA_HUDRules, HUD_Normal, TAG_DONE);
|
||||
HitCenterFrame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Weapon Level 2 (aka Tome of Power) Powerup --------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(APowerWeaponLevel2, false, false)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerWeaponLevel2 :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerWeaponLevel2::InitEffect ()
|
||||
{
|
||||
AWeapon *weapon, *sister;
|
||||
|
||||
Super::InitEffect();
|
||||
|
||||
if (Owner->player == nullptr)
|
||||
return;
|
||||
|
||||
weapon = Owner->player->ReadyWeapon;
|
||||
|
||||
if (weapon == nullptr)
|
||||
return;
|
||||
|
||||
sister = weapon->SisterWeapon;
|
||||
|
||||
if (sister == nullptr)
|
||||
return;
|
||||
|
||||
if (!(sister->WeaponFlags & WIF_POWERED_UP))
|
||||
return;
|
||||
|
||||
assert (sister->SisterWeapon == weapon);
|
||||
|
||||
|
||||
if (weapon->GetReadyState() != sister->GetReadyState())
|
||||
{
|
||||
Owner->player->ReadyWeapon = sister;
|
||||
P_SetPsprite(Owner->player, PSP_WEAPON, sister->GetReadyState());
|
||||
}
|
||||
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(sister);
|
||||
Owner->player->ReadyWeapon = sister;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong. Initiate a regular weapon change.
|
||||
Owner->player->PendingWeapon = sister;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerWeaponLevel2 :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerWeaponLevel2::EndEffect ()
|
||||
{
|
||||
player_t *player = Owner != NULL ? Owner->player : NULL;
|
||||
|
||||
Super::EndEffect();
|
||||
if (player != NULL)
|
||||
{
|
||||
if (player->ReadyWeapon != NULL &&
|
||||
player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP)
|
||||
{
|
||||
player->ReadyWeapon->CallEndPowerup ();
|
||||
}
|
||||
if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE &&
|
||||
player->PendingWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||
player->PendingWeapon->SisterWeapon != NULL)
|
||||
{
|
||||
player->PendingWeapon = player->PendingWeapon->SisterWeapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Speed Powerup -------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(APowerSpeed, false, false)
|
||||
|
|
|
@ -124,30 +124,6 @@ protected:
|
|||
int NewTorch, NewTorchDelta;
|
||||
};
|
||||
|
||||
class APowerFlight : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerFlight, APowerup)
|
||||
public:
|
||||
virtual bool DrawPowerup (int x, int y) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void Tick () override;
|
||||
virtual void EndEffect () override;
|
||||
|
||||
private:
|
||||
bool HitCenterFrame;
|
||||
};
|
||||
|
||||
class APowerWeaponLevel2 : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerWeaponLevel2, APowerup)
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
};
|
||||
|
||||
class APowerSpeed : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerSpeed, APowerup)
|
||||
|
|
|
@ -1279,6 +1279,14 @@ bool AInventory::DrawPowerup (int x, int y)
|
|||
return false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AInventory, DrawPowerup)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AInventory);
|
||||
PARAM_INT(x);
|
||||
PARAM_INT(y);
|
||||
ACTION_RETURN_BOOL(self->DrawPowerup(x, y));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AInventory :: DoRespawn
|
||||
|
|
|
@ -311,7 +311,7 @@ bool AWeapon::Use (bool pickup)
|
|||
// weapon, if one exists.
|
||||
if (SisterWeapon != NULL &&
|
||||
SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||
Owner->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true))
|
||||
Owner->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true))
|
||||
{
|
||||
useweap = SisterWeapon;
|
||||
}
|
||||
|
@ -824,18 +824,6 @@ DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void AWeapon::CallEndPowerup()
|
||||
{
|
||||
IFVIRTUAL(AWeapon, EndPowerup)
|
||||
{
|
||||
// Without the type cast this picks the 'void *' assignment...
|
||||
VMValue params[1] = { (DObject*)this };
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
else EndPowerup();
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: GetUpState
|
||||
|
|
|
@ -161,7 +161,6 @@ public:
|
|||
|
||||
|
||||
virtual void EndPowerup ();
|
||||
void CallEndPowerup();
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -1897,6 +1897,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE
|
|||
DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -58,9 +58,9 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
if ((p->mo->GetClass() == spawntype)
|
||||
&& (p->mo->PlayerFlags & PPF_CANSUPERMORPH)
|
||||
&& (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE))
|
||||
&& (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == nullptr))
|
||||
&& (p->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true) == nullptr))
|
||||
{ // Make a super chicken
|
||||
p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
|
||||
p->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
|||
player->MorphStyle = 0;
|
||||
player->MorphExitFlash = nullptr;
|
||||
player->viewheight = mo->ViewHeight;
|
||||
AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
|
||||
AInventory *level2 = mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true);
|
||||
if (level2 != nullptr)
|
||||
{
|
||||
level2->Destroy ();
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "virtual.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
|
@ -1529,13 +1530,22 @@ void DBaseStatusBar::DrawPowerups ()
|
|||
+ (ST_IsLatencyVisible() ? yshift : 0);
|
||||
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->DrawPowerup (x, y))
|
||||
IFVIRTUALPTR(item, AInventory, DrawPowerup)
|
||||
{
|
||||
x -= POWERUPICONSIZE;
|
||||
if (x < -POWERUPICONSIZE*5)
|
||||
VMValue params[3] = { item, x, y };
|
||||
VMReturn ret;
|
||||
int retv;
|
||||
|
||||
ret.IntAt(&retv);
|
||||
GlobalVMStack.Call(func, params, 3, &ret, 1);
|
||||
if (retv)
|
||||
{
|
||||
x = -20;
|
||||
y += POWERUPICONSIZE*2;
|
||||
x -= POWERUPICONSIZE;
|
||||
if (x < -POWERUPICONSIZE * 5)
|
||||
{
|
||||
x = -20;
|
||||
y += POWERUPICONSIZE * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -767,16 +767,18 @@ void FGLRenderer::SetFixedColormap (player_t *player)
|
|||
}
|
||||
else if (cplayer->fixedlightlevel != -1)
|
||||
{
|
||||
auto torchtype = PClass::FindActor(NAME_PowerTorch);
|
||||
auto litetype = PClass::FindActor(NAME_PowerLightAmp);
|
||||
for(AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
|
||||
{
|
||||
PalEntry color = in->GetBlend ();
|
||||
|
||||
// Need special handling for light amplifiers
|
||||
if (in->IsKindOf(RUNTIME_CLASS(APowerTorch)))
|
||||
if (in->IsKindOf(torchtype))
|
||||
{
|
||||
gl_fixedcolormap = cplayer->fixedlightlevel + CM_TORCH;
|
||||
}
|
||||
else if (in->IsKindOf(RUNTIME_CLASS(APowerLightAmp)))
|
||||
else if (in->IsKindOf(litetype))
|
||||
{
|
||||
gl_fixedcolormap = CM_LITE;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
case CHT_POWER:
|
||||
if (player->mo != NULL && player->health >= 0)
|
||||
{
|
||||
item = player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
|
||||
item = player->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true);
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Destroy ();
|
||||
|
@ -226,7 +226,7 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
}
|
||||
else
|
||||
{
|
||||
player->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
|
||||
player->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
|
||||
msg = GStrings("TXT_CHEATPOWERON");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,15 @@ xx(HealthPickup)
|
|||
xx(autousemode)
|
||||
xx(Ammo)
|
||||
xx(PowerTargeter)
|
||||
xx(PowerInvulnerable)
|
||||
xx(PowerStrength)
|
||||
xx(PowerInvisibility)
|
||||
xx(PowerIronFeet)
|
||||
xx(PowerLightAmp)
|
||||
xx(PowerWeaponLevel2)
|
||||
xx(PowerFlight)
|
||||
xx(PowerSpeed)
|
||||
xx(PowerTorch)
|
||||
|
||||
xx(AcolyteBlue)
|
||||
xx(SpectralLightningV1)
|
||||
|
|
|
@ -476,7 +476,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
|
|||
|
||||
if (source->player->morphTics)
|
||||
{ // Make a super chicken
|
||||
source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
|
||||
source->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
|
||||
}
|
||||
|
||||
if (deathmatch && cl_showsprees)
|
||||
|
|
|
@ -2841,23 +2841,23 @@ FUNC(LS_SetPlayerProperty)
|
|||
// Add or remove a power
|
||||
if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED)
|
||||
{
|
||||
static PClass * const *powers[11] =
|
||||
static ENamedName powers[11] =
|
||||
{
|
||||
&RUNTIME_CLASS_CASTLESS(APowerInvulnerable),
|
||||
&RUNTIME_CLASS_CASTLESS(APowerStrength),
|
||||
&RUNTIME_CLASS_CASTLESS(APowerInvisibility),
|
||||
&RUNTIME_CLASS_CASTLESS(APowerIronFeet),
|
||||
NULL, // MapRevealer
|
||||
&RUNTIME_CLASS_CASTLESS(APowerLightAmp),
|
||||
&RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2),
|
||||
&RUNTIME_CLASS_CASTLESS(APowerFlight),
|
||||
NULL,
|
||||
NULL,
|
||||
&RUNTIME_CLASS_CASTLESS(APowerSpeed)
|
||||
NAME_PowerInvulnerable,
|
||||
NAME_PowerStrength,
|
||||
NAME_PowerInvisibility,
|
||||
NAME_PowerIronFeet,
|
||||
NAME_None,
|
||||
NAME_PowerLightAmp,
|
||||
NAME_PowerWeaponLevel2,
|
||||
NAME_PowerFlight,
|
||||
NAME_None,
|
||||
NAME_None,
|
||||
NAME_PowerSpeed
|
||||
};
|
||||
int power = arg2 - PROP_INVULNERABILITY;
|
||||
|
||||
if (power > 4 && powers[power] == NULL)
|
||||
if (power > 4 && powers[power] == NAME_None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2868,7 +2868,7 @@ FUNC(LS_SetPlayerProperty)
|
|||
{ // Give power to activator
|
||||
if (power != 4)
|
||||
{
|
||||
APowerup *item = static_cast<APowerup*>(it->GiveInventoryType(static_cast<PClassActor *>(*powers[power])));
|
||||
APowerup *item = static_cast<APowerup*>(it->GiveInventoryType(PClass::FindActor(powers[power])));
|
||||
if (item != NULL && power == 0 && arg1 == 1)
|
||||
{
|
||||
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
|
||||
|
@ -2883,7 +2883,7 @@ FUNC(LS_SetPlayerProperty)
|
|||
{ // Take power from activator
|
||||
if (power != 4)
|
||||
{
|
||||
AInventory *item = it->FindInventory(static_cast<PClassActor *>(*powers[power]), true);
|
||||
AInventory *item = it->FindInventory(PClass::FindActor(powers[power]), true);
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Destroy ();
|
||||
|
@ -2908,7 +2908,7 @@ FUNC(LS_SetPlayerProperty)
|
|||
{ // Give power
|
||||
if (power != 4)
|
||||
{
|
||||
APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType (static_cast<PClassActor *>(*powers[power])));
|
||||
APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType ((PClass::FindActor(powers[power]))));
|
||||
if (item != NULL && power == 0 && arg1 == 1)
|
||||
{
|
||||
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
|
||||
|
@ -2923,7 +2923,7 @@ FUNC(LS_SetPlayerProperty)
|
|||
{ // Take power
|
||||
if (power != 4)
|
||||
{
|
||||
AInventory *item = players[i].mo->FindInventory (static_cast<PClassActor *>(*powers[power]));
|
||||
AInventory *item = players[i].mo->FindInventory (PClass::FindActor(powers[power]));
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Destroy ();
|
||||
|
|
|
@ -481,7 +481,7 @@ void P_BringUpWeapon (player_t *player)
|
|||
if (weapon != nullptr &&
|
||||
weapon->SisterWeapon &&
|
||||
weapon->SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||
player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true))
|
||||
player->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true))
|
||||
{
|
||||
weapon = weapon->SisterWeapon;
|
||||
}
|
||||
|
|
|
@ -1673,12 +1673,6 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
|
|||
ACTION_RETURN_INT(self->GetPlaneLight(pos));
|
||||
}
|
||||
|
||||
class FSetTextureID : public FTextureID
|
||||
{
|
||||
public:
|
||||
FSetTextureID(int v) : FTextureID(v) {}
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Sector, SetTexture)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
|
||||
|
|
|
@ -948,7 +948,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
|
|||
int bestOrder = INT_MAX;
|
||||
AInventory *item;
|
||||
AWeapon *weap;
|
||||
bool tomed = NULL != FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
|
||||
bool tomed = NULL != FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true);
|
||||
|
||||
// Find the best weapon the player has.
|
||||
for (item = Inventory; item != NULL; item = item->Inventory)
|
||||
|
|
|
@ -2676,7 +2676,11 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant())
|
||||
if (left->ValueType == TypeTextureID && right->IsInteger())
|
||||
{
|
||||
ValueType = TypeTextureID;
|
||||
}
|
||||
else if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant())
|
||||
{
|
||||
// This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code.
|
||||
ValueType = TypeState;
|
||||
|
@ -2755,6 +2759,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|||
assert(Operator == '+' || Operator == '-');
|
||||
ExpEmit op1 = left->Emit(build);
|
||||
ExpEmit op2 = right->Emit(build);
|
||||
ExpEmit to;
|
||||
if (Operator == '+')
|
||||
{
|
||||
if (op1.RegType == REGT_POINTER)
|
||||
|
@ -2775,7 +2780,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|||
assert(!op1.Konst);
|
||||
op1.Free(build);
|
||||
op2.Free(build);
|
||||
ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (IsVector())
|
||||
{
|
||||
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
||||
|
@ -2798,6 +2803,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|||
assert(ValueType->GetRegType() == REGT_INT);
|
||||
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
||||
build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
||||
if (ValueType == TypeTextureID) goto texcheck;
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
@ -2807,7 +2813,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|||
assert(!op1.Konst || !op2.Konst);
|
||||
op1.Free(build);
|
||||
op2.Free(build);
|
||||
ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (IsVector())
|
||||
{
|
||||
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
||||
|
@ -2825,9 +2831,23 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|||
assert(ValueType->GetRegType() == REGT_INT);
|
||||
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
||||
build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
||||
if (ValueType == TypeTextureID) goto texcheck;
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
texcheck:
|
||||
// Do a bounds check for the texture index. Note that count can change at run time so this needs to read the value from the texture manager.
|
||||
auto * ptr = (FArray*)&TexMan.Textures;
|
||||
auto * countptr = &ptr->Count;
|
||||
ExpEmit bndp(build, REGT_POINTER);
|
||||
ExpEmit bndc(build, REGT_INT);
|
||||
build->Emit(OP_LKP, bndp.RegNum, build->GetConstantAddress(countptr, ATAG_GENERIC));
|
||||
build->Emit(OP_LW, bndc.RegNum, bndp.RegNum, build->GetConstantInt(0));
|
||||
build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum);
|
||||
bndp.Free(build);
|
||||
bndc.Free(build);
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -261,6 +261,15 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF
|
|||
return FTextureID(-1);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_TexMan, CheckForTexture)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(name);
|
||||
PARAM_INT(type);
|
||||
PARAM_INT_DEF(flags);
|
||||
ACTION_RETURN_INT(TexMan.CheckForTexture(name, type, flags).GetIndex());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FTextureManager :: ListTextures
|
||||
|
|
|
@ -339,9 +339,11 @@ public:
|
|||
bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch);
|
||||
};
|
||||
|
||||
class FxAddSub;
|
||||
// Texture manager
|
||||
class FTextureManager
|
||||
{
|
||||
friend class FxAddSub; // needs access to do a bounds check on the texture ID.
|
||||
public:
|
||||
FTextureManager ();
|
||||
~FTextureManager ();
|
||||
|
|
|
@ -130,6 +130,16 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ..
|
|||
DrawTextureParms(img, parms);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Screen, DrawHUDTexture)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(texid);
|
||||
PARAM_FLOAT(x);
|
||||
PARAM_FLOAT(y);
|
||||
screen->DrawTexture(TexMan(FSetTextureID(texid)), x, y, DTA_HUDRules, HUD_Normal, TAG_END);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
|
||||
{
|
||||
#ifndef NO_SWRENDER
|
||||
|
|
|
@ -1,3 +1,42 @@
|
|||
struct TexMan
|
||||
{
|
||||
enum EUseTypes
|
||||
{
|
||||
Type_Any,
|
||||
Type_Wall,
|
||||
Type_Flat,
|
||||
Type_Sprite,
|
||||
Type_WallPatch,
|
||||
Type_Build,
|
||||
Type_SkinSprite,
|
||||
Type_Decal,
|
||||
Type_MiscPatch,
|
||||
Type_FontChar,
|
||||
Type_Override, // For patches between TX_START/TX_END
|
||||
Type_Autopage, // Automap background - used to enable the use of FAutomapTexture
|
||||
Type_SkinGraphic,
|
||||
Type_Null,
|
||||
Type_FirstDefined,
|
||||
};
|
||||
|
||||
enum EFlags
|
||||
{
|
||||
TryAny = 1,
|
||||
Overridable = 2,
|
||||
ReturnFirst = 4,
|
||||
AllowSkins = 8,
|
||||
ShortNameOnly = 16,
|
||||
DontCreate = 32
|
||||
};
|
||||
|
||||
native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny);
|
||||
}
|
||||
|
||||
struct Screen
|
||||
{
|
||||
native static void DrawHUDTexture(TextureID tex, double x, double y);
|
||||
}
|
||||
|
||||
class Object native
|
||||
{
|
||||
native bool bDestroyed;
|
||||
|
@ -143,6 +182,7 @@ struct LevelLocals native
|
|||
native bool polygrind;
|
||||
native bool nomonsters;
|
||||
native bool frozen;
|
||||
native bool infinite_flight;
|
||||
// level_info_t *info cannot be done yet.
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Inventory : Actor native
|
||||
{
|
||||
const BLINKTHRESHOLD = (4*32);
|
||||
|
||||
native Actor Owner; // Who owns this item? NULL if it's still a pickup.
|
||||
native int Amount; // Amount of item this instance has
|
||||
|
@ -37,6 +38,7 @@ class Inventory : Actor native
|
|||
virtual native void PlayPickupSound(Actor user);
|
||||
virtual native void AttachToOwner(Actor user);
|
||||
virtual native void DetachFromOwner();
|
||||
virtual native bool DrawPowerup(int x, int y);
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
|
@ -114,16 +114,146 @@ class PowerLightAmp : Powerup native
|
|||
|
||||
class PowerTorch : PowerLightAmp native {}
|
||||
|
||||
class PowerFlight : Powerup native
|
||||
//===========================================================================
|
||||
//
|
||||
// Flight
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
class PowerFlight : Powerup
|
||||
{
|
||||
Default
|
||||
{
|
||||
Powerup.Duration -60;
|
||||
+INVENTORY.HUBPOWER
|
||||
}
|
||||
|
||||
bool HitCenterFrame;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void InitEffect ()
|
||||
{
|
||||
Super.InitEffect();
|
||||
Owner.bFly = true;
|
||||
Owner.bNoGravity = true;
|
||||
if (Owner.pos.Z <= Owner.floorz)
|
||||
{
|
||||
Owner.Vel.Z = 4;; // thrust the player in the air a bit
|
||||
}
|
||||
if (Owner.Vel.Z <= -35)
|
||||
{ // stop falling scream
|
||||
Owner.A_StopSound (CHAN_VOICE);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: DoEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void Tick ()
|
||||
{
|
||||
// The Wings of Wrath only expire in multiplayer and non-hub games
|
||||
if (!multiplayer && level.infinite_flight)
|
||||
{
|
||||
EffectTics++;
|
||||
}
|
||||
Super.Tick ();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void EndEffect ()
|
||||
{
|
||||
Super.EndEffect();
|
||||
if (Owner == NULL || Owner.player == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(Owner.bFlyCheat))
|
||||
{
|
||||
if (Owner.pos.Z != Owner.floorz)
|
||||
{
|
||||
Owner.player.centering = true;
|
||||
}
|
||||
Owner.bFly = false;
|
||||
Owner.bNoGravity = false;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerFlight :: DrawPowerup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override bool DrawPowerup (int x, int y)
|
||||
{
|
||||
// If this item got a valid icon use that instead of the default spinning wings.
|
||||
if (Icon.isValid())
|
||||
{
|
||||
return Super.DrawPowerup(x, y);
|
||||
}
|
||||
|
||||
if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
|
||||
{
|
||||
TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch);
|
||||
int frame = (level.time/3) & 15;
|
||||
|
||||
if (!picnum.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Owner.bNoGravity)
|
||||
{
|
||||
if (HitCenterFrame && (frame != 15 && frame != 0))
|
||||
{
|
||||
screen.DrawHUDTexture (picnum + 15, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen.DrawHUDTexture (picnum + frame, x, y);
|
||||
HitCenterFrame = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!HitCenterFrame && (frame != 15 && frame != 0))
|
||||
{
|
||||
screen.DrawHUDTexture (picnum + frame, x, y);
|
||||
HitCenterFrame = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
screen.DrawHUDTexture (picnum+15, x, y);
|
||||
HitCenterFrame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class PowerWeaponLevel2 : Powerup native
|
||||
//===========================================================================
|
||||
//
|
||||
// WeaponLevel2
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
class PowerWeaponLevel2 : Powerup
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
@ -131,6 +261,86 @@ class PowerWeaponLevel2 : Powerup native
|
|||
Inventory.Icon "SPINBK0";
|
||||
+INVENTORY.NOTELEPORTFREEZE
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerWeaponLevel2 :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void InitEffect ()
|
||||
{
|
||||
|
||||
Super.InitEffect();
|
||||
|
||||
let player = Owner.player;
|
||||
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
let weap = player.ReadyWeapon;
|
||||
|
||||
if (weap == null)
|
||||
return;
|
||||
|
||||
let sister = weap.SisterWeapon;
|
||||
|
||||
if (sister == null)
|
||||
return;
|
||||
|
||||
if (!sister.bPowered_Up)
|
||||
return;
|
||||
|
||||
let ready = sister.GetReadyState();
|
||||
if (weap.GetReadyState() != ready)
|
||||
{
|
||||
player.ReadyWeapon = sister;
|
||||
player.SetPsprite(PSP_WEAPON, ready);
|
||||
}
|
||||
else
|
||||
{
|
||||
PSprite psp = player.FindPSprite(PSprite.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 = sister;
|
||||
player.ReadyWeapon = sister;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong. Initiate a regular weapon change.
|
||||
player.PendingWeapon = sister;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerWeaponLevel2 :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void EndEffect ()
|
||||
{
|
||||
Super.EndEffect();
|
||||
if (Owner == null) return;
|
||||
let player = Owner.player;
|
||||
if (player != NULL)
|
||||
{
|
||||
if (player.ReadyWeapon != NULL && player.ReadyWeapon.bPowered_Up)
|
||||
{
|
||||
player.ReadyWeapon.EndPowerup ();
|
||||
}
|
||||
if (player.PendingWeapon != NULL && player.PendingWeapon != WP_NOCHANGE &&
|
||||
player.PendingWeapon.bPowered_Up &&
|
||||
player.PendingWeapon.SisterWeapon != NULL)
|
||||
{
|
||||
player.PendingWeapon = player.PendingWeapon.SisterWeapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -139,7 +139,7 @@ class PSprite : Object native
|
|||
};
|
||||
|
||||
native readonly State CurState;
|
||||
native readonly Actor Caller;
|
||||
native Actor Caller;
|
||||
native readonly PSprite Next;
|
||||
native readonly PlayerInfo Owner;
|
||||
native SpriteID Sprite;
|
||||
|
|
Loading…
Reference in a new issue