- scriptified Heretic's wizard.

This commit is contained in:
Christoph Oelckers 2016-11-11 23:32:13 +01:00
parent a5f9eb5be1
commit 14a9c13113
7 changed files with 135 additions and 102 deletions

View file

@ -857,7 +857,6 @@ set( NOT_COMPILED_SOURCE_FILES
g_heretic/a_hereticartifacts.cpp
g_heretic/a_hereticweaps.cpp
g_heretic/a_ironlich.cpp
g_heretic/a_wizard.cpp
g_hexen/a_bats.cpp
g_hexen/a_bishop.cpp
g_hexen/a_blastradius.cpp

View file

@ -1,95 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "gstrings.h"
#include "vm.h"
*/
static FRandom pr_wizatk3 ("WizAtk3");
//----------------------------------------------------------------------------
//
// PROC A_GhostOff
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_GhostOff)
{
PARAM_SELF_PROLOGUE(AActor);
self->RenderStyle = STYLE_Normal;
self->flags3 &= ~MF3_GHOST;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk1
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1)
{
PARAM_SELF_PROLOGUE(AActor);
A_FaceTarget (self);
CALL_ACTION(A_GhostOff, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk2
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2)
{
PARAM_SELF_PROLOGUE(AActor);
A_FaceTarget (self);
self->Alpha = HR_SHADOW;
self->RenderStyle = STYLE_Translucent;
self->flags3 |= MF3_GHOST;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk3
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *mo;
CALL_ACTION(A_GhostOff, self);
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
if (self->CheckMeleeRange())
{
int damage = pr_wizatk3.HitDice (4);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
PClassActor *fx = PClass::FindActor("WizardFX1");
mo = P_SpawnMissile (self, self->target, fx);
if (mo != NULL)
{
P_SpawnMissileAngle(self, fx, mo->Angles.Yaw - 45. / 8, mo->Vel.Z);
P_SpawnMissileAngle(self, fx, mo->Angles.Yaw + 45. / 8, mo->Vel.Z);
}
return 0;
}

View file

@ -6041,6 +6041,13 @@ static double GetDefaultSpeed(PClassActor *type)
return GetDefaultByType(type)->Speed;
}
DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed)
{
PARAM_PROLOGUE;
PARAM_CLASS(type, AActor);
ACTION_RETURN_FLOAT(GetDefaultSpeed(type));
}
//---------------------------------------------------------------------------
//
// FUNC P_SpawnMissile
@ -6283,6 +6290,19 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z,
return (!checkspawn || P_CheckMissileSpawn(mo, source->radius)) ? mo : NULL;
}
DEFINE_ACTION_FUNCTION(AActor, SpawnMissileAngleZSpeed)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(z);
PARAM_CLASS(type, AActor);
PARAM_ANGLE(angle);
PARAM_FLOAT(vz);
PARAM_FLOAT(speed);
PARAM_OBJECT_DEF(owner, AActor);
PARAM_BOOL_DEF(checkspawn);
ACTION_RETURN_OBJECT(P_SpawnMissileAngleZSpeed(self, z, type, angle, vz, speed, owner, checkspawn));
}
/*
================
=
@ -6879,6 +6899,13 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType)
ACTION_RETURN_OBJECT(GetDefaultByType(cls));
}
DEFINE_ACTION_FUNCTION(AActor, GetBobOffset)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT_DEF(frac);
ACTION_RETURN_FLOAT(self->GetBobOffset(frac));
}
// This combines all 3 variations of the internal function
DEFINE_ACTION_FUNCTION(AActor, VelFromAngle)
{

View file

@ -6680,7 +6680,19 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
return nullptr;
}
}
}
else
{
if ((unsigned)implicit < argtypes.Size() && argtypes[implicit] != nullptr)
{
auto flags = Function->Variants[0].ArgFlags[implicit];
if (!(flags & VARF_Optional))
{
ScriptPosition.Message(MSG_ERROR, "Insufficient arguments in call to %s", Function->SymbolName.GetChars());
delete this;
return nullptr;
}
}
}
if (failed)
{

View file

@ -56,6 +56,8 @@ class Actor : Thinker native
native static readonly<Actor> GetDefaultByType(class<Actor> cls);
native static float deltaangle(float ang1, float ang2);
native static float GetDefaultSpeed(class<Actor> type);
native float GetBobOffset(float frac = 0);
native void SetDamage(int dmg);
native static bool isDehState(state st);
native void SetOrigin(vector3 newpos, bool moving);
@ -64,6 +66,8 @@ class Actor : Thinker native
native static Actor Spawn(class<Actor> type, vector3 pos = (0,0,0), int replace = NO_REPLACE);
native Actor SpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
native Actor SpawnMissileZ (double z, Actor dest, class<Actor> type);
native Actor SpawnMissileAngleZSpeed (double z, class<Actor> type, float angle, double vz, double speed, Actor owner = null, bool checkspawn = true);
native Actor OldSpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
native Actor SpawnPuff(class<Actor> pufftype, vector3 pos, float hitdir, float particledir, int updown, int flags = 0, Actor vict = null);
@ -143,6 +147,26 @@ class Actor : Thinker native
void A_SetRipMax(int maximum) { RipLevelMax = maximum; }
void A_ScreamAndUnblock() { A_Scream(); A_NoBlocking(); }
void A_ActiveAndUnblock() { A_ActiveSound(); A_NoBlocking(); }
//---------------------------------------------------------------------------
//
// FUNC P_SpawnMissileAngle
//
// Returns NULL if the missile exploded immediately, otherwise returns
// a mobj_t pointer to the missile.
//
//---------------------------------------------------------------------------
Actor SpawnMissileAngle (class<Actor> type, float angle, double vz)
{
return SpawnMissileAngleZSpeed (pos.z + 32 + GetBobOffset(), type, angle, vz, GetDefaultSpeed (type));
}
Actor SpawnMissileAngleZ (double z, class<Actor> type, double angle, double vz)
{
return SpawnMissileAngleZSpeed (z, type, angle, vz, GetDefaultSpeed (type));
}
void A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false)
{

View file

@ -883,3 +883,10 @@ enum EReplace
NO_REPLACE = 0,
ALLOW_REPLACE = 1
}
// This translucency value produces the closest match to Heretic's TINTTAB.
// ~40% of the value of the overlaid image shows through.
const HR_SHADOW = (0x6800 / 65536.);
// Hexen's TINTTAB is the same as Heretic's, just reversed.
const HX_SHADOW = (0x9800 / 65536.);
const HX_ALTSHADOW = (0x6800 / 65536.);

View file

@ -26,11 +26,6 @@ class Wizard : Actor
DropItem "ArtiTomeOfPower", 4, 0;
}
native void A_GhostOff ();
native void A_WizAtk1 ();
native void A_WizAtk2 ();
native void A_WizAtk3 ();
States
{
Spawn:
@ -70,6 +65,70 @@ class Wizard : Actor
WZRD M -1 A_SetFloorClip;
Stop;
}
//----------------------------------------------------------------------------
//
// PROC A_GhostOff
//
//----------------------------------------------------------------------------
void A_GhostOff ()
{
A_SetRenderStyle(1.0, STYLE_Normal);
bGhost = false;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk1
//
//----------------------------------------------------------------------------
void A_WizAtk1 ()
{
A_FaceTarget ();
A_GhostOff();
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk2
//
//----------------------------------------------------------------------------
void A_WizAtk2 ()
{
A_FaceTarget ();
A_SetRenderStyle(HR_SHADOW, STYLE_Translucent);
bGhost = true;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk3
//
//----------------------------------------------------------------------------
void A_WizAtk3 ()
{
A_GhostOff();
if (!target) return;
A_PlaySound (AttackSound, CHAN_WEAPON);
if (CheckMeleeRange())
{
int damage = random[WizAtk3](1, 8) * 4;
int newdam = target.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
return;
}
Actor mo = SpawnMissile (target, "WizardFX1");
if (mo != null)
{
SpawnMissileAngle("WizardFX1", mo.Angle - 45. / 8, mo.Vel.Z);
SpawnMissileAngle("WizardFX1", mo.Angle + 45. / 8, mo.Vel.Z);
}
}
}
// Projectile --------------------------------------------------------