- Sync scripting branch with what was in trunk on Sunday. I believe that would be revision 2739.
SVN r2790 (scripting)
This commit is contained in:
commit
99670b708c
317 changed files with 17299 additions and 7273 deletions
|
|
@ -66,6 +66,7 @@
|
|||
#include "v_font.h"
|
||||
#include "doomstat.h"
|
||||
#include "v_palette.h"
|
||||
#include "g_shared/a_specialspot.h"
|
||||
|
||||
|
||||
static FRandom pr_camissile ("CustomActorfire");
|
||||
|
|
@ -81,6 +82,7 @@ static FRandom pr_spawndebris ("SpawnDebris");
|
|||
static FRandom pr_spawnitemex ("SpawnItemEx");
|
||||
static FRandom pr_burst ("Burst");
|
||||
static FRandom pr_monsterrefire ("MonsterRefire");
|
||||
static FRandom pr_teleport("A_Teleport");
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -368,6 +370,7 @@ static FRandom pr_seekermissile ("SeekerMissile");
|
|||
enum
|
||||
{
|
||||
SMF_LOOK = 1,
|
||||
SMF_PRECISE = 2,
|
||||
};
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile)
|
||||
{
|
||||
|
|
@ -382,7 +385,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile)
|
|||
{
|
||||
self->tracer = P_RoughMonsterSearch (self, distance);
|
||||
}
|
||||
P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1);
|
||||
P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1, !!(flags & SMF_PRECISE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -500,12 +503,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower)
|
|||
// State jump function
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser)
|
||||
void DoJumpIfCloser(AActor *target, VM_ARGS)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_FIXED (dist);
|
||||
PARAM_STATE (jump);
|
||||
|
||||
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
|
||||
|
||||
// No target - no jump
|
||||
if (target != NULL && P_AproxDistance(self->x-target->x, self->y-target->y) < dist &&
|
||||
( (self->z > target->z && self->z - (target->z + target->height) < dist) ||
|
||||
(self->z <=target->z && target->z - (self->z + self->height) < dist)
|
||||
)
|
||||
)
|
||||
{
|
||||
ACTION_JUMP(jump);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
||||
AActor *target;
|
||||
|
||||
if (self->player == NULL)
|
||||
|
|
@ -517,24 +537,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser)
|
|||
// Does the player aim at something that can be shot?
|
||||
P_BulletSlope(self, &target);
|
||||
}
|
||||
DoJumpIfCloser(target, VM_ARGS_NAMES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
||||
// No target - no jump
|
||||
if (target == NULL)
|
||||
return 0;
|
||||
|
||||
if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist &&
|
||||
( (self->z > target->z && self->z - (target->z + target->height) < dist) ||
|
||||
(self->z <=target->z && target->z - (self->z + self->height) < dist)
|
||||
)
|
||||
)
|
||||
// Is there really any reason to limit this to seeker missiles?
|
||||
if (self->flags2 & MF2_SEEKERMISSILE)
|
||||
{
|
||||
ACTION_JUMP(jump);
|
||||
DoJumpIfCloser(self->tracer, VM_ARGS_NAMES);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
DoJumpIfCloser(self->master, VM_ARGS_NAMES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// State jump function
|
||||
|
|
@ -851,6 +876,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
|
|||
// An even more customizable hitscan attack
|
||||
//
|
||||
//==========================================================================
|
||||
enum CBA_Flags
|
||||
{
|
||||
CBAF_AIMFACING = 1,
|
||||
CBAF_NORANDOM = 2,
|
||||
CBAF_EXPLICITANGLE = 4,
|
||||
CBAF_NOPITCH = 8,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
|
@ -860,7 +893,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
|||
PARAM_INT (damageperbullet);
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); }
|
||||
PARAM_FIXED_OPT (range) { range = MISSILERANGE; }
|
||||
PARAM_BOOL_OPT (aimfacing) { aimfacing = false; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
|
||||
if (range == 0)
|
||||
range = MISSILERANGE;
|
||||
|
|
@ -869,19 +902,35 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
|||
int bangle;
|
||||
int bslope;
|
||||
|
||||
if (self->target || aimfacing)
|
||||
if (self->target || (flags & CBAF_AIMFACING))
|
||||
{
|
||||
if (!aimfacing) A_FaceTarget (self);
|
||||
if (!(flags & CBAF_AIMFACING)) A_FaceTarget (self);
|
||||
bangle = self->angle;
|
||||
|
||||
bslope = P_AimLineAttack (self, bangle, MISSILERANGE);
|
||||
if (!(flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE);
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
for (i = 0; i < numbullets; i++)
|
||||
{
|
||||
int angle = bangle + pr_cabullet.Random2() * (spread_xy / 255);
|
||||
int slope = bslope + pr_cabullet.Random2() * (spread_z / 255);
|
||||
int damage = ((pr_cabullet()%3)+1) * damageperbullet;
|
||||
int angle = bangle;
|
||||
int slope = bslope;
|
||||
|
||||
if (flags & CBAF_EXPLICITANGLE)
|
||||
{
|
||||
angle += spread_xy;
|
||||
slope += spread_z;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle += pr_cwbullet.Random2() * (spread_xy / 255);
|
||||
slope += pr_cwbullet.Random2() * (spread_z / 255);
|
||||
}
|
||||
|
||||
int damage = damageperbullet;
|
||||
|
||||
if (!(flags & CBAF_NORANDOM))
|
||||
damage *= ((pr_cabullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, angle, range, slope, damage, NAME_None, pufftype);
|
||||
}
|
||||
}
|
||||
|
|
@ -1006,6 +1055,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo)
|
|||
// An even more customizable hitscan attack
|
||||
//
|
||||
//==========================================================================
|
||||
enum FB_Flags
|
||||
{
|
||||
FBF_USEAMMO = 1,
|
||||
FBF_NORANDOM = 2,
|
||||
FBF_EXPLICITANGLE = 4,
|
||||
FBF_NOPITCH = 8,
|
||||
FBF_NOFLASH = 16,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
|
@ -1014,7 +1072,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
PARAM_INT (numbullets);
|
||||
PARAM_INT (damageperbullet);
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
|
||||
PARAM_BOOL_OPT (useammo) { useammo = true; }
|
||||
PARAM_INT_OPT (flags) { flags = FBF_USEAMMO; }
|
||||
PARAM_FIXED_OPT (range) { range = 0; }
|
||||
|
||||
if (!self->player) return 0;
|
||||
|
|
@ -1026,7 +1084,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
int bangle;
|
||||
int bslope;
|
||||
|
||||
if (useammo && weapon)
|
||||
if ((flags & FBF_USEAMMO) && weapon)
|
||||
{
|
||||
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
|
||||
return 0; // out of ammo
|
||||
|
|
@ -1035,9 +1093,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
if (range == 0)
|
||||
range = PLAYERMISSILERANGE;
|
||||
|
||||
static_cast<APlayerPawn *>(self)->PlayAttacking2();
|
||||
if (!(flags & FBF_NOFLASH)) static_cast<APlayerPawn *>(self)->PlayAttacking2 ();
|
||||
|
||||
bslope = P_BulletSlope(self);
|
||||
if (!(flags & FBF_NOPITCH)) bslope = P_BulletSlope(self);
|
||||
bangle = self->angle;
|
||||
|
||||
if (pufftype == NULL)
|
||||
|
|
@ -1047,7 +1105,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
|
||||
if ((numbullets == 1 && !player->refire) || numbullets == 0)
|
||||
{
|
||||
int damage = ((pr_cwbullet()%3)+1) * damageperbullet;
|
||||
int damage = damageperbullet;
|
||||
|
||||
if (!(flags & FBF_NORANDOM))
|
||||
damage *= ((pr_cwbullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, bangle, range, bslope, damage, NAME_None, pufftype);
|
||||
}
|
||||
else
|
||||
|
|
@ -1056,9 +1118,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
numbullets = 1;
|
||||
for (i = 0; i < numbullets; i++)
|
||||
{
|
||||
int angle = bangle + pr_cwbullet.Random2() * (spread_xy / 255);
|
||||
int slope = bslope + pr_cwbullet.Random2() * (spread_z / 255);
|
||||
int damage = ((pr_cwbullet()%3)+1) * damageperbullet;
|
||||
int angle = bangle;
|
||||
int slope = bslope;
|
||||
|
||||
if (flags & FBF_EXPLICITANGLE)
|
||||
{
|
||||
angle += spread_xy;
|
||||
slope += spread_z;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle += pr_cwbullet.Random2() * (spread_xy / 255);
|
||||
slope += pr_cwbullet.Random2() * (spread_z / 255);
|
||||
}
|
||||
|
||||
int damage = damageperbullet;
|
||||
|
||||
if (!(flags & FBF_NORANDOM))
|
||||
damage *= ((pr_cwbullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, angle, range, slope, damage, NAME_None, pufftype);
|
||||
}
|
||||
}
|
||||
|
|
@ -1139,14 +1217,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
|
|||
// Berserk is not handled here. That can be done with A_CheckIfInventory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
CPF_USEAMMO = 1,
|
||||
CPF_DAGGER = 2,
|
||||
CPF_PULLIN = 4,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_INT (damage);
|
||||
PARAM_BOOL_OPT (norandom) { norandom = false; }
|
||||
PARAM_BOOL_OPT (useammo) { useammo = true; }
|
||||
PARAM_INT_OPT (flags) { flags = CPF_USEAMMO; }
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
|
||||
PARAM_FIXED_OPT (range) { range = 0; }
|
||||
PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; }
|
||||
|
||||
if (!self->player)
|
||||
return 0;
|
||||
|
|
@ -1168,7 +1255,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
|
|||
pitch = P_AimLineAttack (self, angle, range, &linetarget);
|
||||
|
||||
// only use ammo when actually hitting something!
|
||||
if (useammo && linetarget && weapon)
|
||||
if ((flags & CPF_USEAMMO) && linetarget && weapon)
|
||||
{
|
||||
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
|
||||
return 0; // out of ammo
|
||||
|
|
@ -1177,14 +1264,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
|
|||
if (pufftype == NULL)
|
||||
pufftype = PClass::FindActor(NAME_BulletPuff);
|
||||
|
||||
P_LineAttack (self, angle, range, pitch, damage, NAME_None, pufftype, true);
|
||||
P_LineAttack (self, angle, range, pitch, damage, NAME_None, pufftype, true, &linetarget);
|
||||
|
||||
// turn to face target
|
||||
if (linetarget)
|
||||
{
|
||||
if (lifesteal)
|
||||
P_GiveBody (self, (damage * lifesteal) >> FRACBITS);
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM);
|
||||
|
||||
self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y);
|
||||
|
||||
if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED;
|
||||
if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1193,7 +1287,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
|
|||
enum
|
||||
{
|
||||
RAF_SILENT = 1,
|
||||
RAF_NOPIERCE = 2
|
||||
RAF_NOPIERCE = 2,
|
||||
RAF_EXPLICITANGLE = 4,
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -1212,6 +1307,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
|
|||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; }
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); }
|
||||
PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; }
|
||||
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; }
|
||||
|
||||
if (!self->player)
|
||||
return 0;
|
||||
|
|
@ -1225,7 +1322,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
|
|||
return 0; // out of ammo
|
||||
}
|
||||
|
||||
P_RailAttack (self, damage, spawnofs_xy, color1, color2, float(maxdiff), (flags & RAF_SILENT), pufftype, (!(flags & RAF_NOPIERCE)));
|
||||
angle_t angle;
|
||||
angle_t slope;
|
||||
|
||||
if (flags & RAF_EXPLICITANGLE)
|
||||
{
|
||||
angle = spread_xy;
|
||||
slope = spread_z;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = pr_crailgun.Random2() * (spread_xy / 255);
|
||||
slope = pr_crailgun.Random2() * (spread_z / 255);
|
||||
}
|
||||
|
||||
P_RailAttack (self, damage, spawnofs_xy, color1, color2, maxdiff, (flags & RAF_SILENT), pufftype, (!(flags & RAF_NOPIERCE)), angle, slope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1238,7 +1349,8 @@ enum
|
|||
{
|
||||
CRF_DONTAIM = 0,
|
||||
CRF_AIMPARALLEL = 1,
|
||||
CRF_AIMDIRECT = 2
|
||||
CRF_AIMDIRECT = 2,
|
||||
CRF_EXPLICITANGLE = 4,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
|
||||
|
|
@ -1252,6 +1364,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
|
|||
PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; }
|
||||
PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; }
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); }
|
||||
PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; }
|
||||
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; }
|
||||
|
||||
AActor *linetarget;
|
||||
|
||||
|
|
@ -1318,7 +1432,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
|
|||
|
||||
angle_t angle = (self->angle - ANG90) >> ANGLETOFINESHIFT;
|
||||
|
||||
P_RailAttack (self, damage, spawnofs_xy, color1, color2, float(maxdiff), flags & RAF_SILENT, pufftype, !(flags & RAF_NOPIERCE));
|
||||
angle_t angleoffset;
|
||||
angle_t slopeoffset;
|
||||
|
||||
if (flags & CRF_EXPLICITANGLE)
|
||||
{
|
||||
angleoffset = spread_xy;
|
||||
slopeoffset = spread_z;
|
||||
}
|
||||
else
|
||||
{
|
||||
angleoffset = pr_crailgun.Random2() * (spread_xy / 255);
|
||||
slopeoffset = pr_crailgun.Random2() * (spread_z / 255);
|
||||
}
|
||||
|
||||
P_RailAttack (self, damage, spawnofs_xy, color1, color2, maxdiff, (flags & RAF_SILENT), pufftype, (!(flags & RAF_NOPIERCE)), angleoffset, slopeoffset);
|
||||
|
||||
self->x = saved_x;
|
||||
self->y = saved_y;
|
||||
|
|
@ -1400,11 +1528,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
TIF_NOTAKEINFINITE = 1,
|
||||
};
|
||||
|
||||
void DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS)
|
||||
{
|
||||
int paramnum = NAP-1;
|
||||
PARAM_CLASS (itemtype, AInventory);
|
||||
PARAM_INT_OPT (amount) { amount = 0; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
|
||||
if (itemtype == NULL || receiver == NULL) return;
|
||||
|
||||
|
|
@ -1418,12 +1552,18 @@ void DoTakeInventory(AActor *receiver, StateCallData *statecall, VM_ARGS)
|
|||
{
|
||||
res = true;
|
||||
}
|
||||
if (amount == 0 || amount >= inv->Amount)
|
||||
// Do not take ammo if the "no take infinite/take as ammo depletion" flag is set
|
||||
// and infinite ammo is on
|
||||
if (flags & TIF_NOTAKEINFINITE &&
|
||||
((dmflags & DF_INFINITE_AMMO) || (receiver->player->cheats & CF_INFINITEAMMO)) &&
|
||||
inv->IsKindOf(RUNTIME_CLASS(AAmmo)))
|
||||
{
|
||||
if (inv->ItemFlags & IF_KEEPDEPLETED)
|
||||
inv->Amount = 0;
|
||||
else
|
||||
inv->Destroy();
|
||||
// Nothing to do here, except maybe res = false;? Would it make sense?
|
||||
}
|
||||
else if (!amount || amount>=inv->Amount)
|
||||
{
|
||||
if (inv->ItemFlags&IF_KEEPDEPLETED) inv->Amount=0;
|
||||
else inv->Destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1833,6 +1973,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print)
|
|||
C_MidPrint(font != NULL ? font : SmallFont, formatted.GetChars());
|
||||
con_midtime = saved;
|
||||
}
|
||||
ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1863,6 +2004,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold)
|
|||
FString formatted = strbin1(text);
|
||||
C_MidPrintBold(font != NULL ? font : SmallFont, formatted.GetChars());
|
||||
con_midtime = saved;
|
||||
ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1877,6 +2019,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log)
|
|||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_STRING(text);
|
||||
Printf("%s\n", text);
|
||||
ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1891,6 +2034,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt)
|
|||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_INT(num);
|
||||
Printf("%d\n", num);
|
||||
ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains!
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1926,10 +2070,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn)
|
|||
PARAM_FIXED_OPT(reduce) { reduce = FRACUNIT/10; }
|
||||
|
||||
if (reduce == 0)
|
||||
{
|
||||
reduce = FRACUNIT/10;
|
||||
|
||||
}
|
||||
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
|
||||
self->alpha += reduce;
|
||||
// Should this clamp alpha to 1.0?
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1947,12 +2093,57 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut)
|
|||
PARAM_BOOL_OPT(remove) { remove = true; }
|
||||
|
||||
if (reduce == 0)
|
||||
{
|
||||
reduce = FRACUNIT/10;
|
||||
|
||||
}
|
||||
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
|
||||
self->alpha -= reduce;
|
||||
if (self->alpha<=0 && remove)
|
||||
if (self->alpha <= 0 && remove)
|
||||
{
|
||||
self->Destroy();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_FadeTo
|
||||
//
|
||||
// fades the actor to a specified transparency by a specified amount and
|
||||
// destroys it if so desired
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_FIXED (target);
|
||||
PARAM_FIXED_OPT (amount) { amount = fixed_t(0.1*FRACUNIT); }
|
||||
PARAM_BOOL_OPT (remove) { remove = false; }
|
||||
|
||||
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
|
||||
|
||||
if (self->alpha > target)
|
||||
{
|
||||
self->alpha -= amount;
|
||||
|
||||
if (self->alpha < target)
|
||||
{
|
||||
self->alpha = target;
|
||||
}
|
||||
}
|
||||
else if (self->alpha < target)
|
||||
{
|
||||
self->alpha += amount;
|
||||
|
||||
if (self->alpha > target)
|
||||
{
|
||||
self->alpha = target;
|
||||
}
|
||||
}
|
||||
if (self->alpha == target && remove)
|
||||
{
|
||||
self->Destroy();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2256,49 +2447,51 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst)
|
|||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_CLASS(chunk, AActor);
|
||||
|
||||
int i, numChunks;
|
||||
AActor *mo;
|
||||
int i, numChunks;
|
||||
AActor * mo;
|
||||
|
||||
if (chunk == NULL)
|
||||
return 0;
|
||||
if (chunk == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->velx = self->vely = self->velz = 0;
|
||||
self->height = self->GetDefault()->height;
|
||||
self->velx = self->vely = self->velz = 0;
|
||||
self->height = self->GetDefault()->height;
|
||||
|
||||
// [RH] In Hexen, this creates a random number of shards (range [24,56])
|
||||
// with no relation to the size of the self shattering. I think it should
|
||||
// base the number of shards on the size of the dead thing, so bigger
|
||||
// things break up into more shards than smaller things.
|
||||
// An self with radius 20 and height 64 creates ~40 chunks.
|
||||
numChunks = MAX<int> (4, (self->radius>>FRACBITS)*(self->height>>FRACBITS)/32);
|
||||
i = (pr_burst.Random2()) % (numChunks/4);
|
||||
for (i = MAX (24, numChunks + i); i >= 0; i--)
|
||||
{
|
||||
mo = Spawn(chunk,
|
||||
self->x + (((pr_burst()-128)*self->radius)>>7),
|
||||
self->y + (((pr_burst()-128)*self->radius)>>7),
|
||||
self->z + (pr_burst()*self->height/255), ALLOW_REPLACE);
|
||||
// [RH] In Hexen, this creates a random number of shards (range [24,56])
|
||||
// with no relation to the size of the self shattering. I think it should
|
||||
// base the number of shards on the size of the dead thing, so bigger
|
||||
// things break up into more shards than smaller things.
|
||||
// An self with radius 20 and height 64 creates ~40 chunks.
|
||||
numChunks = MAX<int> (4, (self->radius>>FRACBITS)*(self->height>>FRACBITS)/32);
|
||||
i = (pr_burst.Random2()) % (numChunks/4);
|
||||
for (i = MAX (24, numChunks + i); i >= 0; i--)
|
||||
{
|
||||
mo = Spawn(chunk,
|
||||
self->x + (((pr_burst()-128)*self->radius)>>7),
|
||||
self->y + (((pr_burst()-128)*self->radius)>>7),
|
||||
self->z + (pr_burst()*self->height/255), ALLOW_REPLACE);
|
||||
|
||||
if (mo)
|
||||
{
|
||||
mo->velz = FixedDiv(mo->z - self->z, self->height)<<2;
|
||||
mo->velx = pr_burst.Random2 () << (FRACBITS-7);
|
||||
mo->vely = pr_burst.Random2 () << (FRACBITS-7);
|
||||
mo->RenderStyle = self->RenderStyle;
|
||||
mo->alpha = self->alpha;
|
||||
mo->CopyFriendliness(self, true);
|
||||
}
|
||||
}
|
||||
if (mo)
|
||||
{
|
||||
mo->velz = FixedDiv(mo->z - self->z, self->height)<<2;
|
||||
mo->velx = pr_burst.Random2 () << (FRACBITS-7);
|
||||
mo->vely = pr_burst.Random2 () << (FRACBITS-7);
|
||||
mo->RenderStyle = self->RenderStyle;
|
||||
mo->alpha = self->alpha;
|
||||
mo->CopyFriendliness(self, true);
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Do some stuff to make this more useful outside Hexen
|
||||
if (self->flags4 & MF4_BOSSDEATH)
|
||||
{
|
||||
// [RH] Do some stuff to make this more useful outside Hexen
|
||||
if (self->flags4 & MF4_BOSSDEATH)
|
||||
{
|
||||
CALL_ACTION(A_BossDeath, self);
|
||||
}
|
||||
CALL_ACTION(A_NoBlocking, self);
|
||||
}
|
||||
A_Unblock(self, true);
|
||||
|
||||
self->Destroy();
|
||||
return 0;
|
||||
self->Destroy ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
@ -2508,23 +2701,38 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_JumpIfTargetInLOS (state label, optional fixed fov, optional bool
|
||||
// projectiletarget)
|
||||
// A_JumpIfTargetInLOS (state label, optional fixed fov, optional int flags,
|
||||
// optional fixed dist_max, optional fixed dist_close)
|
||||
//
|
||||
// Jumps if the actor can see its target, or if the player has a linetarget.
|
||||
// ProjectileTarget affects how projectiles are treated. If set, it will use
|
||||
// the target of the projectile for seekers, and ignore the target for
|
||||
// normal projectiles. If not set, it will use the missile's owner instead
|
||||
// (the default).
|
||||
// (the default). ProjectileTarget is now flag JLOSF_PROJECTILE. dist_max
|
||||
// sets the maximum distance that actor can see, 0 means forever. dist_close
|
||||
// uses special behavior if certain flags are set, 0 means no checks.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum JLOS_flags
|
||||
{
|
||||
JLOSF_PROJECTILE=1,
|
||||
JLOSF_NOSIGHT=2,
|
||||
JLOSF_CLOSENOFOV=4,
|
||||
JLOSF_CLOSENOSIGHT=8,
|
||||
JLOSF_CLOSENOJUMP=16,
|
||||
JLOSF_DEADNOJUMP=32,
|
||||
JLOSF_CHECKMASTER=64,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_STATE (jump);
|
||||
PARAM_ANGLE_OPT (fov) { fov = 0; }
|
||||
PARAM_BOOL_OPT (projtarg) { projtarg = false; }
|
||||
PARAM_ANGLE_OPT (fov) { fov = 0; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_FIXED_OPT (dist_max) { dist_max = 0; }
|
||||
PARAM_FIXED_OPT (dist_close) { dist_close = 0; }
|
||||
|
||||
angle_t an;
|
||||
AActor *target;
|
||||
|
|
@ -2533,7 +2741,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
|
|||
|
||||
if (!self->player)
|
||||
{
|
||||
if (self->flags & MF_MISSILE && projtarg)
|
||||
if (flags & JLOSF_CHECKMASTER)
|
||||
{
|
||||
target = self->master;
|
||||
}
|
||||
else if (self->flags & MF_MISSILE && (flags & JLOSF_PROJECTILE))
|
||||
{
|
||||
if (self->flags2 & MF2_SEEKERMISSILE)
|
||||
target = self->tracer;
|
||||
|
|
@ -2548,7 +2760,34 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
|
|||
if (target == NULL)
|
||||
return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case.
|
||||
|
||||
if (!P_CheckSight (self, target, SF_IGNOREVISIBILITY))
|
||||
if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y);
|
||||
distance = P_AproxDistance(distance, target->z - self->z);
|
||||
|
||||
if (dist_max && (distance > dist_max))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool doCheckSight = !(flags & JLOSF_NOSIGHT);
|
||||
|
||||
if (dist_close && (distance < dist_close))
|
||||
{
|
||||
if (flags & JLOSF_CLOSENOJUMP)
|
||||
return 0;
|
||||
|
||||
if (flags & JLOSF_CLOSENOFOV)
|
||||
fov = 0;
|
||||
|
||||
if (flags & JLOSF_CLOSENOSIGHT)
|
||||
doCheckSight = false;
|
||||
}
|
||||
|
||||
if (doCheckSight && !P_CheckSight (self, target, SF_IGNOREVISIBILITY))
|
||||
return 0;
|
||||
|
||||
if (fov && (fov < ANGLE_MAX))
|
||||
|
|
@ -2566,10 +2805,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
|
|||
{
|
||||
// Does the player aim at something that can be shot?
|
||||
P_BulletSlope(self, &target);
|
||||
}
|
||||
|
||||
if (target == NULL)
|
||||
return 0;
|
||||
if (target == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y);
|
||||
distance = P_AproxDistance(distance, target->z - self->z);
|
||||
|
||||
if (dist_max && (distance > dist_max))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (dist_close && (distance < dist_close))
|
||||
{
|
||||
if (flags & JLOSF_CLOSENOJUMP)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_JUMP(jump);
|
||||
return 0;
|
||||
|
|
@ -2578,8 +2832,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// A_JumpIfInTargetLOS (state label, optional fixed fov, optional bool
|
||||
// projectiletarget)
|
||||
// A_JumpIfInTargetLOS (state label, optional fixed fov, optional int flags
|
||||
// optional fixed dist_max, optional fixed dist_close)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
|
@ -2587,15 +2841,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
|
|||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_STATE (jump);
|
||||
PARAM_ANGLE_OPT (fov) { fov = 0; }
|
||||
PARAM_BOOL_OPT (projtarg) { projtarg = false; }
|
||||
PARAM_ANGLE_OPT (fov) { fov = 0; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_FIXED_OPT (dist_max) { dist_max = 0; }
|
||||
PARAM_FIXED_OPT (dist_close) { dist_close = 0; }
|
||||
|
||||
angle_t an;
|
||||
AActor *target;
|
||||
|
||||
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
|
||||
|
||||
if (self->flags & MF_MISSILE && projtarg)
|
||||
if (flags & JLOSF_CHECKMASTER)
|
||||
{
|
||||
target = self->master;
|
||||
}
|
||||
else if (self->flags & MF_MISSILE && (flags & JLOSF_PROJECTILE))
|
||||
{
|
||||
if (self->flags2 & MF2_SEEKERMISSILE)
|
||||
target = self->tracer;
|
||||
|
|
@ -2608,9 +2868,38 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
|
|||
}
|
||||
|
||||
if (target == NULL)
|
||||
return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case.
|
||||
{ // [KS] Let's not call P_CheckSight unnecessarily in this case.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!P_CheckSight (target, self, SF_IGNOREVISIBILITY))
|
||||
if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y);
|
||||
distance = P_AproxDistance(distance, target->z - self->z);
|
||||
|
||||
if (dist_max && (distance > dist_max))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool doCheckSight = !(flags & JLOSF_NOSIGHT);
|
||||
|
||||
if (dist_close && (distance < dist_close))
|
||||
{
|
||||
if (flags & JLOSF_CLOSENOJUMP)
|
||||
return 0;
|
||||
|
||||
if (flags & JLOSF_CLOSENOFOV)
|
||||
fov = 0;
|
||||
|
||||
if (flags & JLOSF_CLOSENOSIGHT)
|
||||
doCheckSight = false;
|
||||
}
|
||||
|
||||
if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY))
|
||||
return 0;
|
||||
|
||||
if (fov && (fov < ANGLE_MAX))
|
||||
|
|
@ -3187,16 +3476,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar)
|
|||
PARAM_NAME (varname);
|
||||
PARAM_INT (value);
|
||||
|
||||
PSymbolVariable *var = dyn_cast<PSymbolVariable>(stateowner->GetClass()->Symbols.FindSymbol(varname, true));
|
||||
PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true));
|
||||
|
||||
if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int)
|
||||
{
|
||||
Printf("%s is not a user variable in class %s\n", varname.GetChars(),
|
||||
stateowner->GetClass()->TypeName.GetChars());
|
||||
self->GetClass()->TypeName.GetChars());
|
||||
return 0;
|
||||
}
|
||||
// Set the value of the specified user variable.
|
||||
*(int *)(reinterpret_cast<BYTE *>(stateowner) + var->offset) = value;
|
||||
*(int *)(reinterpret_cast<BYTE *>(self) + var->offset) = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3213,22 +3502,119 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray)
|
|||
PARAM_INT (pos);
|
||||
PARAM_INT (value);
|
||||
|
||||
PSymbolVariable *var = dyn_cast<PSymbolVariable>(stateowner->GetClass()->Symbols.FindSymbol(varname, true));
|
||||
PSymbolVariable *var = dyn_cast<PSymbolVariable>(self->GetClass()->Symbols.FindSymbol(varname, true));
|
||||
|
||||
if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int)
|
||||
{
|
||||
Printf("%s is not a user array in class %s\n", varname.GetChars(),
|
||||
stateowner->GetClass()->TypeName.GetChars());
|
||||
self->GetClass()->TypeName.GetChars());
|
||||
return 0;
|
||||
}
|
||||
if (pos < 0 || pos >= var->ValueType.size)
|
||||
{
|
||||
Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(),
|
||||
stateowner->GetClass()->TypeName.GetChars());
|
||||
self->GetClass()->TypeName.GetChars());
|
||||
return 0;
|
||||
}
|
||||
// Set the value of the specified user array at index pos.
|
||||
((int *)(reinterpret_cast<BYTE *>(stateowner) + var->offset))[pos] = value;
|
||||
((int *)(reinterpret_cast<BYTE *>(self) + var->offset))[pos] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_Teleport(optional state teleportstate, optional class targettype,
|
||||
// optional class fogtype, optional int flags, optional fixed mindist,
|
||||
// optional fixed maxdist)
|
||||
//
|
||||
// Attempts to teleport to a targettype at least mindist away and at most
|
||||
// maxdist away (0 means unlimited). If successful, spawn a fogtype at old
|
||||
// location and place calling actor in teleportstate.
|
||||
//
|
||||
//===========================================================================
|
||||
enum T_Flags
|
||||
{
|
||||
TF_TELEFRAG = 1, // Allow telefrag in order to teleport.
|
||||
TF_RANDOMDECIDE = 2, // Randomly fail based on health. (A_Srcr2Decide)
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
PARAM_STATE_OPT (teleport_state) { teleport_state = NULL; }
|
||||
PARAM_CLASS_OPT (target_type, ASpecialSpot) { target_type = PClass::FindActor("BossSpot"); }
|
||||
PARAM_CLASS_OPT (fog_type, AActor) { fog_type = PClass::FindActor("TeleportFog"); }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_FIXED_OPT (mindist) { mindist = 128 << FRACBITS; }
|
||||
PARAM_FIXED_OPT (maxdist) { maxdist = 128 << FRACBITS; }
|
||||
|
||||
// Randomly choose not to teleport like A_Srcr2Decide.
|
||||
if (flags & TF_RANDOMDECIDE)
|
||||
{
|
||||
static const int chance[] =
|
||||
{
|
||||
192, 120, 120, 120, 64, 64, 32, 16, 0
|
||||
};
|
||||
|
||||
unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8);
|
||||
|
||||
if (chanceindex >= countof(chance))
|
||||
{
|
||||
chanceindex = countof(chance) - 1;
|
||||
}
|
||||
|
||||
if (pr_teleport() >= chance[chanceindex])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (teleport_state == NULL)
|
||||
{
|
||||
// Default to Teleport.
|
||||
teleport_state = self->FindState("Teleport");
|
||||
// If still nothing, then return.
|
||||
if (teleport_state == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DSpotState *state = DSpotState::GetSpotState();
|
||||
if (state == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (target_type == NULL)
|
||||
{
|
||||
target_type = PClass::FindActor("BossSpot");
|
||||
}
|
||||
|
||||
AActor *spot = state->GetSpotWithMinMaxDistance(target_type, self->x, self->y, mindist, maxdist);
|
||||
if (spot == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixed_t prevX = self->x;
|
||||
fixed_t prevY = self->y;
|
||||
fixed_t prevZ = self->z;
|
||||
if (P_TeleportMove (self, spot->x, spot->y, spot->z, flags & TF_TELEFRAG))
|
||||
{
|
||||
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
|
||||
|
||||
if (fog_type != NULL)
|
||||
{
|
||||
Spawn(fog_type, prevX, prevY, prevZ, ALLOW_REPLACE);
|
||||
}
|
||||
|
||||
ACTION_JUMP(teleport_state);
|
||||
|
||||
self->z = self->floorz;
|
||||
self->angle = spot->angle;
|
||||
self->velx = self->vely = self->velz = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue