From e32e44209e0d25b33c849c3449a2b122fbb2c6bd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 5 Jun 2013 02:15:21 +0000 Subject: [PATCH] - Added SpawnDecal ACS function: int SpawnDecal(int tid, str decalname, int flags, fixed angle, int zoffset, int distance) Traces a line from tid's actor until hitting a wall, then creates a decal there. Returns the number of decals spawned. * tid = Which actor(s) to start the trace at. * decalname = Which decal to spawn. * flags = * SDF_ABSANGLE = Angle parameter is an absolute angle. Otherwise, it's relative to the origin actor's angle. * SDF_PERMANENT = Decal ignores cl_maxdecals. Otherwise, it will eventually disappear. * angle = Direction in which to search for a wall. Defaults to 0.0. * zoffset = Offset from the middle of the origin actor for the Z height of the decal. Defaults to 0. * distance = Maximum distance to search for a wall. Defaults to 64. SVN r4330 (trunk) --- src/g_shared/a_decals.cpp | 65 +++++++++++++++++++++++------------ src/g_shared/a_sharedglobal.h | 3 +- src/p_acs.cpp | 52 ++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 22f53eefa6..576ff6a5cd 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -755,6 +755,48 @@ CCMD (spray) Net_WriteString (argv[1]); } +DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixed_t tracedist, bool permanent) +{ + if (tpl == NULL || (tpl = tpl->GetDecal()) == NULL) + { + return NULL; + } + + FTraceResults trace; + DBaseDecal *decal; + side_t *wall; + + angle >>= ANGLETOFINESHIFT; + + Trace(x, y, z, sec, + finecosine[angle], finesine[angle], 0, + tracedist, 0, 0, NULL, trace, TRACE_NoSky); + + if (trace.HitType == TRACE_HitWall) + { + if (permanent) + { + decal = new DBaseDecal(trace.Z); + wall = trace.Line->sidedef[trace.Side]; + decal->StickToWall(wall, trace.X, trace.Y, trace.ffloor); + tpl->ApplyToDecal(decal, wall); + // Spread decal to nearby walls if it does not all fit on this one + if (cl_spreaddecals) + { + decal->Spread(tpl, wall, trace.X, trace.Y, trace.Z, trace.ffloor); + } + return decal; + } + else + { + return DImpactDecal::StaticCreate(tpl, + trace.X, trace.Y, trace.Z, + trace.Line->sidedef[trace.Side], NULL); + } + } + return NULL; +} + class ADecal : public AActor { DECLARE_CLASS (ADecal, AActor); @@ -767,9 +809,6 @@ IMPLEMENT_CLASS (ADecal) void ADecal::BeginPlay () { const FDecalTemplate *tpl; - FTraceResults trace; - DBaseDecal *decal; - side_t *wall; Super::BeginPlay (); @@ -781,31 +820,13 @@ void ADecal::BeginPlay () if (!tpl->PicNum.Exists()) { Printf("Decal actor at (%d,%d) does not have a valid texture\n", x>>FRACBITS, y>>FRACBITS); - } else { // Look for a wall within 64 units behind the actor. If none can be // found, then no decal is created, and this actor is destroyed // without effectively doing anything. - Trace (x, y, z, Sector, - finecosine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], - finesine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], 0, - 64*FRACUNIT, 0, 0, NULL, trace, TRACE_NoSky); - - if (trace.HitType == TRACE_HitWall) - { - decal = new DBaseDecal (this); - wall = trace.Line->sidedef[trace.Side]; - decal->StickToWall (wall, trace.X, trace.Y, trace.ffloor); - tpl->ApplyToDecal (decal, wall); - // Spread decal to nearby walls if it does not all fit on this one - if (cl_spreaddecals) - { - decal->Spread (tpl, wall, trace.X, trace.Y, z, trace.ffloor); - } - } - else + if (NULL == ShootDecal(tpl, this, Sector, x, y, z, angle + ANGLE_180, 64*FRACUNIT, true)) { DPrintf ("Could not find a wall to stick decal to at (%d,%d)\n", x>>FRACBITS, y>>FRACBITS); } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 87e1039755..a898433f06 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -9,7 +9,8 @@ struct vertex_t; struct side_t; struct F3DFloor; -extern void P_SpawnDirt (AActor *actor, fixed_t radius); +void P_SpawnDirt (AActor *actor, fixed_t radius); +class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixed_t tracedist, bool permanent); class DBaseDecal : public DThinker { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5d3961ac78..ab704e9df9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -73,6 +73,7 @@ #include "po_man.h" #include "actorptrselect.h" #include "farchive.h" +#include "decallib.h" #include "g_shared/a_pickups.h" @@ -111,6 +112,10 @@ FRandom pr_acs ("ACS"); #define NOT_FLOOR 8 #define NOT_CEILING 16 +// SpawnDecal flags +#define SDF_ABSANGLE 1 +#define SDF_PERMANENT 2 + struct CallReturn { CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard, unsigned int runaway) @@ -4192,6 +4197,7 @@ enum EACSFunctions ACSF_GetWeapon, ACSF_SoundVolume, ACSF_PlayActorSound, + ACSF_SpawnDecal, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4440,6 +4446,17 @@ static int SetCVar(AActor *activator, const char *cvarname, int value, bool is_s return 1; } +static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, angle_t angle, fixed_t zofs, fixed_t distance) +{ + if (!(flags & SDF_ABSANGLE)) + { + angle += actor->angle; + } + return NULL != ShootDecal(tpl, actor, actor->Sector, actor->x, actor->y, + actor->z + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, + angle, distance, !!(flags & SDF_PERMANENT)); +} + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth) { AActor *actor; @@ -5141,6 +5158,41 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return GlobalACSStrings.AddString(activator->player->ReadyWeapon->GetClass()->TypeName.GetChars(), stack, stackdepth); } + case ACSF_SpawnDecal: + // int SpawnDecal(int tid, str decalname, int flags, fixed angle, int zoffset, int distance) + // Returns number of decals spawned (not including spreading) + { + int count = 0; + const FDecalTemplate *tpl = DecalLibrary.GetDecalByName(FBehavior::StaticLookupString(args[1])); + if (tpl != NULL) + { + int flags = (argCount > 2) ? args[2] : 0; + angle_t angle = (argCount > 3) ? (args[3] << FRACBITS) : 0; + fixed_t zoffset = (argCount > 4) ? (args[4] << FRACBITS) : 0; + fixed_t distance = (argCount > 5) ? (args[5] << FRACBITS) : 64*FRACUNIT; + + if (args[0] == 0) + { + if (activator != NULL) + { + count += DoSpawnDecal(activator, tpl, flags, angle, zoffset, distance); + } + } + else + { + FActorIterator it(args[0]); + AActor *actor; + + while ((actor = it.Next()) != NULL) + { + count += DoSpawnDecal(actor, tpl, flags, angle, zoffset, distance); + } + } + } + return count; + } + break; + default: break; }