mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
1ae023a13b
Enumerate DLL functions to ease tying functions in main and DLL sides in code.
5549 lines
172 KiB
C++
5549 lines
172 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/dmfc/dmfcbase.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003/08/26 03:57:20 $
|
|
* $Author: kevinb $
|
|
*
|
|
* Base functions for DMFC implementation
|
|
*
|
|
* $Log: dmfcbase.cpp,v $
|
|
* Revision 1.1.1.1 2003/08/26 03:57:20 kevinb
|
|
* initial 1.5 import
|
|
*
|
|
*
|
|
* 170 9/28/01 2:09p Matt
|
|
* Don't show ping/loss info on HUD if peer-to-peer game.
|
|
*
|
|
* 169 9/07/01 8:57a Matt
|
|
* Fixed hud name bug from previous change.
|
|
*
|
|
* 168 9/05/01 6:04p Matt
|
|
* Added code to save the user's preferred HUD name level setting even if
|
|
* the server bashes it down.
|
|
*
|
|
* 167 10/26/99 10:31a Jeff
|
|
* fixed COM interface bug
|
|
*
|
|
* 166 10/21/99 9:27p Jeff
|
|
* B.A. Macintosh code merge
|
|
*
|
|
* 165 8/21/99 12:33a Jeff
|
|
* Changed the name of the GetRealGametime function to
|
|
* GetRealGametimePacket since it was confusing some compilers with the
|
|
* other GetRealGametime function.
|
|
*
|
|
* 164 8/15/99 4:36p Jeff
|
|
* finished exporting all inventory class functions. export object_info
|
|
* array. added check for -nooutragelogo to display Outrage logo display.
|
|
*
|
|
* 163 8/11/99 6:36p Jeff
|
|
* don't set input command list root to NULL when creating input commands
|
|
* (it would create a memleak and ignore any ICs added by a custom mod)
|
|
*
|
|
* 162 8/11/99 1:21p Jeff
|
|
* exported needed functions for camera windows
|
|
*
|
|
* 161 7/30/99 11:59a Jeff
|
|
* fixed bug with autobalance being turned off
|
|
*
|
|
* 160 7/14/99 11:47a Jeff
|
|
* localized text for patch fixes
|
|
*
|
|
* 159 7/13/99 10:05a Jeff
|
|
* text taunt token decoding
|
|
*
|
|
* 158 7/11/99 3:31p Jeff
|
|
* exported game arguments, made command line option to specify
|
|
* autoexec.dmfc
|
|
*
|
|
* 157 7/09/99 7:02p Jeff
|
|
* put in countdown timer for when a level is about to end
|
|
*
|
|
* 156 7/09/99 6:17p Jeff
|
|
* added $remoteadminlogout and $wait commands
|
|
*
|
|
* 155 7/09/99 2:53p Jeff
|
|
* handle gametime better (pause it when needed) if the server is 'waiting
|
|
* for players'
|
|
*
|
|
* 154 7/08/99 6:25p Jeff
|
|
* remote admin in and working
|
|
*
|
|
* 153 7/08/99 2:39a Jeff
|
|
* rough implementation of remote administration checked in. Still needs
|
|
* some polishing, but should work basically.
|
|
*
|
|
* 152 7/07/99 5:00p Jeff
|
|
* removed vararg functions from interface functions, just made different
|
|
* versions of them
|
|
*
|
|
* 151 6/11/99 5:36p Jeff
|
|
* removed ai_info #ifdefs (better way of doing it)
|
|
*
|
|
* 150 6/10/99 12:34p Jeff
|
|
* GetCounterMeasureOwner doesn't use ->ai_info for non-Outrage versions
|
|
*
|
|
* 149 6/10/99 11:10a Jeff
|
|
* don't display the Outrage logo for non-Outrage games
|
|
*
|
|
* 148 5/22/99 1:12a Jeff
|
|
* correctly handle Viewer_object
|
|
*
|
|
* 147 5/20/99 5:32p Jeff
|
|
* called PlayerStopSounds if respawning a player
|
|
*
|
|
* 146 5/20/99 3:51p Jeff
|
|
* for apply damage to player, server says should be 1 (so it works in
|
|
* peer-peer)
|
|
*
|
|
* 145 5/13/99 4:55p Ardussi
|
|
* changes for compiling on the Mac
|
|
*
|
|
* 144 5/12/99 11:04p Jeff
|
|
* dmfc and multiplayer games now have endian friendly packets (*whew*)
|
|
*
|
|
* 143 5/10/99 2:43a Jeff
|
|
* handle new scheme of player's joining in a team game, where the team is
|
|
* set before player enters game in the main code, but the team is
|
|
* determined via event call to dmfc
|
|
*
|
|
* 142 5/09/99 6:20a Jeff
|
|
* improved Entropy (added sounds, max virii per room). Fixed rendering
|
|
* bugs for other multiplayer dlls.
|
|
*
|
|
* 141 5/08/99 11:06a Jeff
|
|
*
|
|
* 140 5/07/99 4:34p Jason
|
|
* fixed audio taunt icon
|
|
*
|
|
* 139 5/07/99 12:52p Jeff
|
|
* audio taunt icon is ppic if available. coop has hard max team set of 4
|
|
*
|
|
* 138 5/04/99 8:46p Jeff
|
|
* display icon when someone plays an audio taunt
|
|
*
|
|
* 137 5/03/99 8:39a Jeff
|
|
* fixed apply damage to player
|
|
*
|
|
* 136 4/30/99 10:52p Jeff
|
|
* added $warp command
|
|
*
|
|
* 135 4/30/99 7:36p Jeff
|
|
* exported vis_effects to dmfc
|
|
*
|
|
* 134 4/27/99 1:56p Jeff
|
|
* audio taunts stuff in pilot menu, added stringtables
|
|
*
|
|
* 133 4/26/99 3:41p Jeff
|
|
* put in debug multiplayer command dump to file
|
|
*
|
|
* 132 4/25/99 7:18p Jeff
|
|
* added code to handle suicides in pinfo
|
|
*
|
|
* 131 4/23/99 6:15p Jeff
|
|
* fixed double calls to GameClose
|
|
*
|
|
* 130 4/23/99 4:49p Jason
|
|
* played with loss colors a bit
|
|
*
|
|
* 129 4/23/99 4:24p Jason
|
|
* fixed ping display bug
|
|
*
|
|
* 128 4/23/99 12:46p Jeff
|
|
* lag loss indicator on by default
|
|
*
|
|
* 127 4/22/99 11:28a Jeff
|
|
* changed percent sign as a result of Samir's change
|
|
*
|
|
* 126 4/21/99 10:35p Jeff
|
|
* fixed lag/loss displays
|
|
*
|
|
* 125 4/20/99 8:57p Jeff
|
|
* compile for Linux
|
|
*
|
|
* 124 4/14/99 3:03p Jeff
|
|
*
|
|
* 123 4/12/99 11:39a Jeff
|
|
* removed movement smoothing, added permissable cs to netgame info
|
|
*
|
|
* 122 4/04/99 4:55p Jeff
|
|
* added functionality to call osiris functions from multiplayer d3ms
|
|
*
|
|
* 121 4/03/99 4:06p Jeff
|
|
* added loss/ping gauge
|
|
*
|
|
* 120 4/02/99 9:02p Jeff
|
|
* fixed crashes if there was an error initializing module
|
|
*
|
|
* 119 3/30/99 9:01p Jeff
|
|
* exported polymodels
|
|
*
|
|
* 118 3/30/99 7:42p Jeff
|
|
* fixed a misspelling on a function name
|
|
*
|
|
* 117 3/22/99 6:20p Jeff
|
|
* added 2 more audio taunts. a mulitplayer event when someone plays an
|
|
* audio taunt. option to disable audio taunts.
|
|
*
|
|
* 116 3/22/99 1:55p Jeff
|
|
* make sure initialization happens (possible crashing)
|
|
*
|
|
* 115 3/17/99 12:23p Jeff
|
|
* converted DMFC to be COM interface
|
|
*
|
|
* 114 3/09/99 1:13p Jeff
|
|
* fixed control packet for wait being overflowed out and accidently sent
|
|
* by the client
|
|
*
|
|
* 113 3/05/99 1:29p Jeff
|
|
* fixed 99% of the high res issues
|
|
*
|
|
* 112 3/01/99 8:48p Jeff
|
|
* fixed banning bug (when not a master tracker game)
|
|
*
|
|
* 111 2/25/99 8:54p Jeff
|
|
* Inventory supports level change persistant items. Inventory supports
|
|
* time-out objects. Inventory Reset changed (takes a level of reset
|
|
* now). Quad lasers stay across level change (single player). Guidebot
|
|
* bug fixed (now back in ship on level start). Quads time out when
|
|
* spewed. Invulnerability and cloak powerups no longer use game
|
|
* event/callbacks, so they can be saved in game saves (moved to
|
|
* MakePlayerInvulnerable and MakeObjectInvisible)
|
|
*
|
|
* 110 2/11/99 12:50a Jeff
|
|
* changed names of exported variables
|
|
*
|
|
* 109 2/10/99 1:47p Matt
|
|
* Changed object handle symbolic constants
|
|
*
|
|
* 108 2/09/99 3:32p Jeff
|
|
* table file parser takes quotes strings for force keywords
|
|
*
|
|
* 107 2/07/99 2:06a Jeff
|
|
* updated coop...fixed bug when getting countermeasure owner, if owner is
|
|
* observer
|
|
*
|
|
* 106 2/07/99 1:19a Jeff
|
|
* added new multiplayer game events EVT_GAMEOBJKILLED and
|
|
* EVT_GAMEOBJDESTROYED
|
|
*
|
|
* 105 2/05/99 8:24p Jeff
|
|
* added table file parser macros
|
|
*
|
|
* 104 2/03/99 4:09p Jeff
|
|
* moved function pointers to seperate file. created autoexec.dmfc
|
|
*
|
|
* 103 2/02/99 8:43a Chris
|
|
* I made buildings with AI work correctly (ie really big robots should be
|
|
* buildings)
|
|
* anim to and from states are now shorts instead of bytes
|
|
*
|
|
* 102 1/31/99 7:26p Matt
|
|
* Renamed a bunch of functions to have HUD capitalized
|
|
*
|
|
* 101 1/21/99 11:16p Jeff
|
|
* exported vecmat functions
|
|
*
|
|
* 100 1/20/99 8:06p Jeff
|
|
* added members into DLLinfo struct for game change segment events, pass
|
|
* them over on execute dll packets
|
|
*
|
|
* 99 1/19/99 5:34p Jeff
|
|
* updated monsterball
|
|
*
|
|
* 98 1/18/99 7:27p Jeff
|
|
* localized strings in dmfcbase.cpp
|
|
*
|
|
* 97 1/17/99 11:52p Jeff
|
|
* added some new events, and changed a couple event handlers
|
|
*
|
|
* 96 1/15/99 8:29p Jeff
|
|
* updates to powerball
|
|
*
|
|
* 95 1/15/99 7:52p Chris
|
|
* Updated ObjSetPos() to include a f_update_attach_children flag
|
|
*
|
|
* 94 1/15/99 3:53a Jeff
|
|
* exported a couple more functions. Added event handlers for Weapon
|
|
* collide event
|
|
*
|
|
* 93 1/12/99 2:55p Jeff
|
|
* added/finished the waiting for player's to join dialog
|
|
*
|
|
* 92 1/12/99 11:29a Jason
|
|
* fixed a broken externed function
|
|
*
|
|
* 91 1/07/99 5:01p Jeff
|
|
* added Int3's and updated all net games to use stats manager...correctly
|
|
* too
|
|
*
|
|
* 90 1/06/99 7:02p Jeff
|
|
* added a multiplayer event for game controls
|
|
*
|
|
* 89 1/06/99 12:53a Jeff
|
|
* put in support for $piggyback and $observer
|
|
*
|
|
* 88 1/04/99 8:11p Jason
|
|
* fixed packet loss tracking problem
|
|
*
|
|
* 87 1/04/99 2:19p Jeff
|
|
* exported table file management functions
|
|
*
|
|
* 86 1/04/99 12:21p Jeff
|
|
* added support for hosts.allow/deny and updates stats manager a little
|
|
*
|
|
* 85 12/13/98 5:32p Jeff
|
|
* fixed ugly crash due to freeing memory allocated in another heap
|
|
*
|
|
* 84 12/09/98 12:38p Jeff
|
|
* removed possible security bug displaying a player's ip address (now
|
|
* server only can see it)
|
|
*
|
|
* 83 12/08/98 4:47p Jeff
|
|
* umm, various changes, fixed pilot pics so that they work for everyone
|
|
* now
|
|
*
|
|
* 82 12/08/98 3:29p Jeff
|
|
* updated the team control dialog so the server can determine if they
|
|
* want to make the clients wait
|
|
*
|
|
* 81 12/08/98 12:17p Jeff
|
|
* various changes that include an improved Team Control dialog (doesn't
|
|
* switch teams until exit..) and spew/respawn players that change teams
|
|
*
|
|
* 80 12/04/98 7:04p Jeff
|
|
* almost finished up dmfc stat manager
|
|
*
|
|
* 79 12/01/98 6:56p Jeff
|
|
* put in quick and dirty implementation of pilot pics for testing
|
|
*
|
|
* 78 11/19/98 5:56p Jeff
|
|
* added slider exported and improved Hoard
|
|
*
|
|
* 77 11/17/98 6:29p Jeff
|
|
* mod can specify whether or not to display the team setup dialog on team
|
|
* game start. Added a menu item to display team setup dialog in mid-game
|
|
*
|
|
* 76 11/17/98 12:36p Jeff
|
|
* fixed dedicated server detection and display a dprintf for setting new
|
|
* team
|
|
*
|
|
* 75 11/16/98 5:35p Jeff
|
|
* removed log functions, added support for changing team names, fixed ctf
|
|
* to work better with different team names
|
|
*
|
|
* 74 11/13/98 6:36p Jeff
|
|
* created dmfc_dll (a DLL version of DMFC) and converted current mods to
|
|
* use it
|
|
*
|
|
* 73 11/12/98 12:16p Jeff
|
|
* more changes to handle (ignore) dedicated server
|
|
*
|
|
* 72 11/11/98 7:19p Jeff
|
|
* changes made so that a dedicated server's team is always -1 (team game
|
|
* or not)
|
|
*
|
|
* 71 11/02/98 4:38p Jeff
|
|
* added ability to sort and display by efficiency
|
|
*
|
|
* 70 11/01/98 1:59a Jeff
|
|
* made a $help inputcommand for help in a dedicated server environment
|
|
*
|
|
* 69 10/30/98 12:47p Jeff
|
|
* cut down a couple bytes on memory usage
|
|
*
|
|
* 68 10/29/98 7:01p Jeff
|
|
* creation of team placement dialog. Moved TranslateEvent into DMFC
|
|
*
|
|
* 67 10/24/98 2:35p Matt
|
|
* Changed "callsign" to "name" or "player name" in the multiplayer menus
|
|
* and commands.
|
|
*
|
|
* 66 10/24/98 2:18p Jeff
|
|
*
|
|
* 65 10/23/98 6:51p Jeff
|
|
* fixed hud num of teams sort in ctf, and memory overwrite in registry
|
|
*
|
|
* 64 10/23/98 11:22a Jeff
|
|
* changes to handle mixcase, and display the client netgame info
|
|
* correctly
|
|
*
|
|
* 63 10/21/98 5:02p Jeff
|
|
* removed player from HUD if in observer nide
|
|
*
|
|
* 62 10/20/98 4:35p Jeff
|
|
* added a flag for menu to add a <None> to MIT_PLIST...
|
|
*
|
|
* 61 10/20/98 12:16p Jeff
|
|
* added death message filter, hud callsign filter
|
|
*
|
|
* 60 10/19/98 7:19p Matt
|
|
* Added system to support different types of damage to the player and
|
|
* have these different types make different sounds.
|
|
*
|
|
* 59 10/18/98 7:59p Jeff
|
|
* functions added to dmfc for client->server objnum matching. Banning
|
|
* now uses tracker id when available.
|
|
*
|
|
* 58 10/17/98 7:30p Jeff
|
|
* network_address compares don't compare port on somethings
|
|
*
|
|
* 57 10/15/98 6:18p Jeff
|
|
* created the is player banned event, removed prejoin event
|
|
*
|
|
* 56 10/15/98 1:34p Jeff
|
|
* added scrollable onscreen menu. Remove ban in dmfc. prejoin event
|
|
*
|
|
* 55 10/13/98 6:01p Jeff
|
|
* added attaching
|
|
*
|
|
* 54 10/13/98 2:15a Jeff
|
|
* created new event for when a player leaves a multiplayer game. Fixed
|
|
* some 'english' bugs in the network games.
|
|
*
|
|
* 53 10/08/98 3:37p Jeff
|
|
* general improvements (Netgame info things, save to registry). Changes
|
|
* so it would send packets on NETSEQ_OBJECTS
|
|
*
|
|
* 51 10/05/98 2:49p Jeff
|
|
*
|
|
* 50 10/02/98 6:10p Jeff
|
|
*
|
|
* 49 10/01/98 11:30a Jeff
|
|
* made the observer mode events into just a client event
|
|
*
|
|
* 48 9/30/98 4:21p Jeff
|
|
* team changing is handled correctly
|
|
*
|
|
* 47 9/30/98 3:50p Jeff
|
|
* general improvements (many)
|
|
*
|
|
* 46 9/29/98 3:04p Jeff
|
|
* added time in game and start_time support
|
|
*
|
|
* 45 9/28/98 5:05p Jeff
|
|
* made the statisitical death messages an option in the menu
|
|
*
|
|
* 44 9/25/98 7:25p Jeff
|
|
*
|
|
* 43 9/25/98 4:50p Jeff
|
|
*
|
|
* 42 9/24/98 6:54p Jeff
|
|
* added DisconnectMe() and made use of it when you get kicked/banned
|
|
*
|
|
* 41 9/24/98 6:29p Jeff
|
|
*
|
|
* 40 9/24/98 5:52p Jeff
|
|
* starting adding statistical death messages, checked in for testing
|
|
*
|
|
* 39 9/23/98 5:27p Jeff
|
|
* fixed death message bug (using objnum instead of pnum)
|
|
*
|
|
* 38 9/23/98 4:17p Jeff
|
|
* basic changes/improvements, started changing death messages
|
|
*
|
|
* 37 9/21/98 7:11p Jeff
|
|
* made InputCommand interface API and moved existing input commands to
|
|
* the interface. Changed mprintf/ASSERT so they are valid in DMFC
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "gamedll_header.h"
|
|
#include "DMFC.h"
|
|
#include "dmfcinternal.h"
|
|
#include "dmfcinputcommands.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <algorithm>
|
|
|
|
char **DMFCStringTable;
|
|
int DMFCStringTableSize = 0;
|
|
const char *_DMFCErrorString = "DMFC Missing String";
|
|
uint8_t seeds1[31] = {49, 73, 0, 44, 87, 253, 35, 74, 62, 250, 4, 247, 251, 72, 244, 30,
|
|
59, 61, 60, 52, 50, 237, 23, 48, 56, 55, 65, 232, 231, 230, 0};
|
|
uint8_t seeds2[6] = {70, 95, 103, 102, 112, 0};
|
|
|
|
const char *DMFCGetString(int d) {
|
|
if ((d < 0) || (d >= DMFCStringTableSize))
|
|
return _DMFCErrorString;
|
|
else
|
|
return DMFCStringTable[d];
|
|
}
|
|
|
|
DMFCBase::DMFCBase(void) {
|
|
m_cPtrs = 0;
|
|
|
|
m_iServerHUDCallsignLevel = HUD_CALLSIGN_LEVEL_FULL;
|
|
m_iMyCurrentHUDCallsignLevel = m_iMyPreferredHUDCallsignLevel = HUD_CALLSIGN_LEVEL_FULL;
|
|
m_iProtectedFlags = 0;
|
|
m_bHasInitialized = false;
|
|
LossGuageEnabled = true;
|
|
DMFCInit = false;
|
|
RealGametime = 0;
|
|
DedicatedLevelWait = 0;
|
|
m_bDisplayTimelimitCountdown = true;
|
|
m_iTimeLimitCountdown = 10;
|
|
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_PLRFIRSTTIME | DMFC_PRF_CANTEAMCHANGE);
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND);
|
|
ENABLE_FLAGS(m_iProtectedFlags,
|
|
DMFC_PRF_AUTOTIMELIMIT | DMFC_PRF_AUTODEATHMSG | DMFC_PRF_AUTOTEAMSELECT | DMFC_PRF_DISPSTATHUDMSGS);
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_INOPTIONS | DMFC_PRF_DISPPLAYERINFO | DMFC_PRF_DISPNETGAMEINFO);
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC | DMFC_PRF_DISPMENUBACKGR | DMFC_PRF_PAUSETIME);
|
|
|
|
m_iNumBanPlayers = 0;
|
|
m_bMakeClientsWait = false;
|
|
m_iPlayerDisplayed = 0;
|
|
|
|
DatabaseRegisteredName[0] = '\0';
|
|
|
|
SPRoot = NULL; // no special packet handlers yet
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_DEATH_MSGS; i++) {
|
|
DeathMsgs[i].inuse = false;
|
|
DeathMsgs[i].message = NULL;
|
|
SuicideMsgs[i].inuse = false;
|
|
SuicideMsgs[i].message = NULL;
|
|
}
|
|
|
|
for (i = 0; i < MAX_WEAPONS; i++) {
|
|
WeaponMessages[i].inuse = false;
|
|
WeaponMessages[i].message = NULL;
|
|
WeaponHash[i] = -1;
|
|
}
|
|
|
|
m_iDeathMsgCount = 0;
|
|
m_iSuicideMsgCount = 0;
|
|
m_iUIWindowID = -1;
|
|
m_UIUserData = NULL;
|
|
|
|
m_DenyList = NULL;
|
|
m_AllowList = NULL;
|
|
m_InputCommandRootNode = NULL;
|
|
Hard_max_players = DLLMAX_PLAYERS;
|
|
|
|
DecryptData(seeds2, 5);
|
|
|
|
TeamMenuItem = NULL;
|
|
AutoBalanceItem = NULL;
|
|
AllowTeamChangeItem = NULL;
|
|
ObserverItem = NULL;
|
|
m_BanList = NULL;
|
|
StatisticMessagesItem = NULL;
|
|
SaveStatsLevelEndItem = NULL;
|
|
SaveStatsDisconnectItem = NULL;
|
|
NetGameInfoItem = NULL;
|
|
MenuBackgroundItem = NULL;
|
|
ServerHUDCallsignsItem = NULL;
|
|
HUDCallsignsItem = NULL;
|
|
DeathMessageFilterItem = NULL;
|
|
ShipLogosItem = NULL;
|
|
HUDIndicatorItem = NULL;
|
|
|
|
DisplayTauntIndicator = false;
|
|
TauntIndicatorPlayerNum = -1;
|
|
TauntIndicatorStartTime = 0;
|
|
TauntIndicatorBMP = -1;
|
|
|
|
for (i = 0; i < DLLMAX_TEAMS; i++)
|
|
DMFC_team_names[i][0] = '\0';
|
|
|
|
for (i = 0; i < DLLMAX_PLAYERS; i++) {
|
|
PilotPicBmpHandles[i] = BAD_BITMAP_HANDLE;
|
|
}
|
|
|
|
InitializeVirtualHandles();
|
|
}
|
|
|
|
DMFCBase::~DMFCBase(void) {
|
|
int i;
|
|
|
|
ResetPInfo();
|
|
|
|
RemoveAllBans();
|
|
|
|
for (i = 0; i < DLLMAX_PLAYERS; i++) {
|
|
if (PilotPicBmpHandles[i] > BAD_BITMAP_HANDLE) {
|
|
DLLbm_FreeBitmap(PilotPicBmpHandles[i]);
|
|
PilotPicBmpHandles[i] = BAD_BITMAP_HANDLE;
|
|
}
|
|
}
|
|
|
|
if (TauntIndicatorBMP > BAD_BITMAP_HANDLE) {
|
|
DLLbm_FreeBitmap(TauntIndicatorBMP);
|
|
TauntIndicatorBMP = BAD_BITMAP_HANDLE;
|
|
}
|
|
|
|
for (i = 0; i < MAX_DEATH_MSGS; i++) {
|
|
if (DeathMsgs[i].inuse) {
|
|
if (DeathMsgs[i].message)
|
|
free(DeathMsgs[i].message);
|
|
DeathMsgs[i].inuse = false;
|
|
}
|
|
if (SuicideMsgs[i].inuse) {
|
|
if (SuicideMsgs[i].message)
|
|
free(SuicideMsgs[i].message);
|
|
SuicideMsgs[i].inuse = false;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_WEAPONS; i++) {
|
|
if (WeaponMessages[i].inuse) {
|
|
if (WeaponMessages[i].message) {
|
|
free(WeaponMessages[i].message);
|
|
WeaponMessages[i].message = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove all the special packet handlers
|
|
tSPHandler *current, *next;
|
|
current = next = SPRoot;
|
|
while (current) {
|
|
next = current->next;
|
|
free(current);
|
|
current = next;
|
|
}
|
|
SPRoot = NULL;
|
|
}
|
|
|
|
// ##################Setup and processing functions#######################
|
|
|
|
// DMFCBase::InitializeForLevel
|
|
//
|
|
//
|
|
void DMFCBase::InitializeForLevel(void) {
|
|
if (m_bHasInitialized)
|
|
return;
|
|
|
|
// Reset the timers
|
|
InitTimers();
|
|
|
|
m_bHasInitialized = true;
|
|
}
|
|
|
|
// DMFCBase::LoadSettings
|
|
//
|
|
// Loads the settings of DMFC from the registry and initializes those variables
|
|
void DMFCBase::LoadSettings(void) {
|
|
// set default values
|
|
ENABLE_FLAGS(m_iProtectedFlags,
|
|
DMFC_PRF_AUTOTIMELIMIT | DMFC_PRF_AUTODEATHMSG | DMFC_PRF_AUTOTEAMSELECT | DMFC_PRF_DISPSTATHUDMSGS);
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND | DMFC_PRF_CANTEAMCHANGE);
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC | DMFC_PRF_DISPMENUBACKGR);
|
|
m_iServerHUDCallsignLevel = HUD_CALLSIGN_LEVEL_FULL;
|
|
m_iMyCurrentHUDCallsignLevel = m_iMyPreferredHUDCallsignLevel = HUD_CALLSIGN_LEVEL_FULL;
|
|
m_iDeathMessageFilter = DM_FILTER_FULL;
|
|
LossGuageEnabled = true;
|
|
|
|
bool bTemp;
|
|
|
|
if (DatabaseRead3("DMFCAutoTimeLimit", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTIMELIMIT);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTIMELIMIT);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCAutoDeathMessage", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTODEATHMSG);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTODEATHMSG);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCAutoTeamSelect", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTEAMSELECT);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTEAMSELECT);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCStatHUDMessages", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPSTATHUDMSGS);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPSTATHUDMSGS);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCAutoSaveStatLevelEnd", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCAutoSaveStatDisconnect", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCMenuBackground", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPMENUBACKGR);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPMENUBACKGR);
|
|
}
|
|
|
|
if (DatabaseRead3("DMFCCanChangeTeams", &bTemp)) {
|
|
if (bTemp)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_CANTEAMCHANGE);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_CANTEAMCHANGE);
|
|
}
|
|
|
|
DatabaseRead3("DMFCLagLossIndicator", &LossGuageEnabled);
|
|
|
|
DatabaseRead2("DMFCShowHudCallsigns", &m_iMyPreferredHUDCallsignLevel, sizeof(m_iMyPreferredHUDCallsignLevel));
|
|
DatabaseRead2("DMFCServerShowHudCallsigns", &m_iServerHUDCallsignLevel, sizeof(m_iServerHUDCallsignLevel));
|
|
DatabaseRead2("DMFCDeathMessageFilter", &m_iDeathMessageFilter, sizeof(m_iDeathMessageFilter));
|
|
|
|
m_iMyCurrentHUDCallsignLevel = m_iMyPreferredHUDCallsignLevel;
|
|
}
|
|
|
|
// DMFCBase::SaveSettings
|
|
//
|
|
// Saves out the settings of DMFC to the registry
|
|
void DMFCBase::SaveSettings(void) {
|
|
bool bTemp;
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_AUTOTIMELIMIT) != 0);
|
|
DatabaseWrite2("DMFCAutoTimeLimit", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_AUTODEATHMSG) != 0);
|
|
DatabaseWrite2("DMFCAutoDeathMessage", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_AUTOTEAMSELECT) != 0);
|
|
DatabaseWrite2("DMFCAutoTeamSelect", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_DISPSTATHUDMSGS) != 0);
|
|
DatabaseWrite2("DMFCStatHUDMessages", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_AUTOSAVELEVELEND) != 0);
|
|
DatabaseWrite2("DMFCAutoSaveStatLevelEnd", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_AUTOSAVEDISC) != 0);
|
|
DatabaseWrite2("DMFCAutoSaveStatDisconnect", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_DISPMENUBACKGR) != 0);
|
|
DatabaseWrite2("DMFCMenuBackground", bTemp);
|
|
|
|
bTemp = (bool)((m_iProtectedFlags & DMFC_PRF_CANTEAMCHANGE) != 0);
|
|
DatabaseWrite2("DMFCCanChangeTeams", bTemp);
|
|
|
|
DatabaseWrite2("DMFCLagLossIndicator", LossGuageEnabled);
|
|
|
|
DatabaseWrite2("DMFCShowHudCallsigns", m_iMyPreferredHUDCallsignLevel);
|
|
DatabaseWrite2("DMFCServerShowHudCallsigns", m_iServerHUDCallsignLevel);
|
|
DatabaseWrite2("DMFCDeathMessageFilter", m_iDeathMessageFilter);
|
|
}
|
|
|
|
// DMFCBase::LoadFunctions
|
|
//
|
|
// Initialized all the functions for a multiplayer game...must be first thing called
|
|
void DMFCBase::LoadFunctions(int *api_func) {
|
|
DLLGetGameAPI = (GetGameAPI_fp)api_func;
|
|
DLLGetGameAPI(&API);
|
|
|
|
Objects = (object *)API.objs;
|
|
Rooms = (room *)API.rooms;
|
|
Terrain_seg = (terrain_segment *)API.terrain;
|
|
Players = (player *)API.players;
|
|
Netgame = (netgame_info *)API.netgame;
|
|
NetPlayers = (netplayer *)API.netplayers;
|
|
Ships = (ship *)API.ships;
|
|
Weapons = (weapon *)API.weapons;
|
|
Current_mission = (tMission *)API.Current_mission;
|
|
GameTextures = (texture *)API.GameTextures;
|
|
GameVClips = (vclip *)API.GameVClips;
|
|
|
|
// Do functions, variables
|
|
// Note, these must match the ordering on the D3 side (Game2DLL.cpp)
|
|
DLLAddHUDMessage = (AddHUDMessage_fp)API.fp[0];
|
|
DLLMultiSendClientExecuteDLL = (MultiSendClientExecuteDLL_fp)API.fp[1];
|
|
DLLFindObjectIDName = (FindObjectIDName_fp)API.fp[2];
|
|
DLLGetGoalRoomForTeam = (GetGoalRoomForTeam_fp)API.fp[3];
|
|
DLLSetMaxTeams = (SetMaxTeams_fp)API.fp[4];
|
|
DLLComputeRoomCenter = (ComputeRoomCenter_fp)API.fp[5];
|
|
DLLObjCreate = (ObjCreate_fp)API.fp[6];
|
|
DLLMultiSendObject = (MultiSendObject_fp)API.fp[7];
|
|
DLLMultiPaintGoalRooms = (MultiPaintGoalRooms_fp)API.fp[8];
|
|
DLLMultiSendSpecialPacket = (MultiSendSpecialPacket_fp)API.fp[9];
|
|
DLLIncTeamScore = (IncTeamScore_fp)API.fp[10];
|
|
DLLDebug_ConsolePrintf = (Debug_ConsolePrintf_fp)API.fp[11];
|
|
DLLObjSetPosNoMark = (ObjSetPosNoMark_fp)API.fp[12];
|
|
DLLInvCheckItem = (InvCheckItem_fp)API.fp[13];
|
|
DLLInvAddTypeID = (InvAddTypeID_fp)API.fp[14];
|
|
DLLInvRemove = (InvRemove_fp)API.fp[15];
|
|
DLLPlayerSetLighting = (PlayerSetLighting_fp)API.fp[16];
|
|
DLLFindShipName = (FindShipName_fp)API.fp[17];
|
|
DLLPlayerSetRotatingBall = (PlayerSetRotatingBall_fp)API.fp[18];
|
|
DLLPlayerChangeShip = (PlayerChangeShip_fp)API.fp[19];
|
|
DLLInvGetTypeIDCount = (InvGetTypeIDCount_fp)API.fp[20];
|
|
DLLPlay3dSound = (D3W_Play3dSound_fp)API.fp[21];
|
|
DLLFindSoundName = (FindSoundName_fp)API.fp[22];
|
|
DLLSpewCreate = (SpewCreate_fp)API.fp[23];
|
|
DLLSpewClearEvent = (SpewClearEvent_fp)API.fp[24];
|
|
DLLbm_AllocLoadFileBitmap = (bm_AllocLoadFileBitmap_fp)API.fp[25];
|
|
DLLbm_FreeBitmap = (bm_FreeBitmap_fp)API.fp[26];
|
|
DLLrend_DrawScaledBitmap = (rend_DrawScaledBitmap_fp)API.fp[27];
|
|
DLLgrtext_Printf = (grtext_Printf_fp)API.fp[28];
|
|
DLLgrtext_Flush = (grtext_Flush_fp)API.fp[29];
|
|
DLLgrtext_SetColor = (grtext_SetColor_fp)API.fp[30];
|
|
DLLgrtext_SetFancyColor = (grtext_SetFancyColor_fp)API.fp[31];
|
|
DLLgrtext_SetAlpha = (grtext_SetAlpha_fp)API.fp[32];
|
|
DLLgrtext_GetAlpha = (grtext_GetAlpha_fp)API.fp[33];
|
|
DLLgrtext_SetFont = (grtext_SetFont_fp)API.fp[34];
|
|
DLLgrtext_GetFont = (grtext_GetFont_fp)API.fp[35];
|
|
DLLgrtext_GetTextLineWidth = (grtext_GetTextLineWidth_fp)API.fp[36];
|
|
DLLgrfont_GetHeight = (grfont_GetHeight_fp)API.fp[37];
|
|
DLLgrtext_CenteredPrintf = (grtext_CenteredPrintf_fp)API.fp[38];
|
|
DLLAddColoredHUDMessage = (AddColoredHUDMessage_fp)API.fp[39];
|
|
DLLbm_w = (bm_w_fp)API.fp[40];
|
|
DLLbm_h = (bm_h_fp)API.fp[41];
|
|
DLLrend_DrawSimpleBitmap = (rend_DrawSimpleBitmap_fp)API.fp[42];
|
|
DLLMultiClientSendSpecialPacket = (MultiClientSendSpecialPacket_fp)API.fp[43];
|
|
DLLAddBlinkingHUDMessage = (AddBlinkingHUDMessage_fp)API.fp[44];
|
|
DLLInvReset = (InvReset_fp)API.fp[45];
|
|
DLLAddHUDItem = (AddHUDItem_fp)API.fp[46];
|
|
DLLRenderHUDQuad = (RenderHUDQuad_fp)API.fp[47];
|
|
DLLRenderHUDText = (RenderHUDText_fp)API.fp[48];
|
|
DLLMultiEndLevel = (MultiEndLevel_fp)API.fp[49];
|
|
DLLbm_data = (bm_data_fp)API.fp[50];
|
|
DLLbm_AllocBitmap = (bm_AllocBitmap_fp)API.fp[51];
|
|
DLLrend_FillRect = (rend_FillRect_fp)API.fp[52];
|
|
DLLbm_CreateChunkedBitmap = (bm_CreateChunkedBitmap_fp)API.fp[53];
|
|
DLLbm_DestroyChunkedBitmap = (bm_DestroyChunkedBitmap_fp)API.fp[54];
|
|
DLLrend_DrawChunkedBitmap = (rend_DrawChunkedBitmap_fp)API.fp[55];
|
|
DLLrend_DrawScaledChunkedBitmap = (rend_DrawScaledChunkedBitmap_fp)API.fp[56];
|
|
DLLOpenCFILE = (OpenCFILE_fp)API.fp[57];
|
|
DLLcfclose = (cfclose_fp)API.fp[58];
|
|
DLLcfeof = (cfeof_fp)API.fp[59];
|
|
DLLcfexist = (cfexist_fp)API.fp[60];
|
|
DLLcf_ReadBytes = (cf_ReadBytes_fp)API.fp[61];
|
|
DLLcf_ReadInt = (cf_ReadInt_fp)API.fp[62];
|
|
DLLcf_ReadShort = (cf_ReadShort_fp)API.fp[63];
|
|
DLLcf_ReadByte = (cf_ReadByte_fp)API.fp[64];
|
|
DLLcf_ReadFloat = (cf_ReadFloat_fp)API.fp[65];
|
|
DLLcf_ReadDouble = (cf_ReadDouble_fp)API.fp[66];
|
|
DLLcf_ReadString = (cf_ReadString_fp)API.fp[67];
|
|
DLLcf_WriteBytes = (cf_WriteBytes_fp)API.fp[68];
|
|
DLLcf_WriteString = (cf_WriteString_fp)API.fp[69];
|
|
DLLcf_WriteInt = (cf_WriteInt_fp)API.fp[70];
|
|
DLLcf_WriteShort = (cf_WriteShort_fp)API.fp[71];
|
|
DLLcf_WriteByte = (cf_WriteByte_fp)API.fp[72];
|
|
DLLcf_WriteFloat = (cf_WriteFloat_fp)API.fp[73];
|
|
DLLcf_WriteDouble = (cf_WriteDouble_fp)API.fp[74];
|
|
DLLcf_CopyFile = (cf_CopyFile_fp)API.fp[75];
|
|
DLLcf_Diff = (cf_Diff_fp)API.fp[76];
|
|
DLLMultiDisconnectPlayer = (MultiDisconnectPlayer_fp)API.fp[77];
|
|
DLLnw_GetNumbersFromHostAddress = (nw_GetNumbersFromHostAddress_fp)API.fp[78];
|
|
DLLnw_GetThisIP = (nw_GetThisIP_fp)API.fp[79];
|
|
DLLCreateStringTable = (CreateStringTable_fp)API.fp[80];
|
|
DLLDestroyStringTable = (DestroyStringTable_fp)API.fp[81];
|
|
DLLRenderHUDTextFlags = (RenderHUDTextFlags_fp)API.fp[82];
|
|
DLLPlayerSpewInventory = (PlayerSpewInventory_fp)API.fp[83];
|
|
DLLPlayerSetHUDNameFOV = (PlayerSetHUDNameFOV_fp)API.fp[84];
|
|
DLLGetUltimateParentForObject = (GetUltimateParentForObject_fp)API.fp[85];
|
|
DLLSetObjectDeadFlagRaw = (SetObjectDeadFlagRaw_fp)API.fp[86];
|
|
FatalError = (DLLFatalError_fp)API.fp[87];
|
|
DLLassert = (assertdll_fp)API.fp[88];
|
|
DLLMultiMatchWeapon = (MultiMatchWeapon_fp)API.fp[89];
|
|
DLLMultiGetMatchChecksum = (MultiGetMatchChecksum_fp)API.fp[90];
|
|
DLLFindWeaponName = (FindWeaponName_fp)API.fp[91];
|
|
DLLcf_OpenLibrary = (cf_OpenLibrary_fp)API.fp[92];
|
|
DLLcf_CloseLibrary = (cf_CloseLibrary_fp)API.fp[93];
|
|
DLLMultiSendRequestToObserve = (MultiSendRequestToObserve_fp)API.fp[94];
|
|
DLLFindTextureName = (FindTextureName_fp)API.fp[95];
|
|
DLLApplyDamageToPlayer = (ApplyDamageToPlayer_fp)API.fp[96];
|
|
DLLMultiMatchGeneric = (MultiMatchGeneric_fp)API.fp[97];
|
|
DLLSetUITextItemText = (SetUITextItemText_fp)API.fp[98];
|
|
DLLNewUIWindowCreate = (NewUIWindowCreate_fp)API.fp[99];
|
|
DLLNewUIWindowDestroy = (NewUIWindowDestroy_fp)API.fp[100];
|
|
DLLNewUIWindowOpen = (NewUIWindowOpen_fp)API.fp[101];
|
|
DLLNewUIWindowClose = (NewUIWindowClose_fp)API.fp[102];
|
|
DLLTextCreate = (TextCreate_fp)API.fp[103];
|
|
DLLEditCreate = (EditCreate_fp)API.fp[104];
|
|
DLLButtonCreate = (ButtonCreate_fp)API.fp[105];
|
|
DLLListCreate = (ListCreate_fp)API.fp[106];
|
|
DLLListRemoveAll = (ListRemoveAll_fp)API.fp[107];
|
|
DLLListAddItem = (ListAddItem_fp)API.fp[108];
|
|
DLLListRemoveItem = (ListRemoveItem_fp)API.fp[109];
|
|
DLLListSelectItem = (ListSelectItem_fp)API.fp[110];
|
|
DLLListGetItem = (ListGetItem_fp)API.fp[111];
|
|
DLLListGetSelectedIndex = (ListGetSelectedIndex_fp)API.fp[112];
|
|
DLLEditSetText = (EditSetText_fp)API.fp[113];
|
|
DLLEditGetText = (EditGetText_fp)API.fp[114];
|
|
DLLDoUI = (DoUI_fp)API.fp[115];
|
|
DLLDoMessageBox = (DoMessageBox_fp)API.fp[116];
|
|
DLLDescentDefer = (DescentDefer_fp)API.fp[117];
|
|
DLLNewUIGameWindowCreate = (NewUIGameWindowCreate_fp)API.fp[118];
|
|
DLLNewUIGameWindowDestroy = (NewUIGameWindowDestroy_fp)API.fp[119];
|
|
DLLNewUIGameWindowOpen = (NewUIGameWindowOpen_fp)API.fp[120];
|
|
DLLNewUIGameWindowClose = (NewUIGameWindowClose_fp)API.fp[121];
|
|
DLLHotSpotCreate = (HotSpotCreate_fp)API.fp[122];
|
|
DLLPollUI = (PollUI_fp)API.fp[123];
|
|
DLLRemoveUITextItem = (RemoveUITextItem_fp)API.fp[124];
|
|
DLLCreateNewUITextItem = (CreateNewUITextItem_fp)API.fp[125];
|
|
DLLUIConsoleGadgetCreate = (UIConsoleGadgetCreate_fp)API.fp[126];
|
|
DLLUIConsoleGadgetputs = (UIConsoleGadgetputs_fp)API.fp[127];
|
|
DLLNewUIWindowSetFocusOnEditGadget = (NewUIWindowSetFocusOnEditGadget_fp)API.fp[128];
|
|
DLLOldEditCreate = (OldEditCreate_fp)API.fp[129];
|
|
DLLOldListCreate = (OldListCreate_fp)API.fp[130];
|
|
DLLOldListRemoveAll = (OldListRemoveAll_fp)API.fp[131];
|
|
DLLOldListAddItem = (OldListAddItem_fp)API.fp[132];
|
|
DLLOldListRemoveItem = (OldListRemoveItem_fp)API.fp[133];
|
|
DLLOldListSelectItem = (OldListSelectItem_fp)API.fp[134];
|
|
DLLOldListGetItem = (OldListGetItem_fp)API.fp[135];
|
|
DLLOldListGetSelectedIndex = (OldListGetSelectedIndex_fp)API.fp[136];
|
|
DLLOldEditSetText = (OldEditSetText_fp)API.fp[137];
|
|
DLLOldEditGetText = (OldEditGetText_fp)API.fp[138];
|
|
DLLToggleUICallback = (ToggleUICallback_fp)API.fp[139];
|
|
DLLSetOldEditBufferLen = (SetOldEditBufferLen_fp)API.fp[140];
|
|
DLLNewUIWindowLoadBackgroundImage = (NewUIWindowLoadBackgroundImage_fp)API.fp[141];
|
|
DLLDeleteUIItem = (DeleteUIItem_fp)API.fp[142];
|
|
DLLHotSpotSetStates = (HotSpotSetStates_fp)API.fp[143];
|
|
DLLSetUICallback = (SetUICallback_fp)API.fp[144];
|
|
DLLGetUICallback = (RetrieveUICallback_fp)API.fp[145];
|
|
DLLSuspendControls = (SuspendControls_fp)API.fp[146];
|
|
DLLResumeControls = (ResumeControls_fp)API.fp[147];
|
|
DLLShowCursor = (ui_ShowCursor_fp)API.fp[148];
|
|
DLLHideCursor = (ui_HideCursor_fp)API.fp[149];
|
|
DLLGameFrame = (GameFrame_fp)API.fp[150];
|
|
DPrintf = (DPrintf_fp)API.fp[151];
|
|
DLLddio_MakePath = (ddio_MakePath_fp)API.fp[152];
|
|
DLLddio_SplitPath = (ddio_SplitPath_fp)API.fp[153];
|
|
DLLPlay2dSound = (Play2dSound_fp)API.fp[154];
|
|
DLLTouchSound = (TouchSound_fp)API.fp[155];
|
|
DatabaseRead1 = (dDatabaseRead_fp1)API.fp[156];
|
|
DatabaseRead2 = (dDatabaseRead_fp2)API.fp[157];
|
|
DatabaseRead3 = (dDatabaseRead_fp3)API.fp[158];
|
|
DatabaseWrite1 = (dDatabaseWrite_fp1)API.fp[159];
|
|
DatabaseWrite2 = (dDatabaseWrite_fp2)API.fp[160];
|
|
DLLAttachObject = (AttachObject_fp)API.fp[161];
|
|
DLLObjGet = (ObjGet_fp)API.fp[162];
|
|
DLLListSetSelectedIndex = (ListSetSelectedIndex_fp)API.fp[163];
|
|
DLLRemoveUIBmpItem = (RemoveUIBmpItem_fp)API.fp[164];
|
|
DLLCreateNewUIBmpItem = (CreateNewUIBmpItem_fp)API.fp[165];
|
|
DLLGetUIItemWidth = (GetUIItemWidth_fp)API.fp[166];
|
|
DLLGetUIItemHeight = (GetUIItemHeight_fp)API.fp[167];
|
|
DLLSliderCreate = (SliderCreate_fp)API.fp[168];
|
|
DLLSliderSetRange = (SliderSetRange_fp)API.fp[169];
|
|
DLLSliderGetRange = (SliderGetRange_fp)API.fp[170];
|
|
DLLSliderSetPos = (SliderSetPos_fp)API.fp[171];
|
|
DLLSliderGetPos = (SliderGetPos_fp)API.fp[172];
|
|
DLLSliderSetSelectChangeCallback = (SliderSetSelectChangeCallback_fp)API.fp[173];
|
|
DLLSliderSetSelectChangeCallbackWData = (SliderSetSelectChangeCallbackWData_fp)API.fp[174];
|
|
DLLTextSetTitle = (TextSetTitle_fp)API.fp[175];
|
|
DLLPPic_GetPilot = (PPic_GetPilot_fp)API.fp[176];
|
|
DLLPPic_GetBitmapHandle = (PPic_GetBitmapHandle_fp)API.fp[177];
|
|
DLLrend_DrawLine = (rend_DrawLine_fp)API.fp[178];
|
|
DLLrend_SetFlatColor = (rend_SetFlatColor_fp)API.fp[179];
|
|
DLLMultiSetLogoState = (MultiSetLogoState_fp)API.fp[180];
|
|
DLLPlayerGetRandomStartPosition = (PlayerGetRandomStartPosition_fp)API.fp[181];
|
|
DLLInitPlayerNewShip = (InitPlayerNewShip_fp)API.fp[182];
|
|
DLLCheckBoxCreate = (CheckBoxCreate_fp)API.fp[183];
|
|
DLLCheckBoxSetCheck = (CheckBoxSetCheck_fp)API.fp[184];
|
|
DLLCheckBoxIsChecked = (CheckBoxIsChecked_fp)API.fp[185];
|
|
DLLnw_GetHostAddressFromNumbers = (nw_GetHostAddressFromNumbers_fp)API.fp[186];
|
|
TableFilesClear = (TableFilesClear_fp)API.fp[187];
|
|
TableFileAdd = (TableFileAdd_fp)API.fp[188];
|
|
DLLDebugBreak_callback_stop = (DebugBreak_callback_stop_fp)API.fp[189];
|
|
DLLDebugBreak_callback_resume = (DebugBreak_callback_resume_fp)API.fp[190];
|
|
DLLInt3MessageBox = (Int3MessageBox_fp)API.fp[191];
|
|
DLLGetUIItemPosition = (GetUIItemPosition_fp)API.fp[192];
|
|
DLLAttachObjectRadius = (AttachObjectRadius_fp)API.fp[193];
|
|
DLLUnattachChildren = (UnattachChildren_fp)API.fp[194];
|
|
DLLUnattachChild = (UnattachChild_fp)API.fp[195];
|
|
DLLUnattachFromParent = (UnattachFromParent_fp)API.fp[196];
|
|
DLLvm_GetMagnitude = (vm_GetMagnitude_fp)API.fp[197];
|
|
DLLvm_MatrixMulVector = (vm_MatrixMulVector_fp)API.fp[198];
|
|
DLLphys_apply_force = (phys_apply_force_fp)API.fp[199];
|
|
DLLphys_apply_rot = (phys_apply_rot_fp)API.fp[200];
|
|
DLLvm_TransposeMatrix = (vm_TransposeMatrix_fp)API.fp[201];
|
|
DLLvm_CrossProduct = (vm_CrossProduct_fp)API.fp[202];
|
|
DLLvm_NormalizeVector = (vm_NormalizeVector_fp)API.fp[203];
|
|
DLLConvertEulerToAxisAmount = (ConvertEulerToAxisAmount_fp)API.fp[204];
|
|
DLLConvertAxisAmountToEuler = (ConvertAxisAmountToEuler_fp)API.fp[205];
|
|
DLLvm_GetMagnitudeFast = (vm_GetMagnitudeFast_fp)API.fp[206];
|
|
DLLvm_MakeIdentity = (vm_MakeIdentity_fp)API.fp[207];
|
|
DLLvm_MakeVectorZero = (vm_MakeVectorZero_fp)API.fp[208];
|
|
DLLvm_MakeAngleZero = (vm_MakeAngleZero_fp)API.fp[209];
|
|
DLLvm_VectorMulTMatrix = (vm_VectorMulTMatrix_fp)API.fp[210];
|
|
DLLvm_MatrixMul = (vm_MatrixMul_fp)API.fp[211];
|
|
DLLvm_MatrixMulTMatrix = (vm_MatrixMulTMatrix_fp)API.fp[212];
|
|
DLLvm_DotProduct = (vm_DotProduct_fp)API.fp[213];
|
|
DLLvm_SubVectors = (vm_SubVectors_fp)API.fp[214];
|
|
DLLvm_AddVectors = (vm_AddVectors_fp)API.fp[215];
|
|
DLLvm_AverageVector = (vm_AverageVector_fp)API.fp[216];
|
|
DLLvm_ScaleVector = (vm_ScaleVector_fp)API.fp[217];
|
|
DLLvm_ScaleAddVector = (vm_ScaleAddVector_fp)API.fp[218];
|
|
DLLvm_DivVector = (vm_DivVector_fp)API.fp[219];
|
|
DLLvm_NormalizeVectorFast = (vm_NormalizeVectorFast_fp)API.fp[220];
|
|
DLLvm_ClearMatrix = (vm_ClearMatrix_fp)API.fp[221];
|
|
DLLvm_AnglesToMatrix = (vm_AnglesToMatrix_fp)API.fp[222];
|
|
DLLvm_Orthogonalize = (vm_Orthogonalize_fp)API.fp[223];
|
|
DLLvm_VectorToMatrix = (vm_VectorToMatrix_fp)API.fp[224];
|
|
DLLvm_VectorAngleToMatrix = (vm_VectorAngleToMatrix_fp)API.fp[225];
|
|
DLLvm_SinCos = (vm_SinCos_fp)API.fp[226];
|
|
DLLvm_GetSlope = (vm_GetSlope_fp)API.fp[227];
|
|
DLLvm_GetPerp = (vm_GetPerp_fp)API.fp[228];
|
|
DLLvm_GetNormal = (vm_GetNormal_fp)API.fp[229];
|
|
DLLvm_VectorDistance = (vm_VectorDistance_fp)API.fp[230];
|
|
DLLvm_VectorDistanceQuick = (vm_VectorDistanceQuick_fp)API.fp[231];
|
|
DLLvm_GetNormalizedDir = (vm_GetNormalizedDir_fp)API.fp[232];
|
|
DLLvm_GetNormalizedDirFast = (vm_GetNormalizedDirFast_fp)API.fp[233];
|
|
DLLvm_ExtractAnglesFromMatrix = (vm_ExtractAnglesFromMatrix_fp)API.fp[234];
|
|
DLLvm_DeltaAngVec = (vm_DeltaAngVec_fp)API.fp[235];
|
|
DLLvm_DeltaAngVecNorm = (vm_DeltaAngVecNorm_fp)API.fp[236];
|
|
DLLvm_DistToPlane = (vm_DistToPlane_fp)API.fp[237];
|
|
DLLvm_CalcDetValue = (vm_CalcDetValue_fp)API.fp[238];
|
|
DLLvm_MakeInverseMatrix = (vm_MakeInverseMatrix_fp)API.fp[239];
|
|
DLLvm_SinCosToMatrix = (vm_SinCosToMatrix_fp)API.fp[240];
|
|
DLLvm_GetCentroid = (vm_GetCentroid_fp)API.fp[241];
|
|
DLLvm_MakeRandomVector = (vm_MakeRandomVector_fp)API.fp[242];
|
|
DLLvm_ComputeBoundingSphere = (vm_ComputeBoundingSphere_fp)API.fp[243];
|
|
DLLvm_GetCentroidFast = (vm_GetCentroidFast_fp)API.fp[244];
|
|
DLLRenderHUDGetTextLineWidth = (RenderHUDGetTextLineWidth_fp)API.fp[245];
|
|
DLLRenderHUDGetTextHeight = (RenderHUDGetTextHeight_fp)API.fp[246];
|
|
DLLStartFrame = (StartFrame_fp)API.fp[247];
|
|
DLLEndFrame = (EndFrame_fp)API.fp[248];
|
|
DLLResetFacings = (ResetFacings_fp)API.fp[249];
|
|
DLLGameRenderWorld = (GameRenderWorld_fp)API.fp[250];
|
|
DLLGetFrameParameters = (GetFrameParameters_fp)API.fp[251];
|
|
DLLrend_SetZBufferState = (rend_SetZBufferState_fp)API.fp[252];
|
|
DLLrend_SetLighting = (rend_SetLighting_fp)API.fp[253];
|
|
DLLrend_SetColorModel = (rend_SetColorModel_fp)API.fp[254];
|
|
DLLrend_SetTextureType = (rend_SetTextureType_fp)API.fp[255];
|
|
DLLrend_DrawPolygon = (rend_DrawPolygon_fp)API.fp[256];
|
|
DLLrend_SetMipState = (rend_SetMipState_fp)API.fp[257];
|
|
DLLrend_SetFogState = (rend_SetFogState_fp)API.fp[258];
|
|
DLLrend_SetFiltering = (rend_SetFiltering_fp)API.fp[259];
|
|
DLLrend_SetOverlayMap = (rend_SetOverlayMap_fp)API.fp[260];
|
|
DLLrend_SetOverlayType = (rend_SetOverlayType_fp)API.fp[261];
|
|
DLLrend_ClearScreen = (rend_ClearScreen_fp)API.fp[262];
|
|
DLLrend_SetPixel = (rend_SetPixel_fp)API.fp[263];
|
|
DLLrend_GetPixel = (rend_GetPixel_fp)API.fp[264];
|
|
DLLrend_FillCircle = (rend_FillCircle_fp)API.fp[265];
|
|
DLLrend_DrawCircle = (rend_DrawCircle_fp)API.fp[266];
|
|
DLLrend_SetAlphaType = (rend_SetAlphaType_fp)API.fp[267];
|
|
DLLrend_SetAlphaValue = (rend_SetAlphaValue_fp)API.fp[268];
|
|
DLLrend_SetWrapType = (rend_SetWrapType_fp)API.fp[269];
|
|
DLLrend_SetZBias = (rend_SetZBias_fp)API.fp[270];
|
|
DLLrend_SetZBufferWriteMask = (rend_SetZBufferWriteMask_fp)API.fp[271];
|
|
DLLrend_GetLFBLock = (rend_GetLFBLock_fp)API.fp[272];
|
|
DLLrend_ReleaseLFBLock = (rend_ReleaseLFBLock_fp)API.fp[273];
|
|
DLLrend_DrawLFBBitmap = (rend_DrawLFBBitmap_fp)API.fp[274];
|
|
DLLrend_DrawSpecialLine = (rend_DrawSpecialLine_fp)API.fp[275];
|
|
DLLfvi_FindIntersection = (fvi_FindIntersection_fp)API.fp[276];
|
|
DLLfvi_QuickDistFaceList = (fvi_QuickDistFaceList_fp)API.fp[277];
|
|
DLLfvi_QuickDistCellList = (fvi_QuickDistCellList_fp)API.fp[278];
|
|
DLLfvi_QuickDistObjectList = (fvi_QuickDistObjectList_fp)API.fp[279];
|
|
DLLfvi_QuickRoomCheck = (fvi_QuickRoomCheck_fp)API.fp[280];
|
|
DLLObjSetPos = (ObjSetPos_fp)API.fp[281];
|
|
DLLSetObjectDeadFlag = (SetObjectDeadFlag_fp)API.fp[282];
|
|
DLLtaunt_AreEnabled = (taunt_AreEnabled_fp)API.fp[283];
|
|
DLLtaunt_Enable = (taunt_Enable_fp)API.fp[284];
|
|
GetPlayerRankIndex = (GetPlayerRankIndex_fp)API.fp[285];
|
|
DLLVisEffectAllocate = (VisEffectAllocate_fp)API.fp[286];
|
|
DLLVisEffectFree = (VisEffectFree_fp)API.fp[287];
|
|
DLLVisEffectInitType = (VisEffectInitType_fp)API.fp[288];
|
|
DLLVisEffectCreate = (VisEffectCreate_fp)API.fp[289];
|
|
DLLVisEffectLink = (VisEffectLink_fp)API.fp[290];
|
|
DLLVisEffectUnlink = (VisEffectUnlink_fp)API.fp[291];
|
|
DLLVisEffectRelink = (VisEffectRelink_fp)API.fp[292];
|
|
DLLVisEffectDelete = (VisEffectDelete_fp)API.fp[293];
|
|
DLLCreateRandomSparks = (CreateRandomSparks_fp)API.fp[294];
|
|
DLLCreateRandomLineSparks = (CreateRandomLineSparks_fp)API.fp[295];
|
|
DLLVisEffectCreateControlled = (VisEffectCreateControlled_fp)API.fp[296];
|
|
DLLCreateRandomParticles = (CreateRandomParticles_fp)API.fp[297];
|
|
DLLAttachRandomNapalmEffectsToObject = (AttachRandomNapalmEffectsToObject_fp)API.fp[298];
|
|
DLLInitObjectScripts = (InitObjectScripts_fp)API.fp[299];
|
|
DLLg3_StartFrame = (g3_StartFrame_fp)API.fp[300];
|
|
DLLg3_EndFrame = (g3_EndFrame_fp)API.fp[301];
|
|
DLLg3_GetViewPosition = (g3_GetViewPosition_fp)API.fp[302];
|
|
DLLg3_GetViewMatrix = (g3_GetViewMatrix_fp)API.fp[303];
|
|
DLLg3_GetUnscaledMatrix = (g3_GetUnscaledMatrix_fp)API.fp[304];
|
|
DLLg3_StartInstanceMatrix = (g3_StartInstanceMatrix_fp)API.fp[305];
|
|
DLLg3_StartInstanceAngles = (g3_StartInstanceAngles_fp)API.fp[306];
|
|
DLLg3_DoneInstance = (g3_DoneInstance_fp)API.fp[307];
|
|
DLLg3_CheckNormalFacing = (g3_CheckNormalFacing_fp)API.fp[308];
|
|
DLLg3_RotatePoint = (g3_RotatePoint_fp)API.fp[309];
|
|
DLLg3_ProjectPoint = (g3_ProjectPoint_fp)API.fp[310];
|
|
DLLg3_CalcPointDepth = (g3_CalcPointDepth_fp)API.fp[311];
|
|
DLLg3_Point2Vec = (g3_Point2Vec_fp)API.fp[312];
|
|
DLLg3_CodePoint = (g3_CodePoint_fp)API.fp[313];
|
|
DLLg3_RotateDeltaX = (g3_RotateDeltaX_fp)API.fp[314];
|
|
DLLg3_RotateDeltaY = (g3_RotateDeltaY_fp)API.fp[315];
|
|
DLLg3_RotateDeltaZ = (g3_RotateDeltaZ_fp)API.fp[316];
|
|
DLLg3_RotateDeltaVec = (g3_RotateDeltaVec_fp)API.fp[317];
|
|
DLLg3_AddDeltaVec = (g3_AddDeltaVec_fp)API.fp[318];
|
|
DLLg3_DrawPoly = (g3_DrawPoly_fp)API.fp[319];
|
|
DLLg3_DrawSphere = (g3_DrawSphere_fp)API.fp[320];
|
|
DLLg3_CheckAndDrawPoly = (g3_CheckAndDrawPoly_fp)API.fp[321];
|
|
DLLg3_DrawLine = (g3_DrawLine_fp)API.fp[322];
|
|
DLLg3_DrawBitmap = (g3_DrawBitmap_fp)API.fp[323];
|
|
DLLg3_DrawRotatedBitmap = (g3_DrawRotatedBitmap_fp)API.fp[324];
|
|
DLLg3_DrawBox = (g3_DrawBox_fp)API.fp[325];
|
|
DLLg3_SetCustomClipPlane = (g3_SetCustomClipPlane_fp)API.fp[326];
|
|
DLLg3_SetFarClipZ = (g3_SetFarClipZ_fp)API.fp[327];
|
|
DLLg3_ClipPolygon = (g3_ClipPolygon_fp)API.fp[328];
|
|
DLLg3_FreeTempPoints = (g3_FreeTempPoints_fp)API.fp[329];
|
|
DLLg3_GetMatrixScale = (g3_GetMatrixScale_fp)API.fp[330];
|
|
DLLg3_SetTriangulationTest = (g3_SetTriangulationTest_fp)API.fp[331];
|
|
DLLg3_DrawSpecialLine = (g3_DrawSpecialLine_fp)API.fp[332];
|
|
DLLg3_DrawPlanarRotatedBitmap = (g3_DrawPlanarRotatedBitmap_fp)API.fp[333];
|
|
DLLPlayerStopSounds = (PlayerStopSounds_fp)API.fp[334];
|
|
DLLFindArg = (FindArg_fp)API.fp[335];
|
|
DLLFireWeaponFromObject = (FireWeaponFromObject_fp)API.fp[336];
|
|
DLLCreateAndFireWeapon = (CreateAndFireWeapon_fp)API.fp[337];
|
|
DLLSelectNextCameraView = (SelectNextCameraView_fp)API.fp[338];
|
|
Inven_Add = (dInven_Add_fp)API.fp[339];
|
|
Inven_AddObject = (dInven_AddObject_fp)API.fp[340];
|
|
Inven_AddCounterMeasure = (dInven_AddCounterMeasure_fp)API.fp[341];
|
|
Inven_Remove = (dInven_Remove_fp)API.fp[342];
|
|
Inven_Use = (dInven_Use_fp)API.fp[343];
|
|
Inven_UseObjHandle = (dInven_UseObjHandle_fp)API.fp[344];
|
|
Inven_Size = (dInven_Size_fp)API.fp[345];
|
|
Inven_CheckItem = (dInven_CheckItem_fp)API.fp[346];
|
|
Inven_Reset = (dInven_Reset_fp)API.fp[347];
|
|
Inven_ResetPos = (dInven_ResetPos_fp)API.fp[348];
|
|
Inven_NextPos = (dInven_NextPos_fp)API.fp[349];
|
|
Inven_PrevPos = (dInven_PrevPos_fp)API.fp[350];
|
|
Inven_GetPosTypeID = (dInven_GetPosTypeID_fp)API.fp[351];
|
|
Inven_GetAuxPosTypeID = (dInven_GetAuxPosTypeID_fp)API.fp[352];
|
|
Inven_GetPosDescription = (dInven_GetPosDescription_fp)API.fp[353];
|
|
Inven_GetPosIconName = (dInven_GetPosIconName_fp)API.fp[354];
|
|
Inven_GetPosName = (dInven_GetPosName_fp)API.fp[355];
|
|
Inven_GetPosInfo = (dInven_GetPosInfo_fp)API.fp[356];
|
|
Inven_GetPosCount = (dInven_GetPosCount_fp)API.fp[357];
|
|
Inven_AtBeginning = (dInven_AtBeginning_fp)API.fp[358];
|
|
Inven_AtEnd = (dInven_AtEnd_fp)API.fp[359];
|
|
Inven_GotoPos = (dInven_GotoPos_fp)API.fp[360];
|
|
Inven_GotoPosTypeID = (dInven_GotoPosTypeID_fp)API.fp[361];
|
|
Inven_UsePos = (dInven_UsePos_fp)API.fp[362];
|
|
Inven_GetPos = (dInven_GetPos_fp)API.fp[363];
|
|
Inven_ValidatePos = (dInven_ValidatePos_fp)API.fp[364];
|
|
Inven_IsSelectable = (dInven_IsSelectable_fp)API.fp[365];
|
|
Inven_IsUsable = (dInven_IsUsable_fp)API.fp[366];
|
|
Inven_GetTypeIDCount = (dInven_GetTypeIDCount_fp)API.fp[367];
|
|
Inven_FindPos = (dInven_FindPos_fp)API.fp[368];
|
|
Inven_GetInventoryItemList = (dInven_GetInventoryItemList_fp)API.fp[369];
|
|
|
|
// Do variables
|
|
Player_num = (int *)API.vp[0];
|
|
Highest_room_index = (int *)API.vp[1];
|
|
Game_window_w = (int *)API.vp[2];
|
|
Game_window_h = (int *)API.vp[3];
|
|
Game_fonts = (int *)API.vp[4];
|
|
Frametime = (float *)API.vp[5];
|
|
Gametime = (float *)API.vp[6];
|
|
ShieldDelta = (float *)API.vp[7];
|
|
Game_interface_mode = (int *)API.vp[8];
|
|
LocalD3Dir = (char *)API.vp[9];
|
|
m_bTrackerGame = (int *)API.vp[10];
|
|
Local_object_list = (uint16_t *)API.vp[11];
|
|
Server_object_list = (uint16_t *)API.vp[12];
|
|
Dedicated_server = (bool *)API.vp[13];
|
|
Player_colors = (ddgr_color *)API.vp[14];
|
|
Hud_aspect_x = (float *)API.vp[15];
|
|
Hud_aspect_y = (float *)API.vp[16];
|
|
Viewer_object = (object **)API.vp[17];
|
|
Render_zoom = (float *)API.vp[18];
|
|
Game_window_x = (int *)API.vp[19];
|
|
Game_window_y = (int *)API.vp[20];
|
|
Poly_models = (poly_model *)API.vp[21];
|
|
VisEffects = (vis_effect *)API.vp[22];
|
|
Highest_vis_effect_index = (int *)API.vp[23];
|
|
Multi_next_level = (int *)API.vp[24];
|
|
Level_info = (level_info *)API.vp[25];
|
|
GameArgs = (void *)API.vp[26];
|
|
Camera_view_mode = (int *)API.vp[27];
|
|
Object_info = (object_info *)API.vp[28];
|
|
}
|
|
|
|
// DMFCBase::GameInit
|
|
//
|
|
// Sets up all the DLL functions and pointers and preps the class for use. This ABSOLUTLY must be
|
|
// called, so if you override DMFCApp::GameInit, make sure that you put a call to this somewhere in
|
|
// the override.
|
|
void DMFCBase::GameInit(int teams) {
|
|
ASSERT(!DMFCInit);
|
|
DMFCInit = true;
|
|
|
|
LoadSettings();
|
|
|
|
DLLCreateStringTable("dmfc.str", &DMFCStringTable, &DMFCStringTableSize);
|
|
mprintf(0, "DMFC Note: %d strings loaded from string table\n", DMFCStringTableSize);
|
|
|
|
// initialize player records
|
|
PRec_Init();
|
|
|
|
// initialize remote administration
|
|
Remote_Initialize();
|
|
|
|
// see if we should display Outrage logo at all
|
|
if (DLLFindArg("-nooutragelogo"))
|
|
m_bDisplayOutrageLogo = false;
|
|
else
|
|
m_bDisplayOutrageLogo = true;
|
|
|
|
SetNumberOfTeams(teams);
|
|
|
|
SetTeamName(RED_TEAM, DTXT_RED, false);
|
|
SetTeamName(BLUE_TEAM, DTXT_BLUE, false);
|
|
SetTeamName(GREEN_TEAM, DTXT_GREEN, false);
|
|
SetTeamName(YELLOW_TEAM, DTXT_YELLOW, false);
|
|
|
|
// Load bitmaps
|
|
hBitmapObserver = DLLbm_AllocLoadFileBitmap("observer icon.ogf", 0, BITMAP_FORMAT_1555);
|
|
if (hBitmapObserver <= BAD_BITMAP_HANDLE)
|
|
hBitmapObserver = BAD_BITMAP_HANDLE;
|
|
|
|
RegisterPacketReceiver(SPID_TEAMASSIGNMENT, &DMFCBase::GetTeamAssignmentPacket);
|
|
RegisterPacketReceiver(SPID_CHANGETEAM, &DMFCBase::GetChangeTeamPacket);
|
|
RegisterPacketReceiver(SPID_REQGAMESTATE, &DMFCBase::GetGameStateRequest);
|
|
RegisterPacketReceiver(SPID_DMFCGAMEINFO, &DMFCBase::GetDMFCGameInfo);
|
|
RegisterPacketReceiver(SPID_VERSIONID, &DMFCBase::GetDMFCVersionCheck);
|
|
RegisterPacketReceiver(SPID_PRECORD, PRec_ReceivePRecFromServer);
|
|
RegisterPacketReceiver(SPID_PRECORDREQ, &DMFCBase::ReceiveRequestForPlayerRecords);
|
|
RegisterPacketReceiver(SPID_CONTROLMSG, &DMFCBase::ReceiveControlMessage);
|
|
RegisterPacketReceiver(SPID_NETGAMESYNC, &DMFCBase::ReceiveNetGameInfoSync);
|
|
RegisterPacketReceiver(SPID_NEWTEAMNAME, &DMFCBase::ReceiveNewTeamName);
|
|
RegisterPacketReceiver(SPID_REMOTEKEY, &DMFCBase::GetRemoteKey);
|
|
RegisterPacketReceiver(SPID_REALGAMETIME, &DMFCBase::GetRealGametimePacket);
|
|
AddWeaponHash("Laser", "Laser Level 1 - Red", "Laser Level 2 - Blue", "Laser Level 3 - Purple",
|
|
"Laser Level 4 - Green", NULL);
|
|
AddWeaponHash("Vauss", "Vauss Spark", NULL);
|
|
AddWeaponHash("Raygun", NULL);
|
|
AddWeaponHash("Plasma", "plasma sparks", NULL);
|
|
AddWeaponHash("Fusion", NULL);
|
|
AddWeaponHash("Super Laser", "Laser Level 5 -Yellow", "Laser Level 6 -White", NULL);
|
|
AddWeaponHash("Mass Driver", NULL);
|
|
AddWeaponHash("Napalm", NULL);
|
|
AddWeaponHash("EMDyellowleft", "EMDyellowright", "EMDgreenleft", "EMDgreenright", NULL);
|
|
AddWeaponHash("Omega", NULL);
|
|
AddWeaponHash("Concussion", NULL);
|
|
AddWeaponHash("Homing", NULL);
|
|
AddWeaponHash("Smart", "SmartPlasmaHomers", NULL);
|
|
AddWeaponHash("Mega", "MegaExplosion", NULL);
|
|
AddWeaponHash("Frag", "frag particles", NULL);
|
|
AddWeaponHash("Guided", NULL);
|
|
AddWeaponHash("NapalmRocket", "NapalmBlob", "NapalmParticles", NULL);
|
|
AddWeaponHash("Cyclone Pack", "Swarm", NULL);
|
|
AddWeaponHash("Yellow Flare", NULL);
|
|
|
|
SetWeaponDeathMessage("Laser", DTXT_DEATHLASER, false);
|
|
SetWeaponDeathMessage("Vauss", DTXT_DEATHVAUSS, false);
|
|
SetWeaponDeathMessage("RayGun", DTXT_DEATHMICROWAVE, true);
|
|
SetWeaponDeathMessage("Plasma", DTXT_DEATHPLASMA, false);
|
|
SetWeaponDeathMessage("Fusion", DTXT_DEATHFUSION, false);
|
|
SetWeaponDeathMessage("Super Laser", DTXT_DEATHSUPERLASER, false);
|
|
SetWeaponDeathMessage("Mass Driver", DTXT_DEATHMASS, false);
|
|
SetWeaponDeathMessage("Napalm", DTXT_DEATHNAPALM, false);
|
|
SetWeaponDeathMessage("EMDyellowleft", DTXT_DEATHEMD, false);
|
|
SetWeaponDeathMessage("Omega", DTXT_DEATHOMEGA, false);
|
|
SetWeaponDeathMessage("Concussion", DTXT_DEATHCONC, true);
|
|
SetWeaponDeathMessage("Homing", DTXT_DEATHHOMING, false);
|
|
SetWeaponDeathMessage("Smart", DTXT_DEATHSMART, true);
|
|
SetWeaponDeathMessage("Mega", DTXT_DEATHMEGA, false);
|
|
SetWeaponDeathMessage("Frag", DTXT_DEATHFRAG, true);
|
|
SetWeaponDeathMessage("Guided", DTXT_DEATHGUIDED, false);
|
|
SetWeaponDeathMessage("NapalmRocket", DTXT_DEATHNAPALMROCKET, true);
|
|
SetWeaponDeathMessage("Cyclone Pack", DTXT_DEATHCYCLONE, false);
|
|
SetWeaponDeathMessage("Yellow Flare", DTXT_DEATHFLARE, false);
|
|
|
|
/*
|
|
$$TABLE_WEAPON "Laser"
|
|
$$TABLE_WEAPON "Laser Level 1 - Red"
|
|
$$TABLE_WEAPON "Laser Level 2 - Blue"
|
|
$$TABLE_WEAPON "Laser Level 3 - Purple"
|
|
$$TABLE_WEAPON "Laser Level 4 - Green"
|
|
$$TABLE_WEAPON "Vauss"
|
|
$$TABLE_WEAPON "Vauss Spark"
|
|
$$TABLE_WEAPON "Raygun"
|
|
$$TABLE_WEAPON "Plasma"
|
|
$$TABLE_WEAPON "plasma sparks"
|
|
$$TABLE_WEAPON "Fusion"
|
|
$$TABLE_WEAPON "Super Laser"
|
|
$$TABLE_WEAPON "Laser Level 5 -Yellow"
|
|
$$TABLE_WEAPON "Laser Level 6 -White"
|
|
$$TABLE_WEAPON "Mass Driver"
|
|
$$TABLE_WEAPON "Napalm"
|
|
$$TABLE_WEAPON "EMDyellowleft"
|
|
$$TABLE_WEAPON "EMDyellowright"
|
|
$$TABLE_WEAPON "EMDgreenleft"
|
|
$$TABLE_WEAPON "EMDgreenright"
|
|
$$TABLE_WEAPON "Omega"
|
|
$$TABLE_WEAPON "Concussion"
|
|
$$TABLE_WEAPON "Homing"
|
|
$$TABLE_WEAPON "Smart"
|
|
$$TABLE_WEAPON "SmartPlasmaHomers"
|
|
$$TABLE_WEAPON "Mega"
|
|
$$TABLE_WEAPON "MegaExplosion"
|
|
$$TABLE_WEAPON "Frag"
|
|
$$TABLE_WEAPON "frag particles"
|
|
$$TABLE_WEAPON "Guided"
|
|
$$TABLE_WEAPON "NapalmRocket"
|
|
$$TABLE_WEAPON "NapalmBlob"
|
|
$$TABLE_WEAPON "NapalmParticles"
|
|
$$TABLE_WEAPON "Cyclone Pack"
|
|
$$TABLE_WEAPON "Swarm"
|
|
$$TABLE_WEAPON "Yellow Flare"
|
|
*/
|
|
|
|
// Set up default messages so we have something
|
|
AddDeathMessage(DTXT_KILLED1, true);
|
|
AddSuicideMessage(DTXT_SUICIDE1);
|
|
|
|
// Setup InputCommand handlers
|
|
InputCommandInit();
|
|
|
|
ParseStartupScript();
|
|
|
|
TauntIndicatorBMP = DLLbm_AllocLoadFileBitmap("Taunt.ogf", 0, BITMAP_FORMAT_1555);
|
|
|
|
MenuBackgroundBMP = DLLbm_AllocBitmap(32, 32, 0);
|
|
if (MenuBackgroundBMP > BAD_BITMAP_HANDLE) {
|
|
uint16_t *data = DLLbm_data(MenuBackgroundBMP, 0);
|
|
int j;
|
|
for (j = 0; j < 32 * 32; j++)
|
|
data[j] = OPAQUE_FLAG | GR_RGB(0, 0, 0);
|
|
}
|
|
|
|
MenuItem *lev1, *lev2, *lev3;
|
|
|
|
if (GetLocalRole() == LR_SERVER) {
|
|
// Start Server Commands Menu
|
|
lev1 = new MenuItem(DTXT_MNUSRVRCOMMAND, MIT_NORMAL, 0, NULL); // Server
|
|
lev2 = new MenuItem(DTXT_MNUKICK, MIT_PLIST, 0, KickPlayer); // |- Kick
|
|
lev1->AddSubMenu(lev2);
|
|
lev2 = new MenuItem(DTXT_MNUBAN, MIT_PLIST, 0, BanPlayer); // |- Ban
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
tCustomMenu cm;
|
|
cm.GetItem = GetBannedPlayerString;
|
|
cm.GetListCount = GetBanPlayerList;
|
|
lev2 = new MenuItem(DTXT_OSM_REMOVEBAN, MIT_CUSTOM, 0, RemoveBanByIndex, &cm);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
lev2 = new MenuItem(DTXT_OSM_REHASHLIST, MIT_NORMAL, 0, RehashAllowDenyLists);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
lev2 = new MenuItem(DTXT_MNUENDLEVEL, MIT_NORMAL, 0, EndMultiLevel); // |- End Level
|
|
lev1->AddSubMenu(lev2);
|
|
ServerHUDCallsignsItem = lev2 =
|
|
new MenuItem(DTXT_OSM_MAXHUDNAME, MIT_STATE, 0, SwitchServerHudPlayerName, 3, m_iServerHUDCallsignLevel,
|
|
DTXT_PLAIN_NONE, DTXT_OSM_TEAMONLY, DTXT_OSM_FULL);
|
|
lev1->AddSubMenu(lev2);
|
|
if (teams > 1) {
|
|
// Team Game Stuff here
|
|
lev2 = new MenuItem(DTXT_MNUTEAMCONTROL, MIT_NORMAL, 0, NULL); // |- Team Control
|
|
lev3 = new MenuItem(DTXT_MNUBALANCE, MIT_NORMAL, 0, BalanceTeams); // |- Balance Teams
|
|
lev2->AddSubMenu(lev3); // |- AutoTeam Balance Off/On
|
|
AutoBalanceItem = lev3 =
|
|
new MenuItem(DTXT_MNUAUTOBALANCE, MIT_STATE, 0, SwitchAutoTeamSelect, 2,
|
|
(m_iProtectedFlags & DMFC_PRF_AUTOTEAMSELECT) ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev2->AddSubMenu(lev3);
|
|
AllowTeamChangeItem = lev3 = new MenuItem(DTXT_MNUALLOWTEAMCNG, MIT_STATE, 0, SwitchTeamChange, 2,
|
|
AllowTeamChange() ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev2->AddSubMenu(lev3);
|
|
lev3 = new MenuItem(DTXT_OSM_TEAMCONFIG, MIT_NORMAL, 0, OnScreenDisplayTeamConfig);
|
|
lev2->AddSubMenu(lev3);
|
|
lev1->AddSubMenu(lev2);
|
|
}
|
|
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
// End Server Commands Menu
|
|
}
|
|
|
|
if (GetLocalRole() == LR_CLIENT) {
|
|
// Start Client Commands Menu
|
|
bool peertopeer = (bool)((Netgame->flags & NF_PEER_PEER) != 0);
|
|
if (!peertopeer) {
|
|
lev1 = HUDIndicatorItem = new MenuItem(DTXT_LOSSPINGIND, MIT_STATE, 0, SwitchLossPingIndicator, 2,
|
|
(LossGuageEnabled) ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
Menu.AddSubMenu(lev1);
|
|
}
|
|
// End Client Commands Menu
|
|
}
|
|
|
|
// Do General stuff here
|
|
lev1 = new MenuItem(DTXT_MNUOBSERVER, MIT_NORMAL, 0, NULL);
|
|
ObserverItem = lev2 = new MenuItem(DTXT_MNUOBSERVER, MIT_STATE, 0, SwitchObserverMode, 2, 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
lev2 = new MenuItem(DTXT_OSM_PIGGYBACK, MIT_PLIST, 0, SwitchPiggyBack);
|
|
lev1->AddSubMenu(lev2);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
/*
|
|
lev1 = new MenuItem("OnScreen Menu Options",MIT_NORMAL,0,NULL);
|
|
lev2 = MenuBackgroundItem = new MenuItem("Background",MIT_STATE,0,SwitchMenuBackground,2,0,DTXT_MNUOFF,DTXT_MNUON);
|
|
lev1->AddSubMenu(lev2);
|
|
Menu.AddSubMenu(lev1);
|
|
*/
|
|
lev1 = MenuBackgroundItem =
|
|
new MenuItem(DTXT_OSM_BACKGROUND, MIT_STATE, 0, SwitchMenuBackground, 2, 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
HUDCallsignsItem = lev1 =
|
|
new MenuItem(DTXT_OSM_HUDNAMELEVEL, MIT_STATE, 0, SwitchHudPlayerNum, 3, m_iMyPreferredHUDCallsignLevel,
|
|
DTXT_PLAIN_NONE, DTXT_OSM_TEAMONLY, DTXT_OSM_FULL);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
ShipLogosItem = lev1 = new MenuItem(DTXT_OSM_SHIPLOGOS, MIT_STATE, 0, SwitchShipLogoEnable, 2,
|
|
(AreLogosEnabled()) ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
AudioTauntsItem = lev1 = new MenuItem(DTXT_OSM_AUDIOTAUNTS, MIT_STATE, 0, SwitchAudioTauntsEnable, 2,
|
|
(AreTauntsEnabled()) ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
// File Statitics menu
|
|
lev1 = new MenuItem(DTXT_OSM_STATSTOFILE, MIT_NORMAL, 0, NULL);
|
|
|
|
lev2 = new MenuItem(DTXT_SAVESTATS, MIT_NORMAL, 0, SaveStatsToFile);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
SaveStatsLevelEndItem = lev2 =
|
|
new MenuItem(DTXT_OSM_STATLEVELEND, MIT_STATE, 0, SwitchSaveStatsLevelEnd, 2, 1, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
SaveStatsDisconnectItem = lev2 =
|
|
new MenuItem(DTXT_OSM_STATDISCONNECT, MIT_STATE, 0, SwitchSaveStatsDisconnect, 2, 1, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
lev1 = new MenuItem(DTXT_MNUGETPLYRINFO, MIT_PLIST, MIF_INCLUDENONE, SwitchPlayerInfo);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
NetGameInfoItem = lev1 =
|
|
new MenuItem(DTXT_OSM_NETGAMEINFO, MIT_STATE, 0, SwitchNetGameInfo, 2,
|
|
(m_iProtectedFlags & DMFC_PRF_DISPNETGAMEINFO) ? 1 : 0, DTXT_MNUOFF, DTXT_MNUON);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
lev1 = new MenuItem(DTXT_OSM_HUDFILTER, MIT_NORMAL, 0, NULL);
|
|
lev2 = DeathMessageFilterItem = new MenuItem(DTXT_OSM_KILLMESSAGES, MIT_STATE, 0, SwitchDeathMessageFilter, 3,
|
|
m_iDeathMessageFilter, DTXT_PLAIN_NONE, DTXT_OSM_SIMPLE, DTXT_OSM_FULL);
|
|
lev1->AddSubMenu(lev2);
|
|
|
|
lev2 = StatisticMessagesItem =
|
|
new MenuItem(DTXT_OSM_STATMESSAGES, MIT_STATE, 0, SwitchStatHUDMessages, 2, 1, DTXT_MNUOFF, DTXT_MNUON);
|
|
lev1->AddSubMenu(lev2);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
if (teams > 1) {
|
|
// Team Game Stuff here
|
|
char names[DLLMAX_TEAMS][MAX_TEAMNAME_LEN];
|
|
strcpy(names[RED_TEAM], GetTeamString(RED_TEAM));
|
|
strcpy(names[BLUE_TEAM], GetTeamString(BLUE_TEAM));
|
|
switch (teams) {
|
|
case 2:
|
|
TeamMenuItem = lev1 = new MenuItem(DTXT_MNUCHANGETEAMS, MIT_STATE, 0, ChangeTeams, 2,
|
|
GetPlayerTeam(GetPlayerNum()), names[RED_TEAM], names[BLUE_TEAM]);
|
|
break;
|
|
case 3:
|
|
strcpy(names[GREEN_TEAM], GetTeamString(GREEN_TEAM));
|
|
TeamMenuItem = lev1 =
|
|
new MenuItem(DTXT_MNUCHANGETEAMS, MIT_STATE, 0, ChangeTeams, 3, GetPlayerTeam(GetPlayerNum()),
|
|
names[RED_TEAM], names[BLUE_TEAM], names[GREEN_TEAM]);
|
|
break;
|
|
case 4:
|
|
strcpy(names[GREEN_TEAM], GetTeamString(GREEN_TEAM));
|
|
strcpy(names[YELLOW_TEAM], GetTeamString(YELLOW_TEAM));
|
|
TeamMenuItem = lev1 =
|
|
new MenuItem(DTXT_MNUCHANGETEAMS, MIT_STATE, 0, ChangeTeams, 4, GetPlayerTeam(GetPlayerNum()),
|
|
names[RED_TEAM], names[BLUE_TEAM], names[GREEN_TEAM], names[YELLOW_TEAM]);
|
|
break;
|
|
}
|
|
Menu.AddSubMenu(lev1);
|
|
}
|
|
|
|
lev1 = new MenuItem(DTXT_OSM_EXIT, MIT_NORMAL, 0, MenuExitMenu);
|
|
Menu.AddSubMenu(lev1);
|
|
|
|
// save the hud level var
|
|
int curr_call_level = m_iMyPreferredHUDCallsignLevel;
|
|
m_iMyCurrentHUDCallsignLevel = -1; // set this to -1 so it definitly gets changes/set
|
|
SwitchShowHudCallsignLevel(curr_call_level, false);
|
|
|
|
Menu.SetInputFocus();
|
|
|
|
EnableShipLogos(true);
|
|
|
|
ReadInHostsAllowDeny();
|
|
|
|
InitializeForLevel();
|
|
}
|
|
|
|
// DMFCBase::GameClose
|
|
//
|
|
// Closes up any needed DLL and DMFC tasks. This ABSOLUTLY must be called, so if you override
|
|
// DMFCApp::GameClose, make sure that you put a call to this somewhere in the override
|
|
void DMFCBase::GameClose(void) {
|
|
ASSERT(DMFCInit);
|
|
DMFCInit = false;
|
|
|
|
SaveSettings();
|
|
|
|
// Free bitmaps
|
|
if (hBitmapObserver > BAD_BITMAP_HANDLE) {
|
|
DLLbm_FreeBitmap(hBitmapObserver);
|
|
hBitmapObserver = BAD_BITMAP_HANDLE;
|
|
}
|
|
|
|
FreeHostsLists();
|
|
|
|
// Close up InputCommands
|
|
InputCommandFree();
|
|
|
|
// close up and free player records
|
|
PRec_Close();
|
|
|
|
if (MenuBackgroundBMP > BAD_BITMAP_HANDLE)
|
|
DLLbm_FreeBitmap(MenuBackgroundBMP);
|
|
|
|
DLLDestroyStringTable(DMFCStringTable, DMFCStringTableSize);
|
|
}
|
|
|
|
void DMFCBase::DrawMenu(void) {
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
// Menu.Draw(10,100,DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX])+1,this,(m_iProtectedFlags&DMFC_PRF_DISPMENUBACKGR)?MenuBackgroundBMP:-1);
|
|
// Menu.Draw(10,100,DLLRenderHUDGetTextHeight("X")+1,this,(m_iProtectedFlags&DMFC_PRF_DISPMENUBACKGR)?MenuBackgroundBMP:-1);
|
|
int font_height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
Menu.Draw(10, (font_height * 8) + 10, font_height + 1,
|
|
(m_iProtectedFlags & DMFC_PRF_DISPMENUBACKGR) ? MenuBackgroundBMP : -1);
|
|
}
|
|
|
|
char DMFCPlayerInfo[6][100];
|
|
void DMFCBase::SetPlayerInfo(int pnum) {
|
|
if (!CheckPlayerNum(pnum)) {
|
|
return;
|
|
}
|
|
|
|
m_iPlayerDisplayed = pnum;
|
|
|
|
int x, y;
|
|
char buffer[100];
|
|
y = 0;
|
|
x = 15;
|
|
int index = 0;
|
|
bool display_addr = false;
|
|
|
|
// Print out callsign
|
|
snprintf(buffer, sizeof(buffer), "%s (%s)", Players[pnum].callsign, (0 == pnum) ? DTXT_SERVER : DTXT_CLIENT);
|
|
strcpy(DMFCPlayerInfo[index], buffer);
|
|
index++;
|
|
|
|
if (m_iNumTeams > 1 && Players[pnum].team != -1) {
|
|
snprintf(buffer, sizeof(buffer), DTXT_TEAMFORMAT, GetTeamString(GetPlayerTeam(pnum)));
|
|
strcpy(DMFCPlayerInfo[index], buffer);
|
|
index++;
|
|
}
|
|
|
|
// Print out playernum
|
|
snprintf(buffer, sizeof(buffer), DTXT_PLRNUMFORMAT, pnum);
|
|
strcpy(DMFCPlayerInfo[index], buffer);
|
|
index++;
|
|
|
|
#ifdef _DEBUG
|
|
display_addr = true;
|
|
#endif
|
|
if (GetLocalRole() == LR_SERVER)
|
|
display_addr = true;
|
|
|
|
// Print out net address
|
|
if (display_addr) {
|
|
network_protocol proto = NP_NONE;
|
|
|
|
if (pnum != GetPlayerNum())
|
|
proto = NetPlayers[pnum].addr.connection_type;
|
|
else
|
|
proto = NP_TCP;
|
|
|
|
if (proto != NP_NONE) {
|
|
char string[32];
|
|
if (pnum != 0) {
|
|
DLLnw_GetNumbersFromHostAddress(&NetPlayers[pnum].addr, string);
|
|
} else {
|
|
int addr = DLLnw_GetThisIP();
|
|
network_address local_addr;
|
|
memset(&local_addr, 0, sizeof(network_address));
|
|
memcpy(local_addr.address, &addr, sizeof(int));
|
|
local_addr.connection_type = NP_TCP;
|
|
|
|
DLLnw_GetNumbersFromHostAddress(&local_addr, string);
|
|
}
|
|
strcpy(DMFCPlayerInfo[index], string);
|
|
index++;
|
|
}
|
|
}
|
|
|
|
// Print out Ship info
|
|
snprintf(buffer, sizeof(buffer), DTXT_SHIPFORM, Ships[Players[pnum].ship_index].name);
|
|
strcpy(DMFCPlayerInfo[index], buffer);
|
|
index++;
|
|
|
|
for (; index < 5; index++) {
|
|
DMFCPlayerInfo[index][0] = '\0';
|
|
}
|
|
}
|
|
|
|
void DMFCBase::DisplayPlayerInfo(int background_bmp, bool dedicated_server) {
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
int height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]) + 1;
|
|
// int height = DLLRenderHUDGetTextHeight("X")+1;
|
|
ddgr_color color = GR_RGB(180, 255, 180);
|
|
int x, y;
|
|
y = 0;
|
|
x = 15;
|
|
int index = 0;
|
|
|
|
if (!CheckPlayerNum(m_iPlayerDisplayed)) {
|
|
m_iPlayerDisplayed = -1;
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPPLAYERINFO);
|
|
return;
|
|
}
|
|
|
|
if ((m_iProtectedFlags & DMFC_PRF_DISPMENUBACKGR) && background_bmp > BAD_BITMAP_HANDLE) {
|
|
// draw the background bitmap
|
|
DLLrend_SetAlphaValue(255 * 0.85f);
|
|
DLLrend_SetZBufferState(0);
|
|
DLLrend_SetTextureType(TT_LINEAR);
|
|
DLLrend_SetLighting(LS_NONE);
|
|
DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE);
|
|
DLLrend_DrawScaledBitmap(0, 0, *Game_window_w, 6 * height, background_bmp, 0, 0, 1, 1, 1.0, -1, NULL);
|
|
DLLrend_SetZBufferState(1);
|
|
}
|
|
|
|
// Print out callsign
|
|
// DLLRenderHUDText(color,255,0,x,y,DMFCPlayerInfo[index]); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DMFCPlayerInfo[index]);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf("%s\n", DMFCPlayerInfo[index]);
|
|
index++;
|
|
color = GR_RGB(40, 255, 40);
|
|
|
|
for (; index < 5; index++) {
|
|
// DLLRenderHUDText(color,255,0,x,y,DMFCPlayerInfo[index]);
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DMFCPlayerInfo[index]);
|
|
|
|
if (DMFCPlayerInfo[index][0] != '\0')
|
|
y += height;
|
|
if (dedicated_server)
|
|
DPrintf("%s\n", DMFCPlayerInfo[index]);
|
|
}
|
|
|
|
// print out the volatile information
|
|
player_record *pr = PRec_GetPRecordByPnum(m_iPlayerDisplayed);
|
|
char temp[150];
|
|
|
|
if (!pr || pr->state != STATE_INGAME)
|
|
return;
|
|
|
|
int precindex = translate_precptr_to_index(pr);
|
|
float ti = GetTimeInGame(precindex);
|
|
|
|
snprintf(temp, sizeof(temp), DTXT_PI_TIMEINGAME, GetTimeString(ti));
|
|
// DLLRenderHUDText(color,255,0,x,y,temp); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, temp);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf("%s\n", temp);
|
|
}
|
|
|
|
// DMFCBase::SwitchPlayerInfoDisplay
|
|
//
|
|
// Switches on/off displaying a Playerinfo
|
|
void DMFCBase::SwitchPlayerInfoDisplay(int pnum) {
|
|
m_iProtectedFlags ^= DMFC_PRF_DISPPLAYERINFO;
|
|
if (m_iProtectedFlags & DMFC_PRF_DISPPLAYERINFO) {
|
|
|
|
if (IsDisplayingNetGameInfo()) // if we are displaying netgame info, turn it off
|
|
SwitchNetGameInfoDisplay(0);
|
|
|
|
if (!CheckPlayerNum(pnum)) {
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPPLAYERINFO);
|
|
return;
|
|
}
|
|
SetPlayerInfo(pnum);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::SwitchNetGameInfoDisplay
|
|
//
|
|
// Switches on/off displaying netgame info
|
|
void DMFCBase::SwitchNetGameInfoDisplay(int on) {
|
|
if (on)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPNETGAMEINFO);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPNETGAMEINFO);
|
|
|
|
if (on) {
|
|
if (DisplayingPlayerInfo() != -1) {
|
|
// turn on displaying of player info before displaying netgame info
|
|
SwitchPlayerInfoDisplay(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::IsDisplayingNetGameInfo
|
|
//
|
|
// returns true if we are currently displaying netgame info
|
|
bool DMFCBase::IsDisplayingNetGameInfo(void) { return (m_iProtectedFlags & DMFC_PRF_DISPNETGAMEINFO) ? true : false; }
|
|
|
|
// DMFCBase::DisplayingPlayerInfo
|
|
//
|
|
// Returns the pnum of the player info being displayed, -1 if none
|
|
int DMFCBase::DisplayingPlayerInfo(void) {
|
|
if (m_iProtectedFlags & DMFC_PRF_DISPPLAYERINFO)
|
|
return m_iPlayerDisplayed;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// DMFCBase::SetTeamName
|
|
//
|
|
// Sets the team name for a given team
|
|
// team: integer value of the team to change
|
|
// name: new name for the team
|
|
// announce: if this is true, and we are the server, it will tell all the clients about the change
|
|
bool DMFCBase::SetTeamName(int team, const char *name, bool announce) {
|
|
if (team < 0 || team > DLLMAX_TEAMS)
|
|
return false;
|
|
if (!name)
|
|
return false;
|
|
|
|
char old_teamname[MAX_TEAMNAME_LEN];
|
|
strcpy(old_teamname, DMFC_team_names[team]);
|
|
|
|
strncpy(DMFC_team_names[team], name, MAX_TEAMNAME_LEN - 1);
|
|
DMFC_team_names[team][MAX_TEAMNAME_LEN - 1] = '\0';
|
|
|
|
CallOnTeamChangeName(team, old_teamname, DMFC_team_names[team]);
|
|
|
|
if (announce && GetLocalRole() == LR_SERVER) {
|
|
// tell the clients about the new team name
|
|
SendNewTeamName(team);
|
|
DPrintf(DTXT_SETTEAMNAME, old_teamname, name);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// DMFCBase::GetTeamFromString
|
|
//
|
|
// Returns the int value of a team based on a string, -1 if not a team
|
|
int DMFCBase::GetTeamFromString(char *str) {
|
|
if (!str)
|
|
return -1;
|
|
for (int i = 0; i < DLLMAX_TEAMS; i++) {
|
|
if (!stricmp(str, DMFC_team_names[i]))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// DMFCBase::GetPlayerNum
|
|
//
|
|
// Returns your playernum, useful when finding out if an event is referring to you (by looking at
|
|
// the playernum passed to the event handler, compared to your playernum
|
|
int DMFCBase::GetPlayerNum(void) { return *Player_num; }
|
|
|
|
// DMFCBase::GetLocalRole
|
|
//
|
|
// Returns your role in the multiplayer game. The result returned will be either LR_SERVER or LR_CLIENT
|
|
int DMFCBase::GetLocalRole(void) { return Netgame->local_role; }
|
|
|
|
// DMFCBase::CheckPlayerNum
|
|
//
|
|
// Returns true if the player number passed in is a valid player number (the player is connected)
|
|
bool DMFCBase::CheckPlayerNum(int player_num) {
|
|
if ((player_num < 0) || (player_num >= DLLMAX_PLAYERS))
|
|
return false;
|
|
if ((NetPlayers[player_num].flags & NPF_CONNECTED) && (NetPlayers[player_num].sequence >= NETSEQ_PLAYING))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::PacketCheckPlayerNum
|
|
//
|
|
// Returns true if it's ok to send a packet to this player
|
|
bool DMFCBase::PacketCheckPlayerNum(int player_num) {
|
|
if ((player_num < 0) || (player_num >= DLLMAX_PLAYERS))
|
|
return false;
|
|
if ((NetPlayers[player_num].flags & NPF_CONNECTED) && (NetPlayers[player_num].sequence >= NETSEQ_OBJECTS))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::CallClientEvent
|
|
//
|
|
// Server Only. This will send an event to a client for it to execute.
|
|
// event = An EVT_CLIENT_*
|
|
// me_objnum,it_objnum = Object numbers of the objects to be me and it for the event
|
|
// destination = Player number of the client to send to, 0or -1 if to send to all
|
|
void DMFCBase::CallClientEvent(int event, int me_objnum, int it_objnum, int destination, bool parms) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
if ((destination < -1) || (destination > DLLMAX_PLAYERS))
|
|
return;
|
|
DLLMultiSendClientExecuteDLL(event, me_objnum, it_objnum, destination, parms ? Data : NULL);
|
|
}
|
|
|
|
// DMFCBase::GetTimeLeft
|
|
//
|
|
// Server Only. This will fill in the float pointer passed to it with how much time is
|
|
// left in the multiplayer game. The value placed in the float is only valid if GetTimeLeft
|
|
// returns true. If it returns false it was because either it is not a game with a time limit
|
|
// or it is being called on a client.
|
|
bool DMFCBase::GetTimeLeft(float *time) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return false;
|
|
if (Netgame->flags & NF_TIMER) {
|
|
*time = (Netgame->timelimit * 60.0f) - RealGametime;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::EndLevel
|
|
//
|
|
// Server Only. This will end the current multiplayer level, and will go on to the next level.
|
|
void DMFCBase::EndLevel(void) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
DLLMultiEndLevel();
|
|
}
|
|
|
|
// DMFCBase::GetScoreLimit
|
|
//
|
|
// Server Only. This will fill in the int pointer passed to it with what the scoring limit
|
|
// is, set in in the multiplayer options. The value point into the int is only valid if
|
|
// GetScoreLimit returns true. If it returns false it is because you are either not the
|
|
// server or this option wasn't set in the multiplayer options
|
|
bool DMFCBase::GetScoreLimit(int *limit) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return false;
|
|
if (Netgame->flags & NF_KILLGOAL) {
|
|
*limit = Netgame->killgoal;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::AutoTimeLimit
|
|
//
|
|
// Server Only. This turns off or on the automatic level ending by DMFC of a timed multiplayer game.
|
|
// If you turn it off, it is your responsibility to end a time multiplayer game when it's time
|
|
// is up. If it is turned on, DMFC will automatically handle ending the game. By default it is on.
|
|
void DMFCBase::AutoTimeLimit(bool turnon) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
if ((Netgame->flags & NF_TIMER) == 0)
|
|
return;
|
|
if (turnon)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTIMELIMIT);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTIMELIMIT);
|
|
}
|
|
|
|
// DMFCBase::AutoDeathMessage
|
|
//
|
|
// This turns on or off DMFC's automatic handling of death messages. If it is turned on (Default)
|
|
// then when a player dies it will display a random death message from the list added by you using
|
|
// AddDeathMessage. If it is turned off, then it is your responsibility to handle the messages, you
|
|
// can use DoRandomDeathMessage to display one when appropriate.
|
|
void DMFCBase::AutoDeathMessage(bool turnon) {
|
|
if (turnon)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTODEATHMSG);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTODEATHMSG);
|
|
}
|
|
|
|
// DMFCBase::AddDeathMessage
|
|
//
|
|
// This will add a death message to DMFC.
|
|
// format = string in a "printf" type format (using %s for player callsigns) of the message
|
|
// victim_first = Set this to true if the victim is listed first in the format
|
|
void DMFCBase::AddDeathMessage(const char *string, bool victim_first) {
|
|
if ((m_iDeathMsgCount >= 0) && (m_iDeathMsgCount < MAX_DEATH_MSGS)) {
|
|
DeathMsgs[m_iDeathMsgCount].message = (char *)malloc(strlen(string) + 1);
|
|
if (DeathMsgs[m_iDeathMsgCount].message) {
|
|
DeathMsgs[m_iDeathMsgCount].inuse = true;
|
|
DeathMsgs[m_iDeathMsgCount].victim_first = victim_first;
|
|
strcpy(DeathMsgs[m_iDeathMsgCount].message, string);
|
|
m_iDeathMsgCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::AddSuicideMessage
|
|
//
|
|
// This will add a death message to DMFC.
|
|
// format = string in a "printf" type format (using %s for player callsigns) of the message
|
|
void DMFCBase::AddSuicideMessage(const char *string) {
|
|
if ((m_iSuicideMsgCount >= 0) && (m_iSuicideMsgCount < MAX_DEATH_MSGS)) {
|
|
SuicideMsgs[m_iSuicideMsgCount].message = (char *)malloc(strlen(string) + 1);
|
|
if (SuicideMsgs[m_iSuicideMsgCount].message) {
|
|
SuicideMsgs[m_iSuicideMsgCount].inuse = true;
|
|
strcpy(SuicideMsgs[m_iSuicideMsgCount].message, string);
|
|
m_iSuicideMsgCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::GetItObjNum
|
|
//
|
|
// Returns the it object number of the current event for use.
|
|
int DMFCBase::GetItObjNum(void) {
|
|
if (Data->it_handle == OBJECT_HANDLE_NONE)
|
|
return -1;
|
|
|
|
return Data->it_handle & HANDLE_OBJNUM_MASK;
|
|
}
|
|
|
|
// DMFCBase::GetMeObjNum
|
|
//
|
|
// Returns the me object number of the current event for use.
|
|
int DMFCBase::GetMeObjNum(void) {
|
|
if (Data->me_handle == OBJECT_HANDLE_NONE)
|
|
return -1;
|
|
return Data->me_handle & HANDLE_OBJNUM_MASK;
|
|
}
|
|
|
|
// DMFCBase::OnGameStateRequest
|
|
//
|
|
// Server only. Override this to listen for Game state requests from the clients
|
|
// When this function is called a client (who's player number is passed in) is requesting
|
|
// game state information. Do what you need to do to send game state information to that player
|
|
void DMFCBase::OnGameStateRequest(int pnum) {
|
|
if (pnum == -1)
|
|
return;
|
|
mprintf(0, "%s is requesting Game State information\n", Players[pnum].callsign);
|
|
}
|
|
|
|
// DMFCBase::GetTeamForNewPlayer
|
|
//
|
|
// A Helper function (Server only), which will give you the optimum team assignment (whoever has the
|
|
// lowest amount of players on their team, for a new player.
|
|
// player_num = player number of the new player
|
|
// num_teams = The number of teams in your game
|
|
int DMFCBase::GetTeamForNewPlayer(int player_num, int num_teams) {
|
|
if ((player_num < 0) || (player_num >= DLLMAX_PLAYERS))
|
|
return 0;
|
|
|
|
// see if it's a dedicated server game, and if so, are we the server
|
|
if (IAmDedicatedServer() && (player_num == GetPlayerNum())) {
|
|
return -1; // place on the special "no team"
|
|
}
|
|
|
|
int i;
|
|
int *Teams;
|
|
Teams = (int *)malloc(sizeof(int) * num_teams);
|
|
if (!Teams)
|
|
return 0;
|
|
|
|
for (i = 0; i < num_teams; i++)
|
|
Teams[i] = 0;
|
|
|
|
for (i = 0; i < DLLMAX_PLAYERS; i++) {
|
|
if ((i != player_num) && (CheckPlayerNum(i)) && (Players[i].team != -1)) {
|
|
if (Players[i].team < num_teams)
|
|
Teams[Players[i].team]++;
|
|
}
|
|
}
|
|
|
|
int low_team, low_count;
|
|
|
|
low_count = Teams[0];
|
|
low_team = 0;
|
|
|
|
for (i = 0; i < num_teams; i++) {
|
|
if (low_count > Teams[i]) {
|
|
low_count = Teams[i];
|
|
low_team = i;
|
|
}
|
|
}
|
|
free(Teams);
|
|
return low_team;
|
|
}
|
|
|
|
// DMFCBase::SetNumberOfTeams
|
|
//
|
|
// Sets the number of teams to be used in the game. By default there is 1 team (everyone against everyone).
|
|
// You can set up to a maximum of 4 teams. Call this function as soon as possible.
|
|
// teams = number of teams
|
|
void DMFCBase::SetNumberOfTeams(int teams) {
|
|
if ((teams < 1) || (teams > 4))
|
|
return;
|
|
|
|
DLLSetMaxTeams(teams);
|
|
DLLMultiPaintGoalRooms(NULL);
|
|
|
|
m_iNumTeams = teams;
|
|
|
|
char names[DLLMAX_TEAMS][MAX_TEAMNAME_LEN];
|
|
strcpy(names[RED_TEAM], GetTeamString(RED_TEAM));
|
|
strcpy(names[BLUE_TEAM], GetTeamString(BLUE_TEAM));
|
|
if (TeamMenuItem) {
|
|
switch (m_iNumTeams) {
|
|
case 2:
|
|
TeamMenuItem->SetStateItemList(m_iNumTeams, names[RED_TEAM], names[BLUE_TEAM]);
|
|
break;
|
|
case 3:
|
|
strcpy(names[GREEN_TEAM], GetTeamString(GREEN_TEAM));
|
|
TeamMenuItem->SetStateItemList(m_iNumTeams, names[RED_TEAM], names[BLUE_TEAM], names[GREEN_TEAM]);
|
|
break;
|
|
case 4:
|
|
strcpy(names[GREEN_TEAM], GetTeamString(GREEN_TEAM));
|
|
strcpy(names[YELLOW_TEAM], GetTeamString(YELLOW_TEAM));
|
|
TeamMenuItem->SetStateItemList(m_iNumTeams, names[RED_TEAM], names[BLUE_TEAM], names[GREEN_TEAM],
|
|
names[YELLOW_TEAM]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::AutoTeamSelect
|
|
//
|
|
// Turns on or off DMFC's auto team assignment. If it is on, then when a new player joins, they will
|
|
// be placed on the team with fewest players. If it is off, then you must handle that. Defualt on.
|
|
void DMFCBase::AutoTeamSelect(bool turnon) {
|
|
if (turnon)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTEAMSELECT);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOTEAMSELECT);
|
|
}
|
|
|
|
// DMFCBase::RequestChangeTeams
|
|
//
|
|
// If you are the server it will make the player change teams. If you
|
|
// are a client then it sends a request to the server to change teams
|
|
void DMFCBase::RequestTeamChange(int team, int pnum, bool spew_on_respawn) {
|
|
if (!CheckPlayerNum(pnum))
|
|
return;
|
|
if (Players[pnum].team == -1) // Dedicated server can't change teams
|
|
return;
|
|
if ((team < 0) || (team >= m_iNumTeams))
|
|
return;
|
|
if (Players[pnum].team == team)
|
|
return;
|
|
|
|
if (GetLocalRole() == LR_SERVER) {
|
|
if (!AllowTeamChange()) {
|
|
return;
|
|
}
|
|
if (!CallOnCanChangeTeam(pnum, team)) {
|
|
return;
|
|
}
|
|
|
|
Players[pnum].team = team;
|
|
CallOnPlayerChangeTeam(pnum, team, true, spew_on_respawn);
|
|
SendTeamAssignment(pnum, team, spew_on_respawn);
|
|
} else {
|
|
if (pnum != GetPlayerNum())
|
|
return;
|
|
SendChangeTeamRequest(team, spew_on_respawn);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::AddHudItemCallback
|
|
//
|
|
// Adds an item to the hud. Everytime the hud needs to be updated, it will call the
|
|
// handler passed in. The handler must be declared as:
|
|
// void func(struct tHUDItem *item);
|
|
// type = HI_BITMAP for bitmap, HI_TEXT for a text item
|
|
// func = function callback
|
|
void DMFCBase::AddHUDItemCallback(int type, void (*func)(struct tHUDItem *)) {
|
|
// add all the needed Hud Items
|
|
tHUDItem item;
|
|
switch (type) {
|
|
case HI_TEXT:
|
|
item.type = HUD_ITEM_CUSTOMTEXT;
|
|
break;
|
|
case HI_BITMAP:
|
|
item.type = HUD_ITEM_CUSTOMIMAGE;
|
|
break;
|
|
default:
|
|
item.type = HUD_ITEM_CUSTOMTEXT;
|
|
break;
|
|
}
|
|
item.stat = STAT_CUSTOM;
|
|
item.flags = HUD_FLAG_PERSISTANT;
|
|
item.data.text = NULL;
|
|
item.render_fn = func;
|
|
item.y = 0;
|
|
item.x = 0;
|
|
DLLAddHUDItem(&item);
|
|
}
|
|
|
|
// DMFCBase::GetMyTeam
|
|
//
|
|
// Returns the int value of the team you are on...only useful in a team game.
|
|
int DMFCBase::GetMyTeam(void) { return Players[GetPlayerNum()].team; }
|
|
|
|
// DMFCBase::GetTeamString
|
|
//
|
|
// Returns a pointer to a string name of a team
|
|
// team = integer value of the team
|
|
const char *DMFCBase::GetTeamString(int team) {
|
|
static char name[20];
|
|
|
|
if (team >= 0 && team < DLLMAX_TEAMS)
|
|
strcpy(name, DMFC_team_names[team]);
|
|
else
|
|
strcpy(name, DTXT_LONER);
|
|
|
|
return name;
|
|
}
|
|
|
|
// DMFCBase::GetTeamColor
|
|
//
|
|
// Returns the color components of a team
|
|
// team = integer value of the team
|
|
ddgr_color DMFCBase::GetTeamColor(int team) {
|
|
switch (team) {
|
|
case RED_TEAM:
|
|
return GR_RGB(255, 40, 40);
|
|
break;
|
|
case BLUE_TEAM:
|
|
return GR_RGB(40, 40, 255);
|
|
break;
|
|
case GREEN_TEAM:
|
|
return GR_RGB(40, 255, 40);
|
|
break;
|
|
case YELLOW_TEAM:
|
|
return GR_RGB(255, 255, 40);
|
|
break;
|
|
default:
|
|
return GR_RGB(255, 255, 255);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// DMFCBase::GetNumTeams
|
|
//
|
|
// Returns the number of teams in the game
|
|
int DMFCBase::GetNumTeams(void) { return m_iNumTeams; }
|
|
|
|
// DMFCBase::AllowTeamChange
|
|
//
|
|
// Returns true if team changing is allowed
|
|
bool DMFCBase::AllowTeamChange(void) { return (m_iProtectedFlags & DMFC_PRF_CANTEAMCHANGE) ? true : false; }
|
|
|
|
// DMFCBase::SwitchAllowTeamChange
|
|
//
|
|
// Turns on/off allowing of team changing
|
|
void DMFCBase::SwitchAllowTeamChange(bool turnon) {
|
|
if (turnon)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_CANTEAMCHANGE);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_CANTEAMCHANGE);
|
|
}
|
|
|
|
// DMFCBase::IsMenuUp
|
|
//
|
|
// Returns true if the on screen menu is being shown
|
|
bool DMFCBase::IsMenuUp(void) { return (m_iProtectedFlags & DMFC_PRF_INOPTIONS) ? true : false; }
|
|
|
|
// DMFCBase::ClipString
|
|
//
|
|
// Given a width, the string will be clipped to that width. If you pass true for arrow, then an arrow will be
|
|
// appended if the string has been clipped. Based off current font
|
|
void DMFCBase::ClipString(int width, char *string, bool arrow) {
|
|
if (!string)
|
|
return;
|
|
|
|
// float ratio = DEFAULT_HUD_WIDTH / ((float)*Game_window_w);
|
|
|
|
int string_length = strlen(string);
|
|
char arrow_string[2];
|
|
int arrow_length = 0;
|
|
snprintf(arrow_string, sizeof(arrow_string), "%c", CHAR_RIGHT_ARROW);
|
|
if (arrow) {
|
|
// arrow_length = ratio * ((float)DLLRenderHUDGetTextLineWidth(arrow_string));
|
|
arrow_length = DLLgrtext_GetTextLineWidth(arrow_string);
|
|
}
|
|
|
|
if (width < arrow_length) {
|
|
// Nothing can fit
|
|
strcpy(string, "");
|
|
return;
|
|
}
|
|
|
|
// adjust width based on the arrow
|
|
width -= arrow_length;
|
|
|
|
int size = 0;
|
|
char save = string[0];
|
|
while (size < string_length) {
|
|
string[size] = '\0';
|
|
// if((((float)DLLRenderHUDGetTextLineWidth(string))*ratio)>=width){
|
|
if (DLLgrtext_GetTextLineWidth(string) >= width) {
|
|
// We have to clip
|
|
size--;
|
|
if (arrow) {
|
|
string[size] = CHAR_RIGHT_ARROW;
|
|
string[size + 1] = '\0';
|
|
}
|
|
return;
|
|
}
|
|
// replace the char and move to the next
|
|
string[size] = save;
|
|
size++;
|
|
save = string[size];
|
|
}
|
|
// The string didn't need to be clipped
|
|
}
|
|
|
|
// DMFCBase::ConvertHUDAlpha
|
|
//
|
|
// Returns a converted alpha based on what you give, it will be a more transparent if the onscreen menu is up
|
|
float DMFCBase::ConvertHUDAlpha(float normal) {
|
|
if (!IsMenuUp())
|
|
return normal;
|
|
return normal * 0.3f;
|
|
}
|
|
uint8_t DMFCBase::ConvertHUDAlpha(uint8_t normal) {
|
|
if (!IsMenuUp())
|
|
return normal;
|
|
|
|
float conv = ((float)normal);
|
|
conv = conv * 0.3f;
|
|
return (uint8_t)conv;
|
|
}
|
|
|
|
bool DMFCBase::DMFC_compare_slots(int a, int b) {
|
|
int ascore, bscore;
|
|
player_record *apr, *bpr;
|
|
apr = GetPlayerRecord(a);
|
|
bpr = GetPlayerRecord(b);
|
|
if (!apr)
|
|
return true;
|
|
if (!bpr)
|
|
return false;
|
|
if (apr->state == STATE_EMPTY)
|
|
return true;
|
|
if (bpr->state == STATE_EMPTY)
|
|
return false;
|
|
if ((apr->state == STATE_INGAME) && (bpr->state == STATE_INGAME)) {
|
|
// both players were in the game
|
|
ascore = apr->dstats.kills[DSTAT_LEVEL] - apr->dstats.suicides[DSTAT_LEVEL];
|
|
bscore = bpr->dstats.kills[DSTAT_LEVEL] - bpr->dstats.suicides[DSTAT_LEVEL];
|
|
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 = apr->dstats.kills[DSTAT_LEVEL] - apr->dstats.suicides[DSTAT_LEVEL];
|
|
bscore = bpr->dstats.kills[DSTAT_LEVEL] - bpr->dstats.suicides[DSTAT_LEVEL];
|
|
return (ascore < bscore);
|
|
}
|
|
|
|
// kills/(kills+deaths+suicides)
|
|
bool DMFCBase::DMFC_compare_slots_efficiency(int a, int b) {
|
|
int ascore, bscore;
|
|
player_record *apr, *bpr;
|
|
float atemp, btemp;
|
|
|
|
apr = GetPlayerRecord(a);
|
|
bpr = GetPlayerRecord(b);
|
|
if (!apr)
|
|
return true;
|
|
if (!bpr)
|
|
return false;
|
|
if (apr->state == STATE_EMPTY)
|
|
return true;
|
|
if (bpr->state == STATE_EMPTY)
|
|
return false;
|
|
if ((apr->state == STATE_INGAME) && (bpr->state == STATE_INGAME)) {
|
|
// both players were in the game
|
|
atemp =
|
|
(float)(apr->dstats.kills[DSTAT_LEVEL] + apr->dstats.suicides[DSTAT_LEVEL] + apr->dstats.deaths[DSTAT_LEVEL]);
|
|
ascore = (float)(apr->dstats.kills[DSTAT_LEVEL]) / ((atemp) ? atemp : 0.0000001f);
|
|
|
|
btemp =
|
|
(float)(bpr->dstats.kills[DSTAT_LEVEL] + bpr->dstats.suicides[DSTAT_LEVEL] + bpr->dstats.deaths[DSTAT_LEVEL]);
|
|
bscore = (float)(bpr->dstats.kills[DSTAT_LEVEL]) / ((btemp) ? btemp : 0.0000001f);
|
|
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
|
|
atemp = (float)(apr->dstats.kills[DSTAT_LEVEL] + apr->dstats.suicides[DSTAT_LEVEL] + apr->dstats.deaths[DSTAT_LEVEL]);
|
|
ascore = (float)(apr->dstats.kills[DSTAT_LEVEL]) / ((atemp) ? atemp : 0.0000001f);
|
|
|
|
btemp = (float)(bpr->dstats.kills[DSTAT_LEVEL] + bpr->dstats.suicides[DSTAT_LEVEL] + bpr->dstats.deaths[DSTAT_LEVEL]);
|
|
bscore = (float)(bpr->dstats.kills[DSTAT_LEVEL]) / ((btemp) ? btemp : 0.0000001f);
|
|
return (ascore < bscore);
|
|
}
|
|
|
|
// DMFCBase::GetSortedPlayerSlots
|
|
//
|
|
// Fills in the passed array (of size maxsize) with the playernums sorted by (kills-suicides)
|
|
void DMFCBase::GetSortedPlayerSlots(int *sortedindex, int maxsize) {
|
|
int t;
|
|
int i, j;
|
|
int tempsort[MAX_PLAYER_RECORDS];
|
|
|
|
// copy scores into scoreinfo array
|
|
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 && DMFC_compare_slots(tempsort[j], t); j--) {
|
|
tempsort[j + 1] = tempsort[j];
|
|
}
|
|
|
|
// insert
|
|
tempsort[j + 1] = t;
|
|
}
|
|
|
|
if (maxsize < MAX_PLAYER_RECORDS)
|
|
memcpy(sortedindex, tempsort, maxsize * sizeof(int));
|
|
else
|
|
memcpy(sortedindex, tempsort, MAX_PLAYER_RECORDS * sizeof(int));
|
|
}
|
|
|
|
// DMFCBase::GetSortedPlayerSlotsByEfficiency
|
|
//
|
|
// Fills in the passed array (of size maxsize) with the playernums sorted by kills/(kills+deaths+suicides)
|
|
void DMFCBase::GetSortedPlayerSlotsByEfficiency(int *sortedindex, int maxsize) {
|
|
int t;
|
|
int i, j;
|
|
int tempsort[MAX_PLAYER_RECORDS];
|
|
|
|
// copy scores into scoreinfo array
|
|
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 && DMFC_compare_slots_efficiency(tempsort[j], t); j--) {
|
|
tempsort[j + 1] = tempsort[j];
|
|
}
|
|
|
|
// insert
|
|
tempsort[j + 1] = t;
|
|
}
|
|
|
|
if (maxsize < MAX_PLAYER_RECORDS)
|
|
memcpy(sortedindex, tempsort, maxsize * sizeof(int));
|
|
else
|
|
memcpy(sortedindex, tempsort, MAX_PLAYER_RECORDS * sizeof(int));
|
|
}
|
|
|
|
// DMFCBase::DisplayOutrageLogo(void)
|
|
//
|
|
// Displays the Outrage Logo for 5 seconds (call repeatedly, after 5 seconds it will just short circuit)
|
|
// Doesn't do anything for non-Outrage games
|
|
void DMFCBase::DisplayOutrageLogo(void) {
|
|
if (!m_bDisplayOutrageLogo)
|
|
return;
|
|
|
|
#ifdef OUTRAGE_VERSION
|
|
static bool done = false;
|
|
static float time = 0;
|
|
static bool loadflag = true;
|
|
static chunked_bitmap bmp;
|
|
|
|
if (done)
|
|
return;
|
|
|
|
if (loadflag) {
|
|
// We need to load the handle
|
|
loadflag = false;
|
|
int temp = DLLbm_AllocLoadFileBitmap("Outlogo.ogf", 0, BITMAP_FORMAT_1555);
|
|
DLLbm_CreateChunkedBitmap(temp, &bmp);
|
|
DLLbm_FreeBitmap(temp);
|
|
time = 0;
|
|
}
|
|
|
|
// draw the Outrage Logo if its time
|
|
if (time < 5.0) {
|
|
int x, y;
|
|
x = (*Game_window_w) - bmp.pw;
|
|
y = (*Game_window_h) - bmp.ph;
|
|
DLLrend_DrawScaledChunkedBitmap(&bmp, x, y, bmp.pw, bmp.ph, 128);
|
|
time += (*Frametime);
|
|
} else {
|
|
// we are done
|
|
done = true;
|
|
DLLbm_DestroyChunkedBitmap(&bmp);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// DMFCBase::SwitchShowHudCallsignLevel
|
|
//
|
|
//
|
|
// Sets the level for displaying of Player's Callsigns on the HUD
|
|
void DMFCBase::SwitchShowHudCallsignLevel(uint8_t level, bool announce) {
|
|
m_iMyPreferredHUDCallsignLevel = level;
|
|
|
|
if (level > m_iServerHUDCallsignLevel)
|
|
level = m_iServerHUDCallsignLevel;
|
|
|
|
if (m_iMyCurrentHUDCallsignLevel == level)
|
|
return;
|
|
|
|
m_iMyCurrentHUDCallsignLevel = level;
|
|
|
|
switch (level) {
|
|
case HUD_CALLSIGN_LEVEL_FULL:
|
|
DLLPlayerSetHUDNameFOV(10);
|
|
if (announce)
|
|
DLLAddHUDMessage(DTXT_HUDLEVEL_FULL);
|
|
break;
|
|
case HUD_CALLSIGN_LEVEL_TEAM:
|
|
DLLPlayerSetHUDNameFOV(10);
|
|
if (announce)
|
|
DLLAddHUDMessage(DTXT_HUDLEVEL_TEAM);
|
|
break;
|
|
case HUD_CALLSIGN_LEVEL_NONE:
|
|
DLLPlayerSetHUDNameFOV(-1);
|
|
if (announce)
|
|
DLLAddHUDMessage(DTXT_HUDLEVEL_NONE);
|
|
break;
|
|
default:
|
|
mprintf(0, "DMFC: Invalid HUD Name Level\n");
|
|
return;
|
|
break;
|
|
};
|
|
}
|
|
|
|
// DMFCBase::SwitchServerHudCallsignLevel
|
|
//
|
|
//
|
|
// Sets the max level of HUD callsign displayage...determined by the server
|
|
void DMFCBase::SwitchServerHudCallsignLevel(uint8_t level) {
|
|
switch (level) {
|
|
case HUD_CALLSIGN_LEVEL_FULL:
|
|
m_iServerHUDCallsignLevel = level;
|
|
DLLAddHUDMessage(DTXT_SHUDLEVEL_FULL);
|
|
break;
|
|
case HUD_CALLSIGN_LEVEL_TEAM:
|
|
m_iServerHUDCallsignLevel = level;
|
|
DLLAddHUDMessage(DTXT_SHUDLEVEL_TEAM);
|
|
break;
|
|
case HUD_CALLSIGN_LEVEL_NONE:
|
|
m_iServerHUDCallsignLevel = level;
|
|
DLLAddHUDMessage(DTXT_SHUDLEVEL_NONE);
|
|
break;
|
|
default:
|
|
mprintf(0, "DMFC: Invalid Server HUD Name Level\n");
|
|
return;
|
|
break;
|
|
}
|
|
|
|
// make sure we're not set higher than the server allows
|
|
SwitchShowHudCallsignLevel(m_iMyPreferredHUDCallsignLevel);
|
|
|
|
if (GetLocalRole() == LR_SERVER)
|
|
SendDMFCGameInfo(SP_ALL);
|
|
}
|
|
|
|
// DMFCBase::ShouldIDisplayHUDName
|
|
//
|
|
// Given a player num, it will determine if the callsign should be drawn on the HUD
|
|
bool DMFCBase::ShouldIDisplayHUDName(int pnum) {
|
|
switch (m_iMyCurrentHUDCallsignLevel) {
|
|
case HUD_CALLSIGN_LEVEL_FULL:
|
|
return true;
|
|
break;
|
|
case HUD_CALLSIGN_LEVEL_TEAM: {
|
|
// see if this is a team game
|
|
if (GetNumTeams() >= 2) {
|
|
// ok it's a team game, see if this player is on my team, if so, than disply
|
|
if (Players[pnum].team == GetMyTeam()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
} break;
|
|
case HUD_CALLSIGN_LEVEL_NONE:
|
|
return false;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::GetCounterMeasureOwner
|
|
//
|
|
//
|
|
// Given a counter measure it will determine the pnum of it's owner...if it can't find it, it returns -1
|
|
int DMFCBase::GetCounterMeasureOwner(object *robot) {
|
|
if (!robot)
|
|
return -1;
|
|
|
|
if (robot->type != OBJ_ROBOT && (!(robot->type == OBJ_BUILDING && robot->ai_info)))
|
|
return -1;
|
|
|
|
object *killer;
|
|
DLLGetUltimateParentForObject(&killer, robot);
|
|
|
|
if (killer == robot)
|
|
return -1;
|
|
|
|
if ((killer->type != OBJ_PLAYER) && (killer->type != OBJ_OBSERVER))
|
|
return -1;
|
|
|
|
return killer->id;
|
|
}
|
|
|
|
// DMFCBase::EncryptData
|
|
//
|
|
// Encrypts (weak) a buffer of data
|
|
void DMFCBase::EncryptData(uint8_t *data, int size) {
|
|
if (!data)
|
|
return;
|
|
if (size <= 0)
|
|
return;
|
|
|
|
int offset = size;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
data[i] = data[i] + i - (offset + i);
|
|
offset++;
|
|
}
|
|
}
|
|
|
|
// DMFCBase::DecryptData
|
|
//
|
|
// Decrypts a buffer of data
|
|
void DMFCBase::DecryptData(uint8_t *data, int size) {
|
|
if (!data)
|
|
return;
|
|
if (size <= 0)
|
|
return;
|
|
|
|
int offset = size;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
data[i] = data[i] - i + (offset + i);
|
|
offset++;
|
|
}
|
|
}
|
|
|
|
void DMFCBase::VersionCheck(int pnum) { SendVersionToClient(pnum); }
|
|
|
|
// DMFCBase::FindPInfo
|
|
//
|
|
// Given a player number it will search the list and find that player, returning the pointer, or NULL if it
|
|
// can't be found or created
|
|
PInfo *DMFCBase::FindPInfo(int pnum) {
|
|
ASSERT((pnum >= 0) && (pnum < DLLMAX_PLAYERS));
|
|
player_record *pr = GetPlayerRecordByPnum(pnum);
|
|
if (!pr)
|
|
return NULL;
|
|
return pr->pinfo;
|
|
}
|
|
|
|
// DMFCBase::UpdatePInfo
|
|
//
|
|
//
|
|
// Updates a victim's pinfo stat (pass in player nums)
|
|
void DMFCBase::UpdatePInfo(int victim, int killer, int amount) {
|
|
ASSERT((victim >= 0) || (victim < DLLMAX_PLAYERS) || (killer >= 0) || (killer < DLLMAX_PLAYERS));
|
|
if ((victim < 0) || (victim >= DLLMAX_PLAYERS) || (killer < 0) || (killer >= DLLMAX_PLAYERS)) {
|
|
|
|
return;
|
|
}
|
|
|
|
PInfo *id;
|
|
int victim_slot = PRec_GetPlayerSlot(victim);
|
|
tPKillerInfo ki;
|
|
|
|
memset(&ki, 0, sizeof(tPKillerInfo));
|
|
id = FindPInfo(killer);
|
|
|
|
if ((id == NULL) || (victim_slot == -1)) {
|
|
mprintf(0, "Unable to find PInfos\n");
|
|
return;
|
|
}
|
|
|
|
// update killer
|
|
ki.kills = amount;
|
|
id->Update(victim_slot, &ki);
|
|
|
|
PInfo *kpi, *vpi;
|
|
kpi = id;
|
|
vpi = FindPInfo(victim);
|
|
int killer_slot = PRec_GetPlayerSlot(killer);
|
|
|
|
if ((vpi == NULL) || (killer_slot == -1)) {
|
|
mprintf(0, "Unable to find PInfos\n");
|
|
return;
|
|
}
|
|
|
|
if (victim != killer) {
|
|
// regular kill
|
|
kpi->HandleKill(victim_slot);
|
|
vpi->HandleDeath(killer_slot);
|
|
} else {
|
|
// suicide
|
|
kpi->HandleSuicide();
|
|
}
|
|
}
|
|
|
|
// DMFCBase::ResetPInfo
|
|
//
|
|
//
|
|
// Resets all the PInfo stats (and frees memory)
|
|
void DMFCBase::ResetPInfo(void) {
|
|
for (int i = 0; i < MAX_PLAYER_RECORDS; i++) {
|
|
player_record *pr = GetPlayerRecord(i);
|
|
if (pr && pr->pinfo) {
|
|
pr->pinfo->ResetAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::WriteDMFCStatsToFile
|
|
//
|
|
//
|
|
// This function will write out DMFC's stats to the file given (it must be opened for writing)
|
|
void DMFCBase::WriteDMFCStatsToFile(CFILE *file) {
|
|
#define BUFSIZE 150
|
|
ASSERT(file != NULL);
|
|
char buffer[BUFSIZE];
|
|
player_record *pr, *dpr;
|
|
tPInfoStat stat;
|
|
int count, length;
|
|
|
|
count = 1;
|
|
|
|
for (int p = 0; p < MAX_PLAYER_RECORDS; p++) {
|
|
pr = GetPlayerRecord(p);
|
|
if (pr && pr->state != STATE_EMPTY) {
|
|
// 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);
|
|
|
|
if (FindPInfoStatFirst(p, &stat)) {
|
|
char tempbuffer[25];
|
|
snprintf(buffer, sizeof(buffer), "%s", DTXT_DMFC_STAT_HEADER);
|
|
DLLcf_WriteString(file, buffer);
|
|
memset(buffer, ' ', BUFSIZE);
|
|
dpr = GetPlayerRecord(stat.slot);
|
|
|
|
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));
|
|
|
|
int pos;
|
|
pos = 40 + strlen(tempbuffer) + 1;
|
|
if (pos < BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE - 1] = '\0';
|
|
DLLcf_WriteString(file, buffer);
|
|
|
|
while (FindPInfoStatNext(&stat)) {
|
|
memset(buffer, ' ', BUFSIZE);
|
|
dpr = GetPlayerRecord(stat.slot);
|
|
|
|
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));
|
|
|
|
int pos;
|
|
pos = 40 + strlen(tempbuffer) + 1;
|
|
if (pos < BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE - 1] = '\0';
|
|
DLLcf_WriteString(file, buffer);
|
|
}
|
|
}
|
|
FindPInfoStatClose();
|
|
DLLcf_WriteString(file, ""); // skip a line
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
tPInfoStat _CurrentPInfoStat;
|
|
int _CurrentPInfoSlot = -1;
|
|
bool _DoneWithKills = false;
|
|
bool _SlotsUsed[MAX_PLAYER_RECORDS];
|
|
|
|
// DMFCBase::FindPInfoStatFirst
|
|
//
|
|
// Fills in a tPInfoStat that contains information about a given player record slot. Returns true on success, false
|
|
// if there is no information available for the given slot. Call this first, then follow with repeated calls to
|
|
// FindPInfoStatNext until you get a false value returned...call FindPInfoStatClose when done.
|
|
bool DMFCBase::FindPInfoStatFirst(int slot, tPInfoStat *stat) {
|
|
for (int i = 0; i < MAX_PLAYER_RECORDS; i++)
|
|
_SlotsUsed[i] = false;
|
|
|
|
if (slot < 0 || slot >= MAX_PLAYER_RECORDS)
|
|
return false;
|
|
|
|
if (!stat)
|
|
return false;
|
|
|
|
FindPInfoStatClose();
|
|
|
|
player_record *pr, *dpr;
|
|
tPKillerInfo *killer, *victim;
|
|
int deaths;
|
|
|
|
_SlotsUsed[slot] = true;
|
|
_CurrentPInfoSlot = slot;
|
|
memset(&_CurrentPInfoStat, 0, sizeof(tPInfoStat));
|
|
|
|
// return the given slot
|
|
pr = GetPlayerRecord(slot);
|
|
if (!pr || pr->state == STATE_EMPTY || !pr->pinfo)
|
|
return false;
|
|
|
|
killer = pr->pinfo->GetFirstKiller();
|
|
victim = NULL;
|
|
|
|
if (!killer) {
|
|
_DoneWithKills = true;
|
|
// go through the slots looking for deaths
|
|
for (int p = 0; p < MAX_PLAYER_RECORDS; p++) {
|
|
if (!_SlotsUsed[p]) {
|
|
_SlotsUsed[p] = true;
|
|
dpr = GetPlayerRecord(p);
|
|
deaths = 0;
|
|
if (dpr && dpr->state != STATE_EMPTY && dpr->pinfo) {
|
|
victim = ((PInfo *)dpr->pinfo)->GetKillerInfo(slot);
|
|
if (victim)
|
|
deaths = victim->kills;
|
|
}
|
|
if (deaths > 0) {
|
|
_CurrentPInfoStat.slot = p;
|
|
_CurrentPInfoStat.kills = 0;
|
|
_CurrentPInfoStat.deaths = deaths;
|
|
memcpy(stat, &_CurrentPInfoStat, sizeof(tPInfoStat));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
_CurrentPInfoStat.slot = killer->slot;
|
|
_CurrentPInfoStat.kills = killer->kills;
|
|
|
|
deaths = 0;
|
|
dpr = GetPlayerRecord(killer->slot);
|
|
if (dpr && dpr->state != STATE_EMPTY && dpr->pinfo) {
|
|
victim = ((PInfo *)dpr->pinfo)->GetKillerInfo(slot);
|
|
}
|
|
|
|
if (victim)
|
|
deaths = victim->kills;
|
|
|
|
_CurrentPInfoStat.deaths = deaths;
|
|
_SlotsUsed[killer->slot] = true;
|
|
|
|
memcpy(stat, &_CurrentPInfoStat, sizeof(tPInfoStat));
|
|
return true;
|
|
}
|
|
|
|
// DMFCBase::FindPInfoStatNext
|
|
//
|
|
// Call this repeatedly until you get a value of false, finish by calling FindPInfoStatClose
|
|
bool DMFCBase::FindPInfoStatNext(tPInfoStat *stat) {
|
|
if (_CurrentPInfoSlot == -1)
|
|
return false;
|
|
if (!stat)
|
|
return false;
|
|
|
|
int slot;
|
|
player_record *pr, *dpr;
|
|
slot = _CurrentPInfoSlot;
|
|
tPKillerInfo *killer, *victim;
|
|
int deaths = 0;
|
|
memset(&_CurrentPInfoStat, 0, sizeof(tPInfoStat));
|
|
|
|
// return the given slot
|
|
pr = GetPlayerRecord(slot);
|
|
if (!pr || pr->state == STATE_EMPTY || !pr->pinfo)
|
|
return false;
|
|
|
|
killer = pr->pinfo->GetNextKiller();
|
|
victim = NULL;
|
|
|
|
if (!killer) {
|
|
_DoneWithKills = true;
|
|
// go through the slots looking for deaths
|
|
for (int p = 0; p < MAX_PLAYER_RECORDS; p++) {
|
|
if (!_SlotsUsed[p]) {
|
|
_SlotsUsed[p] = true;
|
|
dpr = GetPlayerRecord(p);
|
|
deaths = 0;
|
|
if (dpr && dpr->state != STATE_EMPTY && dpr->pinfo) {
|
|
victim = ((PInfo *)dpr->pinfo)->GetKillerInfo(slot);
|
|
if (victim)
|
|
deaths = victim->kills;
|
|
}
|
|
if (deaths > 0) {
|
|
_CurrentPInfoStat.slot = p;
|
|
_CurrentPInfoStat.kills = 0;
|
|
_CurrentPInfoStat.deaths = deaths;
|
|
memcpy(stat, &_CurrentPInfoStat, sizeof(tPInfoStat));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
_CurrentPInfoStat.slot = killer->slot;
|
|
_CurrentPInfoStat.kills = killer->kills;
|
|
|
|
deaths = 0;
|
|
dpr = GetPlayerRecord(killer->slot);
|
|
if (dpr && dpr->state != STATE_EMPTY && dpr->pinfo) {
|
|
victim = dpr->pinfo->GetKillerInfo(slot);
|
|
}
|
|
|
|
if (victim)
|
|
deaths = victim->kills;
|
|
|
|
_CurrentPInfoStat.deaths = deaths;
|
|
_SlotsUsed[killer->slot] = true;
|
|
|
|
memcpy(stat, &_CurrentPInfoStat, sizeof(tPInfoStat));
|
|
return true;
|
|
}
|
|
|
|
// DMFCBase::FindPInfoStatClose
|
|
//
|
|
// Closes up a FindPInfo series of calls
|
|
void DMFCBase::FindPInfoStatClose(void) {
|
|
_CurrentPInfoSlot = -1;
|
|
_DoneWithKills = false;
|
|
}
|
|
|
|
// DMFCBase::SetWeaponDeathMessage
|
|
//
|
|
// Sets a death message for a weapon kill
|
|
bool DMFCBase::SetWeaponDeathMessage(const char *weapon_name, const char *message, bool victim_first) {
|
|
ASSERT(weapon_name != NULL);
|
|
ASSERT(message != NULL);
|
|
|
|
int weapon_index = DLLFindWeaponName(IGNORE_TABLE(weapon_name));
|
|
if (weapon_index == -1) {
|
|
mprintf(0, "Unable to set WeaponMessage for %s...can't find it\n", weapon_name);
|
|
return false;
|
|
}
|
|
|
|
int real_weapon = WeaponHash[weapon_index];
|
|
|
|
if (real_weapon == -1) {
|
|
mprintf(0, "You forgot to call AddWeaponHash before adding this Message\n");
|
|
return false;
|
|
}
|
|
|
|
if ((WeaponMessages[real_weapon].inuse) && (WeaponMessages[real_weapon].message)) {
|
|
free(WeaponMessages[real_weapon].message);
|
|
WeaponMessages[real_weapon].message = NULL;
|
|
}
|
|
|
|
WeaponMessages[real_weapon].message = (char *)malloc(strlen(message) + 1);
|
|
if (WeaponMessages[real_weapon].message) {
|
|
strcpy(WeaponMessages[real_weapon].message, message);
|
|
WeaponMessages[real_weapon].inuse = true;
|
|
WeaponMessages[real_weapon].victim_first = victim_first;
|
|
}
|
|
|
|
return WeaponMessages[real_weapon].inuse;
|
|
}
|
|
|
|
// DMFCBase::GetWeaponDeathMessage
|
|
//
|
|
// Returns the format string for a weapon death message, NULL if it doesn't exist
|
|
char *DMFCBase::GetWeaponDeathMessage(int index, bool *victim_first) {
|
|
if ((index < 0) || (index >= MAX_WEAPONS))
|
|
return NULL;
|
|
|
|
int real_weapon;
|
|
|
|
real_weapon = WeaponHash[index];
|
|
|
|
if (real_weapon == -1)
|
|
return NULL;
|
|
|
|
if (!WeaponMessages[real_weapon].inuse)
|
|
return NULL;
|
|
|
|
*victim_first = WeaponMessages[real_weapon].victim_first;
|
|
return WeaponMessages[real_weapon].message;
|
|
}
|
|
|
|
// DMFCBase::AddWeaponHash
|
|
//
|
|
// Since one weapon may actually consist of many weapons, in order to save space you can create
|
|
// one weapon where all those other weapon id's will be mapped to it...use WeaponHash[id] to
|
|
// get the actual weapon. End list of children with a NULL
|
|
void DMFCBase::AddWeaponHash(const char *parent, ...) {
|
|
ASSERT(parent != NULL);
|
|
|
|
int parent_id = DLLFindWeaponName(IGNORE_TABLE(parent));
|
|
if (parent_id == -1) {
|
|
mprintf(0, "Unable to find parent weapon ID in AddWeaponHash (%s)\n", parent);
|
|
return;
|
|
}
|
|
|
|
va_list marker;
|
|
va_start(marker, parent);
|
|
|
|
WeaponHash[parent_id] = parent_id;
|
|
|
|
bool done = false;
|
|
|
|
while (!done) {
|
|
int id;
|
|
char *name;
|
|
name = va_arg(marker, char *);
|
|
if (name)
|
|
id = DLLFindWeaponName(IGNORE_TABLE(name));
|
|
else
|
|
id = -1;
|
|
|
|
if (id == -1) {
|
|
done = true;
|
|
} else {
|
|
if ((id < 0) || (id >= MAX_WEAPONS))
|
|
done = true;
|
|
else {
|
|
WeaponHash[id] = parent_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
va_end(marker);
|
|
}
|
|
|
|
// DMFCBase::AddWeaponHashArray
|
|
//
|
|
// Since one weapon may actually consist of many weapons, in order to save space you can create
|
|
// one weapon where all those other weapon id's will be mapped to it...use WeaponHash[id] to
|
|
// get the actual weapon.
|
|
void DMFCBase::AddWeaponHashArray(const char *parent, int count, char **array) {
|
|
ASSERT(parent != NULL);
|
|
|
|
int parent_id = DLLFindWeaponName(IGNORE_TABLE(parent));
|
|
if (parent_id == -1) {
|
|
mprintf(0, "Unable to find parent weapon ID in AddWeaponHash (%s)\n", parent);
|
|
return;
|
|
}
|
|
|
|
WeaponHash[parent_id] = parent_id;
|
|
|
|
int index = 0;
|
|
while (index < count) {
|
|
int id;
|
|
char *name;
|
|
name = array[index++];
|
|
if (name)
|
|
id = DLLFindWeaponName(IGNORE_TABLE(name));
|
|
else
|
|
break;
|
|
|
|
if (id >= 0 && id < MAX_WEAPONS) {
|
|
WeaponHash[id] = parent_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::SetupPlayerRecord
|
|
//
|
|
// Sets up memory for multiplayer mod user defined data in the Player Records. Pass in the size (in bytes)
|
|
// of 1 struct (each player will get one). Use GetPlayerRecordData to retrieve a pointer to the data.
|
|
//
|
|
// pack_callback : callback function called when data from the struct needs to be packed
|
|
// into a packet. It is SUPER important that this function packs the data
|
|
// in little endian format. This function gets a pointer to the struct that
|
|
// needs to be packed (user_info), and a buffer in which to pack it to. This
|
|
// function is to return the number of bytes it has packed.
|
|
// unpack_callback : callback function called when data from the struct needs to be unpacket
|
|
// from a packet. This data will be in little endian format. Returns the number of
|
|
// bytes unpacked.
|
|
// returns: 1 if size given was <=0 (if so all previous user stats will be removed)
|
|
// 0 all went ok
|
|
// -1 out of memory (all user stats memory will be freed)
|
|
int DMFCBase::SetupPlayerRecord(int sizeof_individual_data, int (*pack_callback)(void *user_info, uint8_t *data),
|
|
int (*unpack_callback)(void *user_info, uint8_t *data)) {
|
|
return PRec_SetupUserPRec(sizeof_individual_data, pack_callback, unpack_callback);
|
|
}
|
|
|
|
// DMFCBase::GetPlayerRecordData
|
|
//
|
|
// Returns a pointer to the memory set aside for a particular player (NULL on error)
|
|
void *DMFCBase::GetPlayerRecordData(int pnum) {
|
|
int slot;
|
|
slot = PRec_GetPlayerSlot(pnum);
|
|
if (slot == -1)
|
|
return NULL;
|
|
return PRec_GetUserStats(slot);
|
|
}
|
|
|
|
// DMFCBase::GetPlayerRecord
|
|
//
|
|
// Returns a pointer to the player record at the given slot (passed in slot must be in the range
|
|
// 0<=slot<MAX_PLAYER_RECORDS)
|
|
player_record *DMFCBase::GetPlayerRecord(int slot) { return PRec_GetPRecord(slot); }
|
|
|
|
// DMFCBase::GetPlayerRecordByPnum
|
|
//
|
|
// Same as above, but you can specify by a player's pnum, return NULL on error
|
|
player_record *DMFCBase::GetPlayerRecordByPnum(int pnum) {
|
|
int slot;
|
|
slot = PRec_GetPlayerSlot(pnum);
|
|
if (slot == -1)
|
|
return NULL;
|
|
return PRec_GetPRecord(slot);
|
|
}
|
|
|
|
// DMFCBase::BanPlayerFromGame
|
|
//
|
|
// Puts a temp ban on a player which will only last the duration of the game
|
|
void DMFCBase::BanPlayerFromGame(int pnum) {
|
|
if (pnum >= 0 && pnum < DLLMAX_PLAYERS) {
|
|
mprintf(0, "Banning %s\n", Players[pnum].callsign);
|
|
DPrintf(DTXT_DEDS_BAN, Players[pnum].callsign);
|
|
tBanItem *c;
|
|
c = m_BanList;
|
|
if (!m_BanList) {
|
|
c = m_BanList = (tBanItem *)malloc(sizeof(tBanItem));
|
|
if (!c)
|
|
return;
|
|
} else {
|
|
while (c->next) {
|
|
c = c->next;
|
|
}
|
|
c->next = (tBanItem *)malloc(sizeof(tBanItem));
|
|
c = c->next;
|
|
if (!c)
|
|
return;
|
|
}
|
|
c->next = NULL;
|
|
memcpy(&c->addr, &NetPlayers[pnum].addr, sizeof(network_address));
|
|
strncpy(c->callsign, Players[pnum].callsign, MAX_CALLSIGN_SIZE - 1);
|
|
c->callsign[MAX_CALLSIGN_SIZE - 1] = '\0';
|
|
c->tracker_id[0] = '\0';
|
|
|
|
if (IsMasterTrackerGame()) {
|
|
strcpy(c->tracker_id, Players[pnum].tracker_id);
|
|
}
|
|
|
|
m_iNumBanPlayers++;
|
|
} else {
|
|
mprintf(0, "Unable to ban player...pnum not valid\n");
|
|
DPrintf(DTXT_DEDS_BAN_ERROR);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::RemoveAllBans
|
|
//
|
|
// Removes all the temp bans
|
|
void DMFCBase::RemoveAllBans(void) {
|
|
tBanItem *c, *n;
|
|
c = n = m_BanList;
|
|
while (c) {
|
|
n = c->next;
|
|
free(c);
|
|
c = n;
|
|
}
|
|
m_BanList = NULL;
|
|
m_iNumBanPlayers = 0;
|
|
}
|
|
|
|
// DMFCBase::GetNumBannedPlayers
|
|
//
|
|
// Returns the number of players banned from the server
|
|
int DMFCBase::GetNumBannedPlayers(void) { return m_iNumBanPlayers; }
|
|
|
|
// DMCBase::GetBannedPlayerCallsign
|
|
//
|
|
// Returns the callsign of the banned player at position index, NULL on error
|
|
char *DMFCBase::GetBannedPlayerCallsign(int index) {
|
|
if (index < 0 || index >= m_iNumBanPlayers)
|
|
return NULL;
|
|
|
|
tBanItem *c;
|
|
c = m_BanList;
|
|
while (c) {
|
|
if (index == 0) {
|
|
return c->callsign;
|
|
}
|
|
index--;
|
|
c = c->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// DMFCBase::RemoveBan
|
|
//
|
|
// Removes a temp ban on given the ban #...returns true on success
|
|
bool DMFCBase::RemoveBan(int index) {
|
|
if (index < 0 || index >= m_iNumBanPlayers)
|
|
return false;
|
|
|
|
tBanItem *c, *p;
|
|
c = m_BanList;
|
|
p = NULL;
|
|
while (c) {
|
|
if (!index) {
|
|
// we found em, remove em
|
|
if (p) {
|
|
p->next = c->next;
|
|
free(c);
|
|
m_iNumBanPlayers--;
|
|
} else {
|
|
m_BanList = c->next;
|
|
free(c);
|
|
m_iNumBanPlayers--;
|
|
}
|
|
return true;
|
|
}
|
|
p = c;
|
|
c = c->next;
|
|
index--;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::IsPlayerBanned
|
|
//
|
|
// returns true is the given pnum is banned from the game
|
|
bool DMFCBase::IsPlayerBanned(int pnum) {
|
|
mprintf(0, "Checking a ban on a player...");
|
|
|
|
if (pnum < 0 || pnum >= DLLMAX_PLAYERS) {
|
|
mprintf(0, "Playernum not valid\n");
|
|
return false;
|
|
}
|
|
|
|
if (IsAddressBanned(&NetPlayers[pnum].addr, Players[pnum].tracker_id)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::IsAddressBanned
|
|
//
|
|
// returns true if the given address is banned from the game
|
|
bool DMFCBase::IsAddressBanned(network_address *addr, const char *tracker_id) {
|
|
tBanItem *c;
|
|
c = m_BanList;
|
|
|
|
mprintf(0, "Checking a ban on an address...");
|
|
|
|
while (c) {
|
|
if (addr && CompareNetworkAddress(&c->addr, addr, false)) {
|
|
mprintf(0, "Player addr IS BANNED\n");
|
|
return true;
|
|
}
|
|
if (*m_bTrackerGame) {
|
|
if (tracker_id && !strcmp(tracker_id, c->tracker_id)) {
|
|
mprintf(0, "Player tid IS BANNED\n");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
c = c->next;
|
|
}
|
|
|
|
if (!addr) {
|
|
mprintf(0, "Player not banned\n");
|
|
return false;
|
|
}
|
|
|
|
// ok, the player doesn't have a temp ban on him, now, if it's tcp/ip, check
|
|
// the hosts.allow/.deny
|
|
|
|
if (addr->connection_type != NP_TCP) {
|
|
mprintf(0, "Player not banned\n");
|
|
return false;
|
|
}
|
|
|
|
uint32_t address;
|
|
tHostsNode *curr;
|
|
|
|
memcpy(&address, &addr->address, 4);
|
|
|
|
// check the allow list, if the address is specified on this list,
|
|
// than it isn't banned
|
|
curr = m_AllowList;
|
|
while (curr) {
|
|
if ((address & curr->mask) == (curr->ip & curr->mask)) {
|
|
// its a match
|
|
mprintf(0, "Player not banned\n");
|
|
return false;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
|
|
// check the deny list, if the address is specified on this list,
|
|
// than it is banned
|
|
curr = m_DenyList;
|
|
while (curr) {
|
|
if ((address & curr->mask) == (curr->ip & curr->mask)) {
|
|
// its a match
|
|
mprintf(0, "Player IS banned\n");
|
|
return true;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
|
|
mprintf(0, "Player not banned\n");
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::DoDamageToPlayer
|
|
//
|
|
// Server only...applies damage to player
|
|
void DMFCBase::DoDamageToPlayer(int pnum, int type, float amount, bool playsound) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
if (!CheckPlayerNum(pnum))
|
|
return;
|
|
if (pnum == GetPlayerNum()) {
|
|
// apply it to myself
|
|
if (amount <= 0) {
|
|
// just add it...no damage sound
|
|
Objects[Players[pnum].objnum].shields -= amount;
|
|
} else {
|
|
DLLApplyDamageToPlayer(&Objects[Players[pnum].objnum], NULL, type, amount, 1, 255, playsound);
|
|
}
|
|
} else {
|
|
// add it to additional damage
|
|
DLLApplyDamageToPlayer(&Objects[Players[pnum].objnum], NULL, type, amount, 1, 255, playsound);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::StartUIWindow
|
|
//
|
|
// Prepares the game so that you can display UI stuff
|
|
void DMFCBase::StartUIWindow(int id, void *user_data) {
|
|
if (m_iUIWindowID != -1) {
|
|
mprintf(0, "DMFCBase::StartUIWindow(): A Window ID (0x%X) is already defined\n", m_iUIWindowID);
|
|
return;
|
|
}
|
|
|
|
*Game_interface_mode = GAME_DLL_INTERFACE;
|
|
m_iUIWindowID = id;
|
|
m_UIUserData = user_data;
|
|
}
|
|
|
|
// DMFCBase::EnableStatisticalMessages
|
|
//
|
|
// Turns on or off the statistical HUD messages that appear due to a player death
|
|
void DMFCBase::EnableStatisticalMessages(bool on) {
|
|
if (on)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPSTATHUDMSGS);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPSTATHUDMSGS);
|
|
}
|
|
|
|
// DMFCBase::GetTimeInGame
|
|
//
|
|
// Returns the totaltime the player has been in the game at the moment you call
|
|
// this function. Pass in the player record slot.
|
|
float DMFCBase::GetTimeInGame(int slot) {
|
|
if (slot < 0 || slot >= MAX_PLAYER_RECORDS)
|
|
return 0;
|
|
|
|
player_record *pr = PRec_GetPRecord(slot);
|
|
|
|
if (!pr || pr->state == STATE_EMPTY)
|
|
return 0;
|
|
|
|
float ti = pr->total_time_in_game;
|
|
|
|
if (pr->state == STATE_INGAME)
|
|
ti += RealGametime - pr->start_time;
|
|
|
|
return ti;
|
|
}
|
|
|
|
// DMFCBase::GetTimeString
|
|
//
|
|
// Returns a string that contains a formated time (i.e. 32 seconds, 1:15 minutes, 3:21:23 hours)
|
|
char *DMFCBase::GetTimeString(float sec) {
|
|
static char buffer[20];
|
|
int minutes, seconds, hours;
|
|
minutes = seconds = hours = 0;
|
|
|
|
seconds = (int)sec;
|
|
|
|
// we have seconds, so convert to minutes:seconds
|
|
minutes = seconds / 60;
|
|
seconds = seconds % 60;
|
|
|
|
// now we have minutes and seconds, so convert minutes to hours:minutes
|
|
hours = minutes / 60;
|
|
minutes = minutes % 60;
|
|
|
|
// now form our string hh:mm:ss
|
|
if (hours) {
|
|
if (hours == 1 && minutes == 0 && seconds == 0)
|
|
snprintf(buffer, sizeof(buffer), "%s", DTXT_TIME_HOUR);
|
|
else
|
|
snprintf(buffer, sizeof(buffer), DTXT_TIME_HOURS, hours, minutes, seconds);
|
|
} else if (minutes) {
|
|
if (minutes == 1 && seconds == 0)
|
|
snprintf(buffer, sizeof(buffer), "%s", DTXT_TIME_MINUTE);
|
|
else
|
|
snprintf(buffer, sizeof(buffer), DTXT_TIME_MINUTES, minutes, seconds);
|
|
} else {
|
|
if (seconds == 1)
|
|
snprintf(buffer, sizeof(buffer), "%s", DTXT_TIME_SECOND);
|
|
else
|
|
snprintf(buffer, sizeof(buffer), DTXT_TIME_SECONDS, seconds);
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
// DMFCBase::PauseRealGameTime
|
|
//
|
|
// Pauses/unpauses the realgame time
|
|
void DMFCBase::PauseRealGameTime(bool enable) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
|
|
if (enable) {
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_PAUSETIME);
|
|
SendControlMessageToPlayer(SP_ALL, CM_PAUSETIME);
|
|
} else {
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_PAUSETIME);
|
|
SendControlMessageToPlayer(SP_ALL, CM_UNPAUSETIME);
|
|
}
|
|
}
|
|
|
|
/*
|
|
********************************************************************************
|
|
* *
|
|
* Input Command Functions
|
|
**
|
|
* *
|
|
********************************************************************************
|
|
*
|
|
*/
|
|
|
|
// DMFCBase::InputCommandHandle
|
|
//
|
|
// Goes through the list of input commands and calls the associated handle (if it exists). Returns
|
|
// true if it called a handler, else false.
|
|
bool DMFCBase::InputCommandHandle(char *command_string) {
|
|
ASSERT(command_string != NULL);
|
|
|
|
// make sure it's a valid command (starts with a $)
|
|
if (command_string[0] != '$')
|
|
return false;
|
|
|
|
/*
|
|
if(!stricmp(command_string,"$help dump"))
|
|
{
|
|
mprintf(0,"Dumping help commands to file\n");
|
|
tInputCommandNode *node = m_InputCommandRootNode;
|
|
|
|
CFILE *file;
|
|
DLLOpenCFILE(&file,"C:\\DMFCHelp.txt","wt");
|
|
|
|
if(!file)
|
|
return false;
|
|
|
|
char buffer[1024];
|
|
|
|
while(node){
|
|
|
|
sprintf(buffer,"$%s",node->data);
|
|
DLLcf_WriteString(file,buffer);
|
|
DLLcf_WriteString(file,"-------------------------------------------");
|
|
sprintf(buffer,"%s\n",node->desc);
|
|
DLLcf_WriteString(file,buffer);
|
|
node = node->next;
|
|
}
|
|
|
|
DLLcfclose(file);
|
|
}
|
|
*/
|
|
|
|
// now extract the command
|
|
char command[64], index = 0;
|
|
char *p = &command_string[1];
|
|
|
|
// lowercase the command_string
|
|
while (*p && *p != ' ') {
|
|
if ((*p >= 'A') && (*p <= 'Z')) {
|
|
*p = tolower(*p);
|
|
}
|
|
p++;
|
|
}
|
|
|
|
p = &command_string[1];
|
|
|
|
// break off the first string
|
|
while ((*p) && (*p != ' ')) {
|
|
ASSERT(index < 64);
|
|
command[index] = *p;
|
|
p++;
|
|
index++;
|
|
}
|
|
command[index] = '\0'; // tack on an ending NULL
|
|
|
|
// now go through our list and see if we can find the command added by the user
|
|
tInputCommandNode *node = m_InputCommandRootNode;
|
|
while (node) {
|
|
if (!stricmp(node->data, command)) {
|
|
// we found a match!
|
|
if (node->handler) {
|
|
(*node->handler)(command_string);
|
|
return true;
|
|
}
|
|
return false; // for some reason the handler is NULL (it should never happen)
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
// if we got here than no nodes match
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::InputCommandFree
|
|
//
|
|
// Frees up all memory allocated for the input commands ($ messages)
|
|
void DMFCBase::InputCommandFree(void) {
|
|
tInputCommandNode *next, *node = m_InputCommandRootNode;
|
|
|
|
// Destroy the linked list of nodes
|
|
while (node) {
|
|
next = node->next;
|
|
if (node->data)
|
|
free(node->data);
|
|
if (node->desc)
|
|
free(node->desc);
|
|
free(node);
|
|
node = next;
|
|
}
|
|
|
|
// set the root to NULL to finish up
|
|
m_InputCommandRootNode = NULL;
|
|
}
|
|
|
|
// DMFCBase::InputCommandInit
|
|
//
|
|
// Initializes the variables and data for the input commands. Default DMFC commands are to
|
|
// be placed in here.
|
|
void DMFCBase::InputCommandInit(void) {
|
|
if (AddInputCommand(DTXT_IC_ALLOWTEAMCHANGE, DTXT_IC_ALLOWTEAMCHANGED, DMFCInputCommand_AllowTeamChange, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_AUTOBALANCE, DTXT_IC_AUTOBALANCED, DMFCInputCommand_AutoBalance, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_AUTOSAVEDISC, DTXT_IC_AUTOSAVEDISCD, DMFCInputCommand_AutoSaveDisconnect, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_AUTOSAVELEVEL, DTXT_IC_AUTOSAVELEVELD, DMFCInputCommand_AutoSaveLevel, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_BALANCE, DTXT_IC_BALANCED, DMFCInputCommand_Balance, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_BAN, DTXT_IC_BAND, DMFCInputCommand_Ban, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_BANLIST, DTXT_IC_BANLISTD, DMFCInputCommand_BanList) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_CHANGETEAM, DTXT_IC_CHANGETEAMD, DMFCInputCommand_ChangeTeam, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_ENDLEVEL, DTXT_IC_ENDLEVELD, DMFCInputCommand_EndLevel, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_HELP, DTXT_IC_HELPD, DMFCInputCommand_Help) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_HUDNAME, DTXT_IC_HUDNAMED, DMFCInputCommand_HudCallsigns) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_KICK, DTXT_IC_KICKD, DMFCInputCommand_Kick, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_KILLMSGFILTER, DTXT_IC_KILLMSGFILTERD, DMFCInputCommand_KillMsgFilter) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_NETGAMEINFO, DTXT_IC_NETGAMEINFO, DMFCInputCommand_NetGameInfo) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_OBSERVER, DTXT_IC_OBSERVERD, DMFCInputCommand_Observer) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_PIGGYBACK, DTXT_IC_PIGGYBACKD, DMFCInputCommand_Piggyback) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_PLAYERINFO, DTXT_IC_PLAYERINFOD, DMFCInputCommand_PlayerInfo) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_PLAYERS, DTXT_IC_PLAYERSD, DMFCInputCommand_Players) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REHASH, DTXT_IC_REHASHD, DMFCInputCommand_Rehash, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REMOTE, DTXT_IC_REMOTED, DMFCInputCommand_Remote) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REMOTEADMIN, DTXT_IC_REMOTEADMIND, DMFCInputCommand_RemoteAdmin, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REMOTEADMINLOGOUT, DTXT_IC_REMOTEADMINLOGOUTD, DMFCInputCommand_RemoteAdminLogout) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REMOTEADMINPASS, DTXT_IC_REMOTEADMINPASSD, DMFCInputCommand_RemoteAdminPass, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_REMOVEBAN, DTXT_IC_REMOVEBAND, DMFCInputCommand_RemoveBan, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SAVESTATS, DTXT_IC_SAVESTATSD, DMFCInputCommand_SaveStats, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SCORES, DTXT_IC_SCORESD, DMFCInputCommand_Scores) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SERVERHUDNAMES, DTXT_IC_SERVERHUDNAMESD, DMFCInputCommand_ServerHudCallsigns, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETGOALLIMIT, DTXT_IC_SETGOALLIMITD, DMFCInputCommand_SetGoalLimit, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETMAXPLAYERS, DTXT_IC_SETMAXPLAYERSD, DMFCInputCommand_SetMaxPlayers, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETPPS, DTXT_IC_SETPPSD, DMFCInputCommand_SetPPS, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETRESPAWNTIME, DTXT_IC_SETRESPAWNTIMED, DMFCInputCommand_SetRespawnTime, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETTEAMNAME, DTXT_IC_SETTEAMNAMED, DMFCInputCommand_SetTeamName, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_SETTIMELIMIT, DTXT_IC_SETTIMELIMITD, DMFCInputCommand_SetTimeLimit, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_STATMSGS, DTXT_IC_STATMSGSD, DMFCInputCommand_StatMsgs) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_TEAM, DTXT_IC_TEAMD, DMFCInputCommand_Team) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_WAIT, DTXT_IC_WAITD, DMFCInputCommand_Wait, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
|
|
if (AddInputCommand(DTXT_IC_WARP, DTXT_IC_WARPD, DMFCInputCommand_Warp, true) < 1)
|
|
mprintf(0, "DMFC Warning: Error Adding Input Command\n");
|
|
}
|
|
|
|
// Returns true if the input command can be called remotely
|
|
//
|
|
// Returns 1 if the input command can be called remotely
|
|
// Returns -1 if the input command is not found
|
|
// Returns 0 if the input command can be called remotely
|
|
int DMFCBase::CanInputCommandBeUsedRemotely(char *command) {
|
|
tInputCommandNode *node = m_InputCommandRootNode;
|
|
|
|
while (node) {
|
|
if (!stricmp(node->data, command)) {
|
|
// we found a match!
|
|
return (node->allow_remote) ? 1 : 0;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Displays dedicated server help
|
|
void DMFCBase::DisplayInputCommandHelp(const char *s) {
|
|
if (!IAmDedicatedServer())
|
|
return;
|
|
|
|
tInputCommandNode *node = m_InputCommandRootNode;
|
|
|
|
if (s[0] == '\0') {
|
|
char buffer[80];
|
|
DPrintf(DTXT_IC_HEADEERLIST);
|
|
DPrintf(DTXT_IC_HEADERINSTRUCT);
|
|
// just display the list of commands
|
|
while (node) {
|
|
memset(buffer, ' ', 80);
|
|
memcpy(&buffer[0], node->data, strlen(node->data));
|
|
node = node->next;
|
|
if (node) {
|
|
memcpy(&buffer[30], node->data, strlen(node->data));
|
|
int pos = 30 + strlen(node->data);
|
|
if (pos <= 78) {
|
|
buffer[pos] = '\n';
|
|
buffer[pos + 1] = '\0';
|
|
}
|
|
}
|
|
buffer[78] = '\n';
|
|
buffer[79] = '\0';
|
|
|
|
DPrintf(buffer);
|
|
|
|
if (node)
|
|
node = node->next;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// display help description
|
|
while (node) {
|
|
if (!stricmp(node->data, s)) {
|
|
// we found a match!
|
|
DPrintf("%s:\n", node->data);
|
|
if (node->desc)
|
|
DPrintf("%s\n", node->desc);
|
|
else
|
|
DPrintf(DTXT_IC_NOADDITIONALINFO);
|
|
return;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
DPrintf(DTXT_IC_COMMANDNOTFOUND);
|
|
}
|
|
|
|
// copies a string from src to dest, making dest all lower case
|
|
void strlowcpy(char *dest, const char *src) {
|
|
ASSERT((dest != NULL) && (src != NULL));
|
|
char *s, *d;
|
|
s = (char *)src;
|
|
d = dest;
|
|
|
|
while (*s) {
|
|
*d = tolower(*s);
|
|
s++;
|
|
d++;
|
|
}
|
|
// do the final NULL
|
|
*d = '\0';
|
|
}
|
|
|
|
// DMFCBase::AddInputCommand
|
|
//
|
|
// When the client (or dedicated server) types a message that begins with a $, DMFC will look through
|
|
// all the values you passed to AddInputCommand() and see if any match. If so it passes the entire
|
|
// command string to the given function handler. Returns 1 on success, -1 if out of memory, 0 if it already
|
|
// exists. These commands are not case sensitive.
|
|
// Ex. AddInputCommand("team"); //this handles all the '$team' passed in
|
|
int8_t DMFCBase::AddInputCommand(const char *command, const char *description, void (*handler)(const char *), bool allow_remotely) {
|
|
ASSERT(command != NULL);
|
|
ASSERT(handler != NULL);
|
|
|
|
// traverse to the end of the list checking for duplicates along the way
|
|
tInputCommandNode *node = m_InputCommandRootNode;
|
|
|
|
if (!node) {
|
|
// there is none currently in the list, add it now
|
|
node = (tInputCommandNode *)malloc(sizeof(tInputCommandNode));
|
|
if (!node) {
|
|
return -1;
|
|
}
|
|
// fill in data
|
|
node->next = NULL;
|
|
node->handler = handler;
|
|
node->allow_remote = allow_remotely;
|
|
node->data = (char *)malloc(strlen(command) + 1);
|
|
if (!node->data) { // out of memory
|
|
free(node);
|
|
return -1;
|
|
}
|
|
strlowcpy(node->data, command);
|
|
|
|
node->desc = (char *)malloc(strlen(description) + 1);
|
|
if (node->desc)
|
|
strcpy(node->desc, description);
|
|
|
|
// all went ok
|
|
m_InputCommandRootNode = node;
|
|
return 1;
|
|
}
|
|
|
|
while (node->next) {
|
|
// check this node to make sure it's not a duplicate
|
|
if (!stricmp(node->data, command)) {
|
|
// we found a duplicate
|
|
return 0;
|
|
}
|
|
node = node->next;
|
|
}
|
|
|
|
// we need to check the current node since while(node->next) breaks out before checking the last node
|
|
if (!stricmp(node->data, command)) {
|
|
// we found a duplicate
|
|
return 0;
|
|
}
|
|
|
|
// it looks like everything went ok, now just create a new node and tack it on to the end
|
|
// of the list. All that can go wrong now is an out of memory error.
|
|
tInputCommandNode *temp;
|
|
temp = (tInputCommandNode *)malloc(sizeof(tInputCommandNode));
|
|
if (!temp) { // out of memory
|
|
return -1;
|
|
}
|
|
temp->next = NULL;
|
|
temp->handler = handler;
|
|
temp->allow_remote = allow_remotely;
|
|
temp->data = (char *)malloc(strlen(command) + 1);
|
|
if (!temp->data) { // out of memory
|
|
free(temp);
|
|
return -1;
|
|
}
|
|
strlowcpy(temp->data, command);
|
|
|
|
temp->desc = (char *)malloc(strlen(description) + 1);
|
|
if (temp->desc)
|
|
strcpy(temp->desc, description);
|
|
|
|
// now tack it on the end of the list and thats all
|
|
node->next = temp;
|
|
return 1;
|
|
}
|
|
|
|
// DMFCBase::DisconnectMe
|
|
//
|
|
// Disconnects yourself from the game. It should be called when you are kicked or banned to make the
|
|
// whole process a bit nicer/cleaner. Even if it doesn't get called when kicked, you will still
|
|
// eventually disconnect.
|
|
void DMFCBase::DisconnectMe(void) { Netgame->flags |= NF_EXIT_NOW; }
|
|
|
|
// Does a check on on the pinfo info making sure it is valid
|
|
void DMFCBase::CheckPInfo() {
|
|
for (int slot = 0; slot < MAX_PLAYER_RECORDS; slot++) {
|
|
player_record *pr = GetPlayerRecord(slot);
|
|
if (pr && pr->state != STATE_EMPTY) {
|
|
// now go through the victim list and check
|
|
tPKillerInfo *node;
|
|
|
|
ASSERT(pr->pinfo != NULL);
|
|
node = pr->pinfo->GetFirstKiller();
|
|
|
|
while (node) {
|
|
ASSERT(node->slot >= 0 && node->slot < 64);
|
|
node = node->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::EnableOnScreenMenu
|
|
//
|
|
// Turns on/off the onscreen menu
|
|
void DMFCBase::EnableOnScreenMenu(bool enable) {
|
|
if (enable)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_INOPTIONS);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_INOPTIONS);
|
|
}
|
|
|
|
// DMFCBase::EnableAutoSaveLevelEnd
|
|
//
|
|
// Disables/Enables the autosaving of game stats to file on level end
|
|
void DMFCBase::EnableAutoSaveLevelEnd(bool enable) {
|
|
if (enable)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVELEVELEND);
|
|
}
|
|
|
|
// DMFCBase::EnableAutoSaveDisconnect
|
|
//
|
|
// Disables/Enables the autosaving of game stats to file on disconnect from the game
|
|
void DMFCBase::EnableAutoSaveDisconnect(bool enable) {
|
|
if (enable)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_AUTOSAVEDISC);
|
|
}
|
|
|
|
// DMFCBase::GenerateStatFilename
|
|
//
|
|
// Given the following information it will return a full path to what
|
|
// the recommended filename to save stats to should be.
|
|
// root = Multiplayer DLL Name (filename will start with this)
|
|
// end_of_level = pass true if this is the end of a level stats
|
|
void DMFCBase::GenerateStatFilename(char *filename, const char *root, bool end_of_level) {
|
|
int level = Current_mission->cur_level;
|
|
char *name = Netgame->name;
|
|
struct tm *newtime;
|
|
time_t long_time;
|
|
|
|
time(&long_time);
|
|
newtime = localtime(&long_time);
|
|
|
|
char fname[256];
|
|
char timestr[100];
|
|
char day[8], month[8];
|
|
|
|
switch (newtime->tm_wday) {
|
|
case 0:
|
|
strcpy(day, DTXT_SUNDAY);
|
|
break;
|
|
case 1:
|
|
strcpy(day, DTXT_MONDAY);
|
|
break;
|
|
case 2:
|
|
strcpy(day, DTXT_TUESDAY);
|
|
break;
|
|
case 3:
|
|
strcpy(day, DTXT_WEDNESDAY);
|
|
break;
|
|
case 4:
|
|
strcpy(day, DTXT_THURSDAY);
|
|
break;
|
|
case 5:
|
|
strcpy(day, DTXT_FRIDAY);
|
|
break;
|
|
case 6:
|
|
strcpy(day, DTXT_SATURDAY);
|
|
break;
|
|
}
|
|
|
|
switch (newtime->tm_mon) {
|
|
case 0:
|
|
strcpy(month, DTXT_JANUARY);
|
|
break;
|
|
case 1:
|
|
strcpy(month, DTXT_FEBRUARY);
|
|
break;
|
|
case 2:
|
|
strcpy(month, DTXT_MARCH);
|
|
break;
|
|
case 3:
|
|
strcpy(month, DTXT_APRIL);
|
|
break;
|
|
case 4:
|
|
strcpy(month, DTXT_MAY);
|
|
break;
|
|
case 5:
|
|
strcpy(month, DTXT_JUNE);
|
|
break;
|
|
case 6:
|
|
strcpy(month, DTXT_JULY);
|
|
break;
|
|
case 7:
|
|
strcpy(month, DTXT_AUGUST);
|
|
break;
|
|
case 8:
|
|
strcpy(month, DTXT_SEPTEMBER);
|
|
break;
|
|
case 9:
|
|
strcpy(month, DTXT_OCTOBER);
|
|
break;
|
|
case 10:
|
|
strcpy(month, DTXT_NOVEMBER);
|
|
break;
|
|
case 11:
|
|
strcpy(month, DTXT_DECEMBER);
|
|
break;
|
|
}
|
|
|
|
snprintf(timestr, sizeof(timestr), "%s._%s._%d_%d_%02d%02d", day, month, newtime->tm_mday, newtime->tm_year + 1900,
|
|
newtime->tm_hour, newtime->tm_min);
|
|
snprintf(fname, sizeof(fname), "%s_%s_%d_%s%s.stats", root, name, level, (end_of_level) ? DTXT_ENDOFLEVELCONCAT : "",
|
|
timestr);
|
|
|
|
// remove all spaces (convert to _)
|
|
char *p = fname;
|
|
while ((*p)) {
|
|
if (*p == ' ')
|
|
*p = '_';
|
|
p++;
|
|
}
|
|
|
|
// build the path info here
|
|
DLLddio_MakePath(filename, LocalD3Dir, "netgames", fname, NULL);
|
|
}
|
|
|
|
// DMFCBase::IsPlayerObserver
|
|
//
|
|
// Returns true if the given pnum is currently an observer in the game, else returns false.
|
|
// If an invalid pnum is given, then it returns false
|
|
bool DMFCBase::IsPlayerObserver(int pnum) {
|
|
if (!CheckPlayerNum(pnum))
|
|
return false;
|
|
|
|
if (Objects[Players[pnum].objnum].type == OBJ_OBSERVER)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// DMFCBase::EnableOnScreenMenuBackground
|
|
//
|
|
// Enables/disables the onscreen menu background
|
|
void DMFCBase::EnableOnScreenMenuBackground(bool enable) {
|
|
if (enable)
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPMENUBACKGR);
|
|
else
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_DISPMENUBACKGR);
|
|
}
|
|
|
|
// DMFCBase::DisplayNetGameInfo
|
|
//
|
|
// Displays information about the Netgame that is currently being played
|
|
// on to the screen.
|
|
void DMFCBase::DisplayNetGameInfo(int background_bmp, bool dedicated_server) {
|
|
// char server_config_name[PAGENAME_LEN];
|
|
// char connection_name[PAGENAME_LEN];
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
int height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]) + 1;
|
|
// int height = DLLRenderHUDGetTextHeight("X")+1;
|
|
ddgr_color color = GR_RGB(180, 255, 180);
|
|
int x, y;
|
|
y = 0;
|
|
x = 15;
|
|
int w, maxx = 0;
|
|
char fullbuffer[1024];
|
|
|
|
int topy = 0;
|
|
bool peertopeer = (bool)((Netgame->flags & NF_PEER_PEER) != 0);
|
|
bool permissable = (bool)((Netgame->flags & NF_PERMISSABLE) != 0);
|
|
|
|
if ((m_iProtectedFlags & DMFC_PRF_DISPMENUBACKGR) && background_bmp > BAD_BITMAP_HANDLE) {
|
|
// draw the background bitmap
|
|
DLLrend_SetAlphaValue(255 * 0.85f);
|
|
DLLrend_SetZBufferState(0);
|
|
DLLrend_SetTextureType(TT_LINEAR);
|
|
DLLrend_SetLighting(LS_NONE);
|
|
DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE);
|
|
DLLrend_DrawScaledBitmap(0, 0, *Game_window_w, 8 * height, background_bmp, 0, 0, 1, 1, 1.0, -1, NULL);
|
|
DLLrend_SetZBufferState(1);
|
|
}
|
|
|
|
// Print out Title
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_HEADING); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), "%s", DTXT_NGI_HEADING);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_HEADING);
|
|
color = GR_RGB(0, 255, 0);
|
|
topy = y; // save this position
|
|
|
|
// Print out Game name
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_GAMENAME,Netgame->name); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_GAMENAME, Netgame->name);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_GAMENAME, Netgame->name);
|
|
|
|
// Print out Mission name
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_MISSIONNAME,Netgame->mission); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_MISSIONNAME, Netgame->mission);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_MISSIONNAME, Netgame->mission);
|
|
|
|
// Print out Script name
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_SCRIPTNAME,Netgame->scriptname); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_SCRIPTNAME, Netgame->scriptname);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_SCRIPTNAME, Netgame->scriptname);
|
|
|
|
// Print out PPS
|
|
if (GetLocalRole() == LR_SERVER) {
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_PPS,Netgame->packets_per_second); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_PPS, Netgame->packets_per_second);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_PPS, Netgame->packets_per_second);
|
|
} else {
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_PPSSERVER,Netgame->packets_per_second,NetPlayers[GetPlayerNum()].pps);
|
|
// y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_PPSSERVER, Netgame->packets_per_second,
|
|
NetPlayers[GetPlayerNum()].pps);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_PPSSERVER, Netgame->packets_per_second, NetPlayers[GetPlayerNum()].pps);
|
|
}
|
|
|
|
// Print out Max Players
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_MAXPLAYERS,Netgame->max_players); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_MAXPLAYERS, Netgame->max_players);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_MAXPLAYERS, Netgame->max_players);
|
|
|
|
// Accurate Collision Detection
|
|
bool use_acc_weap = (bool)((Netgame->flags & NF_USE_ACC_WEAP) != 0);
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_ACCURATECOLL,(use_acc_weap)?DTXT_MNUON:DTXT_MNUOFF); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_ACCURATECOLL, (use_acc_weap) ? DTXT_MNUON : DTXT_MNUOFF);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
maxx = (w > maxx) ? w : maxx;
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_ACCURATECOLL, (use_acc_weap) ? DTXT_MNUON : DTXT_MNUOFF);
|
|
|
|
// move to second column
|
|
y = topy;
|
|
x += (maxx + 10);
|
|
|
|
// Rotatitional Velocity
|
|
bool rot_vel_sent = (bool)((Netgame->flags & NF_SENDROTVEL) != 0);
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_SENDROTATIONAL,(rot_vel_sent)?DTXT_MNUON:DTXT_MNUOFF); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
snprintf(fullbuffer, sizeof(fullbuffer), DTXT_NGI_SENDROTATIONAL, (rot_vel_sent) ? DTXT_MNUON : DTXT_MNUOFF);
|
|
DLLgrtext_Printf(x, y, fullbuffer);
|
|
w = DLLgrtext_GetTextLineWidth(fullbuffer);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_SENDROTATIONAL, (rot_vel_sent) ? DTXT_MNUON : DTXT_MNUOFF);
|
|
|
|
// Print out time limit
|
|
if (Netgame->flags & NF_TIMER) {
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_TIMELIMIT, Netgame->timelimit,
|
|
(Netgame->timelimit == 1) ? DTXT_MINUTE : DTXT_MINUTES);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_TIMELIMIT, Netgame->timelimit, (Netgame->timelimit == 1) ? DTXT_MINUTE : DTXT_MINUTES);
|
|
|
|
float t_left = 0;
|
|
t_left = (Netgame->timelimit * 60.0f) - RealGametime;
|
|
|
|
// Print out time left
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_TIMELEFT, GetTimeString(t_left));
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_TIMELEFT, GetTimeString(t_left));
|
|
} else {
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_NOTIMELIMIT);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_NOTIMELIMIT);
|
|
}
|
|
|
|
// Print out Goal
|
|
if (Netgame->killgoal > 0) {
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_GOALLIMIT,Netgame->killgoal); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_GOALLIMIT, Netgame->killgoal);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_GOALLIMIT, Netgame->killgoal);
|
|
} else {
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_NOGOAL); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_NOGOAL);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_NOGOAL);
|
|
}
|
|
|
|
// Print out Respawn time
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_RESPAWNTIME,GetTimeString(Netgame->respawn_time)); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_RESPAWNTIME, GetTimeString(Netgame->respawn_time));
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_RESPAWNTIME, GetTimeString(Netgame->respawn_time));
|
|
|
|
// Print out Client/Server Packet Loss
|
|
if ((GetPlayerNum() == 0) || peertopeer) {
|
|
// packet loss info not available
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_PACKETLOSSNA); y+= height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_PACKETLOSSNA);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_PACKETLOSSNA);
|
|
} else {
|
|
float packetloss = NetPlayers[GetPlayerNum()].percent_loss;
|
|
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_PACKETLOSS,packetloss); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_PACKETLOSS, packetloss);
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_PACKETLOSS, packetloss);
|
|
}
|
|
|
|
// Print out Architecture
|
|
// DLLRenderHUDText(color,255,0,x,y,DTXT_NGI_NETWORKMODEL,(peertopeer)?DTXT_PEERTOPEER:DTXT_CLIENTSERVER); y+=height;
|
|
DLLgrtext_SetColor(color);
|
|
DLLgrtext_SetAlpha(255);
|
|
DLLgrtext_Printf(x, y, DTXT_NGI_NETWORKMODEL,
|
|
(peertopeer) ? DTXT_PEERTOPEER : ((permissable) ? DTXT_PERMISSABLE : DTXT_CLIENTSERVER));
|
|
y += height;
|
|
|
|
if (dedicated_server)
|
|
DPrintf(DTXT_NGI_NETWORKMODEL,
|
|
(peertopeer) ? DTXT_PEERTOPEER : ((permissable) ? DTXT_PERMISSABLE : DTXT_CLIENTSERVER));
|
|
}
|
|
|
|
/*
|
|
****************************************************************
|
|
* Registry Database Functions *
|
|
****************************************************************
|
|
*/
|
|
|
|
// DatabaseRegister
|
|
// Registers your multiplayer game with the database. This must be
|
|
// called before any other database function, or they will fail until this
|
|
// is called.
|
|
void DMFCBase::DatabaseRegister(char *name) {
|
|
if (name) {
|
|
strncpy(DatabaseRegisteredName, name, MAX_DBNAME_SIZE - 1);
|
|
DatabaseRegisteredName[MAX_DBNAME_SIZE - 1] = '\0';
|
|
}
|
|
}
|
|
|
|
// DatabaseRead
|
|
// Reads a string from the database
|
|
bool DMFCBase::DatabaseRead(const char *label, char *entry, int *entrylen) {
|
|
if (DatabaseRegisteredName[0] == '\0')
|
|
return false;
|
|
if (!label || !entry || !entrylen)
|
|
return false;
|
|
|
|
int reg_len = strlen(DatabaseRegisteredName);
|
|
int copy = MAX_DBLABEL_SIZE - 1 - reg_len;
|
|
char buffer[MAX_DBLABEL_SIZE];
|
|
|
|
strcpy(buffer, DatabaseRegisteredName);
|
|
strncpy(&buffer[reg_len], label, copy);
|
|
buffer[MAX_DBLABEL_SIZE - 1] = '\0';
|
|
|
|
return DatabaseRead1(buffer, entry, entrylen);
|
|
}
|
|
|
|
// DatabaseRead
|
|
// Reads wordsize bytes from the database
|
|
bool DMFCBase::DatabaseRead(const char *label, void *entry, int wordsize) {
|
|
if (DatabaseRegisteredName[0] == '\0')
|
|
return false;
|
|
if (!label || !entry)
|
|
return false;
|
|
|
|
int reg_len = strlen(DatabaseRegisteredName);
|
|
int copy = MAX_DBLABEL_SIZE - 1 - reg_len;
|
|
char buffer[MAX_DBLABEL_SIZE];
|
|
|
|
strcpy(buffer, DatabaseRegisteredName);
|
|
strncpy(&buffer[reg_len], label, copy);
|
|
buffer[MAX_DBLABEL_SIZE - 1] = '\0';
|
|
|
|
return DatabaseRead2(buffer, entry, wordsize);
|
|
}
|
|
|
|
// DatabaseRead
|
|
// Reads a bool from the database
|
|
bool DMFCBase::DatabaseRead(const char *label, bool *entry) {
|
|
if (DatabaseRegisteredName[0] == '\0')
|
|
return false;
|
|
if (!label || !entry)
|
|
return false;
|
|
|
|
int reg_len = strlen(DatabaseRegisteredName);
|
|
int copy = MAX_DBLABEL_SIZE - 1 - reg_len;
|
|
char buffer[MAX_DBLABEL_SIZE];
|
|
|
|
strcpy(buffer, DatabaseRegisteredName);
|
|
strncpy(&buffer[reg_len], label, copy);
|
|
buffer[MAX_DBLABEL_SIZE - 1] = '\0';
|
|
|
|
return DatabaseRead3(buffer, entry);
|
|
}
|
|
|
|
// DatabaseWrite
|
|
// Writes/Updates a string to the database
|
|
bool DMFCBase::DatabaseWrite(const char *label, const char *entry, int entrylen) {
|
|
if (DatabaseRegisteredName[0] == '\0')
|
|
return false;
|
|
if (!label || !entry)
|
|
return false;
|
|
|
|
int reg_len = strlen(DatabaseRegisteredName);
|
|
int copy = MAX_DBLABEL_SIZE - 1 - reg_len;
|
|
char buffer[MAX_DBLABEL_SIZE];
|
|
|
|
strcpy(buffer, DatabaseRegisteredName);
|
|
strncpy(&buffer[reg_len], label, copy);
|
|
buffer[MAX_DBLABEL_SIZE - 1] = '\0';
|
|
|
|
return DatabaseWrite(buffer, entry, entrylen);
|
|
}
|
|
|
|
// DatabaseWrite
|
|
// Writes/Updates a value to the database
|
|
bool DMFCBase::DatabaseWrite(const char *label, int entry) {
|
|
if (DatabaseRegisteredName[0] == '\0')
|
|
return false;
|
|
if (!label)
|
|
return false;
|
|
|
|
int reg_len = strlen(DatabaseRegisteredName);
|
|
int copy = MAX_DBLABEL_SIZE - 1 - reg_len;
|
|
char buffer[MAX_DBLABEL_SIZE];
|
|
|
|
strcpy(buffer, DatabaseRegisteredName);
|
|
strncpy(&buffer[reg_len], label, copy);
|
|
buffer[MAX_DBLABEL_SIZE - 1] = '\0';
|
|
|
|
return DatabaseWrite(buffer, entry);
|
|
}
|
|
|
|
// CompareNetworkAddress
|
|
//
|
|
// Compare's two network addresses, returns true if they are the same, false if not.
|
|
// use_port: if this is true, than it will consider the port part of the network address
|
|
bool DMFCBase::CompareNetworkAddress(network_address *one, network_address *two, bool use_port) {
|
|
if (use_port) {
|
|
// compare the whole darned thing
|
|
if (!memcmp(one, two, sizeof(network_address)))
|
|
return true;
|
|
else
|
|
return false;
|
|
} else {
|
|
// compare all but the port
|
|
if (!memcmp(one->address, two->address, 6) && !memcmp(one->net_id, two->net_id, 4) &&
|
|
!memcmp(&one->connection_type, &two->connection_type, sizeof(network_protocol))) {
|
|
// looks the same to me
|
|
return true;
|
|
} else {
|
|
// something didn't match
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// IsMasterTrackerGame
|
|
//
|
|
// returns true if this game is being played on the master tracker
|
|
bool DMFCBase::IsMasterTrackerGame(void) { return (bool)((*m_bTrackerGame) != 0); }
|
|
|
|
// ConvertLocalToServerObjnum
|
|
//
|
|
// Given an objnum, it will convert the number from your local objnum to the server's objnum
|
|
// It will return -1 on error
|
|
int DMFCBase::ConvertLocalToServerObjnum(int objnum) {
|
|
if (GetLocalRole() == LR_SERVER)
|
|
return (objnum < 0 || objnum >= MAX_OBJECTS) ? -1 : objnum;
|
|
|
|
if (objnum < 0 || objnum >= MAX_OBJECTS)
|
|
return -1;
|
|
|
|
int s = Local_object_list[objnum];
|
|
|
|
return (s == 65535) ? -1 : s;
|
|
}
|
|
|
|
// ConvertServerToLocalObjnum
|
|
//
|
|
// Given an objnum from the server, this function will convert the objnum to your local objnum
|
|
// It will return -1 on error
|
|
int DMFCBase::ConvertServerToLocalObjnum(int objnum) {
|
|
if (GetLocalRole() == LR_SERVER)
|
|
return (objnum < 0 || objnum >= MAX_OBJECTS) ? -1 : objnum;
|
|
|
|
if (objnum < 0 || objnum >= MAX_OBJECTS)
|
|
return -1;
|
|
|
|
int s = Server_object_list[objnum];
|
|
|
|
return (s == 65535) ? -1 : s;
|
|
}
|
|
|
|
// DMFCBase::AnnounceTeamChangeDeny
|
|
//
|
|
// Tells a player that team change request was denied
|
|
void DMFCBase::AnnounceTeamChangeDeny(int pnum) {
|
|
if (pnum == *Player_num) {
|
|
DLLAddHUDMessage(DTXT_CHANGETEAMDENIED);
|
|
} else {
|
|
if (GetLocalRole() == LR_SERVER) {
|
|
// tell the client the change has been denied
|
|
SendControlMessageToPlayer(pnum, CM_TEAMCHANGEDENIED);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::SetDeathMessageFilter
|
|
//
|
|
// Sets the death message filter
|
|
void DMFCBase::SetDeathMessageFilter(int level) {
|
|
if (level < 0)
|
|
level = 0;
|
|
if (level > 2)
|
|
level = 2;
|
|
|
|
if (level == m_iDeathMessageFilter)
|
|
return;
|
|
|
|
m_iDeathMessageFilter = level;
|
|
switch (level) {
|
|
case DM_FILTER_FULL:
|
|
DLLAddHUDMessage(DTXT_KILLMSGFULL);
|
|
break;
|
|
case DM_FILTER_SIMPLE:
|
|
DLLAddHUDMessage(DTXT_KILLMSGSIMPLE);
|
|
break;
|
|
case DM_FILTER_NONE:
|
|
DLLAddHUDMessage(DTXT_KILLMSGNONE);
|
|
break;
|
|
};
|
|
}
|
|
|
|
// DMFCBase::MakeClientsWait
|
|
//
|
|
// If passed true than all joining clients are forced to wait until they are given the signal to
|
|
// join, either through SignalClientStart() or by passing false to MakeClientsWait
|
|
void DMFCBase::MakeClientsWait(bool wait) {
|
|
m_bMakeClientsWait = wait;
|
|
|
|
if (!wait) {
|
|
// tell all the clients it's time to start
|
|
for (int i = 0; i < DLLMAX_PLAYERS; i++) {
|
|
if (CheckPlayerNum(i)) {
|
|
SignalClientStart(i);
|
|
}
|
|
}
|
|
} else {
|
|
// tell all the clients to hold up
|
|
WaitForServer(true);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::SignalClientStart
|
|
//
|
|
// Given a player num, it tells the client that they can start moving and playing
|
|
void DMFCBase::SignalClientStart(int pnum) {
|
|
if (GetLocalRole() != LR_SERVER) {
|
|
return;
|
|
}
|
|
|
|
SendControlMessageToPlayer(pnum, CM_SIGNALSTART);
|
|
if (pnum == GetPlayerNum())
|
|
WaitForServer(false);
|
|
}
|
|
|
|
// DMFCBase::WaitForServer
|
|
//
|
|
// Call this to start waiting, until the server tells us to stop (by passing false as a parm)
|
|
void DMFCBase::WaitForServer(bool wait) {
|
|
if (wait) {
|
|
Players[GetPlayerNum()].movement_scalar = 0;
|
|
Players[GetPlayerNum()].weapon_recharge_scalar = 99999.9f;
|
|
m_bMakeClientsWait = true;
|
|
} else {
|
|
Players[GetPlayerNum()].movement_scalar = 1.0f;
|
|
Players[GetPlayerNum()].weapon_recharge_scalar = 1.0f;
|
|
m_bMakeClientsWait = false;
|
|
}
|
|
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
|
|
if (!wait)
|
|
return;
|
|
|
|
for (int i = 0; i < DLLMAX_PLAYERS; i++) {
|
|
if (CheckPlayerNum(i)) {
|
|
SendControlMessageToPlayer(i, CM_SIGNALWAIT);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::WaitingForServerLoop
|
|
//
|
|
// Called per frame while waiting for the server to signal go
|
|
void DMFCBase::WaitingForServerLoop(void) {
|
|
static float time_ac = 0;
|
|
static bool show = true;
|
|
|
|
time_ac += *Frametime;
|
|
|
|
if (time_ac > 0.5) {
|
|
time_ac = 0;
|
|
show = !show;
|
|
}
|
|
|
|
if (show) {
|
|
DLLgrtext_SetFont(Game_fonts[MENU_FONT_INDEX]);
|
|
|
|
int height = DLLgrfont_GetHeight(Game_fonts[MENU_FONT_INDEX]);
|
|
|
|
DLLRenderHUDTextFlags(HUDTEXT_CENTERED, GR_WHITE, 255, 0, 0, 240 - (height / 2), DTXT_WAITFORSERVER);
|
|
DLLgrtext_Flush();
|
|
}
|
|
|
|
// Make sure we stay waiting...
|
|
Players[GetPlayerNum()].movement_scalar = 0;
|
|
Players[GetPlayerNum()].weapon_recharge_scalar = 99999.9f;
|
|
}
|
|
|
|
// DMFCBase::IAmDedicatedServer
|
|
//
|
|
// Returns true if we are a dedicated server
|
|
bool DMFCBase::IAmDedicatedServer(void) { return *Dedicated_server; }
|
|
|
|
// DMFCBase::IsPlayerDedicatedServer
|
|
//
|
|
// Returns true if the passed in pnum/player_record is a dedicated server
|
|
bool DMFCBase::IsPlayerDedicatedServer(int pnum) {
|
|
// since we are looking for a server, the pnum must be 0
|
|
if (pnum != 0)
|
|
return false;
|
|
|
|
if (Players[pnum].team == -1)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
bool DMFCBase::IsPlayerDedicatedServer(player_record *pr) {
|
|
if (pr->state == STATE_EMPTY)
|
|
return false;
|
|
|
|
if (pr->state == STATE_DISCONNECTED)
|
|
return (pr->team == -1) ? true : false;
|
|
|
|
return IsPlayerDedicatedServer(pr->pnum);
|
|
}
|
|
|
|
// DMFCBase::GetPlayerTeam
|
|
//
|
|
// Returns the team of the player...call this instead of accessing .team directly
|
|
int DMFCBase::GetPlayerTeam(int pnum) { return (Players[pnum].team == -1) ? 0 : Players[pnum].team; }
|
|
|
|
// DMFCBase::ConvertHUDCoord
|
|
//
|
|
// Given an x,y based on a virtual 640x480 screen, this will convert it to the x,y that should be
|
|
// used based on the current screen size
|
|
void DMFCBase::ConvertHUDCoord(int x, int y, int *rx, int *ry) {
|
|
*rx = ((float)(x) * (*Hud_aspect_x));
|
|
*ry = ((float)(y) * (*Hud_aspect_y));
|
|
}
|
|
|
|
// DMFCBase::GetPlayerLogoBmp
|
|
//
|
|
// Given a player_num, it will return a bitmap handle to that player's ship logo, or
|
|
// -1 if they don't have a logo for their ship.
|
|
// if is_vclip comes back as true, than it is not a bitmap handle, but a handle
|
|
// to a vclip (animated bitmap). It is an index into the DLLGameVClips[].
|
|
int DMFCBase::GetPlayerLogoBmp(int player_num, bool *is_vclip) {
|
|
if (!CheckPlayerNum(player_num))
|
|
return -1; // invalid pnum
|
|
|
|
int texture_handle = Players[player_num].custom_texture_handle;
|
|
|
|
if (GameTextures[texture_handle].bm_handle <= BAD_BITMAP_HANDLE)
|
|
return -1;
|
|
|
|
*is_vclip = (GameTextures[texture_handle].flags & TF_ANIMATED) ? true : false;
|
|
|
|
return GameTextures[texture_handle].bm_handle;
|
|
}
|
|
|
|
// DMFCBase::EnableShipLogos
|
|
//
|
|
// Disables or enables logo displaying for the client
|
|
void DMFCBase::EnableShipLogos(bool enable) {
|
|
if (enable) {
|
|
ENABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_SHIPLOGOSENABLED);
|
|
} else {
|
|
DISABLE_FLAGS(m_iProtectedFlags, DMFC_PRF_SHIPLOGOSENABLED);
|
|
}
|
|
|
|
DLLMultiSetLogoState(enable);
|
|
}
|
|
|
|
// DMFCBase::AreLogosEnabled
|
|
//
|
|
// returns true if ship logos are enabled
|
|
bool DMFCBase::AreLogosEnabled(void) { return (bool)((m_iProtectedFlags & DMFC_PRF_SHIPLOGOSENABLED) != 0); }
|
|
|
|
// DMFCBase::EnableAudioTaunts
|
|
//
|
|
// Disables or enables audio taunts
|
|
void DMFCBase::EnableAudioTaunts(bool enable) { DLLtaunt_Enable(enable); }
|
|
|
|
// DMFCBase::AreTauntsEnabled(void)
|
|
//
|
|
// returns true if audio taunts are enabled
|
|
bool DMFCBase::AreTauntsEnabled(void) { return DLLtaunt_AreEnabled(); }
|
|
|
|
// DMFCBase::RespawnPlayer
|
|
//
|
|
// Takes the given player and respawns his at a random start point (in a team game, team respawn
|
|
// points are taken into consideration, so make sure the player is on the correct team before you
|
|
// respawn him. spew_everything, if false, will override spew_energy_and_shields
|
|
void DMFCBase::RespawnPlayer(int pnum, bool spew_energy_and_shields, bool spew_everything) {
|
|
if (!CheckPlayerNum(pnum))
|
|
return;
|
|
|
|
object *obj = &Objects[Players[pnum].objnum];
|
|
|
|
if (spew_everything)
|
|
DLLPlayerSpewInventory(obj, spew_energy_and_shields, spew_everything);
|
|
|
|
DLLPlayerStopSounds(pnum);
|
|
|
|
DLLInitPlayerNewShip(pnum, (spew_everything) ? INVRESET_ALL : INVRESET_DEATHSPEW);
|
|
|
|
if (pnum != GetPlayerNum())
|
|
return;
|
|
|
|
int slot = DLLPlayerGetRandomStartPosition(pnum);
|
|
|
|
DLLObjSetPos(obj, &Players[slot].start_pos, Players[slot].start_roomnum, &Players[slot].start_orient, false);
|
|
}
|
|
|
|
// If you are going to create submenus you MUST use this function. along with:
|
|
// void SetState(int state);
|
|
// bool SetStateItemList(int count, ... ); for MIT_STATE items
|
|
MenuItem *DMFCBase::CreateMenuItem(const char *title, char type, uint8_t flags, void (*fp)(int), ...) {
|
|
MenuItem *p;
|
|
|
|
if (type != MIT_CUSTOM && type != MIT_STATE) {
|
|
p = new MenuItem(title, type, flags, fp);
|
|
return p;
|
|
} else {
|
|
if (type == MIT_CUSTOM) {
|
|
tCustomMenu cm;
|
|
|
|
va_list marker;
|
|
va_start(marker, fp);
|
|
memcpy(&cm, va_arg(marker, tCustomMenu *), sizeof(tCustomMenu));
|
|
va_end(marker);
|
|
|
|
p = new MenuItem(title, type, flags, fp, &cm);
|
|
return p;
|
|
} else {
|
|
p = new MenuItem(title, type, flags, fp, 0, 0); // set initially to 0 state items
|
|
return p;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ParseHostsFile(char *filename, tHostsNode **root) {
|
|
CFILE *file;
|
|
DLLOpenCFILE(&file, filename, "rt");
|
|
|
|
tHostsNode *curr = *root;
|
|
|
|
if (!file)
|
|
return;
|
|
|
|
char buffer[256];
|
|
char save_buffer[256];
|
|
|
|
char s_ip[16], s_mask[16];
|
|
uint32_t ip_address;
|
|
uint32_t mask;
|
|
char *ptr;
|
|
|
|
while (!DLLcfeof(file)) {
|
|
DLLcf_ReadString(buffer, 256, file);
|
|
|
|
// handle the buffer of data
|
|
ptr = buffer;
|
|
|
|
// parse white space
|
|
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
ptr++;
|
|
strcpy(save_buffer, ptr);
|
|
|
|
if (*ptr) {
|
|
// attempt to parse the dotted ip address (only 0-9,'.' and '*' allowed)
|
|
char *start = ptr;
|
|
|
|
// check to make sure its in a valid form
|
|
|
|
int dot_count = 0;
|
|
while (*ptr) {
|
|
if (*ptr == '.')
|
|
dot_count++;
|
|
if ((*ptr < '0' || *ptr > '9') && *ptr != '*' && *ptr != '.')
|
|
goto error_parse; // invalid character
|
|
ptr++;
|
|
}
|
|
if (dot_count != 3)
|
|
goto error_parse; // not enough dots
|
|
ptr = start;
|
|
|
|
// check the string length, no matter what it shouldn't be more than 15
|
|
if (strlen(ptr) > 15)
|
|
goto error_parse;
|
|
|
|
// break up the string into seperate strings
|
|
while (*ptr) {
|
|
if (*ptr == '.')
|
|
*ptr = '\0';
|
|
ptr++;
|
|
}
|
|
ptr = start;
|
|
|
|
// check to make sure the string length of each string isn't more than 3
|
|
int length, count;
|
|
|
|
for (count = 0; count < 4; count++) {
|
|
length = strlen(ptr);
|
|
if (length > 3 || length == 0)
|
|
goto error_parse;
|
|
|
|
if (length != 1) {
|
|
// make sure it's a pure number
|
|
char *save = ptr;
|
|
while (*ptr) {
|
|
if (!isdigit(*ptr))
|
|
goto error_parse;
|
|
ptr++;
|
|
}
|
|
ptr = save;
|
|
int value = atoi(ptr);
|
|
if (value < 0 || value > 255)
|
|
goto error_parse;
|
|
}
|
|
|
|
ptr += length + 1;
|
|
}
|
|
ptr = start;
|
|
|
|
// Its a valid IP address mask! yeah...*whew* that was fun
|
|
|
|
int value;
|
|
char temp_str[16];
|
|
s_ip[0] = s_mask[0] = '\0';
|
|
|
|
for (count = 0; count < 4; count++) {
|
|
length = strlen(ptr);
|
|
|
|
// Mask
|
|
if (*ptr == '*') {
|
|
value = 0;
|
|
} else {
|
|
value = 255;
|
|
}
|
|
snprintf(temp_str, sizeof(temp_str), "%d", value);
|
|
strcat(s_mask, temp_str);
|
|
if (count != 3)
|
|
strcat(s_mask, ".");
|
|
|
|
// IP Address
|
|
if (*ptr == '*') {
|
|
value = 0;
|
|
} else {
|
|
value = atoi(ptr);
|
|
}
|
|
snprintf(temp_str, sizeof(temp_str), "%d", value);
|
|
strcat(s_ip, temp_str);
|
|
if (count != 3)
|
|
strcat(s_ip, ".");
|
|
|
|
ptr += length + 1;
|
|
}
|
|
|
|
// we now have a valid mask (s_mask) and a valid ip (s_ip)
|
|
mprintf(0, "IP: %s Mask: %s\n", s_ip, s_mask);
|
|
ip_address = DLLnw_GetHostAddressFromNumbers(s_ip);
|
|
mask = DLLnw_GetHostAddressFromNumbers(s_mask);
|
|
|
|
// add the node
|
|
if (!curr) {
|
|
curr = *root = (tHostsNode *)malloc(sizeof(tHostsNode));
|
|
} else {
|
|
curr->next = (tHostsNode *)malloc(sizeof(tHostsNode));
|
|
curr = curr->next;
|
|
}
|
|
if (curr) {
|
|
curr->next = NULL;
|
|
curr->ip = ip_address;
|
|
curr->mask = mask;
|
|
}
|
|
|
|
goto noerror_parse;
|
|
}
|
|
|
|
error_parse:
|
|
mprintf(0, "Error parsing IP Address Mask: %s\n", save_buffer);
|
|
|
|
noerror_parse:;
|
|
}
|
|
|
|
DLLcfclose(file);
|
|
}
|
|
|
|
// DMFCBase::ReadInHostsAllowDeny
|
|
//
|
|
// Reads in the hosts.allow and hosts.deny files (if available)
|
|
void DMFCBase::ReadInHostsAllowDeny(void) {
|
|
char allow_fn[_MAX_PATH], deny_fn[_MAX_PATH];
|
|
bool allow_exist, deny_exist;
|
|
|
|
// build the path info here
|
|
DLLddio_MakePath(allow_fn, LocalD3Dir, "netgames", "hosts.allow", NULL);
|
|
DLLddio_MakePath(deny_fn, LocalD3Dir, "netgames", "hosts.deny", NULL);
|
|
|
|
allow_exist = (bool)(DLLcfexist(allow_fn) != 0);
|
|
deny_exist = (bool)(DLLcfexist(deny_fn) != 0);
|
|
|
|
m_DenyList = NULL;
|
|
m_AllowList = NULL;
|
|
|
|
// parse away
|
|
if (deny_exist) {
|
|
mprintf(0, "Parsing hosts.deny\n");
|
|
ParseHostsFile(deny_fn, &m_DenyList);
|
|
}
|
|
if (allow_exist) {
|
|
mprintf(0, "Parsing hosts.allow\n");
|
|
ParseHostsFile(allow_fn, &m_AllowList);
|
|
}
|
|
}
|
|
|
|
// DMFCBase::FreeHostsLists
|
|
//
|
|
// Frees all the memory allocated for the host allow/deny lists
|
|
void DMFCBase::FreeHostsLists(void) {
|
|
tHostsNode *curr = NULL, *next;
|
|
|
|
curr = m_DenyList;
|
|
while (curr) {
|
|
next = curr->next;
|
|
free(curr);
|
|
curr = next;
|
|
}
|
|
|
|
curr = m_AllowList;
|
|
while (curr) {
|
|
next = curr->next;
|
|
free(curr);
|
|
curr = next;
|
|
}
|
|
}
|
|
|
|
// DMFCBase::RehashAllowDeny
|
|
//
|
|
// Flushes and reloads the hosts.allow/.deny lists
|
|
void DMFCBase::RehashAllowDeny(void) {
|
|
FreeHostsLists();
|
|
ReadInHostsAllowDeny();
|
|
}
|
|
|
|
// DMFCBase::IsPlayerAlive
|
|
//
|
|
// Returns true is the given pnum is a player, flying around the level (not dying, dead or observing)
|
|
bool DMFCBase::IsPlayerAlive(int pnum) {
|
|
if (!CheckPlayerNum(pnum))
|
|
return false;
|
|
|
|
if (Objects[Players[pnum].objnum].type != OBJ_PLAYER)
|
|
return false;
|
|
|
|
if (Players[pnum].flags & (PLAYER_FLAGS_DYING | PLAYER_FLAGS_DEAD))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// DMFCBase::ParseStartupScript
|
|
//
|
|
//
|
|
// Loads up the startup script and sets variables accordingly
|
|
void DMFCBase::ParseStartupScript(void) {
|
|
CFILE *file;
|
|
char path[_MAX_PATH];
|
|
char buffer[256];
|
|
int size;
|
|
bool ok_to_read;
|
|
|
|
int autoexec_arg = -1;
|
|
|
|
if ((autoexec_arg = DLLFindArg("-autoexec")) != 0) {
|
|
// a specific autoexec.dmfc file was specified, use that
|
|
strcpy(path, GetGameArg(autoexec_arg + 1));
|
|
mprintf(0, "Override AUTOEXEC.DMFC to %s\n", path);
|
|
} else {
|
|
// use the default autoexec.dmfc
|
|
DLLddio_MakePath(path, LocalD3Dir, "netgames", "autoexec.dmfc", NULL);
|
|
}
|
|
|
|
DLLOpenCFILE(&file, path, "rt");
|
|
if (!file)
|
|
return;
|
|
|
|
while (!DLLcfeof(file)) {
|
|
ok_to_read = true;
|
|
|
|
size = DLLcf_ReadString(&buffer[1], 254, file);
|
|
buffer[255] = '\0';
|
|
|
|
if (size >= 254) {
|
|
// invalid string, too long..trash the rest of the line
|
|
ok_to_read = false;
|
|
while (size >= 254) {
|
|
size = DLLcf_ReadString(buffer, 254, file);
|
|
}
|
|
}
|
|
|
|
if (!ok_to_read) {
|
|
mprintf(0, "AUTOEXEC.DMFC: Line too long\n");
|
|
} else {
|
|
if (buffer[1] == '$') {
|
|
InputCommandHandle(&buffer[1]);
|
|
} else {
|
|
buffer[0] = '$'; // insert starting $ sign for input command
|
|
InputCommandHandle(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
DLLcfclose(file);
|
|
}
|
|
|
|
dllinfo *DMFCBase::GetDLLInfoCallData(void) { return Data; }
|
|
|
|
int DMFCBase::GetHighestRoomIndex(void) { return *Highest_room_index; }
|
|
|
|
int DMFCBase::GetGameWindowW(void) { return *Game_window_w; }
|
|
|
|
int DMFCBase::GetGameWindowH(void) { return *Game_window_h; }
|
|
|
|
int DMFCBase::GetGameWindowX(void) { return *Game_window_x; }
|
|
|
|
int DMFCBase::GetGameWindowY(void) { return *Game_window_y; }
|
|
|
|
int *DMFCBase::GetGameFontTranslateArray(void) { return Game_fonts; }
|
|
|
|
int DMFCBase::GetObserverModeBitmap(void) { return hBitmapObserver; }
|
|
|
|
float DMFCBase::GetFrametime(void) { return *Frametime; }
|
|
|
|
float DMFCBase::GetGametime(void) { return *Gametime; }
|
|
|
|
float DMFCBase::GetRealGametime(bool *ispaused) {
|
|
if (ispaused) {
|
|
*ispaused = (m_iProtectedFlags & DMFC_PRF_PAUSETIME) ? true : false;
|
|
}
|
|
|
|
return RealGametime;
|
|
}
|
|
|
|
float *DMFCBase::GetShieldDeltaArray(void) { return ShieldDelta; }
|
|
|
|
float DMFCBase::GetHudAspectX(void) { return *Hud_aspect_x; }
|
|
|
|
float DMFCBase::GetHudAspectY(void) { return *Hud_aspect_y; }
|
|
|
|
const char *DMFCBase::GetLocalD3Dir(void) { return LocalD3Dir; }
|
|
|
|
const tMission *DMFCBase::GetCurrentMission(void) { return Current_mission; }
|
|
|
|
room *DMFCBase::GetRooms(void) { return Rooms; }
|
|
|
|
object *DMFCBase::GetObjects(void) { return Objects; }
|
|
|
|
terrain_segment *DMFCBase::GetTerrainSegs(void) { return Terrain_seg; }
|
|
|
|
netgame_info *DMFCBase::GetNetgameInfo(void) { return Netgame; }
|
|
|
|
player *DMFCBase::GetPlayers(void) { return Players; }
|
|
|
|
netplayer *DMFCBase::GetNetPlayers(void) { return NetPlayers; }
|
|
|
|
ship *DMFCBase::GetShips(void) { return Ships; }
|
|
|
|
weapon *DMFCBase::GetWeapons(void) { return Weapons; }
|
|
|
|
texture *DMFCBase::GetGameTextures(void) { return GameTextures; }
|
|
|
|
vclip *DMFCBase::GetGameVClips(void) { return GameVClips; }
|
|
|
|
poly_model *DMFCBase::GetGamePolyModels(void) { return Poly_models; }
|
|
|
|
ddgr_color *DMFCBase::GetPlayerColors(void) { return Player_colors; }
|
|
|
|
game_controls DMFCBase::GetLastGameControls(void) { return Last_game_controls; }
|
|
|
|
int *DMFCBase::GetPilotPicBitmapHandles(void) { return PilotPicBmpHandles; }
|
|
|
|
void DMFCBase::GetViewerObjectPtr(object **v_obj) { *v_obj = *Viewer_object; }
|
|
|
|
void DMFCBase::SetViewerObjectPtr(object *v_obj) { *Viewer_object = v_obj; }
|
|
|
|
float DMFCBase::GetRenderZoom(void) { return *Render_zoom; }
|
|
|
|
IMenuItem *DMFCBase::GetOnScreenMenu(void) { return &Menu; }
|
|
|
|
tOSIRISModuleInit *DMFCBase::GetOsirisModuleData(void) { return API.osiris_functions; }
|
|
|
|
vis_effect *DMFCBase::GetVisEffectArray(int **Highviseptr) {
|
|
if (Highviseptr)
|
|
*Highviseptr = Highest_vis_effect_index;
|
|
|
|
return VisEffects;
|
|
}
|
|
|
|
char *DMFCBase::GetGameArg(int arg) {
|
|
static char EMPTY_ARG[1] = "";
|
|
|
|
ASSERT(arg >= 0 && arg < MAX_ARGS);
|
|
if (arg < 0 || arg >= MAX_ARGS)
|
|
return (char *)EMPTY_ARG;
|
|
|
|
char *arguments = (char *)GameArgs;
|
|
|
|
int position = arg * MAX_CHARS_PER_ARG;
|
|
|
|
return &arguments[position];
|
|
}
|
|
|
|
// DMFCBase::EnableLossGuage
|
|
//
|
|
// Turns on/off the Loss guage on the screen
|
|
void DMFCBase::EnableLossGuage(bool enable) {
|
|
bool peertopeer = (bool)((Netgame->flags & NF_PEER_PEER) != 0);
|
|
|
|
if ((GetLocalRole() == LR_SERVER) || peertopeer) {
|
|
return;
|
|
}
|
|
|
|
LossGuageEnabled = enable;
|
|
}
|
|
|
|
ddgr_color GetTriLinColor(float val, float low, float med, float hi, ddgr_color lowc, ddgr_color medc, ddgr_color hic) {
|
|
ddgr_color low_col, hi_col;
|
|
float perc;
|
|
|
|
if (val <= low) {
|
|
// we're pure lowc
|
|
perc = 1.0f;
|
|
low_col = hi_col = lowc;
|
|
} else if (val <= med) {
|
|
// we're between lowc and medc
|
|
low_col = lowc;
|
|
hi_col = medc;
|
|
|
|
perc = (val - low) / (med - low);
|
|
} else if (val <= hi) {
|
|
// we're between medc and hic
|
|
low_col = medc;
|
|
hi_col = hic;
|
|
perc = (val - med) / (hi - med);
|
|
} else {
|
|
// we're pure hic
|
|
perc = 1.0f;
|
|
low_col = hi_col = hic;
|
|
}
|
|
|
|
if (perc < 0.0f)
|
|
perc = 0.0f;
|
|
if (perc > 1.0f)
|
|
perc = 1.0f;
|
|
|
|
ddgr_color color_to_use;
|
|
int r, g, b;
|
|
float amount_low, amount_hi;
|
|
|
|
amount_low = 1.0 - perc;
|
|
amount_hi = perc;
|
|
|
|
r = GR_COLOR_RED(low_col) * amount_low + GR_COLOR_RED(hi_col) * amount_hi;
|
|
g = GR_COLOR_GREEN(low_col) * amount_low + GR_COLOR_GREEN(hi_col) * amount_hi;
|
|
b = GR_COLOR_BLUE(low_col) * amount_low + GR_COLOR_BLUE(hi_col) * amount_hi;
|
|
|
|
color_to_use = GR_RGB(r, g, b);
|
|
|
|
return color_to_use;
|
|
}
|
|
|
|
// DMFCBase::LossGuageFrame
|
|
//
|
|
// Processes the Loss guage for the frame
|
|
void DMFCBase::LossGuageFrame(void) {
|
|
if (!LossGuageEnabled)
|
|
return;
|
|
|
|
if (GetLocalRole() == LR_SERVER)
|
|
return;
|
|
|
|
// Don't show if peer-to-peer
|
|
if (Netgame->flags & NF_PEER_PEER)
|
|
return;
|
|
|
|
#define LOW_COLOR GR_RGB(20, 255, 20)
|
|
#define MED_COLOR GR_RGB(255, 255, 40)
|
|
#define HI_COLOR GR_RGB(255, 20, 20)
|
|
#define LOW_LOSS 1.0f
|
|
#define MED_LOSS 5.0f
|
|
#define HI_LOSS 10.0f
|
|
|
|
float packetloss = NetPlayers[GetPlayerNum()].percent_loss;
|
|
|
|
ddgr_color loss_color = GetTriLinColor(packetloss, LOW_LOSS, MED_LOSS, HI_LOSS, LOW_COLOR, MED_COLOR, HI_COLOR);
|
|
ddgr_color ping_color =
|
|
GetTriLinColor(NetPlayers[GetPlayerNum()].ping_time * 1000.0f, 0, 200.0f, 400.0f, LOW_COLOR, MED_COLOR, HI_COLOR);
|
|
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
int max_x = 0;
|
|
int y = 2;
|
|
|
|
DLLRenderHUDText(loss_color, 255, 2, 0, y, DTXT_NETWORK_LOSS);
|
|
max_x = DLLRenderHUDGetTextLineWidth(DTXT_NETWORK_LOSS);
|
|
|
|
DLLRenderHUDText(ping_color, 255, 2, 0, y + 10, DTXT_NETWORK_PING);
|
|
max_x = std::max(max_x, DLLRenderHUDGetTextLineWidth(DTXT_NETWORK_PING));
|
|
|
|
max_x += 10;
|
|
DLLRenderHUDText(loss_color, 255, 0, 2 + max_x, y, "%.2f%%", packetloss);
|
|
DLLRenderHUDText(ping_color, 255, 0, 2 + max_x, y + 10, "%dms",
|
|
(int)(NetPlayers[GetPlayerNum()].ping_time * 1000.0f));
|
|
}
|
|
|
|
level_info *DMFCBase::GetLevelInfo(void) { return Level_info; }
|
|
|
|
// 1 - (num_levels)
|
|
void DMFCBase::WarpToLevel(int lev) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
|
|
if (lev < 1 || lev > Current_mission->num_levels)
|
|
return;
|
|
|
|
*Multi_next_level = lev;
|
|
EndLevel();
|
|
}
|
|
|
|
void DMFCBase::SetPlayerTauntIndicator(int pnum) {
|
|
if (!CheckPlayerNum(pnum))
|
|
return;
|
|
|
|
DisplayTauntIndicator = true;
|
|
TauntIndicatorStartTime = *Gametime;
|
|
TauntIndicatorPlayerNum = pnum;
|
|
}
|
|
|
|
void DMFCBase::DisplayTauntIndicatorFrame(void) {
|
|
if (!DisplayTauntIndicator)
|
|
return;
|
|
|
|
if (!CheckPlayerNum(TauntIndicatorPlayerNum)) {
|
|
DisplayTauntIndicator = false;
|
|
return;
|
|
}
|
|
|
|
float alpha, perc;
|
|
int igt = floor((*Gametime));
|
|
float igth = (*Gametime) - igt;
|
|
if (igth > 0.5f) {
|
|
igth -= 0.5f;
|
|
}
|
|
|
|
if (igth > 0.25f) {
|
|
perc = 1.0f - ((igth - 0.25) / 0.25f);
|
|
} else {
|
|
perc = (igth / 0.25f);
|
|
}
|
|
|
|
float base_alpha = 0.40f;
|
|
float range = 1.0f - base_alpha;
|
|
|
|
alpha = base_alpha + (perc * range);
|
|
if (alpha < base_alpha)
|
|
alpha = base_alpha;
|
|
if (alpha > 1.0f)
|
|
alpha = 1.0f;
|
|
|
|
int bmp = TauntIndicatorBMP;
|
|
if (PilotPicBmpHandles[TauntIndicatorPlayerNum] > BAD_BITMAP_HANDLE) {
|
|
bmp = PilotPicBmpHandles[TauntIndicatorPlayerNum];
|
|
}
|
|
|
|
if (bmp <= BAD_BITMAP_HANDLE) {
|
|
DisplayTauntIndicator = false;
|
|
return;
|
|
}
|
|
|
|
int bmh = 32;
|
|
int bmw = 32;
|
|
int x, y;
|
|
|
|
x = 10;
|
|
y = 200;
|
|
|
|
DLLrend_SetAlphaType(AT_CONSTANT_TEXTURE);
|
|
DLLrend_SetAlphaValue(alpha * 255);
|
|
DLLrend_SetLighting(LS_NONE);
|
|
DLLrend_SetColorModel(CM_MONO);
|
|
DLLrend_SetOverlayType(OT_NONE);
|
|
DLLrend_SetFiltering(0);
|
|
DLLrend_SetWrapType(WT_CLAMP);
|
|
DLLrend_SetZBufferState(0);
|
|
DLLrend_SetTextureType(TT_LINEAR);
|
|
|
|
DLLrend_DrawScaledBitmap(x, y, x + bmw, y + bmh, bmp, 0, 0, 1, 1, 1, -1, NULL);
|
|
DLLrend_SetFiltering(1);
|
|
DLLrend_SetZBufferState(1);
|
|
|
|
int font_height;
|
|
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
font_height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]);
|
|
|
|
x = 15 + bmw;
|
|
y = (y + (bmh / 2)) - (font_height / 2);
|
|
|
|
DLLgrtext_SetColor(GR_GREEN);
|
|
DLLgrtext_SetAlpha(alpha * 255.0f);
|
|
DLLgrtext_Printf(x, y, Players[TauntIndicatorPlayerNum].callsign);
|
|
|
|
if ((*Gametime - TauntIndicatorStartTime) > 3.0f)
|
|
DisplayTauntIndicator = false;
|
|
}
|
|
|
|
// DMFCBase::SetMaxPlayerHardLimit
|
|
//
|
|
// Sets a hard limit to the max number of players allowed in the game
|
|
// changing the number of players can never go above this...defaults
|
|
// to DLLMAX_PLAYERS
|
|
void DMFCBase::SetMaxPlayerHardLimit(int max) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return;
|
|
if (max > DLLMAX_PLAYERS || max < 1)
|
|
return;
|
|
|
|
Hard_max_players = max;
|
|
if (Netgame->max_players > Hard_max_players) {
|
|
Netgame->max_players = max;
|
|
DLLAddHUDMessage(DTXT_MAXPLAYERSSETMSG, max);
|
|
SendNetGameInfoSync();
|
|
}
|
|
}
|
|
|
|
// DMFCBase::MarkPlayersInGame
|
|
//
|
|
// Goes through all the player records and marks those that are in the game
|
|
// This is needed because at level end, all clients disconnect, so we lose
|
|
// that information.
|
|
void DMFCBase::MarkPlayersInGame(void) {
|
|
player_record *pr;
|
|
for (int i = 0; i < MAX_PLAYER_RECORDS; i++) {
|
|
pr = GetPlayerRecord(i);
|
|
|
|
if (pr && pr->state == STATE_INGAME) {
|
|
players_in_game[i] = pr->pnum;
|
|
} else {
|
|
players_in_game[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCBase::ResetPlayersInGame
|
|
//
|
|
// Resets the Players-in-game list
|
|
void DMFCBase::ResetPlayersInGame(void) {
|
|
for (int i = 0; i < MAX_PLAYER_RECORDS; i++) {
|
|
players_in_game[i] = -1;
|
|
}
|
|
}
|
|
|
|
// DMFCBase::WasPlayerInGameAtLevelEnd
|
|
//
|
|
// Given a player record it returns true/false whether
|
|
// the player was in the game at the time the level ended.
|
|
int DMFCBase::WasPlayerInGameAtLevelEnd(int prec) {
|
|
if (prec < 0 || prec >= MAX_PLAYER_RECORDS)
|
|
return -1;
|
|
|
|
return players_in_game[prec];
|
|
}
|
|
|
|
// DMFCBase::GetConnectingPlayerTeam
|
|
//
|
|
// Returns the team of a player just connecting, this is to be set by the
|
|
// game and is DMFC assumes that all players have the correct team on join
|
|
int DMFCBase::GetConnectingPlayerTeam(int slot) {
|
|
if (GetLocalRole() != LR_SERVER)
|
|
return -2;
|
|
|
|
int prec_num;
|
|
if (IsMasterTrackerGame())
|
|
prec_num = PRec_FindPlayer(Players[slot].callsign, NULL, Players[slot].tracker_id);
|
|
else
|
|
prec_num = PRec_FindPlayer(Players[slot].callsign, &NetPlayers[slot].addr, NULL);
|
|
|
|
int team = -2;
|
|
|
|
if (prec_num != -1) {
|
|
// we have a reconnecting player
|
|
|
|
// we need to reconnect the player to the player records before we get the team
|
|
if (!PRec_ReconnectPlayerToSlot(slot, prec_num, Players, NetPlayers)) {
|
|
mprintf(0, "Unable to reassign reconnecting player (%s) to Player Record slot #%d\n",
|
|
Players[slot].callsign,
|
|
prec_num);
|
|
Int3();
|
|
} else {
|
|
team = PRec_GetPlayerTeam(slot);
|
|
|
|
// disconnect the player again since he isn't in the game just yet
|
|
PRec_DisconnectPlayer(slot);
|
|
}
|
|
} else {
|
|
// we have a new player
|
|
|
|
if (slot == 0 && IAmDedicatedServer()) {
|
|
team = -1;
|
|
} else {
|
|
// get team assignment
|
|
if (m_iProtectedFlags & DMFC_PRF_AUTOTEAMSELECT) {
|
|
team = GetTeamForNewPlayer(slot, m_iNumTeams);
|
|
} else {
|
|
team = RED_TEAM;
|
|
}
|
|
}
|
|
}
|
|
|
|
mprintf(0, "CONNECTING PLAYER (%s): Team assigned to %d\n", Players[slot].callsign, team);
|
|
|
|
return team;
|
|
}
|
|
|
|
// DMFCBase::SetDedicatedWait
|
|
//
|
|
// Sets the level wait time for the dedicated server. A dedicated server will make all
|
|
// clients wait until this time (in seconds) is up each level.
|
|
void DMFCBase::SetDedicatedWait(float time_secs) {
|
|
if (time_secs < 0)
|
|
time_secs = 0;
|
|
|
|
DedicatedLevelWait = time_secs;
|
|
}
|
|
|
|
// DMFCBase::EnableTimelimitCountdown
|
|
//
|
|
// Enables/Disables the timelimit countdown (if there is a level time limit)
|
|
// Optionally you can specify what time to start the count down. (default 10)
|
|
void DMFCBase::EnableTimelimitCountdown(bool enable, int seconds) {
|
|
m_bDisplayTimelimitCountdown = enable;
|
|
|
|
if (enable && seconds > 0) {
|
|
m_iTimeLimitCountdown = seconds;
|
|
}
|
|
}
|
|
|
|
// DMFCBase::DisplayTimelimitCountdown
|
|
//
|
|
// Displays (if needed) the time limit countdown
|
|
void DMFCBase::DisplayTimelimitCountdown(void) {
|
|
if (!m_bDisplayTimelimitCountdown)
|
|
return;
|
|
|
|
if (!(Netgame->flags & NF_TIMER))
|
|
return;
|
|
|
|
float time_left = (Netgame->timelimit * 60.0f) - RealGametime;
|
|
|
|
if (time_left > m_iTimeLimitCountdown || time_left < 0)
|
|
return;
|
|
|
|
// display a countdown!
|
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
|
DLLgrtext_SetColor(GR_WHITE);
|
|
DLLgrtext_SetAlpha(255);
|
|
|
|
char buffer[256];
|
|
snprintf(buffer, sizeof(buffer), "Time Left: T - %d", (int)time_left);
|
|
|
|
int font_height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]);
|
|
DLLgrtext_CenteredPrintf(0, font_height * 10, buffer);
|
|
}
|
|
|
|
// DMFCBase::TranslateTextMacro
|
|
//
|
|
// Given a macro with tokens, this function will replace the tokens
|
|
// and create a new string for display.
|
|
// All tokens begin with $$ (i.e. $$TEAMBASE)
|
|
void DMFCBase::TranslateTextMacro(const char *src, char *destination, int dest_size) {
|
|
ASSERT(destination != NULL);
|
|
ASSERT(src != NULL);
|
|
ASSERT(dest_size >= 0);
|
|
|
|
if (dest_size <= 0)
|
|
return;
|
|
|
|
char token[128];
|
|
char token_string[512];
|
|
|
|
char *curr_dest = destination;
|
|
int src_idx = 0;
|
|
bool done = false;
|
|
|
|
// now we need to go through the src and copy to destination
|
|
// while looking for tokens, and making sure we don't go over our size
|
|
while (dest_size > 1 && !done) {
|
|
switch (src[src_idx]) {
|
|
case '$': {
|
|
// possible token!, check the next character
|
|
if (src[src_idx + 1] == '$') {
|
|
// TOKEN!!!
|
|
src_idx += 2; // move to the beginning of the token
|
|
if (src[src_idx] == ' ' || src[src_idx] == '\0') {
|
|
// ok, maybe it isn't a token
|
|
*curr_dest = src[src_idx - 2];
|
|
curr_dest++;
|
|
dest_size--;
|
|
*curr_dest = src[src_idx - 1];
|
|
curr_dest++;
|
|
dest_size--;
|
|
*curr_dest = src[src_idx];
|
|
if (*curr_dest == '\0') {
|
|
done = true;
|
|
} else {
|
|
src_idx++;
|
|
}
|
|
curr_dest++;
|
|
dest_size--;
|
|
} else {
|
|
// process it, it's gotta be a token
|
|
|
|
// extract the token out
|
|
char *ptr = token;
|
|
while (src[src_idx] != ' ' && src[src_idx] != '\0') {
|
|
*ptr = src[src_idx];
|
|
ptr++;
|
|
src_idx++;
|
|
}
|
|
*ptr = '\0';
|
|
|
|
// now replace the token...
|
|
*token_string = '\0';
|
|
mprintf(0, "Looking for token for %s\n", token);
|
|
CallOnGetTokenString(token, token_string, 512);
|
|
|
|
// make sure we don't go too far
|
|
int len = strlen(token_string);
|
|
if (len > (dest_size - 1))
|
|
len = dest_size - 1;
|
|
|
|
ptr = token_string;
|
|
|
|
while (len > 0) {
|
|
*curr_dest = *ptr;
|
|
curr_dest++;
|
|
dest_size--;
|
|
ptr++;
|
|
len--;
|
|
}
|
|
}
|
|
} else {
|
|
// just copy the character over
|
|
*curr_dest = src[src_idx];
|
|
src_idx++;
|
|
curr_dest++;
|
|
dest_size--;
|
|
}
|
|
} break;
|
|
case '\0':
|
|
done = true;
|
|
break;
|
|
default: {
|
|
// just copy the character over
|
|
*curr_dest = src[src_idx];
|
|
src_idx++;
|
|
curr_dest++;
|
|
dest_size--;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
*curr_dest = '\0'; // NULL terminate
|
|
}
|
|
|
|
// DMFCBase::SelectNextCameraView
|
|
//
|
|
// This function, given which window (corresponds to left, middle, right), switches the
|
|
// current view of the small camera windows on the screen
|
|
void DMFCBase::SelectNextCameraView(int window) {
|
|
if (window < 0 || window >= NUM_CAMERA_VIEWS)
|
|
return;
|
|
DLLSelectNextCameraView(window);
|
|
}
|
|
|
|
int DMFCBase::GetCameraViewType(int window) {
|
|
if (window < 0 || window >= NUM_CAMERA_VIEWS)
|
|
return -1;
|
|
return Camera_view_mode[window];
|
|
}
|
|
|
|
// Given a generic object (OBJ_POWERUP,OBJ_ROBOT,OBJ_BUILDING or OBJ_CLUTTER) id
|
|
// in the range of 0 to MAX_OBJECT_IDS, this returns a pointer to it's information (see objinfo.h)
|
|
// It returns NULL if an invalid id is given (or it's not used)
|
|
object_info *DMFCBase::GetObjectInfo(int objinfo_id) {
|
|
if (objinfo_id < 0 || objinfo_id >= MAX_OBJECT_IDS)
|
|
return NULL;
|
|
|
|
if (Object_info[objinfo_id].type == OBJ_NONE)
|
|
return NULL;
|
|
|
|
return &Object_info[objinfo_id];
|
|
}
|