- Updated scripting branch to latest version in trunk.

SVN r4337 (scripting)
This commit is contained in:
Randy Heit 2013-06-07 03:31:30 +00:00
commit 459ad5abff
282 changed files with 15968 additions and 3535 deletions

View file

@ -68,6 +68,8 @@
#include "g_shared/a_specialspot.h"
#include "actorptrselect.h"
#include "m_bbox.h"
#include "r_data/r_translate.h"
#include "p_trace.h"
static FRandom pr_camissile ("CustomActorfire");
@ -349,8 +351,8 @@ static void DoAttack (AActor *self, bool domelee, bool domissile,
{
int damage = pr_camelee.HitDice(MeleeDamage);
if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM);
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (damage, self->target, self);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
else if (domissile && MissileType != NULL)
{
@ -366,7 +368,7 @@ static void DoAttack (AActor *self, bool domelee, bool domissile,
{
missile->tracer=self->target;
}
P_CheckMissileSpawn(missile);
P_CheckMissileSpawn(missile, self->radius);
}
}
}
@ -919,8 +921,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust)
bool sourcenothrust = false;
if (force <= 0) force = 128;
if (distance <= 0) distance = force;
if (force == 0) force = 128;
if (distance <= 0) distance = abs(force);
// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
if (!(flags & RTF_NOTMISSILE) && self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST)
@ -928,7 +930,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust)
sourcenothrust = true;
self->target->flags2 &= ~MF2_NODMGTHRUST;
}
int sourceflags2 = self->target != NULL ? self->target->flags2 : 0;
P_RadiusAttack (self, self->target, force, distance, self->DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
P_CheckSplash(self, distance << FRACBITS);
@ -1104,7 +1105,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile)
missile->FriendPlayer = 0;
}
}
P_CheckMissileSpawn(missile);
P_CheckMissileSpawn(missile, self->radius);
}
}
}
@ -1128,6 +1129,7 @@ enum CBA_Flags
CBAF_NORANDOM = 2,
CBAF_EXPLICITANGLE = 4,
CBAF_NOPITCH = 8,
CBAF_NORANDOMPUFFZ = 16,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
@ -1147,6 +1149,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
int i;
int bangle;
int bslope = 0;
int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0;
if (self->target || (flags & CBAF_AIMFACING))
{
@ -1177,7 +1180,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
if (!(flags & CBAF_NORANDOM))
damage *= ((pr_cabullet()%3)+1);
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype);
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
}
}
return 0;
@ -1208,9 +1211,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack)
{
if (meleesound)
S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM);
P_DamageMobj (self->target, self, self, damage, damagetype);
int newdam = P_DamageMobj (self->target, self, self, damage, damagetype);
if (bleed)
P_TraceBleed (damage, self->target, self);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
else
{
@ -1245,9 +1248,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack)
damagetype = NAME_Melee; // Melee is the default type
if (meleesound)
S_Sound (self, CHAN_WEAPON, meleesound, 1, ATTN_NORM);
P_DamageMobj (self->target, self, self, damage, damagetype);
int newdam = P_DamageMobj (self->target, self, self, damage, damagetype);
if (bleed)
P_TraceBleed (damage, self->target, self);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
else if (ti)
{
@ -1263,7 +1266,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack)
{
missile->tracer = self->target;
}
P_CheckMissileSpawn(missile);
P_CheckMissileSpawn(missile, self->radius);
}
}
return 0;
@ -1303,6 +1306,7 @@ enum FB_Flags
FBF_EXPLICITANGLE = 4,
FBF_NOPITCH = 8,
FBF_NOFLASH = 16,
FBF_NORANDOMPUFFZ = 32,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
@ -1324,6 +1328,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
int i;
int bangle;
int bslope = 0;
int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0;
if ((flags & FBF_USEAMMO) && weapon)
{
@ -1342,7 +1347,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
if (pufftype == NULL)
pufftype = PClass::FindActor(NAME_BulletPuff);
S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM);
if (weapon != NULL)
{
S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM);
}
if ((numbullets == 1 && !player->refire) || numbullets == 0)
{
@ -1351,7 +1359,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
if (!(flags & FBF_NORANDOM))
damage *= ((pr_cwbullet()%3)+1);
P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype);
P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
}
else
{
@ -1378,7 +1386,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
if (!(flags & FBF_NORANDOM))
damage *= ((pr_cwbullet()%3)+1);
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype);
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
}
}
return 0;
@ -1464,6 +1472,7 @@ enum
CPF_USEAMMO = 1,
CPF_DAGGER = 2,
CPF_PULLIN = 4,
CPF_NORANDOMPUFFZ = 8,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
@ -1504,8 +1513,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
if (pufftype == NULL)
pufftype = PClass::FindActor(NAME_BulletPuff);
int puffFlags = LAF_ISMELEEATTACK | (flags & CPF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0;
P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, true, &linetarget);
P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &linetarget);
// turn to face target
if (linetarget)
@ -1513,7 +1523,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
if (lifesteal)
P_GiveBody (self, (damage * lifesteal) >> FRACBITS);
S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM);
if (weapon != NULL)
{
S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM);
}
self->angle = R_PointToAngle2 (self->x, self->y, linetarget->x, linetarget->y);
@ -1548,6 +1561,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
PARAM_FLOAT_OPT (sparsity) { sparsity = 1; }
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; }
if (range == 0) range = 8192*FRACUNIT;
if (sparsity == 0) sparsity=1.0;
@ -1578,7 +1592,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
slope = pr_crailgun.Random2() * (spread_z / 255);
}
P_RailAttack (self, damage, spawnofs_xy, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass);
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass);
return 0;
}
@ -1613,6 +1627,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
PARAM_FLOAT_OPT (sparsity) { sparsity = 1; }
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; }
if (range == 0) range = 8192*FRACUNIT;
if (sparsity == 0) sparsity = 1;
@ -1696,7 +1711,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
slopeoffset = pr_crailgun.Random2() * (spread_z / 255);
}
P_RailAttack (self, damage, spawnofs_xy, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass);
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass);
self->x = saved_x;
self->y = saved_y;
@ -1854,92 +1869,139 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget)
// Common code for A_SpawnItem and A_SpawnItemEx
//
//===========================================================================
enum SIX_Flags
{
SIXF_TRANSFERTRANSLATION=1,
SIXF_ABSOLUTEPOSITION=2,
SIXF_ABSOLUTEANGLE=4,
SIXF_ABSOLUTEVELOCITY=8,
SIXF_SETMASTER=16,
SIXF_NOCHECKPOSITION=32,
SIXF_TELEFRAG=64,
// 128 is used by Skulltag!
SIXF_TRANSFERAMBUSHFLAG=256,
SIXF_TRANSFERPITCH=512,
SIXF_TRANSFERPOINTERS=1024,
SIXF_TRANSFERTRANSLATION = 1 << 0,
SIXF_ABSOLUTEPOSITION = 1 << 1,
SIXF_ABSOLUTEANGLE = 1 << 2,
SIXF_ABSOLUTEVELOCITY = 1 << 3,
SIXF_SETMASTER = 1 << 4,
SIXF_NOCHECKPOSITION = 1 << 5,
SIXF_TELEFRAG = 1 << 6,
SIXF_CLIENTSIDE = 1 << 7, // only used by Skulldronum
SIXF_TRANSFERAMBUSHFLAG = 1 << 8,
SIXF_TRANSFERPITCH = 1 << 9,
SIXF_TRANSFERPOINTERS = 1 << 10,
SIXF_USEBLOODCOLOR = 1 << 11,
SIXF_CLEARCALLERTID = 1 << 12,
SIXF_MULTIPLYSPEED = 1 << 13,
SIXF_TRANSFERSCALE = 1 << 14,
SIXF_TRANSFERSPECIAL = 1 << 15,
SIXF_CLEARCALLERSPECIAL = 1 << 16,
};
static bool InitSpawnedItem(AActor *self, AActor *mo, int flags)
{
if (mo)
if (mo == NULL)
{
AActor * originator = self;
return false;
}
AActor *originator = self;
if ((flags & SIXF_TRANSFERTRANSLATION) && !(mo->flags2 & MF2_DONTTRANSLATE))
if (!(mo->flags2 & MF2_DONTTRANSLATE))
{
if (flags & SIXF_TRANSFERTRANSLATION)
{
mo->Translation = self->Translation;
}
if (flags & SIXF_TRANSFERPOINTERS)
else if (flags & SIXF_USEBLOODCOLOR)
{
mo->target = self->target;
mo->master = self->master; // This will be overridden later if SIXF_SETMASTER is set
mo->tracer = self->tracer;
// [XA] Use the spawning actor's BloodColor to translate the newly-spawned object.
PalEntry bloodcolor = self->GetBloodColor();
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
}
}
if (flags & SIXF_TRANSFERPOINTERS)
{
mo->target = self->target;
mo->master = self->master; // This will be overridden later if SIXF_SETMASTER is set
mo->tracer = self->tracer;
}
mo->angle=self->angle;
if (flags & SIXF_TRANSFERPITCH) mo->pitch = self->pitch;
while (originator && originator->isMissile()) originator = originator->target;
mo->angle = self->angle;
if (flags & SIXF_TRANSFERPITCH)
{
mo->pitch = self->pitch;
}
while (originator && originator->isMissile())
{
originator = originator->target;
}
if (flags & SIXF_TELEFRAG)
if (flags & SIXF_TELEFRAG)
{
P_TeleportMove(mo, mo->x, mo->y, mo->z, true);
// This is needed to ensure consistent behavior.
// Otherwise it will only spawn if nothing gets telefragged
flags |= SIXF_NOCHECKPOSITION;
}
if (mo->flags3 & MF3_ISMONSTER)
{
if (!(flags & SIXF_NOCHECKPOSITION) && !P_TestMobjLocation(mo))
{
P_TeleportMove(mo, mo->x, mo->y, mo->z, true);
// This is needed to ensure consistent behavior.
// Otherwise it will only spawn if nothing gets telefragged
flags |= SIXF_NOCHECKPOSITION;
// The monster is blocked so don't spawn it at all!
mo->ClearCounters();
mo->Destroy();
return false;
}
if (mo->flags3&MF3_ISMONSTER)
else if (originator)
{
if (!(flags&SIXF_NOCHECKPOSITION) && !P_TestMobjLocation(mo))
if (originator->flags3 & MF3_ISMONSTER)
{
// The monster is blocked so don't spawn it at all!
mo->ClearCounters();
mo->Destroy();
return false;
// If this is a monster transfer all friendliness information
mo->CopyFriendliness(originator, true);
if (flags & SIXF_SETMASTER) mo->master = originator; // don't let it attack you (optional)!
}
else if (originator)
else if (originator->player)
{
if (originator->flags3&MF3_ISMONSTER)
{
// If this is a monster transfer all friendliness information
mo->CopyFriendliness(originator, true);
if (flags&SIXF_SETMASTER) mo->master = originator; // don't let it attack you (optional)!
}
else if (originator->player)
{
// A player always spawns a monster friendly to him
mo->flags |= MF_FRIENDLY;
mo->SetFriendPlayer(originator->player);
// A player always spawns a monster friendly to him
mo->flags |= MF_FRIENDLY;
mo->SetFriendPlayer(originator->player);
AActor * attacker=originator->player->attacker;
if (attacker)
AActor * attacker=originator->player->attacker;
if (attacker)
{
if (!(attacker->flags&MF_FRIENDLY) ||
(deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer))
{
if (!(attacker->flags&MF_FRIENDLY) ||
(deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer))
{
// Target the monster which last attacked the player
mo->LastHeard = mo->target = attacker;
}
// Target the monster which last attacked the player
mo->LastHeard = mo->target = attacker;
}
}
}
}
else if (!(flags & SIXF_TRANSFERPOINTERS))
{
// If this is a missile or something else set the target to the originator
mo->target=originator? originator : self;
}
}
else if (!(flags & SIXF_TRANSFERPOINTERS))
{
// If this is a missile or something else set the target to the originator
mo->target = originator ? originator : self;
}
if (flags & SIXF_TRANSFERSCALE)
{
mo->scaleX = self->scaleX;
mo->scaleY = self->scaleY;
}
if (flags & SIXF_TRANSFERAMBUSHFLAG)
{
mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH);
}
if (flags & SIXF_CLEARCALLERTID)
{
self->RemoveFromHash();
self->tid = 0;
}
if (flags & SIXF_TRANSFERSPECIAL)
{
mo->special = self->special;
memcpy(mo->args, self->args, sizeof(self->args));
}
if (flags & SIXF_CLEARCALLERSPECIAL)
{
self->special = 0;
memset(self->args, 0, sizeof(self->args));
}
return true;
}
@ -2021,6 +2083,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx)
PARAM_ANGLE_OPT (angle) { angle = 0; }
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_INT_OPT (chance) { chance = 0; }
PARAM_INT_OPT (tid) { tid = 0; }
if (missile == NULL)
{
@ -2066,17 +2129,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx)
xvel = newxvel;
}
AActor * mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE);
AActor *mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE);
bool res = InitSpawnedItem(self, mo, flags);
ACTION_SET_RESULT(res); // for an inventory item's use state
if (mo)
if (res)
{
mo->velx = xvel;
mo->vely = yvel;
mo->velz = zvel;
if (tid != 0)
{
assert(mo->tid == 0);
mo->tid = tid;
mo->AddToHash();
}
if (flags & SIXF_MULTIPLYSPEED)
{
mo->velx = FixedMul(xvel, mo->Speed);
mo->vely = FixedMul(yvel, mo->Speed);
mo->velz = FixedMul(zvel, mo->Speed);
}
else
{
mo->velx = xvel;
mo->vely = yvel;
mo->velz = zvel;
}
mo->angle = angle;
if (flags & SIXF_TRANSFERAMBUSHFLAG)
mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH);
}
return numret;
}
@ -2146,8 +2222,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade)
bo->vely = xy_vely + z_vely + (self->vely >> 1);
bo->velz = xy_velz + z_velz;
bo->target= self;
P_CheckMissileSpawn (bo);
bo->target = self;
P_CheckMissileSpawn (bo, self->radius);
}
else
{
@ -2476,15 +2552,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris)
for (i = 0; i < GetDefaultByType(debris)->health; i++)
{
mo = Spawn(debris, self->x+((pr_spawndebris()-128)<<12),
self->y+((pr_spawndebris()-128)<<12),
self->z+(pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE);
if (mo && transfer_translation)
self->y + ((pr_spawndebris()-128)<<12),
self->z + (pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE);
if (mo)
{
mo->Translation = self->Translation;
}
if (mo && i < mo->GetClass()->NumOwnedStates)
{
mo->SetState (mo->GetClass()->OwnedStates + i);
if (transfer_translation)
{
mo->Translation = self->Translation;
}
if (i < mo->GetClass()->NumOwnedStates)
{
mo->SetState (mo->GetClass()->OwnedStates + i);
}
mo->velz = FixedMul(mult_v, ((pr_spawndebris()&7)+5)*FRACUNIT);
mo->velx = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6));
mo->vely = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6));
@ -2722,11 +2801,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings)
TThinkerIterator<AActor> it;
AActor *mo;
while ( (mo = it.Next()) )
if (self->master != NULL)
{
if (mo->master == self->master && mo != self)
while ( (mo = it.Next()) )
{
P_DamageMobj(mo, self, self, mo->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR);
if (mo->master == self->master && mo != self)
{
P_DamageMobj(mo, self, self, mo->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR);
}
}
}
return 0;
@ -3002,7 +3084,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck)
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
if (self->player != NULL &&
skins[self->player->userinfo.skin].othergame)
skins[self->player->userinfo.GetSkin()].othergame)
{
ACTION_JUMP(jump);
}
@ -3041,6 +3123,295 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget)
return 0;
}
//==========================================================================
//
// A_CheckLOF (state jump, int flags = CRF_AIM_VERT|CRF_AIM_HOR,
// fixed range = 0, angle angle = 0, angle pitch = 0,
// fixed offsetheight = 32, fixed offsetwidth = 0,
// int ptr_target = AAPTR_DEFAULT (target) )
//
//==========================================================================
enum CLOF_flags
{
CLOFF_NOAIM_VERT = 0x1,
CLOFF_NOAIM_HORZ = 0x2,
CLOFF_JUMPENEMY = 0x4,
CLOFF_JUMPFRIEND = 0x8,
CLOFF_JUMPOBJECT = 0x10,
CLOFF_JUMPNONHOSTILE = 0x20,
CLOFF_SKIPENEMY = 0x40,
CLOFF_SKIPFRIEND = 0x80,
CLOFF_SKIPOBJECT = 0x100,
CLOFF_SKIPNONHOSTILE = 0x200,
CLOFF_MUSTBESHOOTABLE = 0x400,
CLOFF_SKIPTARGET = 0x800,
CLOFF_ALLOWNULL = 0x1000,
CLOFF_CHECKPARTIAL = 0x2000,
CLOFF_MUSTBEGHOST = 0x4000,
CLOFF_IGNOREGHOST = 0x8000,
CLOFF_MUSTBESOLID = 0x10000,
CLOFF_BEYONDTARGET = 0x20000,
CLOFF_FROMBASE = 0x40000,
CLOFF_MUL_HEIGHT = 0x80000,
CLOFF_MUL_WIDTH = 0x100000,
CLOFF_JUMP_ON_MISS = 0x200000,
CLOFF_AIM_VERT_NOOFFSET = 0x400000,
};
struct LOFData
{
AActor *Self;
AActor *Target;
int Flags;
bool BadActor;
};
ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata)
{
LOFData *data = (LOFData *)userdata;
int flags = data->Flags;
if (trace.HitType != TRACE_HitActor)
{
return TRACE_Stop;
}
if (trace.Actor == data->Target)
{
if (flags & CLOFF_SKIPTARGET)
{
if (flags & CLOFF_BEYONDTARGET)
{
return TRACE_Skip;
}
return TRACE_Abort;
}
return TRACE_Stop;
}
if (flags & CLOFF_MUSTBESHOOTABLE)
{ // all shootability checks go here
if (!(trace.Actor->flags & MF_SHOOTABLE))
{
return TRACE_Skip;
}
if (trace.Actor->flags2 & MF2_NONSHOOTABLE)
{
return TRACE_Skip;
}
}
if ((flags & CLOFF_MUSTBESOLID) && !(trace.Actor->flags & MF_SOLID))
{
return TRACE_Skip;
}
if (flags & CLOFF_MUSTBEGHOST)
{
if (!(trace.Actor->flags3 & MF3_GHOST))
{
return TRACE_Skip;
}
}
else if (flags & CLOFF_IGNOREGHOST)
{
if (trace.Actor->flags3 & MF3_GHOST)
{
return TRACE_Skip;
}
}
if (
((flags & CLOFF_JUMPENEMY) && data->Self->IsHostile(trace.Actor)) ||
((flags & CLOFF_JUMPFRIEND) && data->Self->IsFriend(trace.Actor)) ||
((flags & CLOFF_JUMPOBJECT) && !(trace.Actor->flags3 & MF3_ISMONSTER)) ||
((flags & CLOFF_JUMPNONHOSTILE) && (trace.Actor->flags3 & MF3_ISMONSTER) && !data->Self->IsHostile(trace.Actor))
)
{
return TRACE_Stop;
}
if (
((flags & CLOFF_SKIPENEMY) && data->Self->IsHostile(trace.Actor)) ||
((flags & CLOFF_SKIPFRIEND) && data->Self->IsFriend(trace.Actor)) ||
((flags & CLOFF_SKIPOBJECT) && !(trace.Actor->flags3 & MF3_ISMONSTER)) ||
((flags & CLOFF_SKIPNONHOSTILE) && (trace.Actor->flags3 & MF3_ISMONSTER) && !data->Self->IsHostile(trace.Actor))
)
{
return TRACE_Skip;
}
data->BadActor = true;
return TRACE_Abort;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
{
// Check line of fire
/*
Not accounted for / I don't know how it works: FLOORCLIP
*/
AActor *target;
fixed_t
x1, y1, z1,
vx, vy, vz;
PARAM_ACTION_PROLOGUE;
PARAM_STATE (jump);
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_FIXED_OPT (range) { range = 0; }
PARAM_FIXED_OPT (minrange) { minrange = 0; }
{
PARAM_ANGLE_OPT (angle) { angle = 0; }
PARAM_ANGLE_OPT (pitch) { pitch = 0; }
PARAM_FIXED_OPT (offsetheight) { offsetheight = 0; }
PARAM_FIXED_OPT (offsetwidth) { offsetwidth = 0; }
PARAM_INT_OPT (ptr_target) { ptr_target = AAPTR_DEFAULT; }
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
target = COPY_AAPTR(self, ptr_target == AAPTR_DEFAULT ? AAPTR_TARGET|AAPTR_PLAYER_GETTARGET|AAPTR_NULL : ptr_target); // no player-support by default
if (flags & CLOFF_MUL_HEIGHT)
{
if (self->player != NULL)
{
// Synced with hitscan: self->player->mo->height is strangely conscientious about getting the right actor for player
offsetheight = FixedMul(offsetheight, FixedMul (self->player->mo->height, self->player->crouchfactor));
}
else
{
offsetheight = FixedMul(offsetheight, self->height);
}
}
if (flags & CLOFF_MUL_WIDTH)
{
offsetwidth = FixedMul(self->radius, offsetwidth);
}
x1 = self->x;
y1 = self->y;
z1 = self->z + offsetheight - self->floorclip;
if (!(flags & CLOFF_FROMBASE))
{ // default to hitscan origin
// Synced with hitscan: self->height is strangely NON-conscientious about getting the right actor for player
z1 += (self->height >> 1);
if (self->player != NULL)
{
z1 += FixedMul (self->player->mo->AttackZOffset, self->player->crouchfactor);
}
else
{
z1 += 8*FRACUNIT;
}
}
if (target)
{
FVector2 xyvec(target->x - x1, target->y - y1);
fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1);
if (range && !(flags & CLOFF_CHECKPARTIAL))
{
if (distance > range)
return numret;
}
{
angle_t ang;
if (flags & CLOFF_NOAIM_HORZ)
{
ang = self->angle;
}
else ang = R_PointToAngle2 (x1, y1, target->x, target->y);
angle += ang;
ang >>= ANGLETOFINESHIFT;
x1 += FixedMul(offsetwidth, finesine[ang]);
y1 -= FixedMul(offsetwidth, finecosine[ang]);
}
if (flags & CLOFF_NOAIM_VERT)
{
pitch += self->pitch;
}
else if (flags & CLOFF_AIM_VERT_NOOFFSET)
{
pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2);
}
else
{
pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2);
}
}
else if (flags & CLOFF_ALLOWNULL)
{
angle += self->angle;
pitch += self->pitch;
angle_t ang = self->angle >> ANGLETOFINESHIFT;
x1 += FixedMul(offsetwidth, finesine[ang]);
y1 -= FixedMul(offsetwidth, finecosine[ang]);
}
else
{
return numret;
}
angle >>= ANGLETOFINESHIFT;
pitch = (0-pitch)>>ANGLETOFINESHIFT;
vx = FixedMul (finecosine[pitch], finecosine[angle]);
vy = FixedMul (finecosine[pitch], finesine[angle]);
vz = -finesine[pitch];
}
/* Variable set:
jump, flags, target
x1,y1,z1 (trace point of origin)
vx,vy,vz (trace unit vector)
range
*/
sector_t *sec = P_PointInSector(x1, y1);
if (range == 0)
{
range = (self->player != NULL) ? PLAYERMISSILERANGE : MISSILERANGE;
}
FTraceResults trace;
LOFData lof_data;
lof_data.Self = self;
lof_data.Target = target;
lof_data.Flags = flags;
lof_data.BadActor = false;
Trace(x1, y1, z1, sec, vx, vy, vz, range, 0xFFFFFFFF, ML_BLOCKEVERYTHING, self, trace, 0,
CheckLOFTraceFunc, &lof_data);
if (trace.HitType == TRACE_HitActor ||
((flags & CLOFF_JUMP_ON_MISS) && !lof_data.BadActor && trace.HitType != TRACE_HitNone))
{
if (minrange > 0 && trace.Distance < minrange)
{
return numret;
}
ACTION_JUMP(jump);
}
return numret;
}
//==========================================================================
//
// A_JumpIfTargetInLOS (state label, optional fixed fov, optional int flags,
@ -3068,7 +3439,8 @@ enum JLOS_flags
JLOSF_TARGETLOS=128,
JLOSF_FLIPFOV=256,
JLOSF_ALLYNOJUMP=512,
JLOSF_COMBATANTONLY=1024
JLOSF_COMBATANTONLY=1024,
JLOSF_NOAUTOAIM=2048,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
@ -3118,7 +3490,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
else
{
// Does the player aim at something that can be shot?
P_BulletSlope(self, &target);
P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0);
if (!target) return numret;
@ -3366,18 +3738,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings)
TThinkerIterator<AActor> it;
AActor *mo;
while ( (mo = it.Next()) )
if (self->master != NULL)
{
if (mo->master == self->master && mo != self)
while ( (mo = it.Next()) )
{
if (amount > 0)
if (mo->master == self->master && mo != self)
{
P_DamageMobj(mo, self, self, amount, damagetype, DMG_NO_ARMOR);
}
else if (amount < 0)
{
amount = -amount;
P_GiveBody(mo, amount);
if (amount > 0)
{
P_DamageMobj(mo, self, self, amount, damagetype, DMG_NO_ARMOR);
}
else if (amount < 0)
{
amount = -amount;
P_GiveBody(mo, amount);
}
}
}
}
@ -3495,14 +3870,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR);
if (linkchange) self->UnlinkFromWorld();
if (value)
{
*flagp |= fd->flagbit;
}
else
{
*flagp &= ~fd->flagbit;
}
ModActorFlag(self, fd, value);
if (linkchange) self->LinkToWorld();
}
kill_after = self->CountsAsKill();
@ -3590,14 +3958,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag)
if (fd != NULL)
{
if (fd->structoffset == -1)
{
if (CheckDeprecatedFlags(owner, cls, fd->flagbit))
{
ACTION_JUMP(jumpto);
}
}
else if (fd->flagbit & *(DWORD*)(((char*)owner) + fd->structoffset))
if (CheckActorFlag(owner, fd))
{
ACTION_JUMP(jumpto);
}
@ -3638,9 +3999,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren)
TThinkerIterator<AActor> it;
AActor *mo;
while ( (mo = it.Next()) )
while ((mo = it.Next()) != NULL)
{
if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) )
if (mo->master == self && (mo->health <= 0 || removeall))
{
P_RemoveThing(mo);
}
@ -3661,11 +4022,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings)
TThinkerIterator<AActor> it;
AActor *mo;
while ( (mo = it.Next()) )
if (self->master != NULL)
{
if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) )
while ((mo = it.Next()) != NULL)
{
P_RemoveThing(mo);
if (mo->master == self->master && mo != self && (mo->health <= 0 || removeall))
{
P_RemoveThing(mo);
}
}
}
return 0;
@ -3698,9 +4062,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren)
TThinkerIterator<AActor> it;
AActor *mo;
while ((mo = it.Next()))
while ((mo = it.Next()) != NULL)
{
if ( mo->master == self )
if (mo->master == self)
{
P_Thing_Raise(mo);
}
@ -3720,11 +4084,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings)
TThinkerIterator<AActor> it;
AActor *mo;
while ( (mo = it.Next()) )
if (self->master != NULL)
{
if ( ( mo->master == self->master ) && ( mo != self ) )
while ((mo = it.Next()) != NULL)
{
P_Thing_Raise(mo);
if (mo->master == self->master && mo != self)
{
P_Thing_Raise(mo);
}
}
}
return 0;
@ -4323,11 +4690,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
damage >>= 2;
if (damage)
{
P_DamageMobj(self->target, self, self, damage, mod, DMG_THRUSTLESS);
int newdam = P_DamageMobj(self->target, self, self, damage, mod, DMG_THRUSTLESS);
if (spawnblood)
{
P_SpawnBlood(dx, dy, dz, angle, damage, self->target);
P_TraceBleed(damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0);
P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target);
P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0);
}
}
}
@ -4768,4 +5135,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics)
self->tics = tics_to_set;
return 0;
}
}
//==========================================================================
//
// A_SetDamageType
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType)
{
PARAM_ACTION_PROLOGUE;
PARAM_NAME(damagetype);
self->DamageType = damagetype;
return 0;
}