diff --git a/src/actor.h b/src/actor.h index 83873adc50..bbe7381a24 100644 --- a/src/actor.h +++ b/src/actor.h @@ -385,6 +385,7 @@ enum ActorFlag7 MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo. MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. + MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. }; // --- mobj.renderflags --- @@ -636,9 +637,6 @@ public: // Made a metadata property so no longer virtual void Howl (); - // Actor just hit the floor - virtual void HitFloor (); - // plays bouncing sound void PlayBounceSound(bool onfloor); diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index b584be0ea0..cc964ecc05 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -45,349 +45,6 @@ void P_DSparilTeleport (AActor *actor); extern bool P_AutoUseChaosDevice (player_t *player); -// --- Mace ----------------------------------------------------------------- - -#define MAGIC_JUNK 1234 - -// Mace FX4 ----------------------------------------------------------------- - -class AMaceFX4 : public AActor -{ - DECLARE_CLASS (AMaceFX4, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AMaceFX4, false, false, false, false) - -int AMaceFX4::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if ((target->flags2 & MF2_BOSS) || (target->flags3 & MF3_DONTSQUASH) || target->IsTeammate (this->target)) - { // Don't allow cheap boss kills and don't instagib teammates - return damage; - } - else if (target->player) - { // Player specific checks - if (target->player->mo->flags2 & MF2_INVULNERABLE) - { // Can't hurt invulnerable players - return -1; - } - if (P_AutoUseChaosDevice (target->player)) - { // Player was saved using chaos device - return -1; - } - } - return TELEFRAG_DAMAGE; // Something's gonna die -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1B -// -//---------------------------------------------------------------------------- - -void FireMacePL1B (AActor *actor) -{ - AActor *ball; - player_t *player; - - if (NULL == (player = actor->player)) - { - return; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; - } - ball = Spawn("MaceFX2", actor->PosPlusZ(28 - actor->Floorclip), ALLOW_REPLACE); - ball->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - ball->target = actor; - ball->Angles.Yaw = actor->Angles.Yaw; - ball->AddZ(ball->Vel.Z); - ball->VelFromAngle(); - ball->Vel += actor->Vel.XY()/2; - S_Sound (ball, CHAN_BODY, "weapons/maceshoot", 1, ATTN_NORM); - P_CheckMissileSpawn (ball, actor->radius); -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *ball; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - if (pr_maceatk() < 28) - { - FireMacePL1B(self); - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - if (!weapon->DepleteAmmo(weapon->bAltFire)) - return 0; - - player->GetPSprite(PSP_WEAPON)->x = ((pr_maceatk() & 3) - 2); - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_maceatk() & 3); - } - ball = P_SpawnPlayerMissile(self, PClass::FindActor("MaceFX1"), self->Angles.Yaw + (((pr_maceatk() & 7) - 4) * (360. / 256))); - if (ball) - { - ball->special1 = 16; // tics till dropoff - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MacePL1Check -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->special1 == 0) - { - return 0; - } - self->special1 -= 4; - if (self->special1 > 0) - { - return 0; - } - self->special1 = 0; - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1. / 8;; - // [RH] Avoid some precision loss by scaling the velocity directly -#if 0 - // This is the original code, for reference. - a.ngle_t ang = self->ang>>ANGLETOF.INESHIFT; - self->velx = F.ixedMul(7*F.RACUNIT, f.inecosine[ang]); - self->vely = F.ixedMul(7*F.RACUNIT, f.inesine[ang]); -#else - double velscale = 7 / self->Vel.XY().Length(); - self->Vel.X *= velscale; - self->Vel.Y *= velscale; -#endif - self->Vel.Z *= 0.5; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - if ((self->health != MAGIC_JUNK) && (self->flags & MF_INBOUNCE)) - { // Bounce - self->health = MAGIC_JUNK; - self->Vel.Z *= 0.75; - self->BounceFlags = BOUNCE_None; - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macebounce", 1, ATTN_NORM); - } - else - { // Explode - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *tiny; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - self->Vel.Z *= 0.75; - self->SetState (self->SpawnState); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw + 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw - 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->BounceFlags = BOUNCE_None; - self->Gravity = 1; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - AActor *mo; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->Angles.Yaw, &t); - if (mo) - { - mo->Vel += self->Vel.XY(); - mo->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - if (t.linetarget && !t.unlinked) - { - mo->tracer = t.linetarget; - } - } - S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_DeathBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - AActor *target; - DAngle ang = 0.; - bool newAngle; - FTranslatedLineTarget t; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - newAngle = false; - target = self->tracer; - if (target) - { - if (!(target->flags&MF_SHOOTABLE)) - { // Target died - self->tracer = NULL; - } - else - { // Seek - ang = self->AngleTo(target); - newAngle = true; - } - } - else - { // Find new target - ang = 0.; - for (i = 0; i < 16; i++) - { - P_AimLineAttack (self, ang, 640., &t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); - if (t.linetarget && self->target != t.linetarget) - { - self->tracer = t.linetarget; - ang = t.angleFromSource; - newAngle = true; - break; - } - ang += 22.5; - } - } - if (newAngle) - { - self->Angles.Yaw = ang; - self->VelFromAngle(); - } - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macestop", 1, ATTN_NORM); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM); - } - return 0; -} - // Blaster FX 1 ------------------------------------------------------------- diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index 6d441ba57c..0dcdc2c5f4 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -32,21 +32,6 @@ void A_PotteryExplode (AActor *); void A_PotteryChooseBit (AActor *); void A_PotteryCheck (AActor *); -class APottery1 : public AActor -{ - DECLARE_CLASS (APottery1, AActor) -public: - void HitFloor (); -}; - -IMPLEMENT_CLASS(APottery1, false, false, false, false) - -void APottery1::HitFloor () -{ - Super::HitFloor (); - P_DamageMobj (this, NULL, NULL, 25, NAME_None); -} - //============================================================================ // // A_PotteryExplode diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp index 35387df450..b333c9a13e 100644 --- a/src/g_raven/a_artitele.cpp +++ b/src/g_raven/a_artitele.cpp @@ -61,21 +61,3 @@ bool AArtiTeleport::Use (bool pickup) return true; } -//--------------------------------------------------------------------------- -// -// FUNC P_AutoUseChaosDevice -// -//--------------------------------------------------------------------------- - -bool P_AutoUseChaosDevice (player_t *player) -{ - AInventory *arti = player->mo->FindInventory(PClass::FindActor("ArtiTeleport")); - - if (arti != NULL) - { - player->mo->UseInventory (arti); - player->health = player->mo->health = (player->health+1)/2; - return true; - } - return false; -} diff --git a/src/namedef.h b/src/namedef.h index 545bf02604..639c762ebd 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -209,6 +209,7 @@ xx(XDeath) xx(Burn) //xx(Ice) // already defined above xx(Disintegrate) +xx(Smash) // Weapon animator names. xx(Select) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8784dc0753..46ecbd3faf 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -948,6 +948,14 @@ bool AActor::UseInventory (AInventory *item) return true; } +DEFINE_ACTION_FUNCTION(AActor, UseInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(item, AInventory); + self->VMSuperCall(); + ACTION_RETURN_BOOL(self->UseInventory(item)); +} + //=========================================================================== // // AActor :: DropInventory @@ -2741,7 +2749,10 @@ void P_ZMovement (AActor *mo, double oldfloorz) return; } // Let the actor do something special for hitting the floor - mo->HitFloor (); + if (mo->flags7 & MF7_SMASHABLE) + { + P_DamageMobj(mo, nullptr, nullptr, mo->health, NAME_Smash); + } if (mo->player) { if (mo->player->jumpTics < 0 || mo->Vel.Z < minvel) @@ -3230,10 +3241,6 @@ void AActor::Howl () } } -void AActor::HitFloor () -{ -} - bool AActor::Slam (AActor *thing) { flags &= ~MF_SKULLFLY; @@ -5945,6 +5952,12 @@ bool P_HitFloor (AActor *thing) return P_HitWater (thing, m->m_sector, pos); } +DEFINE_ACTION_FUNCTION(AActor, HitFloor) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_HitFloor(self)); +} + //--------------------------------------------------------------------------- // // P_CheckSplash @@ -6543,6 +6556,13 @@ bool AActor::IsTeammate (AActor *other) return false; } +DEFINE_ACTION_FUNCTION(AActor, isTeammate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_BOOL(self->IsTeammate(other)); +} + //========================================================================== // // AActor :: GetSpecies diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index ba4eab9e3b..4bf6f076eb 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2323,7 +2323,7 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it if (!pointer.Target) { - ExpEmit out(build, ValueType->GetRegType()); + ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); if (Assignment->IsBitWrite != -1) { build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index bc6e0ad43a..3d7a9d3e11 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -294,6 +294,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), + DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 2e77716808..6f25318d61 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -217,7 +217,7 @@ begin: reg.atag[a] = ATAG_GENERIC; NEXTOP; OP(LV2): - ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); + ASSERTF(a+1); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { auto v = (double *)ptr; @@ -226,7 +226,7 @@ begin: } NEXTOP; OP(LV2_R): - ASSERTF(a+2); ASSERTA(B); ASSERTD(C); + ASSERTF(a+1); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { auto v = (double *)ptr; @@ -331,7 +331,7 @@ begin: *(void **)ptr = reg.a[B]; NEXTOP; OP(SV2): - ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); + ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); { auto v = (double *)ptr; @@ -340,7 +340,7 @@ begin: } NEXTOP; OP(SV2_R): - ASSERTA(a); ASSERTF(B+2); ASSERTD(C); + ASSERTA(a); ASSERTF(B+1); ASSERTD(C); GETADDR(PA,RC,X_WRITE_NIL); { auto v = (double *)ptr; diff --git a/src/virtual.h b/src/virtual.h index 4e0b3f01b7..26fc694ea1 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -39,6 +39,7 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(Activate) VMEXPORTED_NATIVES_FUNC(Deactivate) VMEXPORTED_NATIVES_FUNC(DoSpecialDamage) + VMEXPORTED_NATIVES_FUNC(UseInventory) VMEXPORTED_NATIVES_END @@ -213,6 +214,26 @@ public: return retval; } } + bool UseInventory(AInventory *item) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + return ExportedNatives::Get()->template UseInventory(this, item); + } + else + { + VINDEX(AActor, UseInventory); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)item }; + VMReturn ret; + VMFrameStack stack; + int retval; + ret.IntAt(&retval); + stack.Call(VFUNC, params, 2, &ret, 1, nullptr); + return !!retval; + } + } }; @@ -245,6 +266,7 @@ VMEXPORT_NATIVES_START(AActor, DThinker) VMEXPORT_NATIVES_FUNC(Activate) VMEXPORT_NATIVES_FUNC(Deactivate) VMEXPORT_NATIVES_FUNC(DoSpecialDamage) + VMEXPORT_NATIVES_FUNC(UseInventory) VMEXPORT_NATIVES_END(AActor) /* diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index d2853ddb98..074bb89681 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -99,6 +99,7 @@ zscript/heretic/weaponstaff.txt zscript/heretic/weaponwand.txt zscript/heretic/weaponcrossbow.txt zscript/heretic/weapongauntlets.txt +zscript/heretic/weaponmace.txt zscript/hexen/baseweapons.txt zscript/hexen/korax.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index f4489f575c..0f0acc3077 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -238,6 +238,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); + virtual native bool UseInventory(Inventory item); native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); @@ -247,6 +248,8 @@ class Actor : Thinker native native double GetBobOffset(double frac = 0); native void ClearCounters(); native bool GiveBody (int num, int max=0); + native bool HitFloor(); + native bool isTeammate(Actor other); native void RestoreDamage(); native int SpawnHealth(); diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt index a6faf958f2..07f993efe1 100644 --- a/wadsrc/static/zscript/heretic/hereticweaps.txt +++ b/wadsrc/static/zscript/heretic/hereticweaps.txt @@ -7,210 +7,6 @@ class HereticWeapon : Weapon } } - - -// The mace itself ---------------------------------------------------------- - -class Mace : HereticWeapon -{ - Default - { - Weapon.SelectionOrder 1400; - Weapon.AmmoUse 1; - Weapon.AmmoGive1 50; - Weapon.YAdjust 15; - Weapon.AmmoType "MaceAmmo"; - Weapon.SisterWeapon "MacePowered"; - Inventory.PickupMessage "$TXT_WPNMACE"; - Tag "$TAG_MACE"; - } - - action native void A_FireMacePL1(); - - States - { - Spawn: - WMCE A -1; - Stop; - Ready: - MACE A 1 A_WeaponReady; - Loop; - Deselect: - MACE A 1 A_Lower; - Loop; - Select: - MACE A 1 A_Raise; - Loop; - Fire: - MACE B 4; - Hold: - MACE CDEF 3 A_FireMacePL1; - MACE C 4 A_ReFire; - MACE DEFB 4; - Goto Ready; - } -} - -class MacePowered : Mace -{ - Default - { - +WEAPON.POWERED_UP - Weapon.AmmoUse 5; - Weapon.AmmoGive 0; - Weapon.SisterWeapon "Mace"; - Tag "$TAG_MACEP"; - } - - action native void A_FireMacePL2(); - - States - { - Fire: - Hold: - MACE B 4; - MACE D 4 A_FireMacePL2; - MACE B 4; - MACE A 8 A_ReFire; - Goto Ready; - } -} - -// Mace FX1 ----------------------------------------------------------------- - -class MaceFX1 : Actor -{ - Default - { - Radius 8; - Height 6; - Speed 20; - Damage 2; - Projectile; - +THRUGHOST - BounceType "HereticCompat"; - SeeSound "weapons/maceshoot"; - Obituary "$OB_MPMACE"; - } - - native void A_MacePL1Check(); - native void A_MaceBallImpact(); - - States - { - Spawn: - FX02 AB 4 A_MacePL1Check; - Loop; - Death: - FX02 F 4 BRIGHT A_MaceBallImpact; - FX02 GHIJ 4 BRIGHT; - Stop; - } -} - -// Mace FX2 ----------------------------------------------------------------- - -class MaceFX2 : MaceFX1 -{ - Default - { - Speed 10; - Damage 6; - Gravity 0.125; - -NOGRAVITY - SeeSound ""; - } - - native void A_MaceBallImpact2(); - - States - { - Spawn: - FX02 CD 4; - Loop; - Death: - FX02 F 4 A_MaceBallImpact2; - goto Super::Death+1; - } -} - -// Mace FX3 ----------------------------------------------------------------- - -class MaceFX3 : MaceFX1 -{ - Default - { - Speed 7; - Damage 4; - -NOGRAVITY; - Gravity 0.125; - } - - States - { - Spawn: - FX02 AB 4; - Loop; - } -} - - -// Mace FX4 ----------------------------------------------------------------- - -class MaceFX4 : Actor native -{ - Default - { - Radius 8; - Height 6; - Speed 7; - Damage 18; - Gravity 0.125; - Projectile; - -NOGRAVITY - +TELESTOMP - +THRUGHOST - -NOTELEPORT - BounceType "HereticCompat"; - SeeSound ""; - Obituary "$OB_MPPMACE"; - } - - native void A_DeathBallImpact(); - - States - { - Spawn: - FX02 E 99; - Loop; - Death: - FX02 C 4 A_DeathBallImpact; - FX02 GHIJ 4 BRIGHT; - Stop; - } -} - - -// Mace spawn spot ---------------------------------------------------------- - -class MaceSpawner : SpecialSpot -{ - Default - { - +NOSECTOR - +NOBLOCKMAP - } - - States - { - Spawn: - TNT1 A 1; - TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0); - Stop; - } -} - - // Blaster ------------------------------------------------------------------ class Blaster : HereticWeapon diff --git a/wadsrc/static/zscript/heretic/weaponmace.txt b/wadsrc/static/zscript/heretic/weaponmace.txt new file mode 100644 index 0000000000..fd11e685fd --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponmace.txt @@ -0,0 +1,468 @@ +// The mace itself ---------------------------------------------------------- + +class Mace : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 1400; + Weapon.AmmoUse 1; + Weapon.AmmoGive1 50; + Weapon.YAdjust 15; + Weapon.AmmoType "MaceAmmo"; + Weapon.SisterWeapon "MacePowered"; + Inventory.PickupMessage "$TXT_WPNMACE"; + Tag "$TAG_MACE"; + } + + States + { + Spawn: + WMCE A -1; + Stop; + Ready: + MACE A 1 A_WeaponReady; + Loop; + Deselect: + MACE A 1 A_Lower; + Loop; + Select: + MACE A 1 A_Raise; + Loop; + Fire: + MACE B 4; + Hold: + MACE CDEF 3 A_FireMacePL1; + MACE C 4 A_ReFire; + MACE DEFB 4; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL1 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + if (random[MaceAtk]() < 28) + { + Actor ball = Spawn("MaceFX2", Pos + (0, 0, 28 - Floorclip), ALLOW_REPLACE); + ball.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + ball.target = self; + ball.angle = self.angle; + ball.AddZ(ball.Vel.Z); + ball.VelFromAngle(); + ball.Vel += Vel.xy / 2; + ball.A_PlaySound ("weapons/maceshoot", CHAN_BODY); + ball.CheckMissileSpawn (radius); + } + else + { + player.GetPSprite(PSP_WEAPON).x = ((random[MaceAtk]() & 3) - 2); + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP + (random[MaceAtk]() & 3); + Actor ball = SpawnPlayerMissile("MaceFX1", angle + (((random[MaceAtk]() & 7) - 4) * (360. / 256))); + if (ball) + { + ball.special1 = 16; // tics till dropoff + } + } + } +} + +class MacePowered : Mace +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse 5; + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Mace"; + Tag "$TAG_MACEP"; + } + + States + { + Fire: + Hold: + MACE B 4; + MACE D 4 A_FireMacePL2; + MACE B 4; + MACE A 8 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL2 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("MaceFX4", angle, pLineTarget:t); + if (mo) + { + mo.Vel.xy += Vel.xy; + mo.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + if (t.linetarget && !t.unlinked) + { + mo.tracer = t.linetarget; + } + } + A_PlaySound ("weapons/maceshoot", CHAN_WEAPON); + } +} + +// Mace FX1 ----------------------------------------------------------------- + +class MaceFX1 : Actor +{ + const MAGIC_JUNK = 1234; + + Default + { + Radius 8; + Height 6; + Speed 20; + Damage 2; + Projectile; + +THRUGHOST + BounceType "HereticCompat"; + SeeSound "weapons/maceshoot"; + Obituary "$OB_MPMACE"; + } + + States + { + Spawn: + FX02 AB 4 A_MacePL1Check; + Loop; + Death: + FX02 F 4 BRIGHT A_MaceBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MacePL1Check + // + //---------------------------------------------------------------------------- + + void A_MacePL1Check() + { + if (special1 == 0) return; + special1 -= 4; + if (special1 > 0) return; + special1 = 0; + bNoGravity = false; + Gravity = 1. / 8; + // [RH] Avoid some precision loss by scaling the velocity directly + double velscale = 7 / Vel.XY.Length(); + Vel.XY *= velscale; + Vel.Z *= 0.5; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact() + { + if ((health != MAGIC_JUNK) && bInFloat) + { // Bounce + health = MAGIC_JUNK; + Vel.Z *= 0.75; + bBounceOnFloors = bBounceOnCeilings = false; + SetState (SpawnState); + A_PlaySound ("weapons/macebounce", CHAN_BODY); + } + else + { // Explode + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/macehit", CHAN_BODY); + } + } +} + +// Mace FX2 ----------------------------------------------------------------- + +class MaceFX2 : MaceFX1 +{ + Default + { + Speed 10; + Damage 6; + Gravity 0.125; + -NOGRAVITY + SeeSound ""; + } + + States + { + Spawn: + FX02 CD 4; + Loop; + Death: + FX02 F 4 A_MaceBallImpact2; + goto Super::Death+1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact2 + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact2() + { + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + Vel.Z *= 0.75; + SetState (SpawnState); + + Actor tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle + 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + + tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle - 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + bBounceOnFloors = bBounceOnCeilings = false; + Gravity = 1; + } +} + +// Mace FX3 ----------------------------------------------------------------- + +class MaceFX3 : MaceFX1 +{ + Default + { + Speed 7; + Damage 4; + -NOGRAVITY; + Gravity 0.125; + } + + States + { + Spawn: + FX02 AB 4; + Loop; + } +} + + +// Mace FX4 ----------------------------------------------------------------- + +class MaceFX4 : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 7; + Damage 18; + Gravity 0.125; + Projectile; + -NOGRAVITY + +TELESTOMP + +THRUGHOST + -NOTELEPORT + BounceType "HereticCompat"; + SeeSound ""; + Obituary "$OB_MPPMACE"; + } + + States + { + Spawn: + FX02 E 99; + Loop; + Death: + FX02 C 4 A_DeathBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //--------------------------------------------------------------------------- + // + // FUNC P_AutoUseChaosDevice + // + //--------------------------------------------------------------------------- + + private bool AutoUseChaosDevice (PlayerInfo player) + { + Inventory arti = player.mo.FindInventory("ArtiTeleport"); + + if (arti != null) + { + player.mo.UseInventory (arti); + player.health = player.mo.health = (player.health+1)/2; + return true; + } + return false; + } + + //---------------------------------------------------------------------------- + // + // PROC DoSpecialDamage + // + //---------------------------------------------------------------------------- + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bBoss || target.bDontSquash || target.IsTeammate (self.target)) + { // Don't allow cheap boss kills and don't instagib teammates + return damage; + } + else if (target.player) + { // Player specific checks + if (target.player.mo.bInvulnerable) + { // Can't hurt invulnerable players + return -1; + } + if (AutoUseChaosDevice (target.player)) + { // Player was saved using chaos device + return -1; + } + } + return TELEFRAG_DAMAGE; // Something's gonna die + } + + //---------------------------------------------------------------------------- + // + // PROC A_DeathBallImpact + // + //---------------------------------------------------------------------------- + + void A_DeathBallImpact() + { + FTranslatedLineTarget t; + + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + bool newAngle = false; + double ang = 0; + if (tracer) + { + if (!tracer.bShootable) + { // Target died + tracer = null; + } + else + { // Seek + ang = AngleTo(tracer); + newAngle = true; + } + } + else + { // Find new target + ang = 0.; + for (int i = 0; i < 16; i++) + { + AimLineAttack (ang, 640., t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, null, target); + if (t.linetarget && target != t.linetarget) + { + tracer = t.linetarget; + ang = t.angleFromSource; + newAngle = true; + break; + } + ang += 22.5; + } + } + if (newAngle) + { + angle = ang; + VelFromAngle(); + } + SetState (SpawnState); + A_PlaySound ("weapons/macestop", CHAN_BODY); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/maceexplode", CHAN_BODY); + } +} + + +// Mace spawn spot ---------------------------------------------------------- + +class MaceSpawner : SpecialSpot +{ + Default + { + +NOSECTOR + +NOBLOCKMAP + } + + States + { + Spawn: + TNT1 A 1; + TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0); + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt index 30ae0fff14..558ef8395c 100644 --- a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt +++ b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt @@ -83,14 +83,14 @@ class TreeDestructible : Actor // Pottery1 ------------------------------------------------------------------ -class Pottery1 : Actor native +class Pottery1 : Actor { Default { Health 15; Speed 10; Height 32; - +SOLID +SHOOTABLE +NOBLOOD +DROPOFF + +SOLID +SHOOTABLE +NOBLOOD +DROPOFF +SMASHABLE +SLIDESONWALLS +PUSHABLE +TELESTOMP +CANPASS +NOICEDEATH }