coord_t Mobj_Friction(mobj_t const *mo) { if(Mobj_IsAirborne(mo)) { // Airborne "friction". return FRICTION_FLY; } #if __JHERETIC__ if(P_ToXSector(Mobj_Sector(mo))->special == 15) // Low friction. { return FRICTION_LOW; } #endif #if __JHEXEN__ terraintype_t const *tt = P_MobjFloorTerrain(mo); if(tt->flags & TTF_FRICTION_LOW) { return FRICTION_LOW; } #endif #if LIBCOMMON_HAVE_XG // Use the current sector's friction. return XS_Friction(Mobj_Sector(mo)); #else return FRICTION_NORMAL; #endif }
coord_t Mobj_ThrustMul(mobj_t const *mo) { coord_t mul = 1.0; #if __JHEXEN__ if(P_MobjFloorTerrain(mo)->flags & TTF_FRICTION_LOW) { mul /= 2; } #else // !__JHEXEN__ Sector *sec = Mobj_Sector(mo); #if __JHERETIC__ if(P_ToXSector(sec)->special == 15) // Friction_Low { mul /= 4; return mul; // XG friction ignored. } #endif // Use a thrust multiplier based on the sector's friction. mul = Mobj_ThrustMulForFriction(XS_Friction(sec)); #endif return mul; }
/** * Called every tic frame that the player origin is in a special sector */ void P_PlayerInSpecialSector(player_t *player) { Sector *sector = Mobj_Sector(player->plr->mo); if(IS_CLIENT) return; // Falling, not all the way down yet? if(!FEQUAL(player->plr->mo->origin[VZ], P_GetDoublep(sector, DMU_FLOOR_HEIGHT))) return; // Has hitten ground. switch(P_ToXSector(sector)->special) { default: break; case 5: ///< HELLSLIME DAMAGE if(!player->powers[PT_IRONFEET]) if(!(mapTime & 0x1f)) P_DamageMobj(player->plr->mo, NULL, NULL, 10, false); break; case 7: ///< NUKAGE DAMAGE if(!player->powers[PT_IRONFEET]) if(!(mapTime & 0x1f)) P_DamageMobj(player->plr->mo, NULL, NULL, 5, false); break; case 16: ///< SUPER HELLSLIME DAMAGE case 4: ///< STROBE HURT if(!player->powers[PT_IRONFEET] || (P_Random() < 5)) { if(!(mapTime & 0x1f)) P_DamageMobj(player->plr->mo, NULL, NULL, 20, false); } break; case 9: ///< SECRET SECTOR player->secretCount++; P_ToXSector(sector)->special = 0; if(cfg.secretMsg) { P_SetMessage(player, "You've found a secret area!"); // S_ConsoleSound(SFX_SECRET, 0, player - players); // jd64 } break; } }
static int findMobj(thinker_t *th, void *context) { findmobjparams_t *params = (findmobjparams_t *) context; mobj_t *mo = (mobj_t *) th; // Must be of the correct type? if(params->type >= 0 && params->type != mo->type) return false; // Continue iteration. // Must be in the specified sector? if(params->sec && params->sec != Mobj_Sector(mo)) return false; // Continue iteration. // Found it! params->foundMobj = mo; return true; // Stop iteration. }
int EV_Teleport(Line* line, int side, mobj_t* mo, dd_bool spawnFog) { mobj_t* dest; // Clients cannot teleport on their own. if(IS_CLIENT) return 0; if(mo->flags2 & MF2_NOTELEPORT) return 0; // Don't teleport if hit back of line, so you can get out of teleporter. if(side == 1) return 0; if((dest = getTeleportDestination(P_ToXLine(line)->tag)) != NULL) { // A suitable destination has been found. coord_t oldPos[3], aboveFloor; angle_t oldAngle; mobj_t* fog; uint an; memcpy(oldPos, mo->origin, sizeof(mo->origin)); oldAngle = mo->angle; aboveFloor = mo->origin[VZ] - mo->floorZ; if(!P_TeleportMove(mo, dest->origin[VX], dest->origin[VY], false)) return 0; mo->origin[VZ] = mo->floorZ; if(spawnFog) { // Spawn teleport fog at source and destination. if((fog = P_SpawnMobj(MT_TFOG, oldPos, oldAngle + ANG180, 0))) S_StartSound(SFX_TELEPT, fog); an = dest->angle >> ANGLETOFINESHIFT; if((fog = P_SpawnMobjXYZ(MT_TFOG, dest->origin[VX] + 20 * FIX2FLT(finecosine[an]), dest->origin[VY] + 20 * FIX2FLT(finesine[an]), mo->origin[VZ], dest->angle + ANG180, 0))) { // Emit sound, where? S_StartSound(SFX_TELEPT, fog); } } mo->angle = dest->angle; if(mo->flags2 & MF2_FLOORCLIP) { mo->floorClip = 0; if(FEQUAL(mo->origin[VZ], P_GetDoublep(Mobj_Sector(mo), DMU_FLOOR_HEIGHT))) { terraintype_t const *tt = P_MobjFloorTerrain(mo); if(tt->flags & TTF_FLOORCLIP) { mo->floorClip = 10; } } } mo->mom[MX] = mo->mom[MY] = mo->mom[MZ] = 0; // $voodoodolls Must be the real player. if(mo->player && mo->player->plr->mo == mo) { mo->reactionTime = 18; // Don't move for a bit. if(mo->player->powers[PT_FLIGHT] && aboveFloor > 0) { mo->origin[VZ] = mo->floorZ + aboveFloor; if(mo->origin[VZ] + mo->height > mo->ceilingZ) { mo->origin[VZ] = mo->ceilingZ - mo->height; } } else { //mo->dPlayer->clLookDir = 0; /* $unifiedangles */ mo->dPlayer->lookDir = 0; } mo->player->viewHeight = (coord_t) cfg.common.plrViewHeight; mo->player->viewHeightDelta = 0; mo->player->viewZ = mo->origin[VZ] + mo->player->viewHeight; mo->player->viewOffset[VX] = mo->player->viewOffset[VY] = mo->player->viewOffset[VZ] = 0; mo->player->bob = 0; //mo->dPlayer->clAngle = mo->angle; /* $unifiedangles */ mo->dPlayer->flags |= DDPF_FIXANGLES | DDPF_FIXORIGIN | DDPF_FIXMOM; } return 1; }
int mobj_s::read(MapStateReader *msr) { #define FF_FULLBRIGHT 0x8000 ///< Used to be a flag in thing->frame. #define FF_FRAMEMASK 0x7fff Reader1 *reader = msr->reader(); int ver = Reader_ReadByte(reader); #if !__JHEXEN__ if(ver >= 2) // Version 2 has mobj archive numbers. { msr->addMobjToThingArchive(this, Reader_ReadInt16(reader)); } #endif #if !__JHEXEN__ target = 0; if(ver >= 2) { target = INT2PTR(mobj_t, Reader_ReadInt16(reader)); } #endif #if __JDOOM__ || __JDOOM64__ tracer = 0; if(ver >= 5) { tracer = INT2PTR(mobj_t, Reader_ReadInt16(reader)); } #endif onMobj = 0; #if __JHEXEN__ if(ver >= 8) #else if(ver >= 5) #endif { onMobj = INT2PTR(mobj_t, Reader_ReadInt16(reader)); } origin[VX] = FIX2FLT(Reader_ReadInt32(reader)); origin[VY] = FIX2FLT(Reader_ReadInt32(reader)); origin[VZ] = FIX2FLT(Reader_ReadInt32(reader)); angle = Reader_ReadInt32(reader); sprite = Reader_ReadInt32(reader); frame = Reader_ReadInt32(reader); // might be ORed with FF_FULLBRIGHT if(frame & FF_FULLBRIGHT) frame &= FF_FRAMEMASK; // not used anymore. #if __JHEXEN__ if(ver < 6) { /*floorflat =*/ Reader_ReadInt32(reader); } #else floorZ = FIX2FLT(Reader_ReadInt32(reader)); ceilingZ = FIX2FLT(Reader_ReadInt32(reader)); #endif radius = FIX2FLT(Reader_ReadInt32(reader)); height = FIX2FLT(Reader_ReadInt32(reader)); mom[MX] = FIX2FLT(Reader_ReadInt32(reader)); mom[MY] = FIX2FLT(Reader_ReadInt32(reader)); mom[MZ] = FIX2FLT(Reader_ReadInt32(reader)); valid = Reader_ReadInt32(reader); type = Reader_ReadInt32(reader); #if __JHEXEN__ if(ver < 7) { /*info = (mobjinfo_t *)*/ Reader_ReadInt32(reader); } #endif info = &MOBJINFO[type]; if(info->flags2 & MF2_FLOATBOB) mom[MZ] = 0; if(info->flags & MF_SOLID) ddFlags |= DDMF_SOLID; if(info->flags2 & MF2_DONTDRAW) ddFlags |= DDMF_DONTDRAW; tics = Reader_ReadInt32(reader); state = INT2PTR(state_t, Reader_ReadInt32(reader)); #if __JHEXEN__ damage = Reader_ReadInt32(reader); #endif flags = Reader_ReadInt32(reader); #if __JHEXEN__ flags2 = Reader_ReadInt32(reader); if(ver >= 5) { flags3 = Reader_ReadInt32(reader); } special1 = Reader_ReadInt32(reader); special2 = Reader_ReadInt32(reader); #endif health = Reader_ReadInt32(reader); #if __JHERETIC__ if(ver < 8) { // Fix a bunch of kludges in the original Heretic. switch(type) { case MT_MACEFX1: case MT_MACEFX2: case MT_MACEFX3: case MT_HORNRODFX2: case MT_HEADFX3: case MT_WHIRLWIND: case MT_TELEGLITTER: case MT_TELEGLITTER2: special3 = health; if(type == MT_HORNRODFX2 && special3 > 16) special3 = 16; health = MOBJINFO[type].spawnHealth; break; default: break; } } #endif moveDir = Reader_ReadInt32(reader); moveCount = Reader_ReadInt32(reader); #if __JHEXEN__ target = INT2PTR(mobj_t, Reader_ReadInt32(reader)); #endif reactionTime = Reader_ReadInt32(reader); threshold = Reader_ReadInt32(reader); player = INT2PTR(player_t, Reader_ReadInt32(reader)); lastLook = Reader_ReadInt32(reader); #if __JHEXEN__ floorClip = FIX2FLT(Reader_ReadInt32(reader)); msr->addMobjToThingArchive(this, Reader_ReadInt32(reader)); tid = Reader_ReadInt32(reader); #else // For nightmare respawn. if(ver >= 6) { spawnSpot.origin[VX] = FIX2FLT(Reader_ReadInt32(reader)); spawnSpot.origin[VY] = FIX2FLT(Reader_ReadInt32(reader)); spawnSpot.origin[VZ] = FIX2FLT(Reader_ReadInt32(reader)); spawnSpot.angle = Reader_ReadInt32(reader); if(ver < 10) { /*spawnSpot.type =*/ Reader_ReadInt32(reader); } spawnSpot.flags = Reader_ReadInt32(reader); } else { spawnSpot.origin[VX] = (float) Reader_ReadInt16(reader); spawnSpot.origin[VY] = (float) Reader_ReadInt16(reader); spawnSpot.origin[VZ] = 0; // Initialize with "something". spawnSpot.angle = (angle_t) (ANG45 * (Reader_ReadInt16(reader) / 45)); /*spawnSpot.type = (int)*/ Reader_ReadInt16(reader); spawnSpot.flags = (int) Reader_ReadInt16(reader); } # if __JDOOM__ || __JDOOM64__ if(ver >= 3) # elif __JHERETIC__ if(ver >= 5) # endif { intFlags = Reader_ReadInt32(reader); dropOffZ = FIX2FLT(Reader_ReadInt32(reader)); gear = Reader_ReadInt32(reader); } # if __JDOOM__ || __JDOOM64__ if(ver >= 6) { damage = Reader_ReadInt32(reader); flags2 = Reader_ReadInt32(reader); } else // flags2 will be applied from the defs. { damage = DDMAXINT; // Use the value set in mo->info->damage } # elif __JHERETIC__ damage = Reader_ReadInt32(reader); flags2 = Reader_ReadInt32(reader); # endif if(ver >= 7) { flags3 = Reader_ReadInt32(reader); } // Else flags3 will be applied from the defs. #endif #if __JHEXEN__ special = Reader_ReadInt32(reader); Reader_Read(reader, args, 1 * 5); #elif __JHERETIC__ special1 = Reader_ReadInt32(reader); special2 = Reader_ReadInt32(reader); if(ver >= 8) { special3 = Reader_ReadInt32(reader); } #endif #if __JHEXEN__ if(ver >= 2) #else if(ver >= 4) #endif { translucency = Reader_ReadByte(reader); } #if __JHEXEN__ if(ver >= 3) #else if(ver >= 5) #endif { visTarget = (short) (Reader_ReadByte(reader)) -1; } #if __JHEXEN__ if(ver >= 4) { tracer = INT2PTR(mobj_t, Reader_ReadInt32(reader)); } if(ver >= 4) { lastEnemy = INT2PTR(mobj_t, Reader_ReadInt32(reader)); } #else if(ver >= 5) { floorClip = FIX2FLT(Reader_ReadInt32(reader)); } #endif #if __JHERETIC__ if(ver >= 7) { generator = INT2PTR(mobj_t, Reader_ReadInt16(reader)); } else { generator = 0; } #endif /* * Restore! (unmangle) */ info = &MOBJINFO[type]; Mobj_SetState(this, PTR2INT(state)); #if __JHEXEN__ if(flags2 & MF2_DORMANT) { tics = -1; } #endif if(player) { // The player number translation table is used to find out the // *current* (actual) player number of the referenced player. player = msr->player(PTR2INT(player)); #if __JHEXEN__ if(!player) { // This saved player does not exist in the current game! // Destroy this mobj. Mobj_Destroy(this); return false; } #endif dPlayer = player->plr; dPlayer->mo = this; //dPlayer->clAngle = angle; /* $unifiedangles */ dPlayer->lookDir = 0; /* $unifiedangles */ } visAngle = angle >> 16; #if !__JHEXEN__ if(dPlayer && !dPlayer->inGame) { dPlayer->mo = 0; Mobj_Destroy(this); return false; } #endif #if !__JDOOM64__ // Do we need to update this mobj's flag values? if(ver < MOBJ_SAVEVERSION) { SV_TranslateLegacyMobjFlags(this, ver); } #endif P_MobjLink(this); floorZ = P_GetDoublep(Mobj_Sector(this), DMU_FLOOR_HEIGHT); ceilingZ = P_GetDoublep(Mobj_Sector(this), DMU_CEILING_HEIGHT); return false; #undef FF_FRAMEMASK #undef FF_FULLBRIGHT }
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; } }
static void SV_v13_ReadMobj(void) { coord_t pos[3], mom[3], floorz, ceilingz, radius, height; int frame, valid, type, ddflags = 0; spritenum_t sprite; mobjinfo_t* info; angle_t angle; mobj_t* mo; // The thinker was 3 ints long. Reader_ReadInt32(svReader); Reader_ReadInt32(svReader); Reader_ReadInt32(svReader); pos[VX] = FIX2FLT(Reader_ReadInt32(svReader)); pos[VY] = FIX2FLT(Reader_ReadInt32(svReader)); pos[VZ] = FIX2FLT(Reader_ReadInt32(svReader)); // Sector links. Reader_ReadInt32(svReader); Reader_ReadInt32(svReader); angle = (angle_t) (ANG45 * (Reader_ReadInt32(svReader) / 45)); sprite = Reader_ReadInt32(svReader); frame = Reader_ReadInt32(svReader); frame &= ~FF_FRAMEMASK; // not used anymore. // Block links. Reader_ReadInt32(svReader); Reader_ReadInt32(svReader); // Subsector. Reader_ReadInt32(svReader); floorz = FIX2FLT(Reader_ReadInt32(svReader)); ceilingz = FIX2FLT(Reader_ReadInt32(svReader)); radius = FIX2FLT(Reader_ReadInt32(svReader)); height = FIX2FLT(Reader_ReadInt32(svReader)); mom[MX] = FIX2FLT(Reader_ReadInt32(svReader)); mom[MY] = FIX2FLT(Reader_ReadInt32(svReader)); mom[MZ] = FIX2FLT(Reader_ReadInt32(svReader)); valid = Reader_ReadInt32(svReader); type = Reader_ReadInt32(svReader); info = &MOBJINFO[type]; if(info->flags & MF_SOLID) ddflags |= DDMF_SOLID; if(info->flags2 & MF2_DONTDRAW) ddflags |= DDMF_DONTDRAW; /** * We now have all the information we need to create the mobj. */ mo = Mobj_CreateXYZ(P_MobjThinker, pos[VX], pos[VY], pos[VZ], angle, radius, height, ddflags); mo->sprite = sprite; mo->frame = frame; mo->floorZ = floorz; mo->ceilingZ = ceilingz; mo->mom[MX] = mom[MX]; mo->mom[MY] = mom[MY]; mo->mom[MZ] = mom[MZ]; mo->valid = valid; mo->type = type; mo->moveDir = DI_NODIR; /** * Continue reading the mobj data. */ Reader_ReadInt32(svReader); // info mo->tics = Reader_ReadInt32(svReader); mo->state = INT2PTR(state_t, Reader_ReadInt32(svReader)); mo->damage = Reader_ReadInt32(svReader); mo->flags = Reader_ReadInt32(svReader); mo->flags2 = Reader_ReadInt32(svReader); mo->special1 = Reader_ReadInt32(svReader); mo->special2 = Reader_ReadInt32(svReader); mo->health = Reader_ReadInt32(svReader); // Fix a bunch of kludges in the original Heretic. switch(mo->type) { case MT_MACEFX1: case MT_MACEFX2: case MT_MACEFX3: case MT_HORNRODFX2: case MT_HEADFX3: case MT_WHIRLWIND: case MT_TELEGLITTER: case MT_TELEGLITTER2: mo->special3 = mo->health; mo->health = info->spawnHealth; break; default: break; } mo->moveDir = Reader_ReadInt32(svReader); mo->moveCount = Reader_ReadInt32(svReader); Reader_ReadInt32(svReader); // target mo->reactionTime = Reader_ReadInt32(svReader); mo->threshold = Reader_ReadInt32(svReader); mo->player = INT2PTR(player_t, Reader_ReadInt32(svReader)); mo->lastLook = Reader_ReadInt32(svReader); mo->spawnSpot.origin[VX] = (coord_t) Reader_ReadInt32(svReader); mo->spawnSpot.origin[VY] = (coord_t) Reader_ReadInt32(svReader); mo->spawnSpot.origin[VZ] = 0; // Initialize with "something". mo->spawnSpot.angle = (angle_t) (ANG45 * (Reader_ReadInt32(svReader) / 45)); /*mo->spawnSpot.type = (int)*/ Reader_ReadInt32(svReader); { int spawnFlags = ((int) Reader_ReadInt32(svReader)) & ~MASK_UNKNOWN_MSF_FLAGS; // Spawn on the floor by default unless the mobjtype flags override. spawnFlags |= MSF_Z_FLOOR; mo->spawnSpot.flags = spawnFlags; } mo->info = info; SV_TranslateLegacyMobjFlags(mo, 0); mo->state = &STATES[PTR2INT(mo->state)]; mo->target = NULL; if(mo->player) { mo->player = &players[PTR2INT(mo->player) - 1]; mo->player->plr->mo = mo; mo->player->plr->mo->dPlayer = mo->player->plr; } P_MobjLink(mo); mo->floorZ = P_GetDoublep(Mobj_Sector(mo), DMU_FLOOR_HEIGHT); mo->ceilingZ = P_GetDoublep(Mobj_Sector(mo), DMU_CEILING_HEIGHT); }