void Unlag::reconcilePlayerPositions(byte shooter_id, size_t ticsago) { for (size_t i=0; i<player_history.size(); i++) { player_t *player = player_history[i].player; // skip over the player shooting and any spectators if (player->id == shooter_id || player->spectator || !player->mo) continue; fixed_t dest_x, dest_y, dest_z; // position to move player to if (!reconciled) { // record the player's current position, which hasn't yet // been saved to the history arrays player_history[i].backup_x = player->mo->x; player_history[i].backup_y = player->mo->y; player_history[i].backup_z = player->mo->z; size_t cur = (gametic - ticsago) % Unlag::MAX_HISTORY_TICS; dest_x = player_history[i].history_x[cur]; dest_y = player_history[i].history_y[cur]; dest_z = player_history[i].history_z[cur]; if (player_history[i].history_size < ticsago) { // make the player temporarily unshootable since this player // was not alive when the shot was fired. Kind of a hack. player_history[i].backup_flags = player->mo->flags; player->mo->flags &= ~(MF_SHOOTABLE | MF_SOLID); player_history[i].changed_flags = true; } #ifdef _UNLAG_DEBUG_ // spawn a marker sprite at the reconciled position for debugging AActor *mo = new AActor(dest_x, dest_y, dest_z, MT_KEEN); mo->flags &= ~(MF_SHOOTABLE | MF_SOLID); mo->health = -187; SV_SpawnMobj(mo); #endif // _UNLAG_DEBUG_ } else { // we're moving the player back to proper position dest_x = player_history[i].backup_x; dest_y = player_history[i].backup_y; dest_z = player_history[i].backup_z; // restore a player's shootability if we removed it previously if (player_history[i].changed_flags) { player->mo->flags = player_history[i].backup_flags; player_history[i].changed_flags = false; } } movePlayer(player, dest_x, dest_y, dest_z); } }
// // [Toke - CTF] CTF_SpawnFlag // Spawns a flag of the designated type in the designated location // void CTF_SpawnFlag (flag_t f) { flagdata *data = &CTFdata[f]; AActor *flag = new AActor (data->x, data->y, data->z, flag_table[f][flag_home]); SV_SpawnMobj(flag); data->actor = flag->ptr(); data->state = flag_home; data->flagger = 0; }
// // CTF_SpawnDroppedFlag // Spawns a dropped flag // void CTF_SpawnDroppedFlag (flag_t f, int x, int y, int z) { flagdata *data = &CTFdata[f]; AActor *flag = new AActor (x, y, z, flag_table[f][flag_dropped]); SV_SpawnMobj(flag); data->actor = flag->ptr(); data->state = flag_dropped; data->timeout = (size_t)(ctf_flagtimeout * TICRATE); data->flagger = 0; }
// // P_SpawnPlayer // Called when a player is spawned on the level. // Most of the player structure stays unchanged // between levels. // void P_SpawnPlayer (player_t &player, mapthing2_t *mthing) { // denis - clients should not control spawning if(!serverside) return; // [RH] Things 4001-? are also multiplayer starts. Just like 1-4. // To make things simpler, figure out which player is being // spawned here. player_t *p = &player; // not playing? if(!p->ingame()) return; if (p->playerstate == PST_REBORN || p->playerstate == PST_ENTER) G_PlayerReborn (*p); AActor *mobj = new AActor (mthing->x << FRACBITS, mthing->y << FRACBITS, ONFLOORZ, MT_PLAYER); // set color translations for player sprites // [RH] Different now: MF_TRANSLATION is not used. // mobj->translation = translationtables + 256*playernum; mobj->angle = ANG45 * (mthing->angle/45); mobj->pitch = mobj->roll = 0; mobj->player = p; mobj->health = p->health; // [RH] Set player sprite based on skin if(p->userinfo.skin >= numskins) p->userinfo.skin = 0; mobj->sprite = skins[p->userinfo.skin].sprite; p->fov = 90.0f; p->mo = p->camera = mobj->ptr(); p->playerstate = PST_LIVE; p->refire = 0; p->damagecount = 0; p->bonuscount = 0; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; p->xviewshift = 0; p->attacker = AActor::AActorPtr(); // Set up some special spectator stuff if (p->spectator) { mobj->translucency = 0; p->mo->flags |= MF_SPECTATOR; p->mo->flags2 |= MF2_FLY; } // [RH] Allow chasecam for demo watching //if ((demoplayback || demonew) && chasedemo) // p->cheats = CF_CHASECAM; // setup gun psprite P_SetupPsprites (p); // give all cards in death match mode if (sv_gametype != GM_COOP) { for (int i = 0; i < NUMCARDS; i++) p->cards[i] = true; } if(serverside) { // [RH] If someone is in the way, kill them P_TeleportMove (mobj, mobj->x, mobj->y, mobj->z, true); // [BC] Do script stuff if (level.behavior != NULL) { if (p->playerstate == PST_ENTER) { level.behavior->StartTypedScripts (SCRIPT_Enter, p->mo); } else if (p->playerstate == PST_REBORN) { level.behavior->StartTypedScripts (SCRIPT_Respawn, p->mo); } } // send new objects SV_SpawnMobj(mobj); } }
// // P_SpawnMapThing // The fields of the mapthing should // already be in host byte order. // // [RH] position is used to weed out unwanted start spots // void P_SpawnMapThing (mapthing2_t *mthing, int position) { int i; int bit; AActor *mobj; fixed_t x, y, z; if (mthing->type == 0 || mthing->type == -1) return; // count deathmatch start positions if (mthing->type == 11 || ((mthing->type == 5080 || mthing->type == 5081 || mthing->type == 5082)) && !sv_teamspawns) { if (deathmatch_p == &deathmatchstarts[MaxDeathmatchStarts]) { // [RH] Get more deathmatchstarts int offset = MaxDeathmatchStarts; MaxDeathmatchStarts *= 2; deathmatchstarts = (mapthing2_t *)Realloc (deathmatchstarts, MaxDeathmatchStarts * sizeof(mapthing2_t)); deathmatch_p = &deathmatchstarts[offset]; } memcpy (deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; return; } // [Toke - CTF - starts] CTF starts - count Blue team start positions if (mthing->type == 5080 && sv_teamspawns) { if (blueteam_p == &blueteamstarts[MaxBlueTeamStarts]) { int offset = MaxBlueTeamStarts; MaxBlueTeamStarts *= 2; blueteamstarts = (mapthing2_t *)Realloc (blueteamstarts, MaxBlueTeamStarts * sizeof(mapthing2_t)); blueteam_p = &blueteamstarts[offset]; } memcpy (blueteam_p, mthing, sizeof(*mthing)); blueteam_p++; return; } // [Toke - CTF - starts] CTF starts - count Red team start positions if (mthing->type == 5081 && sv_teamspawns) { if (redteam_p == &redteamstarts[MaxRedTeamStarts]) { int offset = MaxRedTeamStarts; MaxRedTeamStarts *= 2; redteamstarts = (mapthing2_t *)Realloc (redteamstarts, MaxRedTeamStarts * sizeof(mapthing2_t)); redteam_p = &redteamstarts[offset]; } memcpy (redteam_p, mthing, sizeof(*mthing)); redteam_p++; return; } // [RH] Record polyobject-related things if (HexenHack) { switch (mthing->type) { case PO_HEX_ANCHOR_TYPE: mthing->type = PO_ANCHOR_TYPE; break; case PO_HEX_SPAWN_TYPE: mthing->type = PO_SPAWN_TYPE; break; case PO_HEX_SPAWNCRUSH_TYPE: mthing->type = PO_SPAWNCRUSH_TYPE; break; } } if (mthing->type == PO_ANCHOR_TYPE || mthing->type == PO_SPAWN_TYPE || mthing->type == PO_SPAWNCRUSH_TYPE) { polyspawns_t *polyspawn = new polyspawns_t; polyspawn->next = polyspawns; polyspawn->x = mthing->x << FRACBITS; polyspawn->y = mthing->y << FRACBITS; polyspawn->angle = mthing->angle; polyspawn->type = mthing->type; polyspawns = polyspawn; if (mthing->type != PO_ANCHOR_TYPE) po_NumPolyobjs++; return; } // check for players specially if ((mthing->type <= 4 && mthing->type > 0) || (mthing->type >= 4001 && mthing->type <= 4001 + MAXPLAYERSTARTS - 4)) { // [RH] Only spawn spots that match position. if (mthing->args[0] != position) return; playerstarts.push_back(*mthing); return; } // [RH] sound sequence overrides if (mthing->type >= 1400 && mthing->type < 1410) { return; } else if (mthing->type == 1411) { int type; if (mthing->args[0] == 255) type = -1; else type = mthing->args[0]; if (type > 63) { Printf (PRINT_HIGH, "Sound sequence %d out of range\n", type); } else { } return; } /*if (deathmatch) { if (!(mthing->flags & MTF_DEATHMATCH)) return; } else if (multiplayer) { if (!(mthing->flags & MTF_COOPERATIVE)) return; } if (!multiplayer) { if (!(mthing->flags & MTF_SINGLE)) return; }*/ // GhostlyDeath -- Correctly spawn things if (sv_gametype != GM_COOP && !(mthing->flags & MTF_DEATHMATCH)) return; if (sv_gametype == GM_COOP && sv_maxplayers == 1 && !(mthing->flags & MTF_SINGLE)) return; if (sv_gametype == GM_COOP && sv_maxplayers != 1 && !(mthing->flags & MTF_COOPERATIVE)) return; // check for apropriate skill level if (sv_skill == sk_baby) bit = 1; else if (sv_skill == sk_nightmare) bit = 4; else bit = 1 << ((int)sv_skill - 2); if (!(mthing->flags & bit)) return; // [RH] Determine if it is an old ambient thing, and if so, // map it to MT_AMBIENT with the proper parameter. if (mthing->type >= 14001 && mthing->type <= 14064) { mthing->args[0] = mthing->type - 14000; mthing->type = 14065; i = MT_AMBIENT; } // [RH] Check if it's a particle fountain else if (mthing->type >= 9027 && mthing->type <= 9033) { mthing->args[0] = mthing->type - 9026; i = MT_FOUNTAIN; } else { // find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) if (mthing->type == mobjinfo[i].doomednum) break; } if (i >= NUMMOBJTYPES) { // [RH] Don't die if the map tries to spawn an unknown thing Printf (PRINT_HIGH, "Unknown type %i at (%i, %i)\n", mthing->type, mthing->x, mthing->y); i = MT_UNKNOWNTHING; } // [RH] If the thing's corresponding sprite has no frames, also map // it to the unknown thing. else if (sprites[states[mobjinfo[i].spawnstate].sprite].numframes == 0) { Printf (PRINT_HIGH, "Type %i at (%i, %i) has no frames\n", mthing->type, mthing->x, mthing->y); i = MT_UNKNOWNTHING; } // don't spawn keycards and players in deathmatch if (sv_gametype != GM_COOP && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn deathmatch weapons in offline single player mode if (!multiplayer) { switch (i) { case MT_CHAINGUN: case MT_SHOTGUN: case MT_SUPERSHOTGUN: case MT_MISC25: // BFG case MT_MISC26: // chainsaw case MT_MISC27: // rocket launcher case MT_MISC28: // plasma gun if ((mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH) return; break; default: break; } } if (sv_nomonsters) if (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL) ) return; // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (i == MT_WATERZONE) { sector_t *sec = R_PointInSubsector (x, y)->sector; sec->waterzone = 1; return; } else if (i == MT_SECRETTRIGGER) { level.total_secrets++; } if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mobj = new AActor (x, y, z, (mobjtype_t)i); if (z == ONFLOORZ) mobj->z += mthing->z << FRACBITS; else if (z == ONCEILINGZ) mobj->z -= mthing->z << FRACBITS; mobj->spawnpoint = *mthing; if (mobj->flags2 & MF2_FLOATBOB) { // Seed random starting index for bobbing motion mobj->health = M_Random(); mobj->special1 = mthing->z << FRACBITS; } // [RH] Set the thing's special mobj->special = mthing->special; memcpy (mobj->args, mthing->args, sizeof(mobj->args)); if (mobj->tics > 0) mobj->tics = 1 + (P_Random () % mobj->tics); if (mobj->flags & MF_COUNTKILL) level.total_monsters++; if (mobj->flags & MF_COUNTITEM) level.total_items++; if (i != MT_SPARK) mobj->angle = ANG45 * (mthing->angle/45); if (mthing->flags & MTF_AMBUSH) mobj->flags |= MF_AMBUSH; // [RH] Add ThingID to mobj and link it in with the others mobj->tid = mthing->thingid; mobj->AddToHash (); SV_SpawnMobj(mobj); if (sv_gametype == GM_CTF) { // [Toke - CTF] Setup flag sockets if (mthing->type == ID_BLUE_FLAG) { flagdata *data = &CTFdata[it_blueflag]; if (data->flaglocated) return; CTF_RememberFlagPos (mthing); CTF_SpawnFlag(it_blueflag); } if (mthing->type == ID_RED_FLAG) { flagdata *data = &CTFdata[it_redflag]; if (data->flaglocated) return; CTF_RememberFlagPos (mthing); CTF_SpawnFlag(it_redflag); } } // [RH] Go dormant as needed if (mthing->flags & MTF_DORMANT) P_DeactivateMobj (mobj); }
// // P_RespawnSpecials // void P_RespawnSpecials (void) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; AActor* mo; mapthing2_t* mthing; int i; if(!serverside) return; // only respawn items in deathmatch if (sv_gametype == GM_COOP || !sv_itemsrespawn) return; // nothing left to respawn? if (iquehead == iquetail) return; // wait a certain number of seconds if (level.time - itemrespawntime[iquetail] < sv_itemrespawntime*TICRATE) return; mthing = &itemrespawnque[iquetail]; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) { if (mthing->type == mobjinfo[i].doomednum) break; } // [Fly] crashes sometimes without it if (i >= NUMMOBJTYPES) { // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); return; } if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; // spawn a teleport fog at the new spot ss = R_PointInSubsector (x, y); mo = new AActor (x, y, z, MT_IFOG); SV_SpawnMobj(mo); if (clientside) S_Sound (mo, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); // spawn it mo = new AActor (x, y, z, (mobjtype_t)i); mo->spawnpoint = *mthing; mo->angle = ANG45 * (mthing->angle/45); if (z == ONFLOORZ) mo->z += mthing->z << FRACBITS; else if (z == ONCEILINGZ) mo->z -= mthing->z << FRACBITS; if (mo->flags2 & MF2_FLOATBOB) { // Seed random starting index for bobbing motion mo->health = M_Random(); mo->special1 = mthing->z << FRACBITS; } mo->special = 0; // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); SV_SpawnMobj(mo); }