void C_DECL A_CorpseExplode(mobj_t* actor) { int i, n; mobj_t* mo; for(i = (P_Random() & 3) + 3; i; i--) { if((mo = P_SpawnMobj(MT_CORPSEBIT, actor->origin, P_Random() << 24, 0))) { P_MobjChangeState(mo, P_GetState(mo->type, SN_SPAWN) + (P_Random() % 3)); mo->mom[MZ] = FIX2FLT((P_Random() & 7) + 5) * .75f; mo->mom[MX] = FIX2FLT((P_Random() - P_Random()) << 10); mo->mom[MY] = FIX2FLT((P_Random() - P_Random()) << 10); } } // Spawn a skull. if((mo = P_SpawnMobj(MT_CORPSEBIT, actor->origin, P_Random() << 24, 0))) { P_MobjChangeState(mo, S_CORPSEBIT_4); n = (P_Random() & 7) + 5; mo->mom[MZ] = FIX2FLT(n) * .75f; mo->mom[MX] = FIX2FLT((P_Random() - P_Random()) << 10); mo->mom[MY] = FIX2FLT((P_Random() - P_Random()) << 10); S_StartSound(SFX_FIRED_DEATH, mo); } P_MobjRemove(actor, false); }
void C_DECL A_LeafCheck(mobj_t *actor) { int n; actor->special1++; if(actor->special1 >= 20) { P_MobjChangeState(actor, S_NULL); return; } if(P_Random() > 64) { if(FEQUAL(actor->mom[MX], 0) && FEQUAL(actor->mom[MY], 0)) { P_ThrustMobj(actor, actor->target->angle, FIX2FLT(P_Random() << 9) + 1); } return; } P_MobjChangeState(actor, S_LEAF1_8); n = P_Random(); actor->mom[MZ] = FIX2FLT(n << 9) + 1; P_ThrustMobj(actor, actor->target->angle, FIX2FLT(P_Random() << 9) + 2); actor->flags |= MF_MISSILE; }
void C_DECL A_PotteryCheck(mobj_t* actor) { mobj_t* pmo; if(!IS_NETGAME) { pmo = players[CONSOLEPLAYER].plr->mo; if(P_CheckSight(actor, pmo) && (abs((int32_t)(M_PointToAngle2(pmo->origin, actor->origin) - pmo->angle)) <= ANGLE_45)) { // Previous state (pottery bit waiting state). P_MobjChangeState(actor, actor->state - &STATES[0] - 1); } return; } else { int i; for(i = 0; i < MAXPLAYERS; ++i) { if(!players[i].plr->inGame) continue; pmo = players[i].plr->mo; if(P_CheckSight(actor, pmo) && (abs((int32_t)(M_PointToAngle2(pmo->origin, actor->origin) - pmo->angle)) <= ANGLE_45)) { // Previous state (pottery bit waiting state). P_MobjChangeState(actor, actor->state - &STATES[0] - 1); return; } } } }
/** * NOTE: See p_enemy for variable descriptions. */ void C_DECL A_Summon(mobj_t* actor) { mobj_t* mo; if((mo = P_SpawnMobj(MT_MINOTAUR, actor->origin, actor->angle, 0))) { mobj_t* master; if(P_TestMobjLocation(mo) == false || !actor->tracer) { // Didn't fit - change back to item. P_MobjChangeState(mo, S_NULL); if((mo = P_SpawnMobj(MT_SUMMONMAULATOR, actor->origin, actor->angle, 0))) mo->flags2 |= MF2_DROPPED; return; } memcpy((void *) mo->args, &mapTime, sizeof(mapTime)); master = actor->tracer; if(master->flags & MF_CORPSE) { // Master dead. mo->tracer = NULL; // No master. } else { mo->tracer = actor->tracer; // Pointer to master (mobj_t *) P_GivePower(master->player, PT_MINOTAUR); } // Make smoke puff. P_SpawnMobj(MT_MNTRSMOKE, actor->origin, P_Random() << 24, 0); S_StartSound(SFX_MAULATOR_ACTIVE, actor); } }
void C_DECL A_PotteryExplode(mobj_t* actor) { int i, maxBits = (P_Random() & 3) + 3; mobj_t* potteryBit; for(i = 0; i < maxBits; ++i) { if((potteryBit = P_SpawnMobj(MT_POTTERYBIT1, actor->origin, P_Random() << 24, 0))) { P_MobjChangeState(potteryBit, P_GetState(potteryBit->type, SN_SPAWN) + (P_Random() % 5)); potteryBit->mom[MZ] = FIX2FLT(((P_Random() & 7) + 5) * (3 * FRACUNIT / 4)); potteryBit->mom[MX] = FIX2FLT((P_Random() - P_Random()) << 10); potteryBit->mom[MY] = FIX2FLT((P_Random() - P_Random()) << 10); } } S_StartSound(SFX_POTTERY_EXPLODE, potteryBit); if(actor->args[0]) { // Spawn an item. if(!G_Ruleset_NoMonsters() || !(MOBJINFO[TranslateThingType[actor->args[0]]]. flags & MF_COUNTKILL)) { // Only spawn monsters if not -nomonsters. P_SpawnMobj(TranslateThingType[actor->args[0]], actor->origin, actor->angle, 0); } } P_MobjRemove(actor, false); }
void C_DECL A_CheckThrowBomb(mobj_t* actor) { if(fabs(actor->mom[MX]) < 1.5f && fabs(actor->mom[MY]) < 1.5f && actor->mom[MZ] < 2 && actor->state == &STATES[S_THROWINGBOMB6]) { P_MobjChangeState(actor, S_THROWINGBOMB7); actor->origin[VZ] = actor->floorZ; actor->mom[MZ] = 0; actor->flags2 &= ~MF2_FLOORBOUNCE; actor->flags &= ~MF_MISSILE; actor->flags |= MF_VIEWALIGN; } if(!--actor->health) { P_MobjChangeState(actor, P_GetState(actor->type, SN_DEATH)); } }
void C_DECL A_PoisonBagCheck(mobj_t *actor) { if(!--actor->special1) { P_MobjChangeState(actor, S_POISONCLOUD_X1); } else { return; } }
/** * The player can fire the weapon or change to another weapon at this time. * Follows after getting weapon up, or after previous attack/fire sequence. */ void C_DECL A_WeaponReady(player_t* player, pspdef_t* psp) { weaponmodeinfo_t* wminfo; // Enable the pspr Y offset (might be disabled in A_Lower). DD_SetInteger(DD_WEAPON_OFFSET_SCALE_Y, 1000); // Get out of attack state. if(player->plr->mo->state == &STATES[PCLASS_INFO(player->class_)->attackState] || player->plr->mo->state == &STATES[PCLASS_INFO(player->class_)->attackEndState]) { P_MobjChangeState(player->plr->mo, PCLASS_INFO(player->class_)->normalState); } if(player->readyWeapon != WT_NOCHANGE) { wminfo = WEAPON_INFO(player->readyWeapon, player->class_, 0); // A weaponready sound? if(psp->state == &STATES[wminfo->states[WSN_READY]] && wminfo->readySound) S_StartSound(wminfo->readySound, player->plr->mo); // Check for change. If player is dead, put the weapon away. if(player->pendingWeapon != WT_NOCHANGE || !player->health) { // (pending weapon should allready be validated) P_SetPsprite(player, ps_weapon, wminfo->states[WSN_DOWN]); return; } } // Check for autofire. if(player->brain.attack) { wminfo = WEAPON_INFO(player->readyWeapon, player->class_, 0); if(!player->attackDown || wminfo->autoFire) { player->attackDown = true; P_FireWeapon(player); return; } } else player->attackDown = false; // Bob the weapon based on movement speed. R_GetWeaponBob(player - players, &psp->pos[0], &psp->pos[1]); // Psprite state. player->plr->pSprites[0].state = DDPSP_BOBBING; }
void P_FireWeapon(player_t *player) { statenum_t newstate; if(!P_CheckAmmo(player)) return; // Psprite state. player->plr->pSprites[0].state = DDPSP_FIRE; P_MobjChangeState(player->plr->mo, PCLASS_INFO(player->class_)->attackState); newstate = weaponInfo[player->readyWeapon][player->class_].mode[0].states[WSN_ATTACK]; P_SetPsprite(player, ps_weapon, newstate); P_NoiseAlert(player->plr->mo, player->plr->mo); }
void C_DECL A_BridgeOrbit(mobj_t* actor) { if(!actor) return; if(actor->target->special1) { P_MobjChangeState(actor, S_NULL); } actor->args[0] += 3; P_MobjUnlink(actor); actor->origin[VX] = actor->target->origin[VX]; actor->origin[VY] = actor->target->origin[VY]; actor->origin[VX] += orbitTableX[actor->args[0]]; actor->origin[VY] += orbitTableY[actor->args[0]]; P_MobjLink(actor); }
static dd_bool DeactivateThing(mobj_t *mobj) { if(mobj->flags & MF_COUNTKILL) { // Monster if(!(mobj->flags2 & MF2_DORMANT)) { mobj->flags2 |= MF2_DORMANT; mobj->tics = -1; return true; } return false; } switch(mobj->type) { case MT_ZTWINEDTORCH: case MT_ZTWINEDTORCH_UNLIT: P_MobjChangeState(mobj, S_ZTWINEDTORCH_UNLIT); break; case MT_ZWALLTORCH: case MT_ZWALLTORCH_UNLIT: P_MobjChangeState(mobj, S_ZWALLTORCH_U); break; case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: if(mobj->args[0] == 1) { S_StartSound(SFX_THRUSTSPIKE_RAISE, mobj); if(mobj->args[1]) P_MobjChangeState(mobj, S_BTHRUSTLOWER); else P_MobjChangeState(mobj, S_THRUSTLOWER); } break; case MT_ZFIREBULL: case MT_ZFIREBULL_UNLIT: P_MobjChangeState(mobj, S_ZFIREBULL_DEATH); break; case MT_ZCAULDRON: case MT_ZCAULDRON_UNLIT: P_MobjChangeState(mobj, S_ZCAULDRON_U); break; case MT_FLAME_SMALL: P_MobjChangeState(mobj, S_FLAME_SDORM1); break; case MT_FLAME_LARGE: P_MobjChangeState(mobj, S_FLAME_LDORM1); break; case MT_BAT_SPAWNER: P_MobjChangeState(mobj, S_SPAWNBATS_OFF); break; default: return false; break; } return true; }
static dd_bool ActivateThing(mobj_t *mobj) { if(mobj->flags & MF_COUNTKILL) { // Monster if(mobj->flags2 & MF2_DORMANT) { mobj->flags2 &= ~MF2_DORMANT; mobj->tics = 1; return true; } return false; } switch(mobj->type) { case MT_ZTWINEDTORCH: case MT_ZTWINEDTORCH_UNLIT: P_MobjChangeState(mobj, S_ZTWINEDTORCH_1); S_StartSound(SFX_IGNITE, mobj); break; case MT_ZWALLTORCH: case MT_ZWALLTORCH_UNLIT: P_MobjChangeState(mobj, S_ZWALLTORCH1); S_StartSound(SFX_IGNITE, mobj); break; case MT_ZGEMPEDESTAL: P_MobjChangeState(mobj, S_ZGEMPEDESTAL2); break; case MT_ZWINGEDSTATUENOSKULL: P_MobjChangeState(mobj, S_ZWINGEDSTATUENOSKULL2); break; case MT_THRUSTFLOOR_UP: case MT_THRUSTFLOOR_DOWN: if(mobj->args[0] == 0) { S_StartSound(SFX_THRUSTSPIKE_LOWER, mobj); mobj->flags2 &= ~MF2_DONTDRAW; if(mobj->args[1]) P_MobjChangeState(mobj, S_BTHRUSTRAISE1); else P_MobjChangeState(mobj, S_THRUSTRAISE1); } break; case MT_ZFIREBULL: case MT_ZFIREBULL_UNLIT: P_MobjChangeState(mobj, S_ZFIREBULL_BIRTH); S_StartSound(SFX_IGNITE, mobj); break; case MT_ZBELL: if(mobj->health > 0) { P_DamageMobj(mobj, NULL, NULL, 10, false); // 'ring' the bell } break; case MT_ZCAULDRON: case MT_ZCAULDRON_UNLIT: P_MobjChangeState(mobj, S_ZCAULDRON1); S_StartSound(SFX_IGNITE, mobj); break; case MT_FLAME_SMALL: S_StartSound(SFX_IGNITE, mobj); P_MobjChangeState(mobj, S_FLAME_SMALL1); break; case MT_FLAME_LARGE: S_StartSound(SFX_IGNITE, mobj); P_MobjChangeState(mobj, S_FLAME_LARGE1); break; case MT_BAT_SPAWNER: P_MobjChangeState(mobj, S_SPAWNBATS1); break; default: return false; break; } return true; }
void C_DECL A_GunFlash(player_t *player, pspdef_t *psp) { P_MobjChangeState(player->plr->mo, PCLASS_INFO(player->class_)->attackEndState); P_SetPsprite(player, ps_flash, weaponInfo[player->readyWeapon][player->class_].mode[0].states[WSN_FLASH]); }
void Mobj_XYMoveStopping(mobj_t *mo) { DENG_ASSERT(mo != 0); player_t *player = mo->player; if(player && (P_GetPlayerCheats(player) & CF_NOMOMENTUM)) { // Debug option for no sliding at all. mo->mom[MX] = mo->mom[MY] = 0; return; } if(mo->flags & (MF_MISSILE | MF_SKULLFLY)) { // No friction for missiles. return; } if(mo->origin[VZ] > mo->floorZ && !mo->onMobj && !(mo->flags2 & MF2_FLY)) { // No friction when falling. return; } #ifndef __JHEXEN__ if(cfg.slidingCorpses) { // $dropoff_fix: Add objects falling off ledges. Does not apply to players! if(((mo->flags & MF_CORPSE) || (mo->intFlags & MIF_FALLING)) && !mo->player) { // Do not stop sliding if halfway off a step with some momentum. if(!INRANGE_OF(mo->mom[MX], 0, DROPOFFMOMENTUM_THRESHOLD) || !INRANGE_OF(mo->mom[MY], 0, DROPOFFMOMENTUM_THRESHOLD)) { if(!FEQUAL(mo->floorZ, P_GetDoublep(Mobj_Sector(mo), DMU_FLOOR_HEIGHT))) return; } } } #endif bool isVoodooDoll = Mobj_IsVoodooDoll(mo); bool belowWalkStop = (INRANGE_OF(mo->mom[MX], 0, WALKSTOP_THRESHOLD) && INRANGE_OF(mo->mom[MY], 0, WALKSTOP_THRESHOLD)); bool belowStandSpeed = false; bool isMovingPlayer = false; if(player) { belowStandSpeed = (INRANGE_OF(mo->mom[MX], 0, STANDSPEED) && INRANGE_OF(mo->mom[MY], 0, STANDSPEED)); isMovingPlayer = (!FEQUAL(player->plr->forwardMove, 0) || !FEQUAL(player->plr->sideMove, 0)); } // Stop player walking animation (only real players). if(!isVoodooDoll && player && belowStandSpeed && !isMovingPlayer && !IS_NETWORK_SERVER) // Netgame servers use logic elsewhere for player animation. { // If in a walking frame, stop moving. if(P_PlayerInWalkState(player)) { P_MobjChangeState(player->plr->mo, statenum_t(PCLASS_INFO(player->class_)->normalState)); } } // Apply friction. if(belowWalkStop && !isMovingPlayer) { // $voodoodolls: Do not zero mom for voodoo dolls! if(!isVoodooDoll) { // Momentum is below the walkstop threshold; stop it completely. mo->mom[MX] = mo->mom[MY] = 0; // $voodoodolls: Stop view bobbing if this isn't a voodoo doll. if(player) player->bob = 0; } } else { coord_t friction = Mobj_Friction(mo); mo->mom[MX] *= friction; mo->mom[MY] *= friction; } }
void P_KillMobj(mobj_t *source, mobj_t *target, dd_bool stomping) { mobjtype_t item; mobj_t* mo; unsigned int an; angle_t angle; if(!target) return; // Nothing to kill... target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY); if(target->type != MT_SKULL) target->flags &= ~MF_NOGRAVITY; target->flags |= MF_CORPSE | MF_DROPOFF; target->flags2 &= ~MF2_PASSMOBJ; target->corpseTics = 0; target->height /= 2*2; if(source && source->player) { // Count for intermission. if(target->flags & MF_COUNTKILL) { source->player->killCount++; source->player->update |= PSF_COUNTERS; } if(target->player) { source->player->frags[target->player - players]++; NetSv_FragsForAll(source->player); NetSv_KillMessage(source->player, target->player, stomping); } } else if(!IS_NETGAME && (target->flags & MF_COUNTKILL)) { // Count all monster deaths (even those caused by other monsters). players[0].killCount++; } if(target->player) { // Count environment kills against the player. if(!source) { target->player->frags[target->player - players]++; NetSv_FragsForAll(target->player); NetSv_KillMessage(target->player, target->player, stomping); } target->flags &= ~MF_SOLID; target->flags2 &= ~MF2_FLY; target->player->powers[PT_FLIGHT] = 0; target->player->playerState = PST_DEAD; target->player->rebornWait = PLAYER_REBORN_TICS; target->player->update |= PSF_STATE; target->player->plr->flags |= DDPF_DEAD; P_DropWeapon(target->player); // Don't die with the automap open. ST_AutomapOpen(target->player - players, false, false); #if __JHERETIC__ || __JHEXEN__ Hu_InventoryOpen(target->player - players, false); #endif } if(target->health < -target->info->spawnHealth && P_GetState(target->type, SN_XDEATH)) { // Extreme death. P_MobjChangeState(target, P_GetState(target->type, SN_XDEATH)); } else { // Normal death. P_MobjChangeState(target, P_GetState(target->type, SN_DEATH)); } target->tics -= P_Random() & 3; if(target->tics < 1) target->tics = 1; // Enemies in Chex Quest don't drop stuff. if(gameMode == doom_chex) return; // Drop stuff. // This determines the kind of object spawned during the death frame // of a thing. switch(target->type) { case MT_WOLFSS: case MT_POSSESSED: item = MT_CLIP; break; case MT_SHOTGUY: item = MT_SHOTGUN; break; case MT_CHAINGUY: item = MT_CHAINGUN; break; default: return; } // Don't drop at the exact same place, causes Z flickering with // 3D sprites. angle = P_Random() << 24; an = angle >> ANGLETOFINESHIFT; if((mo = P_SpawnMobjXYZ(item, target->origin[VX] + 3 * FIX2FLT(finecosine[an]), target->origin[VY] + 3 * FIX2FLT(finesine[an]), 0, angle, MSF_Z_FLOOR))) mo->flags |= MF_DROPPED; // Special versions of items. }
void C_DECL A_PotteryChooseBit(mobj_t* actor) { P_MobjChangeState(actor, P_GetState(actor->type, SN_DEATH) + (P_Random() % 5) + 1); actor->tics = 256 + (P_Random() << 1); }
void C_DECL A_BridgeRemove(mobj_t *actor) { actor->special1 = true; // Removing the bridge. actor->flags &= ~MF_SOLID; P_MobjChangeState(actor, S_FREE_BRIDGE1); }