mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-16 17:21:10 +00:00
- MBF21: ported the code pointers to ZScript.
So far it's just the functions and some initial changes to Dehacked's parser. None of this is usable yet.
This commit is contained in:
parent
f701ef5c68
commit
c700682a36
18 changed files with 677 additions and 60 deletions
|
@ -1111,3 +1111,4 @@ xx(zoomsize)
|
|||
xx(ScreenJobRunner)
|
||||
xx(RazeStatusBar)
|
||||
xx(RipSound)
|
||||
xx(Archvile)
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "types.h"
|
||||
#include "m_argv.h"
|
||||
#include "actorptrselect.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
void JitDumpLog(FILE *file, VMScriptFunction *func);
|
||||
|
||||
|
@ -147,14 +148,15 @@ struct MBFParamState
|
|||
{
|
||||
FState *state;
|
||||
int pointer;
|
||||
int args[8];
|
||||
int argsused;
|
||||
};
|
||||
static TArray<MBFParamState> MBFParamStates;
|
||||
// Data on how to correctly modify the codepointers
|
||||
struct CodePointerAlias
|
||||
{
|
||||
FName name;
|
||||
char alias[20];
|
||||
uint8_t params;
|
||||
FString alias;
|
||||
};
|
||||
static TArray<CodePointerAlias> MBFCodePointers;
|
||||
|
||||
|
@ -630,7 +632,7 @@ static int GetLine (void)
|
|||
|
||||
|
||||
// misc1 = vrange (arg +3), misc2 = hrange (arg+4)
|
||||
static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_Mushroom
|
||||
emitters.AddParameterPointerConst(PClass::FindClass("FatShot")); // itemtype
|
||||
emitters.AddParameterIntConst(0); // numspawns
|
||||
|
@ -640,7 +642,7 @@ static void CreateMushroomFunc(FunctionCallEmitter &emitters, int value1, int va
|
|||
}
|
||||
|
||||
// misc1 = type (arg +0), misc2 = Z-pos (arg +2)
|
||||
static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_SpawnItem
|
||||
if (InfoNames[value1-1] == nullptr)
|
||||
{
|
||||
|
@ -655,13 +657,13 @@ static void CreateSpawnFunc(FunctionCallEmitter &emitters, int value1, int value
|
|||
|
||||
|
||||
// misc1 = angle (in degrees) (arg +0 but factor in current actor angle too)
|
||||
static void CreateTurnFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateTurnFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_Turn
|
||||
emitters.AddParameterFloatConst(value1); // angle
|
||||
}
|
||||
|
||||
// misc1 = angle (in degrees) (arg +0)
|
||||
static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_SetAngle
|
||||
emitters.AddParameterFloatConst(value1); // angle
|
||||
emitters.AddParameterIntConst(0); // flags
|
||||
|
@ -669,7 +671,7 @@ static void CreateFaceFunc(FunctionCallEmitter &emitters, int value1, int value2
|
|||
}
|
||||
|
||||
// misc1 = damage, misc 2 = sound
|
||||
static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_CustomMeleeAttack
|
||||
emitters.AddParameterIntConst(value1); // damage
|
||||
emitters.AddParameterIntConst(value2 ? (int)SoundMap[value2 - 1] : 0); // hit sound
|
||||
|
@ -679,7 +681,7 @@ static void CreateScratchFunc(FunctionCallEmitter &emitters, int value1, int val
|
|||
}
|
||||
|
||||
// misc1 = sound, misc2 = attenuation none (true) or normal (false)
|
||||
static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_PlaySound
|
||||
emitters.AddParameterIntConst(value1 ? (int)SoundMap[value1 - 1] : 0); // soundid
|
||||
emitters.AddParameterIntConst(CHAN_BODY); // channel
|
||||
|
@ -691,7 +693,7 @@ static void CreatePlaySoundFunc(FunctionCallEmitter &emitters, int value1, int v
|
|||
}
|
||||
|
||||
// misc1 = state, misc2 = probability
|
||||
static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_Jump
|
||||
auto symlabel = StateLabels.AddPointer(FindState(value1));
|
||||
|
||||
|
@ -701,7 +703,7 @@ static void CreateRandomJumpFunc(FunctionCallEmitter &emitters, int value1, int
|
|||
}
|
||||
|
||||
// misc1 = Boom linedef type, misc2 = sector tag
|
||||
static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_LineEffect
|
||||
// This is the second MBF codepointer that couldn't be translated easily.
|
||||
// Calling P_TranslateLineDef() here was a simple matter, as was adding an
|
||||
|
@ -713,7 +715,7 @@ static void CreateLineEffectFunc(FunctionCallEmitter &emitters, int value1, int
|
|||
}
|
||||
|
||||
// No misc, but it's basically A_Explode with an added effect
|
||||
static void CreateNailBombFunc(FunctionCallEmitter &emitters, int value1, int value2)
|
||||
static void CreateNailBombFunc(FunctionCallEmitter &emitters, int value1, int value2, int* args, int argsused)
|
||||
{ // A_Explode
|
||||
// This one does not actually have MBF-style parameters. But since
|
||||
// we're aliasing it to an extension of A_Explode...
|
||||
|
@ -728,8 +730,17 @@ static void CreateNailBombFunc(FunctionCallEmitter &emitters, int value1, int va
|
|||
emitters.AddParameterIntConst(NAME_None); // damage type
|
||||
}
|
||||
|
||||
static PClassActor* GetDehType(int num)
|
||||
{
|
||||
PClassActor* type = nullptr;
|
||||
if (num >= 0 && num < int(InfoNames.Size())) type = InfoNames[num];
|
||||
if (type == nullptr) type = RUNTIME_CLASS(AActor);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// This array must be in sync with the Aliases array in DEHSUPP.
|
||||
static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) =
|
||||
static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int, int*, int) =
|
||||
{
|
||||
// Die and Detonate are not in this list because these codepointers have
|
||||
// no dehacked arguments and therefore do not need special handling.
|
||||
|
@ -742,12 +753,12 @@ static void (*MBFCodePointerFactories[])(FunctionCallEmitter&, int, int) =
|
|||
CreatePlaySoundFunc,
|
||||
CreateRandomJumpFunc,
|
||||
CreateLineEffectFunc,
|
||||
CreateNailBombFunc
|
||||
CreateNailBombFunc,
|
||||
};
|
||||
|
||||
// Creates new functions for the given state so as to convert MBF-args (misc1 and misc2) into real args.
|
||||
|
||||
static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &disasmdump)
|
||||
static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &disasmdump, int* args, int argsused)
|
||||
{
|
||||
static const uint8_t regts[] = { REGT_POINTER, REGT_POINTER, REGT_POINTER };
|
||||
int value1 = state->GetMisc1();
|
||||
|
@ -786,7 +797,7 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di
|
|||
emitters.AddParameterPointer(i, false);
|
||||
}
|
||||
// Emit code for action parameters.
|
||||
MBFCodePointerFactories[codepointer](emitters, value1, value2);
|
||||
MBFCodePointerFactories[codepointer](emitters, value1, value2, args, argsused);
|
||||
auto where = emitters.EmitCall(&buildit);
|
||||
if (!returnsState) buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
||||
else buildit.Emit(OP_RET, RET_FINAL, EncodeRegType(where), where.RegNum);
|
||||
|
@ -1039,7 +1050,7 @@ static int PatchThing (int thingy)
|
|||
}
|
||||
else if (linelen == 11 && stricmp(Line1, "melee range") == 0)
|
||||
{
|
||||
info->meleerange = DEHToDouble(val);
|
||||
info->meleerange = DEHToDouble(val) - 20; // -20 is needed because DSDA subtracts it in P_CheckMeleeRange, while GZDoom does not.
|
||||
}
|
||||
else if (linelen == 10 && stricmp(Line1, "MBF21 Bits") == 0)
|
||||
{
|
||||
|
@ -1502,6 +1513,8 @@ DehBits sbits[] = {
|
|||
|
||||
static int PatchFrame (int frameNum)
|
||||
{
|
||||
int args[8]{};
|
||||
int argsused = 0;
|
||||
int result;
|
||||
int tics, misc1, frame;
|
||||
FState *info, dummy;
|
||||
|
@ -1583,6 +1596,19 @@ static int PatchFrame (int frameNum)
|
|||
{
|
||||
frame = val;
|
||||
}
|
||||
else if (keylen == 5 && strnicmp(Line1, "Args", 4) == 0)
|
||||
{
|
||||
int arg = Line1[4] - '1';
|
||||
if (arg < 0 || arg >= 8)
|
||||
{
|
||||
Printf("Invalid frame arg %d\n", arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
args[arg] = val;
|
||||
argsused |= (1 << arg);
|
||||
}
|
||||
}
|
||||
else if (stricmp(Line1, "MBF21 Bits") == 0)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
@ -1962,12 +1988,11 @@ static int PatchWeapon (int weapNum)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void SetPointer(FState *state, PFunction *sym, int frame = 0)
|
||||
static int SetPointer(FState *state, PFunction *sym, int frame = 0)
|
||||
{
|
||||
if (sym == NULL)
|
||||
{
|
||||
state->ClearAction();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1977,14 +2002,12 @@ static void SetPointer(FState *state, PFunction *sym, int frame = 0)
|
|||
{
|
||||
if (sym->SymbolName == MBFCodePointers[i].name)
|
||||
{
|
||||
MBFParamState newstate;
|
||||
newstate.state = state;
|
||||
newstate.pointer = i;
|
||||
MBFParamStates.Push(newstate);
|
||||
break; // No need to cycle through the rest of the list.
|
||||
MBFParamState newstate = { state, int(i) };
|
||||
return MBFParamStates.Push(newstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int PatchPointer (int ptrNum)
|
||||
|
@ -2885,7 +2908,7 @@ static void UnloadDehSupp ()
|
|||
// Handle MBF params here, before the required arrays are cleared
|
||||
for (unsigned int i=0; i < MBFParamStates.Size(); i++)
|
||||
{
|
||||
SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer, disasmdump);
|
||||
SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer, disasmdump, MBFParamStates[i].args, MBFParamStates[i].argsused);
|
||||
}
|
||||
MBFParamStates.Clear();
|
||||
MBFParamStates.ShrinkToFit();
|
||||
|
@ -3202,14 +3225,10 @@ static bool LoadDehSupp ()
|
|||
{
|
||||
CodePointerAlias temp;
|
||||
sc.MustGetString();
|
||||
strncpy(temp.alias, sc.String, 19);
|
||||
temp.alias[19]=0;
|
||||
temp.alias = sc.String;
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetString();
|
||||
temp.name = sc.String;
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetNumber();
|
||||
temp.params = sc.Number;
|
||||
MBFCodePointers.Push(temp);
|
||||
if (sc.CheckString("}")) break;
|
||||
sc.MustGetStringName(",");
|
||||
|
@ -3401,3 +3420,241 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType)
|
|||
}
|
||||
ACTION_RETURN_POINTER(nullptr);
|
||||
}
|
||||
|
||||
// Handling the flags is not as trivial as it seems...
|
||||
|
||||
struct FlagHandler
|
||||
{
|
||||
void (*setter)(AActor*);
|
||||
void (*clearer)(AActor*);
|
||||
bool (*checker)(AActor*);
|
||||
};
|
||||
|
||||
// cut down on boilerplate
|
||||
#define F(flag) { [](AActor* a) { a->flags |= flag; }, [](AActor* a) { a->flags &= ~flag; }, [](AActor* a)->bool { return a->flags & flag; } }
|
||||
#define F2(flag) { [](AActor* a) { a->flags2 |= flag; }, [](AActor* a) { a->flags2 &= ~flag; }, [](AActor* a)->bool { return a->flags2 & flag; } }
|
||||
#define F3(flag) { [](AActor* a) { a->flags3 |= flag; }, [](AActor* a) { a->flags3 &= ~flag; }, [](AActor* a)->bool { return a->flags3 & flag; } }
|
||||
#define F4(flag) { [](AActor* a) { a->flags4 |= flag; }, [](AActor* a) { a->flags4 &= ~flag; }, [](AActor* a)->bool { return a->flags4 & flag; } }
|
||||
#define F8(flag) { [](AActor* a) { a->flags8 |= flag; }, [](AActor* a) { a->flags8 &= ~flag; }, [](AActor* a)->bool { return a->flags8 & flag; } }
|
||||
#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, nullptr, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, nullptr, false, flag); }, [](AActor* a)->bool { return CheckDeprecatedFlags(a, nullptr, flag); } }
|
||||
|
||||
void SetNoSector(AActor* a)
|
||||
{
|
||||
a->UnlinkFromWorld(nullptr);
|
||||
a->flags |= MF_NOSECTOR;
|
||||
a->LinkToWorld(nullptr);
|
||||
}
|
||||
|
||||
void ClearNoSector(AActor* a)
|
||||
{
|
||||
a->UnlinkFromWorld(nullptr);
|
||||
a->flags &= ~MF_NOSECTOR;
|
||||
a->LinkToWorld(nullptr);
|
||||
}
|
||||
|
||||
void SetNoBlockmap(AActor* a)
|
||||
{
|
||||
a->UnlinkFromWorld(nullptr);
|
||||
a->flags |= MF_NOBLOCKMAP;
|
||||
a->LinkToWorld(nullptr);
|
||||
}
|
||||
|
||||
void ClearNoBlockmap(AActor* a)
|
||||
{
|
||||
a->UnlinkFromWorld(nullptr);
|
||||
a->flags &= ~MF_NOBLOCKMAP;
|
||||
a->LinkToWorld(nullptr);
|
||||
}
|
||||
|
||||
void SetCountkill(AActor* a)
|
||||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags |= MF_COUNTKILL;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
void ClearCountkill(AActor* a)
|
||||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags &= ~MF_COUNTKILL;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
void SetCountitem(AActor* a)
|
||||
{
|
||||
if (!(a->flags & MF_COUNTITEM))
|
||||
{
|
||||
a->flags |= MF_COUNTITEM;
|
||||
a->Level->total_items++;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearCountitem(AActor* a)
|
||||
{
|
||||
if (a->flags & MF_COUNTITEM)
|
||||
{
|
||||
a->flags |= MF_COUNTITEM;
|
||||
a->Level->total_items--;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFriendly(AActor* a)
|
||||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags |= MF_FRIENDLY;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
void ClearFriendly(AActor* a)
|
||||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags &= ~MF_FRIENDLY;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
void SetFullVol(AActor* a)
|
||||
{
|
||||
a->flags8 |= MF8_FULLVOLSEE;
|
||||
a->flags3 |= MF3_FULLVOLDEATH;
|
||||
}
|
||||
|
||||
void ClearFullVol(AActor* a)
|
||||
{
|
||||
a->flags8 &= ~MF8_FULLVOLSEE;
|
||||
a->flags3 &= ~MF3_FULLVOLDEATH;
|
||||
}
|
||||
|
||||
|
||||
static FlagHandler flag1handlers[32] = {
|
||||
F(MF_SPECIAL),
|
||||
F(MF_SOLID),
|
||||
F(MF_SHOOTABLE),
|
||||
{ SetNoSector, ClearNoSector, [](AActor* a)->bool { return a->flags & MF_NOSECTOR; } },
|
||||
{ SetNoBlockmap, ClearNoBlockmap, [](AActor* a)->bool { return a->flags & MF_NOBLOCKMAP; } },
|
||||
F(MF_AMBUSH),
|
||||
F(MF_JUSTHIT),
|
||||
F(MF_JUSTATTACKED),
|
||||
F(MF_SPAWNCEILING),
|
||||
F(MF_NOGRAVITY),
|
||||
F(MF_DROPOFF),
|
||||
F(MF_PICKUP),
|
||||
F(MF_NOCLIP),
|
||||
{ nullptr, nullptr, nullptr}, // MF_SLIDE no longer exists.
|
||||
F(MF_FLOAT),
|
||||
F(MF_TELEPORT),
|
||||
F(MF_MISSILE),
|
||||
F(MF_DROPPED),
|
||||
F(MF_SHADOW),
|
||||
F(MF_NOBLOOD),
|
||||
F(MF_CORPSE),
|
||||
F(MF_INFLOAT),
|
||||
{ SetCountkill, ClearCountkill, [](AActor* a)->bool { return a->flags & MF_COUNTKILL; } },
|
||||
{ SetCountitem, ClearCountitem, [](AActor* a)->bool { return a->flags & MF_COUNTITEM; } },
|
||||
F(MF_SKULLFLY),
|
||||
F(MF_NOTDMATCH),
|
||||
// translation, unused and translucent are no longer checkable in any way. Pity.
|
||||
};
|
||||
|
||||
static FlagHandler flag2handlers[32] = {
|
||||
DEPF(DEPF_LOWGRAVITY),
|
||||
DEPF(DEPF_SHORTMISSILERANGE),
|
||||
F3(MF3_NOTARGET),
|
||||
F3(MF3_NORADIUSDMG),
|
||||
F4(MF4_FORCERADIUSDMG),
|
||||
DEPF(DEPF_HIGHERMPROB),
|
||||
F4(MF4_MISSILEMORE),
|
||||
F4(MF4_QUICKTORETALIATE),
|
||||
DEPF(DEPF_LONGMELEERANGE),
|
||||
F2(MF2_BOSS),
|
||||
F8(MF8_MAP07BOSS1),
|
||||
F8(MF8_MAP07BOSS2),
|
||||
F8(MF8_E1M8BOSS),
|
||||
F8(MF8_E2M8BOSS),
|
||||
F8(MF8_E3M8BOSS),
|
||||
F8(MF8_E4M6BOSS),
|
||||
F8(MF8_E4M8BOSS),
|
||||
F2(MF2_RIP),
|
||||
{ SetFullVol, ClearFullVol, [](AActor* a)->bool { return a->flags8 & MF8_FULLVOLSEE; } }, // checking one of the two flags should suffice here.
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// A_JumpIfFlagsSet
|
||||
// Jumps to a state if caller has the specified thing flags set.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Standard Flag(s) to check
|
||||
// args[2]: MBF21 Flag(s) to check
|
||||
//
|
||||
DEFINE_ACTION_FUNCTION(AActor, MBF21_JumpIfFlagsSet)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_POINTER(tstate, FState);
|
||||
PARAM_INT(flags);
|
||||
PARAM_INT(flags2);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (flags & (1 << i) && flag1handlers[i].checker)
|
||||
{
|
||||
if (!flag1handlers[i].checker(self)) return 0;
|
||||
}
|
||||
if (flags2 & (1 << i) && flag2handlers[i].checker)
|
||||
{
|
||||
if (!flag2handlers[i].checker(self)) return 0;
|
||||
}
|
||||
}
|
||||
self->SetState(tstate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// A_AddFlags
|
||||
// Adds the specified thing flags to the caller.
|
||||
// args[0]: Standard Flag(s) to add
|
||||
// args[1]: MBF21 Flag(s) to add
|
||||
//
|
||||
DEFINE_ACTION_FUNCTION(AActor, MBF21_AddFlags)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(flags);
|
||||
PARAM_INT(flags2);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (flags & (1 << i) && flag1handlers[i].setter)
|
||||
{
|
||||
flag1handlers[i].setter(self);
|
||||
}
|
||||
if (flags2 & (1 << i) && flag2handlers[i].setter)
|
||||
{
|
||||
flag2handlers[i].setter(self);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// A_RemoveFlags
|
||||
// Removes the specified thing flags from the caller.
|
||||
// args[0]: Flag(s) to remove
|
||||
// args[1]: MBF21 Flag(s) to remove
|
||||
//
|
||||
DEFINE_ACTION_FUNCTION(AActor, MBF21_RemoveFlags)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(flags);
|
||||
PARAM_INT(flags2);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (flags & (1 << i) && flag1handlers[i].clearer)
|
||||
{
|
||||
flag1handlers[i].clearer(self);
|
||||
}
|
||||
if (flags2 & (1 << i) && flag2handlers[i].clearer)
|
||||
{
|
||||
flag2handlers[i].clearer(self);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -697,7 +697,7 @@ public:
|
|||
void AlterWeaponSprite(visstyle_t *vis);
|
||||
|
||||
// Returns true if this actor is within melee range of its target
|
||||
bool CheckMeleeRange();
|
||||
bool CheckMeleeRange(double range = -1);
|
||||
|
||||
bool CheckNoDelay();
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ void P_NoiseAlert (AActor *emitter, AActor *target, bool splash, double maxdist)
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool AActor::CheckMeleeRange ()
|
||||
bool AActor::CheckMeleeRange (double range)
|
||||
{
|
||||
AActor *pl = target;
|
||||
|
||||
|
@ -270,8 +270,9 @@ bool AActor::CheckMeleeRange ()
|
|||
return false;
|
||||
|
||||
dist = Distance2D (pl);
|
||||
if (range < 0) range = meleerange;
|
||||
|
||||
if (dist >= meleerange + pl->radius)
|
||||
if (dist >= range + pl->radius)
|
||||
return false;
|
||||
|
||||
// [RH] If moving toward goal, then we've reached it.
|
||||
|
@ -300,7 +301,8 @@ bool AActor::CheckMeleeRange ()
|
|||
DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_INT(self->CheckMeleeRange());
|
||||
PARAM_FLOAT(range);
|
||||
ACTION_RETURN_INT(self->CheckMeleeRange(range));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -2616,7 +2618,7 @@ bool P_CanResurrect(AActor *raiser, AActor *thing)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
||||
bool P_CheckForResurrection(AActor* self, bool usevilestates, FState* state = nullptr, FSoundID sound = 0)
|
||||
{
|
||||
const AActor *info;
|
||||
AActor *temp;
|
||||
|
@ -2702,8 +2704,8 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
|||
self->target = temp;
|
||||
|
||||
// Make the state the monster enters customizable.
|
||||
FState * state = self->FindState(NAME_Heal);
|
||||
if (state != NULL)
|
||||
if (state == nullptr) state = self->FindState(NAME_Heal);
|
||||
if (state != nullptr)
|
||||
{
|
||||
self->SetState(state);
|
||||
}
|
||||
|
@ -2711,13 +2713,14 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
|||
{
|
||||
// For Dehacked compatibility this has to use the Arch Vile's
|
||||
// heal state as a default if the actor doesn't define one itself.
|
||||
PClassActor *archvile = PClass::FindActor("Archvile");
|
||||
PClassActor *archvile = PClass::FindActor(NAME_Archvile);
|
||||
if (archvile != NULL)
|
||||
{
|
||||
self->SetState(archvile->FindState(NAME_Heal));
|
||||
}
|
||||
}
|
||||
S_Sound(corpsehit, CHAN_BODY, 0, "vile/raise", 1, ATTN_IDLE);
|
||||
if (sound == 0) sound = "vile/raise";
|
||||
S_Sound(corpsehit, CHAN_BODY, 0, sound, 1, ATTN_IDLE);
|
||||
info = corpsehit->GetDefault();
|
||||
|
||||
if (GetTranslationType(corpsehit->Translation) == TRANSLATION_Blood)
|
||||
|
|
|
@ -72,7 +72,7 @@ void A_DoChase(AActor *actor, bool fastchase, FState *meleestate, FState *missil
|
|||
void A_Chase(AActor *self);
|
||||
void A_FaceTarget(AActor *actor);
|
||||
void A_Face(AActor *self, AActor *other, DAngle max_turn = 0., DAngle max_pitch = 270., DAngle ang_offset = 0., DAngle pitch_offset = 0., int flags = 0, double z_add = 0);
|
||||
bool P_CheckForResurrection(AActor *self, bool usevilestates);
|
||||
class FSoundID;
|
||||
|
||||
int CheckBossDeath (AActor *);
|
||||
int P_Massacre (bool baddies = false, PClassActor *cls = nullptr);
|
||||
|
|
|
@ -228,8 +228,9 @@ enum PCM
|
|||
};
|
||||
|
||||
|
||||
int P_CheckFov(AActor* t1, AActor* t2, double fov);
|
||||
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL);
|
||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false);
|
||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false, double fov = 0);
|
||||
|
||||
//
|
||||
// P_MAP
|
||||
|
|
|
@ -1679,6 +1679,23 @@ FPathTraverse::~FPathTraverse()
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// P_CheckFov
|
||||
// Returns true if t2 is within t1's field of view.
|
||||
//
|
||||
int P_CheckFov(AActor* t1, AActor* t2, double fov)
|
||||
{
|
||||
return absangle(t1->AngleTo(t2), t1->Angles.Yaw) <= fov;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, CheckFov, P_CheckFov)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_POINTER(t, AActor);
|
||||
PARAM_FLOAT(fov);
|
||||
ACTION_RETURN_BOOL(P_CheckFov(self, t, fov));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// P_RoughMonsterSearch
|
||||
|
@ -1784,6 +1801,7 @@ struct BlockCheckInfo
|
|||
bool onlyseekable;
|
||||
bool frontonly;
|
||||
divline_t frontline;
|
||||
double fov;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
@ -1810,6 +1828,12 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param)
|
|||
{
|
||||
continue;
|
||||
}
|
||||
// skip actors outside of specified FOV
|
||||
if (info->fov > 0 && !P_CheckFov(mo, link->Me, info->fov))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mo->IsOkayToAttack (link->Me))
|
||||
{
|
||||
return link->Me;
|
||||
|
@ -1819,7 +1843,7 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly)
|
||||
AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly, double fov)
|
||||
{
|
||||
BlockCheckInfo info;
|
||||
info.onlyseekable = onlyseekable;
|
||||
|
|
|
@ -3306,7 +3306,7 @@ bool AActor::IsOkayToAttack (AActor *link)
|
|||
// its target; and for a summoned minion, its tracer.
|
||||
AActor * Friend;
|
||||
if (flags5 & MF5_SUMMONEDMONSTER) Friend = tracer;
|
||||
else if (flags2 & MF2_SEEKERMISSILE) Friend = target;
|
||||
else if (flags & MF_MISSILE) Friend = target;
|
||||
else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = Level->Players[FriendPlayer-1]->mo;
|
||||
else Friend = this;
|
||||
|
||||
|
|
|
@ -228,6 +228,7 @@ enum
|
|||
DEPF_HEXENBOUNCE = 10,
|
||||
DEPF_DOOMBOUNCE = 11,
|
||||
DEPF_INTERHUBSTRIP = 12,
|
||||
DEPF_HIGHERMPROB = 13,
|
||||
};
|
||||
|
||||
// Types of old style decorations
|
||||
|
|
|
@ -397,6 +397,7 @@ static FFlagDef MoreFlagDefs[] =
|
|||
DEFINE_DEPRECATED_FLAG(HERETICBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(HEXENBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(DOOMBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(HIGHERMPROB),
|
||||
|
||||
// Deprecated flags with no more existing functionality.
|
||||
DEFINE_DUMMY_FLAG(FASTER, true), // obsolete, replaced by 'Fast' state flag
|
||||
|
|
|
@ -325,6 +325,10 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
|
|||
defaults->IntVar(NAME_InterHubAmount) = set ? 0 : 1;
|
||||
break;
|
||||
|
||||
case DEPF_HIGHERMPROB:
|
||||
defaults->MinMissileChance = set ? 160 : 200;
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // silence GCC
|
||||
}
|
||||
|
@ -384,6 +388,9 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index)
|
|||
|
||||
case DEPF_INTERHUBSTRIP:
|
||||
return !(actor->IntVar(NAME_InterHubAmount));
|
||||
|
||||
case DEPF_HIGHERMPROB:
|
||||
return actor->MinMissileChance <= 160;
|
||||
}
|
||||
|
||||
return false; // Any entirely unknown flag is not set
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
DVector2 AM_GetPosition();
|
||||
int Net_GetLatency(int *ld, int *ad);
|
||||
void PrintPickupMessage(bool localview, const FString &str);
|
||||
bool P_CheckForResurrection(AActor* self, bool usevilestates, FState* state = nullptr, FSoundID sound = 0);
|
||||
|
||||
// FCheckPosition requires explicit construction and destruction when used in the VM
|
||||
|
||||
|
@ -328,6 +329,18 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetDamage, SetDamage)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static double PitchFromVel(AActor* self)
|
||||
{
|
||||
return self->Vel.Pitch().Degrees;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, PitchFromVel, PitchFromVel)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_FLOAT(PitchFromVel(self));
|
||||
}
|
||||
|
||||
|
||||
// This combines all 3 variations of the internal function
|
||||
static void VelFromAngle(AActor *self, double speed, double angle)
|
||||
{
|
||||
|
@ -1373,7 +1386,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, RoughMonsterSearch, P_RoughMonsterSearch)
|
|||
PARAM_INT(distance);
|
||||
PARAM_BOOL(onlyseekable);
|
||||
PARAM_BOOL(frontonly);
|
||||
ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly));
|
||||
PARAM_FLOAT(fov);
|
||||
ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly, fov));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckSight, P_CheckSight)
|
||||
|
@ -1576,15 +1590,17 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_ExtChase, A_ExtChase)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CheckForResurrection(AActor *self)
|
||||
int CheckForResurrection(AActor *self, FState* state, int sound)
|
||||
{
|
||||
return P_CheckForResurrection(self, false);
|
||||
return P_CheckForResurrection(self, false, state, sound);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_CheckForResurrection, CheckForResurrection)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_BOOL(P_CheckForResurrection(self, false));
|
||||
PARAM_STATE(state);
|
||||
PARAM_INT(sound);
|
||||
ACTION_RETURN_BOOL(P_CheckForResurrection(self, false, state, sound));
|
||||
}
|
||||
|
||||
static void ZS_Face(AActor *self, AActor *faceto, double max_turn, double max_pitch, double ang_offset, double pitch_offset, int flags, double z_add)
|
||||
|
|
|
@ -1185,13 +1185,27 @@ WeaponNames
|
|||
// when parsing a DEHACKED lump.
|
||||
Aliases
|
||||
{
|
||||
A_Mushroom, A_Mushroom, 5,
|
||||
A_Spawn, A_SpawnItem, 5,
|
||||
A_Turn, A_Turn, 1,
|
||||
A_Face, A_SetAngle, 1,
|
||||
A_Scratch, A_CustomMeleeAttack, 5, // 19 characters for "A_CustomMeleeAttack"!
|
||||
A_PlaySound, A_PlaySound, 5, // A function name any longer and the definition
|
||||
A_RandomJump, A_Jump, 3, // for CodePointerAlias would need to be updated.
|
||||
A_LineEffect, A_LineEffect, 2,
|
||||
A_NailBomb, A_Explode, 7,
|
||||
A_Mushroom, A_Mushroom,
|
||||
A_Spawn, A_SpawnItem,
|
||||
A_Turn, A_Turn,
|
||||
A_Face, A_SetAngle,
|
||||
A_Scratch, A_CustomMeleeAttack,
|
||||
A_PlaySound, A_PlaySound,
|
||||
A_RandomJump, A_Jump,
|
||||
A_LineEffect, A_LineEffect,
|
||||
A_NailBomb, A_Explode,
|
||||
A_SpawnObject, MBF21_SpawnObject,
|
||||
A_MonsterProjectile, MBF21_MonsterProjectile,
|
||||
A_MonsterBulletAttack, MBF21_MonsterBulletAttack,
|
||||
A_MonsterMeleeAttack, MBF21_MonsterMeleeAttack
|
||||
A_RadiusDamage, A_Explode,
|
||||
A_NoiseAlert, SoundAlert,
|
||||
A_HealChase, MBF21_HealChase,
|
||||
A_SeekTracer, A_SeekerMissile,
|
||||
A_FindTracer, A_FindTracer,
|
||||
A_JumpIfHealthBelow, MBF21_JumpIfHealthBelow,
|
||||
A_JumpIfTracerInSight, MBF21_JumpIfTracerInSight,
|
||||
A_JumpIfTracerCloser, MBF21_JumpIfTracerCloser,
|
||||
A_JumpIfTracerInSight, MBF21_JumpIfTracerInSight,
|
||||
A_JumpIfTracerCloser, MBF21_JumpIfTracerCloser,
|
||||
};
|
||||
|
|
|
@ -46,6 +46,7 @@ version "4.5"
|
|||
#include "zscript/actors/actions.zs"
|
||||
#include "zscript/actors/attacks.zs"
|
||||
#include "zscript/actors/morph.zs"
|
||||
#include "zscript/actors/mbf21.zs"
|
||||
|
||||
#include "zscript/actors/inventory/inventory.zs"
|
||||
#include "zscript/actors/inventory/inv_misc.zs"
|
||||
|
|
|
@ -682,10 +682,11 @@ class Actor : Thinker native
|
|||
native Actor SpawnSubMissile(Class<Actor> type, Actor target);
|
||||
native Actor, Actor SpawnPlayerMissile(class<Actor> type, double angle = 1e37, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0);
|
||||
native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget);
|
||||
native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false);
|
||||
native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false, double fov = 0);
|
||||
native int ApplyDamageFactor(Name damagetype, int damage);
|
||||
native int GetModifiedDamage(Name damagetype, int damage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0);
|
||||
native bool CheckBossDeath();
|
||||
native bool CheckFov(Actor target, double fov);
|
||||
|
||||
void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); }
|
||||
void A_Light0() { if (player) player.extralight = 0; }
|
||||
|
@ -706,7 +707,7 @@ class Actor : Thinker native
|
|||
native void TraceBleedAngle(int damage, double angle, double pitch);
|
||||
|
||||
native void SetIdle(bool nofunction = false);
|
||||
native bool CheckMeleeRange();
|
||||
native bool CheckMeleeRange(double range = -1);
|
||||
native bool TriggerPainChance(Name mod, bool forcedPain = false);
|
||||
native virtual int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0);
|
||||
native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type);
|
||||
|
@ -759,6 +760,7 @@ class Actor : Thinker native
|
|||
native clearscope vector2 Vec2Angle(double length, double angle, bool absolute = false) const;
|
||||
native clearscope vector2 Vec2Offset(double x, double y, bool absolute = false) const;
|
||||
native clearscope vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const;
|
||||
native double PitchFromVel();
|
||||
native void VelIntercept(Actor targ, double speed = -1, bool aimpitch = true, bool oldvel = false, bool resetvel = false);
|
||||
native void VelFromAngle(double speed = 1e37, double angle = 1e37);
|
||||
native void Vel3DFromAngle(double speed, double angle, double pitch);
|
||||
|
@ -1061,7 +1063,7 @@ class Actor : Thinker native
|
|||
native void A_Look();
|
||||
native void A_Chase(statelabel melee = '_a_chase_default', statelabel missile = '_a_chase_default', int flags = 0);
|
||||
native void A_VileChase();
|
||||
native bool A_CheckForResurrection();
|
||||
native bool A_CheckForResurrection(State state = null, Sound snd = 0);
|
||||
native void A_BossDeath();
|
||||
bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0)
|
||||
{
|
||||
|
|
|
@ -80,6 +80,7 @@ class Weapon : StateProvider
|
|||
flagdef NoDeathDeselect: WeaponFlags, 16; // Don't jump to the Deselect state when the player dies
|
||||
flagdef NoDeathInput: WeaponFlags, 17; // The weapon cannot be fired/reloaded/whatever when the player is dead
|
||||
flagdef CheatNotWeapon: WeaponFlags, 18; // Give cheat considers this not a weapon (used by Sigil)
|
||||
flagdef NoAutoSwitchTo : WeaponFlags, 19; // do not auto switch to this weapon ever!
|
||||
|
||||
// no-op flags
|
||||
flagdef NoLMS: none, 0;
|
||||
|
|
288
wadsrc/static/zscript/actors/mbf21.zs
Normal file
288
wadsrc/static/zscript/actors/mbf21.zs
Normal file
|
@ -0,0 +1,288 @@
|
|||
// no attempt has been made to merge this with existing code.
|
||||
extend class Actor
|
||||
{
|
||||
//
|
||||
// [XA] New mbf21 codepointers
|
||||
//
|
||||
|
||||
//
|
||||
// A_SpawnObject
|
||||
// Basically just A_Spawn with better behavior and more args.
|
||||
// args[0]: Type of actor to spawn
|
||||
// args[1]: Angle (degrees, in fixed point), relative to calling actor's angle
|
||||
// args[2]: X spawn offset (fixed point), relative to calling actor
|
||||
// args[3]: Y spawn offset (fixed point), relative to calling actor
|
||||
// args[4]: Z spawn offset (fixed point), relative to calling actor
|
||||
// args[5]: X velocity (fixed point)
|
||||
// args[6]: Y velocity (fixed point)
|
||||
// args[7]: Z velocity (fixed point)
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_SpawnObject(class<Actor> type, double angle, double xofs, double yofs, double zofs, double xvel, double yvel, double zvel)
|
||||
{
|
||||
if (type == null)
|
||||
return;
|
||||
|
||||
// Don't spawn monsters if this actor has been massacred
|
||||
if (DamageType == 'Massacre' && GetDefaultByType(type).bIsMonster)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate position offsets
|
||||
angle += self.Angle;
|
||||
double s = sin(angle);
|
||||
double c = cos(angle);
|
||||
let pos = Vec2Offset(xofs * c - yofs * s, xofs * s + yofs * c);
|
||||
|
||||
// spawn it, yo
|
||||
let mo = Spawn(type, (pos, self.pos.Z - Floorclip + GetBobOffset() + zofs), ALLOW_REPLACE);
|
||||
if (!mo)
|
||||
return;
|
||||
|
||||
// angle dangle
|
||||
mo.angle = angle;
|
||||
|
||||
// set velocity
|
||||
// Same orientation issue here!
|
||||
mo.vel.X = xvel * c - yvel * s;
|
||||
mo.vel.Y = xvel * s + yvel * c;
|
||||
mo.vel.Z = zvel;
|
||||
|
||||
// if spawned object is a missile, set target+tracer
|
||||
if (mo.bMissile || mo.bMbfBouncer)
|
||||
{
|
||||
// if spawner is also a missile, copy 'em
|
||||
if (bMissile || bMbfBouncer)
|
||||
{
|
||||
mo.target = self.target;
|
||||
mo.tracer = self.tracer;
|
||||
}
|
||||
// otherwise, set 'em as if a monster fired 'em
|
||||
else
|
||||
{
|
||||
mo.target = self;
|
||||
mo.tracer = self.target;
|
||||
}
|
||||
}
|
||||
|
||||
// [XA] don't bother with the dont-inherit-friendliness hack
|
||||
// that exists in A_Spawn, 'cause WTF is that about anyway?
|
||||
|
||||
// unfortunately this means that this function cannot transfer friendliness at all. Oh well...
|
||||
}
|
||||
|
||||
//
|
||||
// A_MonsterProjectile
|
||||
// A parameterized monster projectile attack.
|
||||
// args[0]: Type of actor to spawn
|
||||
// args[1]: Angle (degrees, in fixed point), relative to calling actor's angle
|
||||
// args[2]: Pitch (degrees, in fixed point), relative to calling actor's pitch; approximated
|
||||
// args[3]: X/Y spawn offset, relative to calling actor's angle
|
||||
// args[4]: Z spawn offset, relative to actor's default projectile fire height
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_MonsterProjectile(class<Actor> type, double angle, double pitch, double spawnofs_xy, double spawnofs_z)
|
||||
{
|
||||
if (!target || !type)
|
||||
return;
|
||||
|
||||
A_FaceTarget();
|
||||
let mo = SpawnMissile(target, type);
|
||||
if (!mo)
|
||||
return;
|
||||
|
||||
// adjust angle
|
||||
mo.angle += angle;
|
||||
|
||||
Pitch += mo.PitchFromVel();
|
||||
let missilespeed = abs(cos(Pitch) * mo.Speed);
|
||||
mo.Vel3DFromAngle(mo.Speed, mo.angle, Pitch);
|
||||
|
||||
// adjust position
|
||||
double x = Spawnofs_xy * cos(self.angle);
|
||||
double y = Spawnofs_xy * sin(self.angle);
|
||||
mo.SetOrigin(mo.Vec3Offset(x, y, Spawnofs_z), false);
|
||||
|
||||
// always set the 'tracer' field, so this pointer
|
||||
// can be used to fire seeker missiles at will.
|
||||
mo.tracer = target;
|
||||
}
|
||||
|
||||
//
|
||||
// A_MonsterBulletAttack
|
||||
// A parameterized monster bullet attack.
|
||||
// args[0]: Horizontal spread (degrees, in fixed point)
|
||||
// args[1]: Vertical spread (degrees, in fixed point)
|
||||
// args[2]: Number of bullets to fire; if not set, defaults to 1
|
||||
// args[3]: Base damage of attack (e.g. for 3d5, customize the 3); if not set, defaults to 3
|
||||
// args[4]: Attack damage modulus (e.g. for 3d5, customize the 5); if not set, defaults to 5
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_MonsterBulletAttack(double hspread, double vspread, int numbullets, int damagebase, int damagemod)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
A_FaceTarget();
|
||||
A_StartSound(AttackSound, CHAN_WEAPON);
|
||||
|
||||
let bangle = angle;
|
||||
let slope = AimLineAttack(bangle, MISSILERANGE);
|
||||
|
||||
for (int i = 0; i < numbullets; i++)
|
||||
{
|
||||
int damage = (random[mbf21]() % damagemod + 1) * damagebase;
|
||||
let pangle = bangle + hspread * Random2[mbf21]() / 255.;
|
||||
let pslope = slope + vspread * Random2[mbf21]() / 255.;
|
||||
LineAttack(pangle, MISSILERANGE, pslope, damage, "Hitscan", "Bulletpuff");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// A_MonsterMeleeAttack
|
||||
// A parameterized monster melee attack.
|
||||
// args[0]: Base damage of attack (e.g. for 3d8, customize the 3); if not set, defaults to 3
|
||||
// args[1]: Attack damage modulus (e.g. for 3d8, customize the 8); if not set, defaults to 8
|
||||
// args[2]: Sound to play if attack hits
|
||||
// args[3]: Range (fixed point); if not set, defaults to monster's melee range
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_MonsterMeleeAttack(int damagebase, int damagemod, Sound hitsound, double range)
|
||||
{
|
||||
let targ = target;
|
||||
if (!targ)
|
||||
return;
|
||||
|
||||
if (range == 0) range = meleerange;
|
||||
else range -= 20; // DSDA always subtracts 20 from the melee range.
|
||||
|
||||
A_FaceTarget();
|
||||
if (!CheckMeleeRange(range))
|
||||
return;
|
||||
|
||||
A_StartSound(hitsound, CHAN_WEAPON);
|
||||
|
||||
int damage = (random[mbf21]() % damagemod + 1) * damagebase;
|
||||
int newdam = targ.DamageMobj(self, self, damage, "Melee");
|
||||
targ.TraceBleed(newdam > 0 ? newdam : damage, self);
|
||||
}
|
||||
|
||||
//
|
||||
// A_HealChase
|
||||
// A parameterized version of A_VileChase.
|
||||
// args[0]: State to jump to on the calling actor when resurrecting a corpse
|
||||
// args[1]: Sound to play when resurrecting a corpse
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_HealChase(State healstate, Sound healsound)
|
||||
{
|
||||
if (!A_CheckForResurrection(healstate, healsound))
|
||||
A_Chase();
|
||||
}
|
||||
|
||||
//
|
||||
// A_FindTracer
|
||||
// Search for a valid tracer (seek target), if the calling actor doesn't already have one.
|
||||
// args[0]: field-of-view to search in (degrees, in fixed point); if zero, will search in all directions
|
||||
// args[1]: distance to search (map blocks, i.e. 128 units)
|
||||
//
|
||||
void A_FindTracer(double fov, int dist)
|
||||
{
|
||||
if (!tracer) tracer = RoughMonsterSearch(dist, fov: fov);
|
||||
}
|
||||
|
||||
//
|
||||
// A_ClearTracer
|
||||
// Clear current tracer (seek target).
|
||||
//
|
||||
void A_ClearTracer()
|
||||
{
|
||||
tracer = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// A_JumpIfHealthBelow
|
||||
// Jumps to a state if caller's health is below the specified threshold.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Health threshold
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_JumpIfHealthBelow(State tstate, int health)
|
||||
{
|
||||
if (self.health < health) self.SetState(tstate);
|
||||
}
|
||||
|
||||
//
|
||||
// A_JumpIfTargetInSight
|
||||
// Jumps to a state if caller's target is in line-of-sight.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Field-of-view to check (degrees, in fixed point); if zero, will check in all directions
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_JumpIfTargetInSight(State tstate, double fov)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
// Check FOV first since it's faster
|
||||
if (fov > 0 && !CheckFov(target, fov))
|
||||
return;
|
||||
|
||||
if (CheckSight(target)) self.SetState(tstate);
|
||||
}
|
||||
|
||||
//
|
||||
// A_JumpIfTargetCloser
|
||||
// Jumps to a state if caller's target is closer than the specified distance.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Distance threshold
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_JumpIfTargetCloser(State tstate, double dist)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (dist > Distance2D(target)) self.SetState(tstate);
|
||||
}
|
||||
|
||||
//
|
||||
// A_JumpIfTracerInSight
|
||||
// Jumps to a state if caller's tracer (seek target) is in line-of-sight.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Field-of-view to check (degrees, in fixed point); if zero, will check in all directions
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_JumpIfTracerInSight(State tstate, double fov)
|
||||
{
|
||||
if (!tracer)
|
||||
return;
|
||||
|
||||
// Check FOV first since it's faster
|
||||
if (fov > 0 && !CheckFov(tracer, fov))
|
||||
return;
|
||||
|
||||
if (CheckSight(tracer)) self.SetState(tstate);
|
||||
}
|
||||
|
||||
//
|
||||
// A_JumpIfTracerCloser
|
||||
// Jumps to a state if caller's tracer (seek target) is closer than the specified distance.
|
||||
// args[0]: State to jump to
|
||||
// args[1]: Distance threshold (fixed point)
|
||||
//
|
||||
deprecated("2.3", "for Dehacked use only")
|
||||
void MBF21_JumpIfTracerCloser(State tstate, double dist)
|
||||
{
|
||||
if (!tracer)
|
||||
return;
|
||||
|
||||
if (dist > Distance2D(tracer)) self.SetState(tstate);
|
||||
}
|
||||
|
||||
// These are native to lock away the insanity.
|
||||
deprecated("2.3", "for Dehacked use only") native void MBF21_JumpIfFlagsSet(State tstate, int flags, int flags2);
|
||||
deprecated("2.3", "for Dehacked use only") native void MBF21_AddFlags(int flags, int flags2);
|
||||
deprecated("2.3", "for Dehacked use only") native void MBF21_RemoveFlags(int flags, int flags2);
|
||||
}
|
|
@ -333,8 +333,8 @@ class PlayerPawn : Actor
|
|||
(player.ReadyWeapon == NULL || player.ReadyWeapon.bWimpy_Weapon))
|
||||
{
|
||||
let best = BestWeapon (ammotype);
|
||||
if (best != NULL && && !best.bNoAutoSwitchTo && (player.ReadyWeapon == NULL ||
|
||||
best.SelectionOrder < player.ReadyWeapon.SelectionOrder))
|
||||
if (best != NULL && !best.bNoAutoSwitchTo &&
|
||||
(player.ReadyWeapon == NULL || best.SelectionOrder < player.ReadyWeapon.SelectionOrder))
|
||||
{
|
||||
player.PendingWeapon = best;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue