// ticks the game forward in time void GameInfo::Ticker() { tic++; // TODO read/write demo ticcmd's here // do main actions switch (state) { case GS_INTRO: if (--pagetic <= 0) AdvanceIntro(); break; case GS_LEVEL: if (!paused && currentcluster) currentcluster->Ticker(); if (!dedicated) { hud.Ticker(); automap.Ticker(); } break; case GS_INTERMISSION: wi.Ticker(); break; case GS_FINALE: F_Ticker(); break; case GS_NULL: default: // do nothing break; } MapInfo *m; PlayerInfo *p; if (state != GS_LEVEL) return; // manage players for (player_iter_t t = Players.begin(); t != Players.end(); ) { p = t->second; t++; // because "old t" may be invalidated if (p->playerstate == PST_REMOVE) { // the player is removed from the game (invalidates "old t") if (!p->mp) RemovePlayer(p->number); // first the maps throw out the removed player, then the game proper. // TODO purge the removed players from the frag maps of other players? } else p->Ticker(); } if (!server) return; // for (player_iter_t t = Players.begin(); t != Players.end(); t++) { p = t->second; if (p->playerstate == PST_NEEDMAP) { LConnection *conn = p->connection; if (conn && !conn->isGhostAvailable(p)) { // remote player, is it already being ghosted? if not, wait. CONS_Printf(" server waiting for client ghost\n"); continue; } // assign the player to a map CONS_Printf("Map request.."); if (p->requestmap == 0) { m = initial_map; // first map in game p->entrypoint = initial_ep; } else m = FindMapInfo(p->requestmap); if (!m) { // game ends currentcluster->Finish(p->requestmap, p->entrypoint); StartFinale(NULL); break; } else if (!m->found) m = currentcluster->maps[0]; // TODO or give an error? // cluster change? if (currentcluster->number != m->cluster) { // TODO minor thing: if several players exit maps on the same tick, // and someone besides the first one causes a cluster change, some // maps could be loaded in vain... // cluster change! currentcluster->Finish(p->requestmap, p->entrypoint); MapCluster *next = FindCluster(m->cluster); StartFinale(next); currentcluster = next; break; // this is important! no need to check the other players. } p->Reset(!currentcluster->keepstuff, true); // normal individual mapchange if (!m->Activate(p)) I_Error("Darn!\n"); if (conn) { CONS_Printf(" server sending rpc\n"); // nonlocal player enters a new map, notify client // send the EnterMap rpc only to the owning connection NetEvent *e = TNL_RPC_CONSTRUCT_NETEVENT(p, s2cEnterMap, (m->mapnumber)); conn->postNetEvent(e); } } } }
void G_Ticker(void) { int i, buf; ticcmd_t *cmd = NULL; // // do player reborns if needed // for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].playerstate == PST_REBORN) G_DoReborn(i); // // do things to change the game state // while (gameaction != ga_nothing) { switch (gameaction) { case ga_loadlevel: G_DoLoadLevel(); break; case ga_newgame: G_DoNewGame(); break; case ga_loadgame: G_DoLoadGame(); break; case ga_savegame: G_DoSaveGame(); break; case ga_playdemo: G_DoPlayDemo(); break; case ga_screenshot: V_ScreenShot("HTIC%02i.%s"); gameaction = ga_nothing; break; case ga_completed: G_DoCompleted(); break; case ga_worlddone: G_DoWorldDone(); break; case ga_victory: F_StartFinale(); break; default: break; } } // // get commands, check consistancy, and build new consistancy check // //buf = gametic%BACKUPTICS; buf = (gametic / ticdup) % BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { cmd = &players[i].cmd; memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); if (demoplayback) G_ReadDemoTiccmd(cmd); if (demorecording) G_WriteDemoTiccmd(cmd); if (netgame && !(gametic % ticdup)) { if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy) { I_Error("consistency failure (%i should be %i)", cmd->consistancy, consistancy[i][buf]); } if (players[i].mo) consistancy[i][buf] = players[i].mo->x; else consistancy[i][buf] = rndindex; } } // // check for special buttons // for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { if (players[i].cmd.buttons & BT_SPECIAL) { switch (players[i].cmd.buttons & BT_SPECIALMASK) { case BTS_PAUSE: paused ^= 1; if (paused) { S_PauseSound(); } else { S_ResumeSound(); } break; case BTS_SAVEGAME: if (!savedescription[0]) { if (netgame) { M_StringCopy(savedescription, DEH_String("NET GAME"), sizeof(savedescription)); } else { M_StringCopy(savedescription, DEH_String("SAVE GAME"), sizeof(savedescription)); } } savegameslot = (players[i].cmd. buttons & BTS_SAVEMASK) >> BTS_SAVESHIFT; gameaction = ga_savegame; break; } } } // turn inventory off after a certain amount of time if (inventory && !(--inventoryTics)) { players[consoleplayer].readyArtifact = players[consoleplayer].inventory[inv_ptr].type; inventory = false; cmd->arti = 0; } // // do main actions // // // do main actions // switch (gamestate) { case GS_LEVEL: P_Ticker(); SB_Ticker(); AM_Ticker(); CT_Ticker(); break; case GS_INTERMISSION: IN_Ticker(); break; case GS_FINALE: F_Ticker(); break; case GS_DEMOSCREEN: D_PageTicker(); break; } }