- scriptified PowerFlight and PowerWeaponLevel2.

This commit is contained in:
Christoph Oelckers 2017-01-15 23:21:38 +01:00
parent 4837e1e770
commit d2d6e5d486
25 changed files with 369 additions and 306 deletions

View file

@ -186,6 +186,13 @@ private:
int texnum; 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 // Screenshot buffer image data types

View file

@ -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 ------------------------------------------------------------- // Speed Powerup -------------------------------------------------------------
IMPLEMENT_CLASS(APowerSpeed, false, false) IMPLEMENT_CLASS(APowerSpeed, false, false)

View file

@ -124,30 +124,6 @@ protected:
int NewTorch, NewTorchDelta; 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 class APowerSpeed : public APowerup
{ {
DECLARE_CLASS (APowerSpeed, APowerup) DECLARE_CLASS (APowerSpeed, APowerup)

View file

@ -1279,6 +1279,14 @@ bool AInventory::DrawPowerup (int x, int y)
return false; 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 // AInventory :: DoRespawn

View file

@ -311,7 +311,7 @@ bool AWeapon::Use (bool pickup)
// weapon, if one exists. // weapon, if one exists.
if (SisterWeapon != NULL && if (SisterWeapon != NULL &&
SisterWeapon->WeaponFlags & WIF_POWERED_UP && SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
Owner->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true)) Owner->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true))
{ {
useweap = SisterWeapon; useweap = SisterWeapon;
} }
@ -824,18 +824,6 @@ DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup)
return 0; 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 // AWeapon :: GetUpState

View file

@ -161,7 +161,6 @@ public:
virtual void EndPowerup (); virtual void EndPowerup ();
void CallEndPowerup();
enum enum
{ {

View file

@ -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, polygrind, LEVEL2_POLYGRIND)
DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS)
DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN) DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN)
DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT)
//========================================================================== //==========================================================================
// //

View file

@ -58,9 +58,9 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
if ((p->mo->GetClass() == spawntype) if ((p->mo->GetClass() == spawntype)
&& (p->mo->PlayerFlags & PPF_CANSUPERMORPH) && (p->mo->PlayerFlags & PPF_CANSUPERMORPH)
&& (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) && (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 { // Make a super chicken
p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); p->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
} }
return false; return false;
} }
@ -263,7 +263,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
player->MorphStyle = 0; player->MorphStyle = 0;
player->MorphExitFlash = nullptr; player->MorphExitFlash = nullptr;
player->viewheight = mo->ViewHeight; player->viewheight = mo->ViewHeight;
AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); AInventory *level2 = mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true);
if (level2 != nullptr) if (level2 != nullptr)
{ {
level2->Destroy (); level2->Destroy ();

View file

@ -56,6 +56,7 @@
#include "r_utility.h" #include "r_utility.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "virtual.h"
#include "../version.h" #include "../version.h"
@ -1529,13 +1530,22 @@ void DBaseStatusBar::DrawPowerups ()
+ (ST_IsLatencyVisible() ? yshift : 0); + (ST_IsLatencyVisible() ? yshift : 0);
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
{ {
if (item->DrawPowerup (x, y)) IFVIRTUALPTR(item, AInventory, DrawPowerup)
{ {
x -= POWERUPICONSIZE; VMValue params[3] = { item, x, y };
if (x < -POWERUPICONSIZE*5) VMReturn ret;
int retv;
ret.IntAt(&retv);
GlobalVMStack.Call(func, params, 3, &ret, 1);
if (retv)
{ {
x = -20; x -= POWERUPICONSIZE;
y += POWERUPICONSIZE*2; if (x < -POWERUPICONSIZE * 5)
{
x = -20;
y += POWERUPICONSIZE * 2;
}
} }
} }
} }

View file

@ -767,16 +767,18 @@ void FGLRenderer::SetFixedColormap (player_t *player)
} }
else if (cplayer->fixedlightlevel != -1) 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) for(AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
{ {
PalEntry color = in->GetBlend (); PalEntry color = in->GetBlend ();
// Need special handling for light amplifiers // Need special handling for light amplifiers
if (in->IsKindOf(RUNTIME_CLASS(APowerTorch))) if (in->IsKindOf(torchtype))
{ {
gl_fixedcolormap = cplayer->fixedlightlevel + CM_TORCH; gl_fixedcolormap = cplayer->fixedlightlevel + CM_TORCH;
} }
else if (in->IsKindOf(RUNTIME_CLASS(APowerLightAmp))) else if (in->IsKindOf(litetype))
{ {
gl_fixedcolormap = CM_LITE; gl_fixedcolormap = CM_LITE;
} }

View file

@ -218,7 +218,7 @@ void cht_DoCheat (player_t *player, int cheat)
case CHT_POWER: case CHT_POWER:
if (player->mo != NULL && player->health >= 0) 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) if (item != NULL)
{ {
item->Destroy (); item->Destroy ();
@ -226,7 +226,7 @@ void cht_DoCheat (player_t *player, int cheat)
} }
else else
{ {
player->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); player->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
msg = GStrings("TXT_CHEATPOWERON"); msg = GStrings("TXT_CHEATPOWERON");
} }
} }

