Gez Posted May 30, 2010 Some of you probably you this trick: The poison cloud spawned from a cleric's flechette can be blasted away with a disc of repulsion, creating a projectile that deals a lot of damage. (Explained because of the actor's mass of MAXINT, since collision damage inflicted by blasted things depends on their mass.) But it gets weird. This is the poison cloud definition:{ // MT_POISONCLOUD -1, // doomednum S_POISONCLOUD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_NULL, // painstate 0, // painchance SFX_NONE, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_NULL, // deathstate S_NULL, // xdeathstate SFX_POISONSHROOM_DEATH, // deathsound 0, // speed 1, // radius 1, // height MAXINT, // mass 0, // damage SFX_NONE, // activesound MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SHADOW|MF_NOCLIP|MF_DROPOFF, // flags MF2_NODMGTHRUST // flags2 },Here's the function that determines whether something can be blasted or not:// Blast all mobj things away void P_BlastRadius(player_t *player) { mobj_t *mo; mobj_t *pmo=player->mo; thinker_t *think; fixed_t dist; S_StartSound(pmo, SFX_ARTIFACT_BLAST); P_NoiseAlert(player->mo, player->mo); for(think = thinkercap.next; think != &thinkercap; think = think->next) { if(think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *)think; if((mo == pmo) || (mo->flags2&MF2_BOSS)) { // Not a valid monster continue; } if ((mo->type == MT_POISONCLOUD) || // poison cloud (mo->type == MT_HOLY_FX) || // holy fx (mo->flags&MF_ICECORPSE)) // frozen corpse { // Let these special cases go } else if ((mo->flags&MF_COUNTKILL) && (mo->health <= 0)) { continue; } else if (!(mo->flags&MF_COUNTKILL) && !(mo->player) && !(mo->flags&MF_MISSILE)) { // Must be monster, player, or missile continue; } if (mo->flags2&MF2_DORMANT) { continue; // no dormant creatures } if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW)) { continue; // no underground wraiths } if ((mo->type == MT_SPLASHBASE) || (mo->type == MT_SPLASH)) { continue; } if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER) { continue; } dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y); if(dist > BLAST_RADIUS_DIST) { // Out of range continue; } P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH); } }The relevant part here is: if ((mo->type == MT_POISONCLOUD) || // poison cloud (mo->type == MT_HOLY_FX) || // holy fx (mo->flags&MF_ICECORPSE)) // frozen corpse { // Let these special cases go }The function doing the actual blasting does not have any special case handling for MT_POISONCLOUD, so it's treated like all others when it gets there. But here it is for the curious:void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength) { angle_t angle,ang; mobj_t *mo; fixed_t x,y,z; angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y); angle >>= ANGLETOFINESHIFT; if (strength < BLAST_FULLSTRENGTH) { victim->momx = FixedMul(strength, finecosine[angle]); victim->momy = FixedMul(strength, finesine[angle]); if (victim->player) { // Players handled automatically } else { victim->flags2 |= MF2_SLIDE; victim->flags2 |= MF2_BLASTED; } } else // full strength blast from artifact { if (victim->flags&MF_MISSILE) { switch(victim->type) { case MT_SORCBALL1: // don't blast sorcerer balls case MT_SORCBALL2: case MT_SORCBALL3: return; break; case MT_MSTAFF_FX2: // Reflect to originator victim->special1 = (int)victim->target; victim->target = source; break; default: break; } } if (victim->type == MT_HOLY_FX) { if ((mobj_t *)(victim->special1) == source) { victim->special1 = (int)victim->target; victim->target = source; } } victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]); victim->momy = FixedMul(BLAST_SPEED, finesine[angle]); // Spawn blast puff ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y); ang >>= ANGLETOFINESHIFT; x = victim->x + FixedMul(victim->radius+FRACUNIT, finecosine[ang]); y = victim->y + FixedMul(victim->radius+FRACUNIT, finesine[ang]); z = victim->z - victim->floorclip + (victim->height>>1); mo=P_SpawnMobj(x, y, z, MT_BLASTEFFECT); if (mo) { mo->momx = victim->momx; mo->momy = victim->momy; } if (victim->flags&MF_MISSILE) { victim->momz = 8*FRACUNIT; mo->momz = victim->momz; } else { victim->momz = (1000/victim->info->mass)<<FRACBITS; } if (victim->player) { // Players handled automatically } else { victim->flags2 |= MF2_SLIDE; victim->flags2 |= MF2_BLASTED; } } }This MT_POISONCLOUD actor is spawned by one function, this one:void A_PoisonBagInit(mobj_t *actor) { mobj_t *mo; mo = P_SpawnMobj(actor->x, actor->y, actor->z+28*FRACUNIT, MT_POISONCLOUD); if(!mo) { return; } mo->momx = 1; // missile objects must move to impact other objects mo->special1 = 24+(P_Random()&7); mo->special2 = 0; mo->target = actor->target; mo->radius = 20*FRACUNIT; mo->height = 30*FRACUNIT; mo->flags &= ~MF_NOCLIP; }There are two states which call this function; here's one, the activated cleric's flechette:{SPR_PSBG,32768,18,NULL,S_POISONBAG2,0,0}, // S_POISONBAG1 {SPR_PSBG,32769,4,NULL,S_POISONBAG3,0,0}, // S_POISONBAG2 {SPR_PSBG,2,3,NULL,S_POISONBAG4,0,0}, // S_POISONBAG3 {SPR_PSBG,2,1,A_PoisonBagInit,S_NULL,0,0}, // S_POISONBAG4And here's the other, the poison mushroom:{SPR_SHRM,0,5,A_PoisonShroom,S_ZPOISONSHROOM_P2,0,0}, // S_ZPOISONSHROOM1 {SPR_SHRM,0,6,NULL,S_ZPOISONSHROOM_P2,0,0}, // S_ZPOISONSHROOM_P1 {SPR_SHRM,1,8,A_Pain,S_ZPOISONSHROOM1,0,0}, // S_ZPOISONSHROOM_P2 {SPR_SHRM,2,5,NULL,S_ZPOISONSHROOM_X2,0,0}, // S_ZPOISONSHROOM_X1 {SPR_SHRM,3,5,NULL,S_ZPOISONSHROOM_X3,0,0}, // S_ZPOISONSHROOM_X2 {SPR_SHRM,4,5,A_PoisonBagInit,S_ZPOISONSHROOM_X4,0,0}, // S_ZPOISONSHROOM_X3 {SPR_SHRM,5,-1,NULL,S_NULL,0,0}, // S_ZPOISONSHROOM_X4So now the question is: why cannot the cloud blasting trick work when the poison cloud is spawned from a mushroom rather than a flechette? It's the same actor which is spawned with the same function and treated in the same way by the P_BlastRadius() function. Where is the difference? 0 Quote Share this post Link to post
Worst Posted May 30, 2010 The only differences I can think of would be maybe the ownership or the height the poison cloud spawns at? But there doesn't seem to be any code where that would matter.. Perhaps using a slow, but hopefully fool-proof method, you could figure out the difference: Choose either poison cloud spawner of the two, the mushroom or the flechette. Start changing its relevant code little by little towards the other one, testing after each change, untill both poison cloud spawners act exactly the same. If its possible to 'transform' the code of one to the other, then maybe you'll spot which change affects the blasting.. ..If the code that is resulting in the different behaviour for one or the other is not specific to them, then this method probably doesn't work. 0 Quote Share this post Link to post
Vermil Posted May 30, 2010 The interesting thing is that the graphic of something being hit by the disc does appear on a mushroom spawned poison cloud when a disc is used on one and flies off as if the cloud was affected. 0 Quote Share this post Link to post
Gez Posted May 30, 2010 Worst said:The only differences I can think of would be maybe the ownership or the height the poison cloud spawns at? But there doesn't seem to be any code where that would matter.. There is no ownership. The height is the same (28 units above the spawner's origin). The only thing that's taken from the spawner is the target -- but there are no target checks for MT_POISONCLOUD in P_BlastRadius! Worst said:Perhaps using a slow, but hopefully fool-proof method, you could figure out the difference: I can't compile the Hexen source code. Vermil said:The interesting thing is that the graphic of something being hit by the disc does appear on a mushroom spawned poison cloud when a disc is used on one and flies off as if the cloud was affected. Well, it IS affected, and that was a deliberate design decision from Raven Software given the "// Let these special cases go" comment. What's odd is that if it is spawned from a dying mushroom, then it is not affected. This discrepancy must have an explanation somewhere, but I don't see where. 0 Quote Share this post Link to post
Graf Zahl Posted May 30, 2010 Maybe it gets stuck in the mushroom? The dead Mushroom's MF_SOLID flag is never cleared. 0 Quote Share this post Link to post
Vermil Posted May 30, 2010 Graf Zahl said:Maybe it gets stuck in the mushroom? The dead Mushroom's MF_SOLID flag is never cleared. You are right. That is why a mushroom created cloud doesn't move when hit by a disc; it is stuck in the mushroom when it spawns. Remove the MF_SOLID flag from the mushroom and a mushroom spawned poison cloud can be moved around by the disc. I'd say it was intentional by Raven, abeit, maybe not the best way to do it. 0 Quote Share this post Link to post
Gez Posted May 30, 2010 Maybe, though the shroom is 20 units high and the cloud is spawned 28 units above the spawner's origin, so there is 8 units of vacuum between the "dead" mushroom and the cloud. So if it gets stuck, it's because of poorly-written over/under physics code rather than a deliberate decision; if it was wanted the shroom would have been 28 or more units tall. { // MT_ZPOISONSHROOM 8104, // doomednum S_ZPOISONSHROOM1, // spawnstate 30, // spawnhealth S_NULL, // seestate SFX_NONE, // seesound 8, // reactiontime SFX_NONE, // attacksound S_ZPOISONSHROOM_P1, // painstate 255, // painchance SFX_POISONSHROOM_PAIN, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // crashstate S_ZPOISONSHROOM_X1, // deathstate S_NULL, // xdeathstate SFX_POISONSHROOM_DEATH, // deathsound 0, // speed 6*FRACUNIT, // radius 20*FRACUNIT, // height MAXINT, // mass 0, // damage SFX_NONE, // activesound MF_SHOOTABLE|MF_SOLID|MF_NOBLOOD, // flags 0 // flags2 }, 0 Quote Share this post Link to post
Vermil Posted May 30, 2010 Wheter or not it actually was intentional. Making a mushroom spawned poison cloud not get stuck in the mushroom would impact game play. 0 Quote Share this post Link to post
Graf Zahl Posted May 30, 2010 Height is not relevant here because both actors involved don't use the MF2_PASSMOBJ flag so for the collision detection code they are infinitely tall. The reason this does not happen in ZDoom is because of a Boom fix concerning the collision detection between solid and non-solid things. Well, at least now I know how to fix it... 0 Quote Share this post Link to post
Vermil Posted May 30, 2010 Amusingly, Doomsday has introduced this mistake somewhere in the 1.9 betas. In 1.8.6 the cloud spawned by a mushroom "correctly" doesn't move when shot by a disc, but in 1.9 beta 6.9 it does. 0 Quote Share this post Link to post
DaniJ Posted May 30, 2010 Its exactly the same issue in Doomsday and yes, it will be fixed and compat-optioned. 0 Quote Share this post Link to post
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.