Descent3/netgames/dmfc/dmfcbase.cpp
Azamat H. Hackimov 1ae023a13b Enumerate all DLL functions manually
Enumerate DLL functions to ease tying functions in main and DLL sides in code.
2024-07-09 02:08:25 +03:00

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];
}