View file

@ -172,6 +172,15 @@ xx(HealthPickup)
xx(autousemode) xx(autousemode)
xx(Ammo) xx(Ammo)
xx(PowerTargeter) xx(PowerTargeter)
xx(PowerInvulnerable)
xx(PowerStrength)
xx(PowerInvisibility)
xx(PowerIronFeet)
xx(PowerLightAmp)
xx(PowerWeaponLevel2)
xx(PowerFlight)
xx(PowerSpeed)
xx(PowerTorch)
xx(AcolyteBlue) xx(AcolyteBlue)
xx(SpectralLightningV1) xx(SpectralLightningV1)

View file

@ -476,7 +476,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
if (source->player->morphTics) if (source->player->morphTics)
{ // Make a super chicken { // Make a super chicken
source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); source->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
} }
if (deathmatch && cl_showsprees) if (deathmatch && cl_showsprees)

View file

@ -2841,23 +2841,23 @@ FUNC(LS_SetPlayerProperty)
// Add or remove a power // Add or remove a power
if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED) if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED)
{ {
static PClass * const *powers[11] = static ENamedName powers[11] =
{ {
&RUNTIME_CLASS_CASTLESS(APowerInvulnerable), NAME_PowerInvulnerable,
&RUNTIME_CLASS_CASTLESS(APowerStrength), NAME_PowerStrength,
&RUNTIME_CLASS_CASTLESS(APowerInvisibility), NAME_PowerInvisibility,
&RUNTIME_CLASS_CASTLESS(APowerIronFeet), NAME_PowerIronFeet,
NULL, // MapRevealer NAME_None,
&RUNTIME_CLASS_CASTLESS(APowerLightAmp), NAME_PowerLightAmp,
&RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), NAME_PowerWeaponLevel2,
&RUNTIME_CLASS_CASTLESS(APowerFlight), NAME_PowerFlight,
NULL, NAME_None,
NULL, NAME_None,
&RUNTIME_CLASS_CASTLESS(APowerSpeed) NAME_PowerSpeed
}; };
int power = arg2 - PROP_INVULNERABILITY; int power = arg2 - PROP_INVULNERABILITY;
if (power > 4 && powers[power] == NULL) if (power > 4 && powers[power] == NAME_None)
{ {
return false; return false;
} }
@ -2868,7 +2868,7 @@ FUNC(LS_SetPlayerProperty)
{ // Give power to activator { // Give power to activator
if (power != 4) 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) if (item != NULL && power == 0 && arg1 == 1)
{ {
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
@ -2883,7 +2883,7 @@ FUNC(LS_SetPlayerProperty)
{ // Take power from activator { // Take power from activator
if (power != 4) 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) if (item != NULL)
{ {
item->Destroy (); item->Destroy ();
@ -2908,7 +2908,7 @@ FUNC(LS_SetPlayerProperty)
{ // Give power { // Give power
if (power != 4) 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) if (item != NULL && power == 0 && arg1 == 1)
{ {
item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
@ -2923,7 +2923,7 @@ FUNC(LS_SetPlayerProperty)
{ // Take power { // Take power
if (power != 4) 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) if (item != NULL)
{ {
item->Destroy (); item->Destroy ();

View file

@ -481,7 +481,7 @@ void P_BringUpWeapon (player_t *player)
if (weapon != nullptr && if (weapon != nullptr &&
weapon->SisterWeapon && weapon->SisterWeapon &&
weapon->SisterWeapon->WeaponFlags & WIF_POWERED_UP && weapon->SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true)) player->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true))
{ {
weapon = weapon->SisterWeapon; weapon = weapon->SisterWeapon;
} }

View file

@ -1673,12 +1673,6 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
ACTION_RETURN_INT(self->GetPlaneLight(pos)); ACTION_RETURN_INT(self->GetPlaneLight(pos));
} }
class FSetTextureID : public FTextureID
{
public:
FSetTextureID(int v) : FTextureID(v) {}
};
DEFINE_ACTION_FUNCTION(_Sector, SetTexture) DEFINE_ACTION_FUNCTION(_Sector, SetTexture)
{ {
PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_SELF_STRUCT_PROLOGUE(sector_t);

View file

@ -948,7 +948,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype)
int bestOrder = INT_MAX; int bestOrder = INT_MAX;
AInventory *item; AInventory *item;
AWeapon *weap; 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. // Find the best weapon the player has.
for (item = Inventory; item != NULL; item = item->Inventory) for (item = Inventory; item != NULL; item = item->Inventory)

View file

@ -2676,7 +2676,11 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
return nullptr; 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. // 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; ValueType = TypeState;
@ -2755,6 +2759,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(Operator == '+' || Operator == '-'); assert(Operator == '+' || Operator == '-');
ExpEmit op1 = left->Emit(build); ExpEmit op1 = left->Emit(build);
ExpEmit op2 = right->Emit(build); ExpEmit op2 = right->Emit(build);
ExpEmit to;
if (Operator == '+') if (Operator == '+')
{ {
if (op1.RegType == REGT_POINTER) if (op1.RegType == REGT_POINTER)
@ -2775,7 +2780,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(!op1.Konst); assert(!op1.Konst);
op1.Free(build); op1.Free(build);
op2.Free(build); op2.Free(build);
ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount());
if (IsVector()) if (IsVector())
{ {
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
@ -2798,6 +2803,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(ValueType->GetRegType() == REGT_INT); assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == 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); build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum);
if (ValueType == TypeTextureID) goto texcheck;
return to; return to;
} }
} }
@ -2807,7 +2813,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(!op1.Konst || !op2.Konst); assert(!op1.Konst || !op2.Konst);
op1.Free(build); op1.Free(build);
op2.Free(build); op2.Free(build);
ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount());
if (IsVector()) if (IsVector())
{ {
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
@ -2825,9 +2831,23 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(ValueType->GetRegType() == REGT_INT); assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == 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); 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; 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;
} }
//========================================================================== //==========================================================================

View file

@ -261,6 +261,15 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF
return FTextureID(-1); 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 // FTextureManager :: ListTextures

View file

@ -339,9 +339,11 @@ public:
bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch); bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch);
}; };
class FxAddSub;
// Texture manager // Texture manager
class FTextureManager class FTextureManager
{ {
friend class FxAddSub; // needs access to do a bounds check on the texture ID.
public: public:
FTextureManager (); FTextureManager ();
~FTextureManager (); ~FTextureManager ();

View file

@ -130,6 +130,16 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, ..
DrawTextureParms(img, parms); 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) void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
{ {
#ifndef NO_SWRENDER #ifndef NO_SWRENDER

View file

@ -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 class Object native
{ {
native bool bDestroyed; native bool bDestroyed;
@ -143,6 +182,7 @@ struct LevelLocals native
native bool polygrind; native bool polygrind;
native bool nomonsters; native bool nomonsters;
native bool frozen; native bool frozen;
native bool infinite_flight;
// level_info_t *info cannot be done yet. // level_info_t *info cannot be done yet.
} }

View file

@ -1,5 +1,6 @@
class Inventory : Actor native class Inventory : Actor native
{ {
const BLINKTHRESHOLD = (4*32);
native Actor Owner; // Who owns this item? NULL if it's still a pickup. native Actor Owner; // Who owns this item? NULL if it's still a pickup.
native int Amount; // Amount of item this instance has 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 PlayPickupSound(Actor user);
virtual native void AttachToOwner(Actor user); virtual native void AttachToOwner(Actor user);
virtual native void DetachFromOwner(); virtual native void DetachFromOwner();
virtual native bool DrawPowerup(int x, int y);
//=========================================================================== //===========================================================================
// //

View file

@ -114,16 +114,146 @@ class PowerLightAmp : Powerup native
class PowerTorch : PowerLightAmp native {} class PowerTorch : PowerLightAmp native {}
class PowerFlight : Powerup native //===========================================================================
//
// Flight
//
//===========================================================================
class PowerFlight : Powerup
{ {
Default Default
{ {
Powerup.Duration -60; Powerup.Duration -60;
+INVENTORY.HUBPOWER +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 Default
{ {
@ -131,6 +261,86 @@ class PowerWeaponLevel2 : Powerup native
Inventory.Icon "SPINBK0"; Inventory.Icon "SPINBK0";
+INVENTORY.NOTELEPORTFREEZE +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;
}
}
}
} }
//=========================================================================== //===========================================================================

View file

@ -139,7 +139,7 @@ class PSprite : Object native
}; };
native readonly State CurState; native readonly State CurState;
native readonly Actor Caller; native Actor Caller;
native readonly PSprite Next; native readonly PSprite Next;
native readonly PlayerInfo Owner; native readonly PlayerInfo Owner;
native SpriteID Sprite; native SpriteID Sprite;