mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- 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.
This commit is contained in:
parent
ab6b2f369e
commit
bb25c5faaa
11 changed files with 359 additions and 376 deletions
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -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<PStruct*>(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,6 +7266,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
bool writable;
|
||||
ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested.
|
||||
if (ArgList[i]->ValueType != TypeNullPtr)
|
||||
{
|
||||
ArgList[i]->RequestAddress(ctx, &writable);
|
||||
ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType);
|
||||
// For a reference argument the types must match 100%.
|
||||
|
@ -7263,6 +7281,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
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;
|
||||
|
|
|
@ -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<VMScriptFunction*>(callfunc)->PrintableName : callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]";
|
||||
printf_wrapper(out, " [%s]\n", callname);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -364,7 +364,6 @@ class Actor : Thinker native
|
|||
// End of MBF redundant functions.
|
||||
|
||||
native void A_MonsterRail();
|
||||
native void A_BFGSpray(class<Actor> 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(); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
//
|
||||
// [RH] A_FireRailgun
|
||||
//
|
||||
action void A_FireRailgun(int offset_xy = 0)
|
||||
{
|
||||
Height 20;
|
||||
Weapon.SelectionOrder 2800;
|
||||
Weapon.AmmoUse 40;
|
||||
Weapon.AmmoGive 40;
|
||||
Weapon.AmmoType "Cell";
|
||||
+WEAPON.NOAUTOFIRE;
|
||||
Inventory.PickupMessage "$GOTBFG9000";
|
||||
Tag "$TAG_BFG9000";
|
||||
}
|
||||
States
|
||||
if (player == null)
|
||||
{
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
259
wadsrc/static/zscript/doom/weaponbfg.txt
Normal file
259
wadsrc/static/zscript/doom/weaponbfg.txt
Normal file
|
@ -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<Actor>)("PlasmaBall1") : (class<Actor>)("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<Actor> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue