From 2ffc06c0bc9eb3f5d3604d15bf076678fd3b69cd Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Jun 2016 00:00:31 +0100 Subject: [PATCH] Fan particle generators now suck less! For the object... * Tag via its angle field * Number of objects to spawn per tic around it via its z field, if zero then just spawn at center * Is flipped if given MTF_OBJECTFLIP. Now there's a linedef type 15! * Tag is tag of object(s!) * Object type set via concatenation of frontside textures, MT_PARTICLE is default * The length of the linedef is the radius the particle is spawned out (zeroed if z field is 0) * Frontside x offset is speed upwards * Frontside y offset is number of degrees to turn each tic (zeroed if z field is 0) * Frontside floor and ceiling heights are the heights in which the particle is bound through some fun mathematics and/or BDSM Of course, not every story has a happy ending. * A_ParticleSpawn no longer accepts objects via its var1 because of how specialised it's gotten. Considering it can be set via abuse of actor->cvmem, I don't consider this an issue. Maybe you might disagree. --- src/p_enemy.c | 48 +++++++++++++++++-------------- src/p_mobj.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/p_setup.c | 1 + 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 4e11dc494..fc46f697a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3359,41 +3359,45 @@ void A_ScoreRise(mobj_t *actor) // Function: A_ParticleSpawn // -// Description: Spawns a particle at a specified interval +// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN. // -// var1 = type (if 0, defaults to MT_PARTICLE) +// var1 = unused // var2 = unused // void A_ParticleSpawn(mobj_t *actor) { - INT32 locvar1 = var1; - fixed_t speed; - mobjtype_t type; + INT32 i = 0; mobj_t *spawn; #ifdef HAVE_BLUA if (LUA_CallAction("A_ParticleSpawn", actor)) return; #endif - if (!actor->spawnpoint) - { - P_RemoveMobj(actor); + if (!actor->health) return; + + if ((actor->lastlook) && (actor->cvmem)) + { + for (i = 0; i < actor->lastlook; i++) + { + spawn = P_SpawnMobj(actor->x + FixedMul(actor->friction, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), + actor->y + FixedMul(actor->friction, FINESINE(actor->angle>>ANGLETOFINESHIFT)), + actor->z, + (mobjtype_t)actor->cvmem); + P_SetScale(spawn, actor->scale); + spawn->momz = actor->movefactor; + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/actor->health; + spawn->tics = (tic_t)actor->health; + spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + if (spawn->frame & FF_ANIMATE) + spawn->frame += P_RandomKey(spawn->state->var1); + + actor->angle += actor->movedir; + } + actor->angle += (angle_t)actor->movecount; } - - if (locvar1) - type = (mobjtype_t)locvar1; - else - type = MT_PARTICLE; - - speed = FixedMul((actor->spawnpoint->angle >> 12)<scale); - - spawn = P_SpawnMobj(actor->x, actor->y, actor->z, type); - P_SetScale(spawn, actor->scale); - spawn->momz = speed; - spawn->destscale = FixedDiv(spawn->scale<scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) << FRACBITS, 100<tics = actor->spawnpoint->extrainfo + 1; } // Function: A_BunnyHop diff --git a/src/p_mobj.c b/src/p_mobj.c index 3e87130b0..df136edd6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9303,6 +9303,85 @@ ML_NOCLIMB : Direction not controllable } break; } + case MT_PARTICLEGEN: + { + fixed_t radius, speed, bottomheight, topheight; + INT32 type, numdivisions, time, anglespeed; + angle_t angledivision; + size_t line; + const size_t mthingi = (size_t)(mthing - mapthings); + + for (line = 0; line < numlines; line++) + { + if (lines[line].special == 15 && lines[line].tag == mthing->angle) + break; + } + + if (line == numlines) + { + CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); + return; + } + + if (sides[lines[line].sidenum[0]].toptexture) + type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c... + else + type = (INT32)MT_PARTICLE; + + speed = abs(sides[lines[line].sidenum[0]].textureoffset); + bottomheight = lines[line].frontsector->floorheight; + topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + + numdivisions = (mthing->options >> ZSHIFT); + + if (numdivisions) + { + radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y); + anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360; + angledivision = 360/numdivisions; + } + else + { + numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler. + radius = 0; + anglespeed = 0; + angledivision = 0; + } + + if ((speed) && (topheight > bottomheight)) + time = (INT32)(FixedDiv((topheight - bottomheight), speed) >> FRACBITS); + else + time = 1; // There's no reasonable way to set it, so just show the object for one tic and move on. + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->z = topheight; + speed *= -1; + } + else + mobj->z = bottomheight; + + CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" + "Radius is %d\n" + "Speed is %d\n" + "Anglespeed is %d\n" + "Numdivisions is %d\n" + "Angledivision is %d\n" + "Time is %d\n" + "Type is %d\n", + sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, time, type); + + mobj->angle = 0; + mobj->movefactor = speed; + mobj->lastlook = numdivisions; + mobj->movedir = angledivision*ANG1; + mobj->movecount = anglespeed*ANG1; + mobj->health = time; + mobj->friction = radius; + mobj->cvmem = type; + + break; + } case MT_ROCKSPAWNER: mobj->threshold = mthing->angle; mobj->movecount = mthing->extrainfo; diff --git a/src/p_setup.c b/src/p_setup.c index cfcc7d405..50df019ef 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1479,6 +1479,7 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) } case 14: // Bustable block parameters + case 15: // Fan particle spawner parameters case 425: // Calls P_SetMobjState on calling mobj case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors