From bb25c5faaaccdfa029d56b08127e0bae3732ab85 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Nov 2016 12:27:26 +0100 Subject: [PATCH] - scriptified the remaining Doom weapon code. - implemented method calls from struct instances. - optimized disassembly of VM call instructions to print the function's name at the end where it is more visible and does not need to be truncated. Also use the printable name for script functions here. --- src/g_doom/a_doommisc.cpp | 1 - src/g_doom/a_doomweaps.cpp | 251 -------------------- src/p_map.cpp | 11 + src/scripting/codegeneration/codegen.cpp | 54 +++-- src/scripting/vm/vmdisasm.cpp | 9 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/constants.txt | 2 + wadsrc/static/zscript/doom/doomweapons.txt | 139 ++++------- wadsrc/static/zscript/doom/weaponbfg.txt | 259 +++++++++++++++++++++ wadsrc/static/zscript/shared/inventory.txt | 7 - 11 files changed, 359 insertions(+), 376 deletions(-) delete mode 100644 src/g_doom/a_doomweaps.cpp create mode 100644 wadsrc/static/zscript/doom/weaponbfg.txt diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 467297761..ca13ac7ee 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -20,7 +20,6 @@ #include "g_shared/a_pickups.h" // Include all the other Doom stuff here to reduce compile time -#include "a_doomweaps.cpp" #include "a_painelemental.cpp" #include "a_scriptedmarine.cpp" diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp deleted file mode 100644 index 067a106be..000000000 --- a/src/g_doom/a_doomweaps.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_pickups.h" -#include "d_player.h" -#include "p_pspr.h" -#include "p_local.h" -#include "gstrings.h" -#include "p_effect.h" -#include "gi.h" -#include "templates.h" -#include "vm.h" -#include "doomstat.h" -*/ - -void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); -static FRandom pr_firerail ("FireRail"); -static FRandom pr_bfgspray ("BFGSpray"); -static FRandom pr_oldbfg ("OldBFG"); - - -// -// [RH] A_FireRailgun -// -static void FireRailgun(AActor *self, int offset_xy, bool fromweapon) -{ - int damage; - player_t *player; - - if (NULL == (player = self->player)) - { - return; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && fromweapon) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return; - - FState *flash = weapon->FindState(NAME_Flash); - if (flash != NULL) - { - P_SetSafeFlash(weapon, player, flash, (pr_firerail()&1)); - } - } - - damage = deathmatch ? 100 : 150; - - FRailParams p; - p.source = self; - p.damage = damage; - p.offset_xy = offset_xy; - P_RailAttack (&p); -} - - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, 0, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, 10, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft) -{ - PARAM_ACTION_PROLOGUE(AActor); - FireRailgun(self, -10, ACTION_CALL_FROM_PSPRITE()); - return 0; -} - -// -// A_FireBFG -// - -DEFINE_ACTION_FUNCTION(AActor, A_FireBFG) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells)) - return 0; - } - - P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindActor("BFGBall"), self->Angles.Yaw, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG)); - return 0; -} - - -// -// A_BFGSpray -// Spawn a BFG explosion on every monster in view -// -enum BFG_Flags -{ - BFGF_HURTSOURCE = 1, - BFGF_MISSILEORIGIN = 2, -}; - -DEFINE_ACTION_FUNCTION(AActor, A_BFGSpray) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_DEF (spraytype, AActor) - PARAM_INT_DEF (numrays) - PARAM_INT_DEF (damagecnt) - PARAM_ANGLE_DEF (angle) - PARAM_FLOAT_DEF (distance) - PARAM_ANGLE_DEF (vrange) - PARAM_INT_DEF (defdamage) - PARAM_INT_DEF (flags) - - int i; - int j; - int damage; - DAngle an; - FTranslatedLineTarget t; - AActor *originator; - - if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra"); - if (numrays <= 0) numrays = 40; - if (damagecnt <= 0) damagecnt = 15; - if (angle == 0) angle = 90.; - if (distance <= 0) distance = 16 * 64; - if (vrange == 0) vrange = 32.; - - // [RH] Don't crash if no target - if (!self->target) - return 0; - - // [XA] Set the originator of the rays to the projectile (self) if - // the new flag is set, else set it to the player (self->target) - originator = (flags & BFGF_MISSILEORIGIN) ? self : (AActor *)(self->target); - - // offset angles from its attack angle - for (i = 0; i < numrays; i++) - { - an = self->Angles.Yaw - angle / 2 + angle / numrays*i; - - P_AimLineAttack(originator, an, distance, &t, vrange); - - if (t.linetarget != NULL) - { - AActor *spray = Spawn(spraytype, t.linetarget->PosPlusZ(t.linetarget->Height / 4), ALLOW_REPLACE); - - int dmgFlags = 0; - FName dmgType = NAME_BFGSplash; - - if (spray != NULL) - { - if ((spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies()) || - (!(flags & BFGF_HURTSOURCE) && self->target == t.linetarget)) // [XA] Don't hit oneself unless we say so. - { - spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. - continue; - } - if (spray->flags5 & MF5_PUFFGETSOWNER) spray->target = self->target; - if (spray->flags3 & MF3_FOILINVUL) dmgFlags |= DMG_FOILINVUL; - if (spray->flags7 & MF7_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA; - dmgType = spray->DamageType; - } - - if (defdamage == 0) - { - damage = 0; - for (j = 0; j < damagecnt; ++j) - damage += (pr_bfgspray() & 7) + 1; - } - else - { - // if this is used, damagecnt will be ignored - damage = defdamage; - } - - int newdam = P_DamageMobj(t.linetarget, originator, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource.Degrees); - P_TraceBleed(newdam > 0 ? newdam : damage, &t, self); - } - } - return 0; -} - -// -// A_FireOldBFG -// -// This function emulates Doom's Pre-Beta BFG -// By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 -// -// This code may not be used in other mods without appropriate credit given. -// Code leeches will be telefragged. - -DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG) -{ - PARAM_ACTION_PROLOGUE(AActor); - PClassActor *plasma[] = { PClass::FindActor("PlasmaBall1"), PClass::FindActor("PlasmaBall2") }; - AActor * mo = NULL; - - player_t *player; - bool doesautoaim = false; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = self->player->ReadyWeapon; - if (!ACTION_CALL_FROM_PSPRITE()) weapon = NULL; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - doesautoaim = !(weapon->WeaponFlags & WIF_NOAUTOAIM); - weapon->WeaponFlags |= WIF_NOAUTOAIM; // No autoaiming that gun - } - self->player->extralight = 2; - - // Save values temporarily - DAngle SavedPlayerAngle = self->Angles.Yaw; - DAngle SavedPlayerPitch = self->Angles.Pitch; - for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence - { - self->Angles.Yaw += ((pr_oldbfg()&127) - 64) * (90./768); - self->Angles.Pitch += ((pr_oldbfg()&127) - 64) * (90./640); - mo = P_SpawnPlayerMissile (self, plasma[i]); - // Restore saved values - self->Angles.Yaw = SavedPlayerAngle; - self->Angles.Pitch = SavedPlayerPitch; - } - if (doesautoaim && weapon != NULL) - { // Restore autoaim setting - weapon->WeaponFlags &= ~WIF_NOAUTOAIM; - } - return 0; -} diff --git a/src/p_map.cpp b/src/p_map.cpp index 26dc3d473..eedd503d8 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4660,6 +4660,17 @@ void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff) P_TraceBleed(damage, t->linetarget->PosPlusZ(t->linetarget->Height/2), t->linetarget, t->angleFromSource, pitch); } +DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget); + PARAM_INT(damage); + PARAM_OBJECT(missile, AActor); + + P_TraceBleed(damage, self, missile); + return 0; +} + + //========================================================================== // // diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 56ee12eaf..6dac05d7b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -6878,6 +6878,22 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } } + else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + bool writable; + if (Self->RequestAddress(ctx, &writable) && writable) + { + cls = static_cast(Self->ValueType); + Self->ValueType = NewPointer(Self->ValueType); + } + else + { + // Cannot be made writable so we cannot use its methods. + ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); + delete this; + return nullptr; + } + } else { ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); @@ -7250,18 +7266,22 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { bool writable; ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. - ArgList[i]->RequestAddress(ctx, &writable); - ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); - // For a reference argument the types must match 100%. - if (type != ArgList[i]->ValueType) + if (ArgList[i]->ValueType != TypeNullPtr) { - ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); - x = nullptr; - } - else - { - x = ArgList[i]; + ArgList[i]->RequestAddress(ctx, &writable); + ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); + // For a reference argument the types must match 100%. + if (type != ArgList[i]->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); + x = nullptr; + } + else + { + x = ArgList[i]; + } } + else x = ArgList[i]; } failed |= (x == nullptr); ArgList[i] = x; @@ -7305,13 +7325,6 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = TypeVoid; } - // If self is a struct, it will be a value type, not a reference, so we need to make an addresss request. - if (Self != nullptr && Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool writable; - Self->RequestAddress(ctx, &writable); - } - return this; } @@ -8852,6 +8865,13 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) return this; } } + else if (basex->ValueType == TypeString || basex->ValueType == TypeName) + { + FxExpression *x = new FxClassTypeCast(to, basex); + basex = nullptr; + delete this; + return x->Resolve(ctx); + } // Everything else is an error. ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName()); delete this; diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 07d6fb8e3..031f3328b 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -323,15 +323,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case OP_CALL_K: case OP_TAIL_K: + { callfunc = (VMFunction *)func->KonstA[code[i].a].o; - callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; - col = printf_wrapper(out, "%.23s,%d", callname, code[i].b); + col = printf_wrapper(out, "[%p],%d", callfunc, code[i].b); if (code[i].op == OP_CALL_K) { col += printf_wrapper(out, ",%d", code[i].c); } break; - + } case OP_RET: if (code[i].b != REGT_NIL) { @@ -494,7 +494,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { - printf_wrapper(out, " [%p]\n", callfunc); + callname = callfunc->IsKindOf(RUNTIME_CLASS(VMScriptFunction)) ? static_cast(callfunc)->PrintableName : callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; + printf_wrapper(out, " [%s]\n", callname); } else { diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 192089d85..fdf057b58 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -56,6 +56,7 @@ zscript/doom/weaponchaingun.txt zscript/doom/weaponchainsaw.txt zscript/doom/weaponrlaunch.txt zscript/doom/weaponplasma.txt +zscript/doom/weaponbfg.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2288b6c1b..7f088154f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -364,7 +364,6 @@ class Actor : Thinker native // End of MBF redundant functions. native void A_MonsterRail(); - native void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float angle = 90, float distance = 16*64, float vrange = 32, int damage = 0, int flags = 0); native void A_Pain(); native void A_NoBlocking(bool drop = true); void A_Fall() { A_NoBlocking(); } diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index cfdc98425..29c60450c 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -840,6 +840,8 @@ struct FTranslatedLineTarget Actor linetarget; double angleFromSource; bool unlinked; // found by a trace that went through an unlinked portal. + + native void TraceBleed(int damage, Actor missile); } enum EAimFlags diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 7f8d7478f..75f856218 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -1,6 +1,6 @@ // -------------------------------------------------------------------------- // -// Doom weapon base class +// Doom weap base class // // -------------------------------------------------------------------------- @@ -13,102 +13,51 @@ class DoomWeapon : Weapon } -// -------------------------------------------------------------------------- -// -// BFG 9000 -// -// -------------------------------------------------------------------------- -class BFG9000 : DoomWeapon +extend class StateProvider { - Default - { - Height 20; - Weapon.SelectionOrder 2800; - Weapon.AmmoUse 40; - Weapon.AmmoGive 40; - Weapon.AmmoType "Cell"; - +WEAPON.NOAUTOFIRE; - Inventory.PickupMessage "$GOTBFG9000"; - Tag "$TAG_BFG9000"; - } - States - { - Ready: - BFGG A 1 A_WeaponReady; - Loop; - Deselect: - BFGG A 1 A_Lower; - Loop; - Select: - BFGG A 1 A_Raise; - Loop; - Fire: - BFGG A 20 A_BFGsound; - BFGG B 10 A_GunFlash; - BFGG B 10 A_FireBFG; - BFGG B 20 A_ReFire; - Goto Ready; - Flash: - BFGF A 11 Bright A_Light1; - BFGF B 6 Bright A_Light2; - Goto LightDone; - Spawn: - BFUG A -1; - Stop; - OldFire: - BFGG A 10 A_BFGsound; - BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; - BFGG B 0 A_Light0; - BFGG B 20 A_ReFire; - Goto Ready; - } -} + // + // [RH] A_FireRailgun + // + action void A_FireRailgun(int offset_xy = 0) + { + if (player == null) + { + return; + } -class BFGBall : Actor -{ - Default - { - Radius 13; - Height 8; - Speed 25; - Damage 100; - Projectile; - +RANDOMIZE - RenderStyle "Add"; - Alpha 0.75; - DeathSound "weapons/bfgx"; - Obituary "$OB_MPBFG_BOOM"; - } - States - { - Spawn: - BFS1 AB 4 Bright; - Loop; - Death: - BFE1 AB 8 Bright; - BFE1 C 8 Bright A_BFGSpray; - BFE1 DEF 8 Bright; - Stop; - } -} - -class BFGExtra : Actor -{ - Default - { - +NOBLOCKMAP - +NOGRAVITY - RenderStyle "Add"; - Alpha 0.75; - DamageType "BFGSplash"; - } - States - { - Spawn: - BFE2 ABCD 8 Bright; - Stop; - } -} + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + State flash = weap.FindState('Flash'); + if (flash != null) + { + player.SetSafeFlash(weap, flash, random[FireRail]()&1); + } + + } + int damage = GetCVar("deathmatch") ? 100 : 150; + A_RailAttack(damage, offset_xy, false); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. + } + + action void A_FireRailgunLeft() + { + A_FireRailgun(-10); + } + + action void A_FireRailgunRight() + { + A_FireRailgun(10); + } + + action void A_RailWait() + { + // only here to satisfy old Dehacked patches. + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt new file mode 100644 index 000000000..27f318daf --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -0,0 +1,259 @@ +// -------------------------------------------------------------------------- +// +// BFG 9000 +// +// -------------------------------------------------------------------------- + +class BFG9000 : DoomWeapon +{ + Default + { + Height 20; + Weapon.SelectionOrder 2800; + Weapon.AmmoUse 40; + Weapon.AmmoGive 40; + Weapon.AmmoType "Cell"; + +WEAPON.NOAUTOFIRE; + Inventory.PickupMessage "$GOTBFG9000"; + Tag "$TAG_BFG9000"; + } + States + { + Ready: + BFGG A 1 A_WeaponReady; + Loop; + Deselect: + BFGG A 1 A_Lower; + Loop; + Select: + BFGG A 1 A_Raise; + Loop; + Fire: + BFGG A 20 A_BFGsound; + BFGG B 10 A_GunFlash; + BFGG B 10 A_FireBFG; + BFGG B 20 A_ReFire; + Goto Ready; + Flash: + BFGF A 11 Bright A_Light1; + BFGF B 6 Bright A_Light2; + Goto LightDone; + Spawn: + BFUG A -1; + Stop; + OldFire: + BFGG A 10 A_BFGsound; + BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; + BFGG B 0 A_Light0; + BFGG B 20 A_ReFire; + Goto Ready; + } +} + +//=========================================================================== +// +// Weapon code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_BFGsound() + { + A_PlaySound("weapons/bfgf", CHAN_WEAPON); + } + + + // + // A_FireBFG + // + + action void A_FireBFG() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + SpawnPlayerMissile("BFGBall", angle, 0, 0, 0, null, false, GetCVar("sv_nobfgaim")); + } + + + // + // A_FireOldBFG + // + // This function emulates Doom's Pre-Beta BFG + // By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 + // + // This code may not be used in other mods without appropriate credit given. + // Code leeches will be telefragged. + + action void A_FireOldBFG() + { + bool doesautoaim = false; + + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + + if (invoker != weap || stateinfo == null || stateinfo.mStateType != STATE_Psprite) weap = null; + if (weap != null) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + doesautoaim = weap.bNoAutoaim; + weap.bNoAutoaim = true; + } + player.extralight = 2; + + // Save values temporarily + double SavedPlayerAngle = angle; + double SavedPlayerPitch = pitch; + for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence + { + angle += ((random[OldBFG]() & 127) - 64) * (90./768); + pitch += ((random[OldBFG]() & 127) - 64) * (90./640); + SpawnPlayerMissile (i == 0? (class)("PlasmaBall1") : (class)("PlasmaBall2")); + // Restore saved values + angle = SavedPlayerAngle; + pitch = SavedPlayerPitch; + } + // Restore autoaim setting + if (weap != null) weap.bNoAutoaim = doesautoaim; + } +} + +class BFGBall : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 100; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + DeathSound "weapons/bfgx"; + Obituary "$OB_MPBFG_BOOM"; + } + States + { + Spawn: + BFS1 AB 4 Bright; + Loop; + Death: + BFE1 AB 8 Bright; + BFE1 C 8 Bright A_BFGSpray; + BFE1 DEF 8 Bright; + Stop; + } +} + +class BFGExtra : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Add"; + Alpha 0.75; + DamageType "BFGSplash"; + } + States + { + Spawn: + BFE2 ABCD 8 Bright; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + // + // A_BFGSpray + // Spawn a BFG explosion on every monster in view + // + void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0) + { + int damage; + FTranslatedLineTarget t; + + // validate parameters + if (spraytype == null) spraytype = "BFGExtra"; + if (numrays <= 0) numrays = 40; + if (damagecnt <= 0) damagecnt = 15; + if (ang == 0) ang = 90.; + if (distance <= 0) distance = 16 * 64; + if (vrange == 0) vrange = 32.; + + // [RH] Don't crash if no target + if (!target) return; + + // [XA] Set the originator of the rays to the projectile (self) if + // the new flag is set, else set it to the player (target) + Actor originator = (flags & BFGF_MISSILEORIGIN) ? self : target; + + // offset angles from its attack ang + for (int i = 0; i < numrays; i++) + { + double an = angle - ang / 2 + ang / numrays*i; + + originator.AimLineAttack(an, distance, t, vrange); + + if (t.linetarget != null) + { + Actor spray = Spawn(spraytype, t.linetarget.pos + (0, 0, t.linetarget.Height / 4), ALLOW_REPLACE); + + int dmgFlags = 0; + Name dmgType = 'BFGSplash'; + + if (spray != null) + { + if ((spray.bMThruSpecies && target.GetSpecies() == t.linetarget.GetSpecies()) || + (!(flags & BFGF_HURTSOURCE) && target == t.linetarget)) // [XA] Don't hit oneself unless we say so. + { + spray.Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. + continue; + } + if (spray.bPuffGetsOwner) spray.target = target; + if (spray.bFoilInvul) dmgFlags |= DMG_FOILINVUL; + if (spray.bFoilBuddha) dmgFlags |= DMG_FOILBUDDHA; + dmgType = spray.DamageType; + } + + if (defdamage == 0) + { + damage = 0; + for (int j = 0; j < damagecnt; ++j) + damage += Random[BFGSpray](1, 8); + } + else + { + // if this is used, damagecnt will be ignored + damage = defdamage; + } + + int newdam = t.linetarget.DamageMobj(originator, target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource); + t.TraceBleed(newdam > 0 ? newdam : damage, self); + } + } + } +} diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index 270d5e6d7..d5734e149 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -51,13 +51,6 @@ class StateProvider : Inventory native action native void A_Lower(); action native void A_Raise(); - action native void A_FireRailgun(); - action native void A_FireRailgunLeft(); - action native void A_FireRailgunRight(); - action void A_RailWait() {} - action void A_BFGsound() { A_PlaySound("weapons/bfgf", CHAN_WEAPON); } - action native void A_FireBFG(); - action native void A_FireOldBFG(); action native void A_ReFire(statelabel flash = null); action native void A_ClearReFire(); action native void A_CheckReload();