// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2008 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // //----------------------------------------------------------------------------- // P_tick.c #include "doomdef.h" #include "i_system.h" #include "p_local.h" #include "v_video.h" int leveltime; int TimerGame; /* ==================== = = P_ArchivePlayers = ==================== */ void P_ArchivePlayers(void) { int i; int j; player_t dest; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) { continue; } memcpy(&dest, &players[i], sizeof(player_t)); for (j = 0; j < NUMPSPRITES; j++) { if (dest.psprites[j].state) { dest.psprites[j].state = (state_t *) (dest.psprites[j].state - states); } } SV_Write(&dest, sizeof(player_t)); } } /* ==================== = = P_UnArchivePlayers = ==================== */ void P_UnArchivePlayers(void) { int i, j; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; memcpy(&players[i], save_p, sizeof(player_t)); save_p += sizeof(player_t); players[i].mo = NULL; // will be set when unarc thinker players[i].message = NULL; players[i].attacker = NULL; for (j = 0; j < NUMPSPRITES; j++) if (players[i].psprites[j].state) players[i].psprites[j].state = &states[(int) players[i].psprites[j].state]; } } //============================================================================= /* ==================== = = P_ArchiveWorld = ==================== */ void P_ArchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; // Sectors for (i = 0, sec = sectors; i < numsectors; i++, sec++) { SV_WriteWord(sec->floorheight >> FRACBITS); SV_WriteWord(sec->ceilingheight >> FRACBITS); SV_WriteWord(sec->floorpic); SV_WriteWord(sec->ceilingpic); SV_WriteWord(sec->lightlevel); SV_WriteWord(sec->special); // needed? SV_WriteWord(sec->tag); // needed? } // Lines for (i = 0, li = lines; i < numlines; i++, li++) { SV_WriteWord(li->flags); SV_WriteWord(li->special); SV_WriteWord(li->tag); for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) { continue; } si = &sides[li->sidenum[j]]; SV_WriteWord(si->textureoffset >> FRACBITS); SV_WriteWord(si->rowoffset >> FRACBITS); SV_WriteWord(si->toptexture); SV_WriteWord(si->bottomtexture); SV_WriteWord(si->midtexture); } } } /* ==================== = = P_UnArchiveWorld = ==================== */ void P_UnArchiveWorld(void) { int i, j; sector_t *sec; line_t *li; side_t *si; short *get; get = (short *) save_p; // // do sectors // for (i = 0, sec = sectors; i < numsectors; i++, sec++) { sec->floorheight = *get++ << FRACBITS; sec->ceilingheight = *get++ << FRACBITS; sec->floorpic = *get++; sec->ceilingpic = *get++; sec->lightlevel = *get++; sec->special = *get++; // needed? sec->tag = *get++; // needed? sec->specialdata = 0; sec->soundtarget = 0; } // // do lines // for (i = 0, li = lines; i < numlines; i++, li++) { li->flags = *get++; li->special = *get++; li->tag = *get++; for (j = 0; j < 2; j++) { if (li->sidenum[j] == -1) continue; si = &sides[li->sidenum[j]]; si->textureoffset = *get++ << FRACBITS; si->rowoffset = *get++ << FRACBITS; si->toptexture = *get++; si->bottomtexture = *get++; si->midtexture = *get++; } } save_p = (byte *) get; } //============================================================================= typedef enum { tc_end, tc_mobj } thinkerclass_t; /* ==================== = = P_ArchiveThinkers = ==================== */ void P_ArchiveThinkers(void) { thinker_t *th; mobj_t mobj; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == P_MobjThinker) { SV_WriteByte(tc_mobj); memcpy(&mobj, th, sizeof(mobj_t)); mobj.state = (state_t *) (mobj.state - states); if (mobj.player) { mobj.player = (player_t *) ((mobj.player - players) + 1); } SV_Write(&mobj, sizeof(mobj_t)); continue; } //I_Error("P_ArchiveThinkers: Unknown thinker function"); } // Add a terminating marker SV_WriteByte(tc_end); } /* ==================== = = P_UnArchiveThinkers = ==================== */ void P_UnArchiveThinkers(void) { byte tclass; thinker_t *currentthinker, *next; mobj_t *mobj; // // remove all the current thinkers // currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { next = currentthinker->next; if (currentthinker->function == P_MobjThinker) P_RemoveMobj((mobj_t *) currentthinker); else Z_Free(currentthinker); currentthinker = next; } P_InitThinkers(); // read in saved thinkers while (1) { tclass = *save_p++; switch (tclass) { case tc_end: return; // end of list case tc_mobj: mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL); memcpy(mobj, save_p, sizeof(*mobj)); save_p += sizeof(*mobj); mobj->state = &states[(int) mobj->state]; mobj->target = NULL; if (mobj->player) { mobj->player = &players[(int) mobj->player - 1]; mobj->player->mo = mobj; } P_SetThingPosition(mobj); mobj->info = &mobjinfo[mobj->type]; mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; mobj->thinker.function = P_MobjThinker; P_AddThinker(&mobj->thinker); break; default: I_Error("Unknown tclass %i in savegame", tclass); } } } //============================================================================= /* ==================== = = P_ArchiveSpecials = ==================== */ enum { tc_ceiling, tc_door, tc_floor, tc_plat, tc_flash, tc_strobe, tc_glow, tc_endspecials } specials_e; void P_ArchiveSpecials(void) { /* T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list T_VerticalDoor, (vldoor_t: sector_t * swizzle), T_MoveFloor, (floormove_t: sector_t * swizzle), T_LightFlash, (lightflash_t: sector_t * swizzle), T_StrobeFlash, (strobe_t: sector_t *), T_Glow, (glow_t: sector_t *), T_PlatRaise, (plat_t: sector_t *), - active list */ thinker_t *th; ceiling_t ceiling; vldoor_t door; floormove_t floor; plat_t plat; lightflash_t flash; strobe_t strobe; glow_t glow; for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function == T_MoveCeiling) { SV_WriteByte(tc_ceiling); memcpy(&ceiling, th, sizeof(ceiling_t)); ceiling.sector = (sector_t *) (ceiling.sector - sectors); SV_Write(&ceiling, sizeof(ceiling_t)); continue; } if (th->function == T_VerticalDoor) { SV_WriteByte(tc_door); memcpy(&door, th, sizeof(vldoor_t)); door.sector = (sector_t *) (door.sector - sectors); SV_Write(&door, sizeof(vldoor_t)); continue; } if (th->function == T_MoveFloor) { SV_WriteByte(tc_floor); memcpy(&floor, th, sizeof(floormove_t)); floor.sector = (sector_t *) (floor.sector - sectors); SV_Write(&floor, sizeof(floormove_t)); continue; } if (th->function == T_PlatRaise) { SV_WriteByte(tc_plat); memcpy(&plat, th, sizeof(plat_t)); plat.sector = (sector_t *) (plat.sector - sectors); SV_Write(&plat, sizeof(plat_t)); continue; } if (th->function == T_LightFlash) { SV_WriteByte(tc_flash); memcpy(&flash, th, sizeof(lightflash_t)); flash.sector = (sector_t *) (flash.sector - sectors); SV_Write(&flash, sizeof(lightflash_t)); continue; } if (th->function == T_StrobeFlash) { SV_WriteByte(tc_strobe); memcpy(&strobe, th, sizeof(strobe_t)); strobe.sector = (sector_t *) (strobe.sector - sectors); SV_Write(&strobe, sizeof(strobe_t)); continue; } if (th->function == T_Glow) { SV_WriteByte(tc_glow); memcpy(&glow, th, sizeof(glow_t)); glow.sector = (sector_t *) (glow.sector - sectors); SV_Write(&glow, sizeof(glow_t)); continue; } } // Add a terminating marker SV_WriteByte(tc_endspecials); } /* ==================== = = P_UnArchiveSpecials = ==================== */ void P_UnArchiveSpecials(void) { byte tclass; ceiling_t *ceiling; vldoor_t *door; floormove_t *floor; plat_t *plat; lightflash_t *flash; strobe_t *strobe; glow_t *glow; // read in saved thinkers while (1) { tclass = *save_p++; switch (tclass) { case tc_endspecials: return; // end of list case tc_ceiling: ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL); memcpy(ceiling, save_p, sizeof(*ceiling)); save_p += sizeof(*ceiling); ceiling->sector = §ors[(int) ceiling->sector]; ceiling->sector->specialdata = T_MoveCeiling; if (ceiling->thinker.function) ceiling->thinker.function = T_MoveCeiling; P_AddThinker(&ceiling->thinker); P_AddActiveCeiling(ceiling); break; case tc_door: door = Z_Malloc(sizeof(*door), PU_LEVEL, NULL); memcpy(door, save_p, sizeof(*door)); save_p += sizeof(*door); door->sector = §ors[(int) door->sector]; door->sector->specialdata = door; door->thinker.function = T_VerticalDoor; P_AddThinker(&door->thinker); break; case tc_floor: floor = Z_Malloc(sizeof(*floor), PU_LEVEL, NULL); memcpy(floor, save_p, sizeof(*floor)); save_p += sizeof(*floor); floor->sector = §ors[(int) floor->sector]; floor->sector->specialdata = T_MoveFloor; floor->thinker.function = T_MoveFloor; P_AddThinker(&floor->thinker); break; case tc_plat: plat = Z_Malloc(sizeof(*plat), PU_LEVEL, NULL); memcpy(plat, save_p, sizeof(*plat)); save_p += sizeof(*plat); plat->sector = §ors[(int) plat->sector]; plat->sector->specialdata = T_PlatRaise; if (plat->thinker.function) plat->thinker.function = T_PlatRaise; P_AddThinker(&plat->thinker); P_AddActivePlat(plat); break; case tc_flash: flash = Z_Malloc(sizeof(*flash), PU_LEVEL, NULL); memcpy(flash, save_p, sizeof(*flash)); save_p += sizeof(*flash); flash->sector = §ors[(int) flash->sector]; flash->thinker.function = T_LightFlash; P_AddThinker(&flash->thinker); break; case tc_strobe: strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, NULL); memcpy(strobe, save_p, sizeof(*strobe)); save_p += sizeof(*strobe); strobe->sector = §ors[(int) strobe->sector]; strobe->thinker.function = T_StrobeFlash; P_AddThinker(&strobe->thinker); break; case tc_glow: glow = Z_Malloc(sizeof(*glow), PU_LEVEL, NULL); memcpy(glow, save_p, sizeof(*glow)); save_p += sizeof(*glow); glow->sector = §ors[(int) glow->sector]; glow->thinker.function = T_Glow; P_AddThinker(&glow->thinker); break; default: I_Error("P_UnarchiveSpecials:Unknown tclass %i " "in savegame", tclass); } } } /* =============================================================================== THINKERS All thinkers should be allocated by Z_Malloc so they can be operated on uniformly. The actual structures will vary in size, but the first element must be thinker_t. =============================================================================== */ thinker_t thinkercap; // both the head and tail of the thinker list /* =============== = = P_InitThinkers = =============== */ void P_InitThinkers(void) { thinkercap.prev = thinkercap.next = &thinkercap; } /* =============== = = P_AddThinker = = Adds a new thinker at the end of the list = =============== */ void P_AddThinker(thinker_t * thinker) { thinkercap.prev->next = thinker; thinker->next = &thinkercap; thinker->prev = thinkercap.prev; thinkercap.prev = thinker; } /* =============== = = P_RemoveThinker = = Deallocation is lazy -- it will not actually be freed until its = thinking turn comes up = =============== */ void P_RemoveThinker(thinker_t * thinker) { thinker->function = (think_t) - 1; } /* =============== = = P_AllocateThinker = = Allocates memory and adds a new thinker at the end of the list = =============== */ void P_AllocateThinker(thinker_t * thinker) { } /* =============== = = P_RunThinkers = =============== */ void P_RunThinkers(void) { thinker_t *currentthinker; currentthinker = thinkercap.next; while (currentthinker != &thinkercap) { if (currentthinker->function == (think_t) - 1) { // time to remove it currentthinker->next->prev = currentthinker->prev; currentthinker->prev->next = currentthinker->next; Z_Free(currentthinker); } else { if (currentthinker->function) currentthinker->function(currentthinker); } currentthinker = currentthinker->next; } } //---------------------------------------------------------------------------- // // PROC P_Ticker // //---------------------------------------------------------------------------- void P_Ticker(void) { int i; if (paused) { return; } for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { P_PlayerThink(&players[i]); } } if (TimerGame) { if (!--TimerGame) { G_ExitLevel(); } } P_RunThinkers(); P_UpdateSpecials(); P_AmbientSound(); leveltime++; }