/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 3 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, see . */ /* * $Logfile: /DescentIII/Main/hyperanarchy/hyperanarchy.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003/08/26 03:57:56 $ * $Author: kevinb $ * * * * $Log: hyperanarchy.cpp,v $ * Revision 1.1.1.1 2003/08/26 03:57:56 kevinb * initial 1.5 import * * * 68 10/21/99 9:27p Jeff * B.A. Macintosh code merge * * 67 7/12/99 1:22p Jeff * updated for new netflags * * 66 7/11/99 6:45p Jeff * cleaner plr if the list is too long * * 65 5/23/99 3:04a Jason * fixed bug with player rankings not being updated correctly * * 64 5/20/99 5:03p Jeff * fixed HUD display bugs * * 63 5/12/99 11:04p Jeff * dmfc and multiplayer games now have endian friendly packets (*whew*) * * 62 5/12/99 11:28a Jeff * added sourcesafe comment block * * $NoKeywords: $ */ #include #include #include "gamedll_header.h" #include "idmfc.h" #include "HyperAnarchy.h" #include "hyperstr.h" IDMFC *DMFCBase = NULL; IDmfcStats *dstat = NULL; object *dObjects; player *dPlayers; #define SPID_HYPERINFO 0 #define SPID_HYPERPOS 1 #define HCM_PLAYERCOLOR 0 #define HCM_NORMAL 1 typedef struct { int Score[2]; } tPlayerStat; int pack_pstat(tPlayerStat *user_info, ubyte *data) { int count = 0; MultiAddInt(user_info->Score[0], data, &count); MultiAddInt(user_info->Score[1], data, &count); return count; } int unpack_pstat(tPlayerStat *user_info, ubyte *data) { int count = 0; user_info->Score[0] = MultiGetInt(data, &count); user_info->Score[1] = MultiGetInt(data, &count); return count; } int SortedPlayers[MAX_PLAYER_RECORDS]; bool DisplayScoreScreen; int HyperOrbID = -1; int WhoHasOrb = -1; int KillCount = 0; int HyperOrbIcon = -1; bool DisplayFlagBlink = true; int WhoJustScoredTimer = -1; int HyperMoveTimer = -1; ubyte HUD_color_model = HCM_PLAYERCOLOR; int Highlight_bmp = -1; bool display_my_welcome = false; void OnClientPlayerEntersGame(int player_num); /////////////////////////////////////////////// // localization info char **StringTable; int StringTableSize = 0; const char *_ErrorString = "Missing String"; const char *GetStringFromTable(int d) { if ((d < 0) || (d >= StringTableSize)) return _ErrorString; else return StringTable[d]; } /////////////////////////////////////////////// void SwitchHUDColor(int i); // handles a Hyper Anarchy Game State packet void ReceiveHyperGameState(ubyte *data); // sends a Hyper Anarchy Game State packet void SendHyperGameState(int playernum); // Displays HUD scores void DisplayHUDScores(struct tHUDItem *hitem); // Displays the Stats screen void DisplayScores(void); // Sorts based on score void SortPlayerScores(int *sortedindex, int size); // Updates the effect on all the players void UpdateEffect(void); // Displays the Welcome Screen void DisplayWelcomeScreen(int pnum); // Handler for menu item for turning on/off blinking hud void SwitchBlinkingHud(int i); // Generates a valid random room int GetRandomValidRoom(void); // Moves the HyperOrb to the center of a random room // if objnum is -1, than the HyperOrb is created and moved void MoveHyperOrbToRoom(int objnum); // Given a room the HyperOrb is created and placed in the center of it void CreateHyperOrbInRoom(int room); // Given the objnum and room it will move the HyperOrb to the center of that room. Objnum better be valid. void MoveHyperOrbToRoomCenter(int objnum, int room); // handles a Hyper Anarchy Object Placement packet void ReceiveHyperPos(ubyte *data); // Searches through all the objects and looks for the HyperOrb, returns it's objnum. -1 if it doesn't exist int FindHyperObjectNum(void); // Searches through all the player's inventory, returns the pnum of the player who has the HyperOrb, -1 // if no one does. int FindHyperOrbInInventory(void); void ResetTimer(void); void SaveStatsToFile(char *filename); void DetermineScore(int precord_num, int column_num, char *buffer, int buffer_size) { player_record *pr = DMFCBase->GetPlayerRecord(precord_num); if (!pr || pr->state == STATE_EMPTY) { buffer[0] = '\0'; return; } tPlayerStat *stat = (tPlayerStat *)pr->user_info; snprintf(buffer, buffer_size, "%d[%d]", stat->Score[DSTAT_LEVEL], stat->Score[DSTAT_OVERALL]); } void ShowStatBitmap(int precord_num, int column_num, int x, int y, int w, int h, ubyte alpha_to_use) { player_record *pr = DMFCBase->GetPlayerRecord(precord_num); if (pr && pr->state == STATE_INGAME) { if (WhoHasOrb == pr->pnum) { // draw hyper orb icon DLLRenderHUDQuad(x + 3, y, 10, 10, 0, 0, 1, 1, HyperOrbIcon, alpha_to_use, 0); } } } // Timer handlers void OnTimer(void); void OnTimerKill(void); void OnTimerFlagReturn(void); void OnTimerFlagReturnKill(void); // This function gets called by the game when it wants to learn some info about the game void DLLFUNCCALL DLLGetGameInfo(tDLLOptions *options) { options->flags = DOF_MAXTEAMS; options->max_teams = 1; strcpy(options->game_name, TXT_GAMENAME); strcpy(options->requirements, ""); } // Initializes the game function pointers void DLLFUNCCALL DLLGameInit(int *api_func, ubyte *all_ok, int num_teams_to_use) { *all_ok = 1; DMFCBase = CreateDMFC(); if (!DMFCBase) { *all_ok = 0; return; } dstat = CreateDmfcStats(); if (!dstat) { *all_ok = 0; return; } DMFCBase->LoadFunctions(api_func); DMFCBase->Set_OnInterval(OnInterval); DMFCBase->Set_OnHUDInterval(OnHUDInterval); DMFCBase->Set_OnKeypress(OnKeypress); DMFCBase->Set_OnServerGameCreated(OnServerGameCreated); DMFCBase->Set_OnServerLevelStart(OnServerLevelStart); DMFCBase->Set_OnClientLevelStart(OnClientLevelStart); DMFCBase->Set_OnClientLevelEnd(OnClientLevelEnd); DMFCBase->Set_OnGameStateRequest(OnGameStateRequest); DMFCBase->Set_OnPlayerConnect(OnPlayerConnect); DMFCBase->Set_OnServerCollide(OnServerCollide); DMFCBase->Set_OnClientCollide(OnClientCollide); DMFCBase->Set_OnClientPlayerKilled(OnClientPlayerKilled); DMFCBase->Set_OnPLRInterval(OnPLRInterval); DMFCBase->Set_OnPLRInit(OnPLRInit); DMFCBase->Set_OnServerPlayerDisconnect(OnServerPlayerDisconnect); DMFCBase->Set_OnClientPlayerDisconnect(OnClientPlayerDisconnect); DMFCBase->Set_OnSaveStatsToFile(OnSaveStatsToFile); DMFCBase->Set_OnLevelEndSaveStatsToFile(OnLevelEndSaveStatsToFile); DMFCBase->Set_OnDisconnectSaveStatsToFile(OnDisconnectSaveStatsToFile); DMFCBase->Set_OnPrintScores(OnPrintScores); DMFCBase->Set_OnPlayerEntersObserver(OnPlayerEntersObserver); DMFCBase->Set_OnClientPlayerEntersGame(OnClientPlayerEntersGame); DLLCreateStringTable("hyper.str", &StringTable, &StringTableSize); DLLmprintf((0, "%d strings loaded from string table\n", StringTableSize)); if (!StringTableSize) { *all_ok = 0; return; } // add the anarchy menu/submenus IMenuItem *lev1, *lev2, *MainMenu; lev1 = CreateMenuItemWArgs(TXT_GAMENAME, MIT_NORMAL, 0, NULL); lev2 = CreateMenuItemWArgs(TXT_HUDSCORECOLORS, MIT_STATE, 0, SwitchHUDColor); lev2->SetStateItemList(2, TXT_PLAYERCOLORS, TXT_NORMAL); lev2->SetState(HUD_color_model); lev1->AddSubMenu(lev2); MainMenu = DMFCBase->GetOnScreenMenu(); MainMenu->AddSubMenu(lev1); dObjects = DMFCBase->GetObjects(); dPlayers = DMFCBase->GetPlayers(); DMFCBase->GameInit(1); // add the death and suicide messages DMFCBase->AddDeathMessage(TXT_DEATH1, true); DMFCBase->AddSuicideMessage(TXT_SUICIDE1); HyperOrbID = DLLFindObjectIDName("Hyperorb"); if (HyperOrbID == -1) { DLLmprintf((0, "Hyper Anarchy: BIG WARNING, COULDN'T FIND HyperOrb ID...YOUR GAME IS IN JEOPARDY!\n")); *all_ok = 0; return; } // setup the Playerstats struct so DMFC can handle it automatically when a new player enters the game DMFCBase->SetupPlayerRecord(sizeof(tPlayerStat), (int (*)(void *, ubyte *))pack_pstat, (int (*)(void *, ubyte *))unpack_pstat); DMFCBase->RegisterPacketReceiver(SPID_HYPERINFO, ReceiveHyperGameState); DMFCBase->RegisterPacketReceiver(SPID_HYPERPOS, ReceiveHyperPos); DMFCBase->SetNumberOfTeams(1); (DMFCBase->GetNetgameInfo())->flags |= (NF_DAMAGE_FRIENDLY | NF_TRACK_RANK); DMFCBase->AddHUDItemCallback(HI_TEXT, DisplayHUDScores); DisplayScoreScreen = false; WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; HyperOrbIcon = DLLbm_AllocLoadFileBitmap("HyperOrbICON.ogf", 0, BITMAP_FORMAT_1555); if (HyperOrbIcon == -1) { *all_ok = 0; return; } Highlight_bmp = DLLbm_AllocBitmap(32, 32, 0); if (Highlight_bmp > BAD_BITMAP_HANDLE) { ushort *data = DLLbm_data(Highlight_bmp, 0); if (!data) { // bail on out of here *all_ok = 0; return; } for (int x = 0; x < 32 * 32; x++) { data[x] = GR_RGB16(50, 50, 50) | OPAQUE_FLAG; } } // Initialize the Stats Manager // ---------------------------- tDmfcStatsInit tsi; tDmfcStatsColumnInfo pl_col[7]; char gname[20]; strcpy(gname, TXT_STATSGAMENAME); tsi.flags = DSIF_SHOW_PIC | DSIF_SHOW_OBSERVERICON; tsi.cColumnCountDetailed = 0; tsi.cColumnCountPlayerList = 7; tsi.clbDetailedColumn = NULL; tsi.clbDetailedColumnBMP = NULL; tsi.clbPlayerColumn = DetermineScore; tsi.clbPlayerColumnBMP = ShowStatBitmap; tsi.DetailedColumns = NULL; tsi.GameName = gname; tsi.MaxNumberDisplayed = NULL; tsi.PlayerListColumns = pl_col; tsi.SortedPlayerRecords = SortedPlayers; pl_col[0].color_type = DSCOLOR_TEAM; pl_col[0].title[0] = '\0'; pl_col[0].type = DSCOL_BMP; pl_col[0].width = 15; pl_col[1].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[1].title, TXT_PILOT); pl_col[1].type = DSCOL_PILOT_NAME; pl_col[1].width = 120; pl_col[2].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[2].title, TXT_SCORE); pl_col[2].type = DSCOL_CUSTOM; pl_col[2].width = 60; pl_col[3].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[3].title, TXT_KILLS_SHORT); pl_col[3].type = DSCOL_KILLS_LEVEL; pl_col[3].width = 57; pl_col[4].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[4].title, TXT_DEATHS_SHORT); pl_col[4].type = DSCOL_DEATHS_LEVEL; pl_col[4].width = 57; pl_col[5].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[5].title, TXT_SUICIDES_SHORT); pl_col[5].type = DSCOL_SUICIDES_LEVEL; pl_col[5].width = 57; pl_col[6].color_type = DSCOLOR_SHIPCOLOR; strcpy(pl_col[6].title, TXT_PING); pl_col[6].type = DSCOL_PING; pl_col[6].width = 40; dstat->Initialize(&tsi); } // Called when the DLL is shutdown void DLLFUNCCALL DLLGameClose() { if (Highlight_bmp > BAD_BITMAP_HANDLE) DLLbm_FreeBitmap(Highlight_bmp); DLLDestroyStringTable(StringTable, StringTableSize); if (HyperOrbIcon > 0) DLLbm_FreeBitmap(HyperOrbIcon); if (dstat) { dstat->DestroyPointer(); dstat = NULL; } if (DMFCBase) { DMFCBase->GameClose(); DMFCBase->DestroyPointer(); DMFCBase = NULL; } } ////////////////////////////////////////////////////////////// /////// Overrides /////////////////////////////////////////// void OnHUDInterval(void) { dstat->DoFrame(); DMFCBase->DisplayOutrageLogo(); DMFCBase->OnHUDInterval(); } void OnInterval(void) { // Set a Timer to display if ((HyperMoveTimer == -1) && (WhoHasOrb == -1)) HyperMoveTimer = DMFCBase->SetTimerInterval(OnTimerFlagReturn, 30.0f, 30.0f); SortPlayerScores(SortedPlayers, MAX_PLAYER_RECORDS); DMFCBase->OnInterval(); } void OnPlayerEntersObserver(int pnum, object *piggy) { if (WhoHasOrb == pnum) { WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; DLLAddHUDMessage(TXT_LOSTORB, dPlayers[pnum].callsign); UpdateEffect(); } DMFCBase->OnPlayerEntersObserver(pnum, piggy); } void OnKeypress(int key) { dllinfo *Data = DMFCBase->GetDLLInfoCallData(); switch (key) { case K_F7: DisplayScoreScreen = !DisplayScoreScreen; DMFCBase->EnableOnScreenMenu(false); dstat->Enable(DisplayScoreScreen); break; case K_PAGEDOWN: if (DisplayScoreScreen) { dstat->ScrollDown(); Data->iRet = 1; } break; case K_PAGEUP: if (DisplayScoreScreen) { dstat->ScrollUp(); Data->iRet = 1; } break; case K_F6: DisplayScoreScreen = false; dstat->Enable(false); break; case K_ESC: if (DisplayScoreScreen) { dstat->Enable(false); DisplayScoreScreen = false; Data->iRet = 1; } break; } DMFCBase->OnKeypress(key); } // The server has just started, so clear out all the stats and game info void OnServerGameCreated(void) { DMFCBase->OnServerGameCreated(); player_record *pr; tPlayerStat *stat; for (int i = 0; i < MAX_PLAYER_RECORDS; i++) { pr = DMFCBase->GetPlayerRecord(i); if (pr) stat = (tPlayerStat *)pr->user_info; else stat = NULL; if (stat) { stat->Score[DSTAT_LEVEL] = 0; stat->Score[DSTAT_OVERALL] = 0; } } } void OnServerLevelStart(void) { // Now create a hyper orb in a random room -eek if (HyperOrbID != -1) { DLLmprintf((0, "Attempting to create HyperOrb in a random room\n")); int room = GetRandomValidRoom(); DLLmprintf((0, "Room %d selected\n", room)); // We got a good room // Safe to create the flag CreateHyperOrbInRoom(room); } KillCount = 0; WhoHasOrb = -1; HyperMoveTimer = -1; UpdateEffect(); DMFCBase->OnServerLevelStart(); } void OnClientLevelEnd(void) { DMFCBase->OnClientLevelEnd(); } // The server has started a new level, so clear out level scores void OnClientLevelStart(void) { DMFCBase->OnClientLevelStart(); player_record *pr; tPlayerStat *stat; for (int i = 0; i < MAX_PLAYER_RECORDS; i++) { pr = DMFCBase->GetPlayerRecord(i); if (pr) stat = (tPlayerStat *)pr->user_info; else stat = NULL; if (stat) { stat->Score[DSTAT_LEVEL] = 0; } } DMFCBase->RequestGameState(); UpdateEffect(); } // We need to send all the inventory info out to the new player void OnGameStateRequest(int player_num) { SendHyperGameState(player_num); DMFCBase->OnGameStateRequest(player_num); } // A new player has entered the game, zero there stats out void OnPlayerConnect(int player_num) { tPlayerStat *stat = (tPlayerStat *)DMFCBase->GetPlayerRecordData(player_num); if (stat) { stat->Score[DSTAT_LEVEL] = 0; stat->Score[DSTAT_OVERALL] = 0; } DMFCBase->OnPlayerConnect(player_num); } // A new player has entered the game, zero there stats out void OnClientPlayerEntersGame(int player_num) { DMFCBase->OnClientPlayerEntersGame(player_num); if (player_num != DMFCBase->GetPlayerNum()) DisplayWelcomeScreen(player_num); else display_my_welcome = true; } void OnPrintScores(int level) { char buffer[256]; char name[50]; memset(buffer, ' ', 256); int t; int pos[6]; int len[6]; pos[0] = 0; t = len[0] = 20; // give ample room for pilot name pos[1] = pos[0] + t + 1; t = len[1] = strlen(TXT_SCORE); pos[2] = pos[1] + t + 1; t = len[2] = strlen(TXT_KILLS); pos[3] = pos[2] + t + 1; t = len[3] = strlen(TXT_DEATHS); pos[4] = pos[3] + t + 1; t = len[4] = strlen(TXT_SUICIDES); pos[5] = pos[4] + t + 1; t = len[5] = strlen(TXT_PING); memcpy(&buffer[pos[0]], TXT_PILOT, strlen(TXT_PILOT)); memcpy(&buffer[pos[1]], TXT_SCORE, len[1]); memcpy(&buffer[pos[2]], TXT_KILLS, len[2]); memcpy(&buffer[pos[3]], TXT_DEATHS, len[3]); memcpy(&buffer[pos[4]], TXT_SUICIDES, len[4]); memcpy(&buffer[pos[5]], TXT_PING, len[5]); buffer[pos[5] + len[5] + 1] = '\n'; buffer[pos[5] + len[5] + 2] = '\0'; DPrintf(buffer); int slot; player_record *pr; int pcount; if (level < 0 || level >= MAX_PLAYER_RECORDS) pcount = MAX_PLAYER_RECORDS; else pcount = level; int sortedplayers[MAX_PLAYER_RECORDS]; DMFCBase->GetSortedPlayerSlots(sortedplayers, MAX_PLAYER_RECORDS); for (int i = 0; i < pcount; i++) { slot = sortedplayers[i]; pr = DMFCBase->GetPlayerRecord(slot); if ((pr) && (pr->state != STATE_EMPTY)) { if (DMFCBase->IsPlayerDedicatedServer(pr)) continue; // skip dedicated server snprintf(name, sizeof(name), "%s%s:", (pr->state == STATE_DISCONNECTED) ? "*" : "", pr->callsign); name[19] = '\0'; tPlayerStat *stat = (tPlayerStat *)pr->user_info; memset(buffer, ' ', 256); t = strlen(name); memcpy(&buffer[pos[0]], name, (t < len[0]) ? t : len[0]); snprintf(name, sizeof(name), "%d[%d]", (stat) ? stat->Score[DSTAT_LEVEL] : 0, (stat) ? stat->Score[DSTAT_OVERALL] : 0); t = strlen(name); memcpy(&buffer[pos[1]], name, (t < len[1]) ? t : len[1]); snprintf(name, sizeof(name), "%d[%d]", pr->dstats.kills[DSTAT_LEVEL], pr->dstats.kills[DSTAT_OVERALL]); t = strlen(name); memcpy(&buffer[pos[2]], name, (t < len[2]) ? t : len[2]); snprintf(name, sizeof(name), "%d[%d]", pr->dstats.deaths[DSTAT_LEVEL], pr->dstats.deaths[DSTAT_OVERALL]); t = strlen(name); memcpy(&buffer[pos[3]], name, (t < len[3]) ? t : len[3]); snprintf(name, sizeof(name), "%d[%d]", pr->dstats.suicides[DSTAT_LEVEL], pr->dstats.suicides[DSTAT_OVERALL]); t = strlen(name); memcpy(&buffer[pos[4]], name, (t < len[4]) ? t : len[4]); if (pr->state == STATE_INGAME) snprintf(name, sizeof(name), "%.0f", (DMFCBase->GetNetPlayers())[pr->pnum].ping_time * 1000.0f); else strcpy(name, "---"); t = strlen(name); memcpy(&buffer[pos[5]], name, (t < len[5]) ? t : len[5]); buffer[pos[5] + len[5] + 1] = '\n'; buffer[pos[5] + len[5] + 2] = '\0'; DPrintf(buffer); } } } bool compare_slots(int a, int b) { int ascore, bscore; player_record *apr, *bpr; tPlayerStat *astat, *bstat; apr = DMFCBase->GetPlayerRecord(a); bpr = DMFCBase->GetPlayerRecord(b); if (!apr) return true; if (!bpr) return false; if (apr->state == STATE_EMPTY) return true; if (bpr->state == STATE_EMPTY) return false; astat = (tPlayerStat *)apr->user_info; bstat = (tPlayerStat *)bpr->user_info; if ((apr->state == STATE_INGAME) && (bpr->state == STATE_INGAME)) { // both players were in the game ascore = (astat) ? astat->Score[DSTAT_LEVEL] : 0; bscore = (bstat) ? bstat->Score[DSTAT_LEVEL] : 0; return (ascore < bscore); } if ((apr->state == STATE_INGAME) && (bpr->state == STATE_DISCONNECTED)) { // apr gets priority since he was in the game on exit return false; } if ((apr->state == STATE_DISCONNECTED) && (bpr->state == STATE_INGAME)) { // bpr gets priority since he was in the game on exit return true; } // if we got here then both players were disconnected ascore = (astat) ? astat->Score[DSTAT_LEVEL] : 0; bscore = (bstat) ? bstat->Score[DSTAT_LEVEL] : 0; return (ascore < bscore); } void OnPLRInit(void) { int i, t, j; for (i = 0; i < MAX_PLAYER_RECORDS; i++) { SortedPlayers[i] = i; } for (i = 1; i <= MAX_PLAYER_RECORDS - 1; i++) { t = SortedPlayers[i]; // Shift elements down until // insertion point found. for (j = i - 1; j >= 0 && compare_slots(SortedPlayers[j], t); j--) { SortedPlayers[j + 1] = SortedPlayers[j]; } // insert SortedPlayers[j + 1] = t; } DMFCBase->OnPLRInit(); } void OnPLRInterval(void) { #define PLAYERS_COL 110 #define SCORE_COL 240 #define KILLS_COL 300 #define DEATHS_COL 360 #define SUICIDES_COL 420 DMFCBase->OnPLRInterval(); int y = 40; int height = DLLgrfont_GetHeight((DMFCBase->GetGameFontTranslateArray())[SMALL_UI_FONT_INDEX]) + 1; DLLgrtext_SetFont((DMFCBase->GetGameFontTranslateArray())[SMALL_UI_FONT_INDEX]); // print out header DLLgrtext_SetColor(GR_RGB(255, 255, 150)); DLLgrtext_Printf(PLAYERS_COL, y, TXT_PILOT); DLLgrtext_Printf(SCORE_COL, y, TXT_SCORE); DLLgrtext_Printf(KILLS_COL, y, TXT_KILLS); DLLgrtext_Printf(DEATHS_COL, y, TXT_DEATHS); DLLgrtext_Printf(SUICIDES_COL, y, TXT_SUICIDES); y += height; // print out player stats int rank = 1; int slot; tPlayerStat *stat; player_record *pr; for (int i = 0; i < MAX_PLAYER_RECORDS; i++) { slot = SortedPlayers[i]; pr = DMFCBase->GetPlayerRecord(slot); if (pr && pr->state != STATE_EMPTY) { if (DMFCBase->IsPlayerDedicatedServer(pr)) continue; // skip dedicated server stat = (tPlayerStat *)pr->user_info; int pnum = DMFCBase->WasPlayerInGameAtLevelEnd(slot); if (pnum != -1) { DLLgrtext_SetColor((DMFCBase->GetPlayerColors())[pnum]); } else { DLLgrtext_SetColor(GR_RGB(128, 128, 128)); } DLLgrtext_Printf(PLAYERS_COL, y, "%d)%s", rank, pr->callsign); DLLgrtext_Printf(SCORE_COL, y, "%d[%d]", (stat) ? stat->Score[DSTAT_LEVEL] : 0, (stat) ? stat->Score[DSTAT_OVERALL] : 0); DLLgrtext_Printf(KILLS_COL, y, "%d[%d]", pr->dstats.kills[DSTAT_LEVEL], pr->dstats.kills[DSTAT_OVERALL]); DLLgrtext_Printf(DEATHS_COL, y, "%d[%d]", pr->dstats.deaths[DSTAT_LEVEL], pr->dstats.deaths[DSTAT_OVERALL]); DLLgrtext_Printf(SUICIDES_COL, y, "%d[%d]", pr->dstats.suicides[DSTAT_LEVEL], pr->dstats.suicides[DSTAT_OVERALL]); y += height; rank++; if (y >= 440) goto quick_exit; } } quick_exit:; } void OnServerCollide(object *me_obj, object *it_obj) { if (!me_obj || !it_obj) return; if (it_obj->type != OBJ_PLAYER) { DMFCBase->OnServerCollide(me_obj, it_obj); return; } if ((me_obj->type == OBJ_PLAYER) && (DLLInvCheckItem(it_obj->id, OBJ_POWERUP, HyperOrbID))) { /* //Two Players collided...one had orb DLLmprintf((0,"Player2Player\n")); DMFCBase->CallClientEvent(EVT_CLIENT_GAMECOLLIDE,DMFCBase->GetMeObjNum(),DMFCBase->GetItObjNum(),-1); DMFCBase->CallOnClientCollide(me_obj,it_obj); */ } else if (me_obj->type == OBJ_POWERUP && me_obj->id == HyperOrbID) { // A Player collided with the HyperOrb // Sent this information to the clients to process DMFCBase->CallClientEvent(EVT_CLIENT_GAMECOLLIDE, DMFCBase->GetMeObjNum(), DMFCBase->GetItObjNum(), -1); DMFCBase->CallOnClientCollide(me_obj, it_obj); } DMFCBase->OnServerCollide(me_obj, it_obj); } void OnClientCollide(object *me_objp, object *it_objp) { if (me_objp->type == OBJ_PLAYER) { // spew this puppy DLLPlayerSpewInventory(it_objp, false, false); DLLAddHUDMessage(TXT_LOSTORB, dPlayers[it_objp->id].callsign); WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; UpdateEffect(); } else { // We'll only get here if me_objp is HyperOrb and it_objp is the collider WhoHasOrb = it_objp->id; KillCount = 0; // reset this variable, since they just picked up the HyperOrb // add the hyper orb to the players inventory DLLInvAddTypeID(it_objp->id, me_objp->type, me_objp->id, -1, -1, 0, NULL); // if we are the server, remove the orb from the world and tell the clients to do the same if (DMFCBase->GetLocalRole() == LR_SERVER) { DLLSetObjectDeadFlag(me_objp, true, 0); } DLLAddHUDMessage(TXT_GOTORB, dPlayers[it_objp->id].callsign); // Play a sound int id = DLLFindSoundName("PwrHyperOrb"); if (id != -1) DLLPlay3dSound(id, &dObjects[dPlayers[DMFCBase->GetPlayerNum()].objnum], 1, 0); UpdateEffect(); // Set a Timer to display if (WhoJustScoredTimer != -1) DMFCBase->KillTimer(WhoJustScoredTimer); WhoJustScoredTimer = DMFCBase->SetTimerInterval(OnTimer, 0.5f, 5.0f, OnTimerKill); } DMFCBase->OnClientCollide(me_objp, it_objp); } void OnClientPlayerKilled(object *killer_obj, int victim_pnum) { int score = 0; int kpnum; if (killer_obj) { if ((killer_obj->type == OBJ_PLAYER) || (killer_obj->type == OBJ_GHOST)) kpnum = killer_obj->id; else if (killer_obj->type == OBJ_ROBOT || (killer_obj->type == OBJ_BUILDING && killer_obj->ai_info)) { // countermeasure kill kpnum = DMFCBase->GetCounterMeasureOwner(killer_obj); } else { kpnum = -1; } } else kpnum = -1; bool suicide = (bool)(kpnum == victim_pnum); if (victim_pnum == WhoHasOrb) { // The guy with the score orb lost it! KillCount++; if (!suicide) { score = KillCount + 1; if (score > 5) score = 5; } else { score = -(KillCount + 1); if (score < -5) score = -5; } WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; DLLAddHUDMessage(TXT_LOSTORB, dPlayers[victim_pnum].callsign); UpdateEffect(); } else { if (kpnum != -1) { // Was the killer the guy with the HyperOrb? if (kpnum == WhoHasOrb) { // Yup! KillCount++; score = KillCount + 1; if (score > 5) score = 5; if (!suicide) DLLAddHUDMessage(TXT_SCOREPOINTS, dPlayers[kpnum].callsign, score); } else { // Nope! if (!suicide) score = 1; else score = -1; } } } tPlayerStat *stat = (tPlayerStat *)DMFCBase->GetPlayerRecordData(kpnum); if (kpnum != -1 && stat) { stat->Score[DSTAT_LEVEL] += score; stat->Score[DSTAT_OVERALL] += score; } if ((DMFCBase->GetLocalRole() == LR_SERVER) && (kpnum != -1) && (stat)) { // check the score to see if we hit the limit if ((DMFCBase->GetScoreLimit(&score))) { if (score <= stat->Score[DSTAT_LEVEL]) { DLLmprintf((0, "Score limit reached\n")); DMFCBase->EndLevel(); } } } DMFCBase->OnClientPlayerKilled(killer_obj, victim_pnum); } void OnServerPlayerDisconnect(int player_num) { DMFCBase->OnServerPlayerDisconnect(player_num); if (player_num == WhoHasOrb) { // send this event to the clients so they can handle it DMFCBase->CallClientEvent(EVT_CLIENT_GAMEPLAYERDISCONNECT, DMFCBase->GetMeObjNum(), DMFCBase->GetItObjNum(), -1); DMFCBase->CallOnClientPlayerDisconnect(player_num); } } void OnClientPlayerDisconnect(int player_num) { if (player_num == WhoHasOrb) { WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; ResetTimer(); } DMFCBase->OnClientPlayerDisconnect(player_num); } void SaveStatsToFile(char *filename) { CFILE *file; DLLOpenCFILE(&file, filename, "wt"); if (!file) { DLLmprintf((0, "Unable to open output file\n")); return; } // write out game stats #define BUFSIZE 150 char buffer[BUFSIZE]; char tempbuffer[25]; int sortedslots[MAX_PLAYER_RECORDS]; player_record *pr, *dpr; tPInfoStat stat; tPlayerStat *ps; int count, length, p; // sort the stats SortPlayerScores(sortedslots, MAX_PLAYER_RECORDS); count = 1; snprintf(buffer, sizeof(buffer), TXT_SAVESTATSA, (DMFCBase->GetNetgameInfo())->name, (DMFCBase->GetCurrentMission())->cur_level); DLLcf_WriteString(file, buffer); snprintf(buffer, sizeof(buffer), "%s", TXT_SAVESTATSB); DLLcf_WriteString(file, buffer); snprintf(buffer, sizeof(buffer), "%s", TXT_SAVESTATSC); DLLcf_WriteString(file, buffer); strcpy(buffer, "----------------------------------------------------------------------------------------------"); DLLcf_WriteString(file, buffer); for (p = 0; p < MAX_PLAYER_RECORDS; p++) { pr = DMFCBase->GetPlayerRecord(sortedslots[p]); if (pr && pr->state != STATE_EMPTY) { if (DMFCBase->IsPlayerDedicatedServer(pr)) continue; // skip dedicated server memset(buffer, ' ', BUFSIZE); ps = (tPlayerStat *)pr->user_info; snprintf(tempbuffer, sizeof(tempbuffer), "%d)", count); memcpy(&buffer[0], tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%s%s", (pr->state == STATE_INGAME) ? "" : "*", pr->callsign); memcpy(&buffer[7], tempbuffer, strlen(tempbuffer)); if (ps) { snprintf(tempbuffer, sizeof(tempbuffer), "%d[%d]", ps->Score[DSTAT_LEVEL], ps->Score[DSTAT_OVERALL]); memcpy(&buffer[35], tempbuffer, strlen(tempbuffer)); } snprintf(tempbuffer, sizeof(tempbuffer), "%d[%d]", pr->dstats.kills[DSTAT_LEVEL], pr->dstats.kills[DSTAT_OVERALL]); memcpy(&buffer[47], tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%d[%d]", pr->dstats.deaths[DSTAT_LEVEL], pr->dstats.deaths[DSTAT_OVERALL]); memcpy(&buffer[59], tempbuffer, strlen(tempbuffer)); int pos; snprintf(tempbuffer, sizeof(tempbuffer), "%d[%d]", pr->dstats.suicides[DSTAT_LEVEL], pr->dstats.suicides[DSTAT_OVERALL]); memcpy(&buffer[70], tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%s", DMFCBase->GetTimeString(DMFCBase->GetTimeInGame(sortedslots[p]))); memcpy(&buffer[81], tempbuffer, strlen(tempbuffer)); pos = 81 + strlen(tempbuffer) + 1; if (pos < BUFSIZE) buffer[pos] = '\0'; buffer[BUFSIZE - 1] = '\0'; DLLcf_WriteString(file, buffer); count++; } } DLLcf_WriteString(file, TXT_SAVESTATSD); count = 1; for (p = 0; p < MAX_PLAYER_RECORDS; p++) { pr = DMFCBase->GetPlayerRecord(p); if (pr && pr->state != STATE_EMPTY) { if (DMFCBase->IsPlayerDedicatedServer(pr)) continue; // skip dedicated server // Write out header snprintf(buffer, sizeof(buffer), "%d) %s%s", count, (pr->state == STATE_INGAME) ? "" : "*", pr->callsign); DLLcf_WriteString(file, buffer); length = strlen(buffer); memset(buffer, '=', length); buffer[length] = '\0'; DLLcf_WriteString(file, buffer); // time in game snprintf(buffer, sizeof(buffer), TXT_TIMEINGAME, DMFCBase->GetTimeString(DMFCBase->GetTimeInGame(p))); DLLcf_WriteString(file, buffer); if (DMFCBase->FindPInfoStatFirst(p, &stat)) { snprintf(buffer, sizeof(buffer), "%s", TXT_SAVESTATSE); DLLcf_WriteString(file, buffer); if (stat.slot != p) { memset(buffer, ' ', BUFSIZE); dpr = DMFCBase->GetPlayerRecord(stat.slot); if (dpr) { int pos; snprintf(tempbuffer, sizeof(tempbuffer), "%s", dpr->callsign); memcpy(buffer, tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%d", stat.kills); memcpy(&buffer[30], tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%d", stat.deaths); memcpy(&buffer[40], tempbuffer, strlen(tempbuffer)); pos = 40 + strlen(tempbuffer) + 1; if (pos < BUFSIZE) buffer[pos] = '\0'; buffer[BUFSIZE - 1] = '\0'; DLLcf_WriteString(file, buffer); } } while (DMFCBase->FindPInfoStatNext(&stat)) { if (stat.slot != p) { int pos; memset(buffer, ' ', BUFSIZE); dpr = DMFCBase->GetPlayerRecord(stat.slot); if (dpr) { strncpy(tempbuffer, dpr->callsign, sizeof(tempbuffer)); memcpy(buffer, tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%d", stat.kills); memcpy(&buffer[30], tempbuffer, strlen(tempbuffer)); snprintf(tempbuffer, sizeof(tempbuffer), "%d", stat.deaths); memcpy(&buffer[40], tempbuffer, strlen(tempbuffer)); pos = 40 + strlen(tempbuffer) + 1; if (pos < BUFSIZE) buffer[pos] = '\0'; buffer[BUFSIZE - 1] = '\0'; DLLcf_WriteString(file, buffer); } } } } DMFCBase->FindPInfoStatClose(); DLLcf_WriteString(file, ""); // skip a line count++; } } // done writing stats DLLcfclose(file); DLLAddHUDMessage(TXT_STATSAVED); } #define ROOTFILENAME "Hyper" void OnSaveStatsToFile(void) { char filename[256]; DMFCBase->GenerateStatFilename(filename, ROOTFILENAME, false); SaveStatsToFile(filename); } void OnLevelEndSaveStatsToFile(void) { char filename[256]; DMFCBase->GenerateStatFilename(filename, ROOTFILENAME, true); SaveStatsToFile(filename); } void OnDisconnectSaveStatsToFile(void) { char filename[256]; DMFCBase->GenerateStatFilename(filename, ROOTFILENAME, false); SaveStatsToFile(filename); } ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// // handles a Hyper Anarchy Game State packet void ReceiveHyperGameState(ubyte *data) { // remove all the HyperOrbs from everyone's inventory for (int i = 0; i < DLLMAX_PLAYERS; i++) DLLInvRemove(i, OBJ_POWERUP, HyperOrbID); int count = 0; WhoHasOrb = MultiGetInt(data, &count); KillCount = MultiGetInt(data, &count); if (WhoHasOrb != -1) { DLLmprintf((0, "%s has the score orb!\n", dPlayers[WhoHasOrb].callsign)); DLLInvAddTypeID(WhoHasOrb, OBJ_POWERUP, HyperOrbID, -1, -1, 0, NULL); } UpdateEffect(); } // sends a Hyper Anarchy Game State packet void SendHyperGameState(int playernum) { bool updateall = false; int count = 0; ubyte data[MAX_GAME_DATA_SIZE]; DMFCBase->StartPacket(data, SPID_HYPERINFO, &count); if ((WhoHasOrb != -1) && (!DMFCBase->CheckPlayerNum(WhoHasOrb))) { WhoHasOrb = -1; KillCount = 0; HyperMoveTimer = -1; updateall = true; } MultiAddInt(WhoHasOrb, data, &count); MultiAddInt(KillCount, data, &count); DMFCBase->SendPacket(data, count, (updateall) ? SP_ALL : playernum); if (updateall) { // remove all the HyperOrbs from everyone's inventory for (int i = 0; i < DLLMAX_PLAYERS; i++) DLLInvRemove(i, OBJ_POWERUP, HyperOrbID); UpdateEffect(); } } // Displays HUD scores void DisplayHUDScores(struct tHUDItem *hitem) { if (display_my_welcome) { DisplayWelcomeScreen(DMFCBase->GetPlayerNum()); display_my_welcome = false; } if (DisplayScoreScreen) return; int height = DLLgrfont_GetHeight((DMFCBase->GetGameFontTranslateArray())[HUD_FONT_INDEX]) + 3; ubyte alpha = DMFCBase->ConvertHUDAlpha((ubyte)((DisplayScoreScreen) ? 128 : 255)); int y = (DMFCBase->GetGameWindowH() / 2) - ((height * 5) / 2); int x = 510; int rank = 1; ddgr_color color = 0; bool hasorb; char temp[50]; bool hdisp = false; // determine coordinates to use here // we'll use a virtual width of 85 pixels on a 640x480 screen // so first determine the new width int name_width = 85.0f * DMFCBase->GetHudAspectX(); int score_width = DLLgrtext_GetTextLineWidth("888"); int name_x = DMFCBase->GetGameWindowW() - name_width - score_width - 10; int score_x = DMFCBase->GetGameWindowW() - score_width - 5; int icon_size = height - 3; int icon_x = name_x - 5 - icon_size; bool player_shown; #define NUM_PLAYERS_TO_SHOW_PLUS_ONE 6 for (int i = 0; i < MAX_PLAYER_RECORDS; i++) { int slot = SortedPlayers[i]; player_record *pr = DMFCBase->GetPlayerRecord(slot); player_shown = false; if (pr && pr->state != STATE_EMPTY) { hasorb = false; if (DMFCBase->IsPlayerDedicatedServer(pr)) continue; // skip dedicated server if ((pr->state == STATE_DISCONNECTED) || (pr->state == STATE_INGAME && !DMFCBase->IsPlayerObserver(pr->pnum))) { tPlayerStat *stat = (tPlayerStat *)pr->user_info; if ((rank < NUM_PLAYERS_TO_SHOW_PLUS_ONE) || (pr->state == STATE_INGAME && pr->pnum == DMFCBase->GetPlayerNum())) player_shown = true; if (pr->state == STATE_INGAME && WhoHasOrb == pr->pnum) { hasorb = true; if (player_shown) hdisp = true; } if (((pr->state == STATE_INGAME) && (WhoHasOrb != pr->pnum)) || (DisplayFlagBlink) || pr->state == STATE_DISCONNECTED) { strcpy(temp, pr->callsign); DMFCBase->ClipString(name_width, temp, true); if (pr->state == STATE_INGAME && pr->pnum == DMFCBase->GetPlayerNum()) { switch (HUD_color_model) { case HCM_PLAYERCOLOR: color = (DMFCBase->GetPlayerColors())[pr->pnum]; break; case HCM_NORMAL: color = GR_RGB(40, 255, 40); break; }; if (Highlight_bmp > BAD_BITMAP_HANDLE) { // draw the highlight bar in the background DLLrend_SetAlphaValue(alpha * 0.50f); DLLrend_SetZBufferState(0); DLLrend_SetTextureType(TT_LINEAR); DLLrend_SetLighting(LS_NONE); DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE); DLLrend_DrawScaledBitmap(icon_x - 2, y - 2, score_x + score_width + 2, y + height - 1, Highlight_bmp, 0, 0, 1, 1, 1.0f, -1, NULL); DLLrend_SetZBufferState(1); } DLLgrtext_SetAlpha(alpha); DLLgrtext_SetColor(color); DLLgrtext_Printf(name_x, y, temp); DLLgrtext_Printf(score_x, y, "%d", (stat) ? stat->Score[DSTAT_LEVEL] : 0); } else if (rank < NUM_PLAYERS_TO_SHOW_PLUS_ONE) { if (pr->state == STATE_DISCONNECTED) { color = GR_GREY; } else { switch (HUD_color_model) { case HCM_PLAYERCOLOR: color = (DMFCBase->GetPlayerColors())[pr->pnum]; break; case HCM_NORMAL: color = GR_RGB(40, 255, 40); break; }; } DLLgrtext_SetAlpha(alpha); DLLgrtext_SetColor(color); DLLgrtext_Printf(name_x, y, temp); DLLgrtext_Printf(score_x, y, "%d", (stat) ? stat->Score[DSTAT_LEVEL] : 0); } } if (hasorb && DisplayFlagBlink) { DLLrend_SetZBufferState(0); DLLrend_SetTextureType(TT_LINEAR); DLLrend_SetAlphaValue(alpha); DLLrend_SetLighting(LS_NONE); DLLrend_SetWrapType(WT_CLAMP); DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE); DLLrend_DrawScaledBitmap(icon_x, y, icon_x + icon_size, y + icon_size, HyperOrbIcon, 0, 0, 1, 1, 1.0f, -1, NULL); DLLrend_SetZBufferState(1); } if (player_shown) y += height; rank++; } } } if (WhoHasOrb != -1 && DisplayFlagBlink && !hdisp) { player_record *pr = DMFCBase->GetPlayerRecordByPnum(WhoHasOrb); if (pr && pr->state == STATE_INGAME) { // the player with the orb needs to be shown strcpy(temp, dPlayers[WhoHasOrb].callsign); DMFCBase->ClipString(name_width, temp, true); DLLgrtext_SetAlpha(alpha); DLLgrtext_SetColor(GR_RGB(40, 255, 40)); DLLgrtext_Printf(name_x, y, temp); tPlayerStat *stat = (tPlayerStat *)pr->user_info; DLLgrtext_Printf(score_x, y, "%d", (stat) ? stat->Score[DSTAT_LEVEL] : 0); DLLrend_SetZBufferState(0); DLLrend_SetTextureType(TT_LINEAR); DLLrend_SetAlphaValue(alpha); DLLrend_SetLighting(LS_NONE); DLLrend_SetWrapType(WT_CLAMP); DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE); DLLrend_DrawScaledBitmap(icon_x, y, icon_x + icon_size, y + icon_size, HyperOrbIcon, 0, 0, 1, 1, 1.0f, -1, NULL); DLLrend_SetZBufferState(1); } } // Display the HyperOrb in the corner if we have it if (DMFCBase->GetPlayerNum() == WhoHasOrb) { DLLrend_SetZBufferState(0); DLLrend_SetTextureType(TT_LINEAR); DLLrend_SetAlphaValue(alpha); DLLrend_SetLighting(LS_NONE); DLLrend_SetWrapType(WT_CLAMP); DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE); int x1, x2, y1, y2; x1 = DMFCBase->GetGameWindowW() - 5 - DLLbm_w(HyperOrbIcon, 0); y1 = 25; x2 = x1 + DLLbm_w(HyperOrbIcon, 0); y2 = y1 + DLLbm_h(HyperOrbIcon, 0); DLLrend_DrawScaledBitmap(x1, y1, x2, y2, HyperOrbIcon, 0, 0, 1, 1, 1.0f, -1, NULL); DLLrend_SetZBufferState(1); } } // Update Effect on the guy who has the Orb void UpdateEffect(void) { float redb[4]; float greenb[4]; float blueb[4]; int i; for (i = 0; i < 4; i++) { redb[i] = 0.83f; greenb[i] = 0.17f; blueb[i] = 0; } for (i = 0; i < DLLMAX_PLAYERS; i++) { if (DMFCBase->CheckPlayerNum(i)) { // Player valid if (i == WhoHasOrb) { // Do the effect on this guy DLLPlayerSetRotatingBall(i, 3, 4, redb, greenb, blueb); } else { // Reset effect on this guy DLLPlayerSetRotatingBall(i, 0, 4, NULL, NULL, NULL); } } } } // Displays the Welcome Screen void DisplayWelcomeScreen(int player_num) { char name_buffer[64]; strcpy(name_buffer, (DMFCBase->GetPlayers())[player_num].callsign); if (player_num == DMFCBase->GetPlayerNum()) { DLLAddHUDMessage(TXT_WELCOME, name_buffer); } else { DLLAddHUDMessage(TXT_JOINED, name_buffer); } } void SortPlayerScores(int *sortedindex, int size) { int tempsort[MAX_PLAYER_RECORDS]; int i, t, j; for (i = 0; i < MAX_PLAYER_RECORDS; i++) { tempsort[i] = i; } for (i = 1; i <= MAX_PLAYER_RECORDS - 1; i++) { t = tempsort[i]; // Shift elements down until // insertion point found. for (j = i - 1; j >= 0 && compare_slots(tempsort[j], t); j--) { tempsort[j + 1] = tempsort[j]; } // insert tempsort[j + 1] = t; } // copy the array over memcpy(sortedindex, tempsort, ((size > MAX_PLAYER_RECORDS) ? MAX_PLAYER_RECORDS : size) * sizeof(int)); } // Generates a valid random room int GetRandomValidRoom(void) { while (1) { int room; room = rand() % (DMFCBase->GetHighestRoomIndex() + 1); if ((!ROOMNUM_OUTSIDE(room)) && ((DMFCBase->GetRooms())[room].used)) { if (!((DMFCBase->GetRooms())[room].flags & RF_EXTERNAL)) { DLLmprintf((0, "Room %d selected\n", room)); return room; } } } } // Moves the HyperOrb to the center of a random room // if objnum is -1, than the HyperOrb is created and moved void MoveHyperOrbToRoom(int objnum) { if ((objnum < 0) || (objnum >= MAX_OBJECTS)) objnum = -1; else if (dObjects[objnum].type != OBJ_POWERUP) objnum = -1; if (objnum == -1) { // we need to create it and place it somewhere in the level CreateHyperOrbInRoom(GetRandomValidRoom()); } else { // we need to just move it MoveHyperOrbToRoomCenter(objnum, GetRandomValidRoom()); } } // Given a room the HyperOrb is created and placed in the center of it void CreateHyperOrbInRoom(int room) { if (DMFCBase->GetLocalRole() != LR_SERVER) return; vector vpos; int objnum; DLLComputeRoomCenter(&vpos, &((DMFCBase->GetRooms())[room])); objnum = DLLObjCreate(OBJ_POWERUP, HyperOrbID, room, &vpos, NULL, OBJECT_HANDLE_NONE); DLLMultiSendObject(&dObjects[objnum], 0, true); } // Given the objnum and room it will move the HyperOrb to the center of that room. Objnum better be valid. void MoveHyperOrbToRoomCenter(int objnum, int room) { vector home_pos; DLLComputeRoomCenter(&home_pos, &((DMFCBase->GetRooms())[room])); DLLObjSetPos(&dObjects[objnum], &home_pos, room, NULL, false); if (DMFCBase->GetLocalRole() == LR_SERVER) { // tell the clients to move ubyte data[MAX_GAME_DATA_SIZE]; int count = 0; DMFCBase->StartPacket(data, SPID_HYPERPOS, &count); MultiAddInt(room, data, &count); DMFCBase->SendPacket(data, count, SP_ALL); } } // handles a Hyper Anarchy Object Placement packet void ReceiveHyperPos(ubyte *data) { int count = 0; int room = MultiGetInt(data, &count); // first find the Orb's number int objnum = FindHyperObjectNum(); if (objnum == -1) { // THIS BETTER NOT HAPPEN!!!!!!! Int3(); } MoveHyperOrbToRoomCenter(objnum, room); } // Searches through all the objects and looks for the HyperOrb, returns it's objnum. -1 if it doesn't exist int FindHyperObjectNum(void) { // go through all the objects until we find it for (int i = 0; i < MAX_OBJECTS; i++) { if ((dObjects[i].type == OBJ_POWERUP) && (dObjects[i].id == HyperOrbID)) { // we found it return i; } } return -1; } // Searches through all the player's inventory, returns the pnum of the player who has the HyperOrb, -1 // if no one does. int FindHyperOrbInInventory(void) { // go through everyone's inventory looking for HyperOrb for (int pnum = 0; pnum < DLLMAX_PLAYERS; pnum++) { if (DMFCBase->CheckPlayerNum(pnum)) { if (DLLInvCheckItem(pnum, OBJ_POWERUP, HyperOrbID)) return pnum; } } return -1; } void ResetTimer(void) { if (HyperMoveTimer != -1) DMFCBase->KillTimer(HyperMoveTimer); HyperMoveTimer = -1; } ///////////////////////////////// // Timer event handlers void OnTimer(void) { DisplayFlagBlink = !DisplayFlagBlink; } void OnTimerKill(void) { DisplayFlagBlink = true; } void OnTimerFlagReturn(void) { if (DMFCBase->GetLocalRole() != LR_SERVER) return; if (WhoHasOrb == -1) { // time to return move the hyperorb home int objnum = FindHyperObjectNum(); if (objnum != -1) { // ok, so it's in some place, lets move it home MoveHyperOrbToRoom(objnum); } else { // did it disappear?, check all the players inventories WhoHasOrb = FindHyperOrbInInventory(); if (WhoHasOrb == -1) { // no one has it, it's missing!, create it and place it in a room MoveHyperOrbToRoom(-1); } } } HyperMoveTimer = -1; } void OnTimerFlagReturnKill(void) { HyperMoveTimer = -1; } void SwitchHUDColor(int i) { HUD_color_model = i; }