2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* Player data at runtime */
# include <C4Include.h>
# include <C4Player.h>
# include <C4Application.h>
2011-03-03 16:10:22 +00:00
# include <C4DefList.h>
2009-05-08 13:28:41 +00:00
# include <C4Object.h>
# include <C4ObjectInfo.h>
# include <C4Command.h>
# include <C4League.h>
# include <C4Network2Stats.h>
# include <C4MessageInput.h>
# include <C4GamePadCon.h>
# include <C4Random.h>
# include <C4Log.h>
# include <C4FullScreen.h>
# include <C4GameOverDlg.h>
# include <C4ObjectMenu.h>
2009-06-05 18:00:23 +00:00
# include <C4MouseControl.h>
2009-06-05 18:12:43 +00:00
# include <C4GameMessage.h>
2009-06-12 18:52:21 +00:00
# include <C4GraphicsResource.h>
# include <C4GraphicsSystem.h>
# include <C4Landscape.h>
# include <C4Game.h>
2009-06-12 23:09:32 +00:00
# include <C4PlayerList.h>
2009-06-15 21:47:26 +00:00
# include <C4GameObjects.h>
2009-06-15 22:06:37 +00:00
# include <C4GameControl.h>
2010-09-08 21:49:42 +00:00
# include <C4Viewport.h>
2009-05-08 13:28:41 +00:00
C4Player : : C4Player ( ) : C4PlayerInfoCore ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Default ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Player : : ~ C4Player ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : ObjectInCrew ( C4Object * tobj )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! tobj ) return false ;
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : Crew )
2010-03-27 16:05:02 +00:00
if ( cobj = = tobj ) return true ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ClearPointers ( C4Object * pObj , bool fDeath )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Crew
while ( Crew . Remove ( pObj ) ) { }
2010-03-27 16:05:02 +00:00
// Cursor
if ( Cursor = = pObj )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
// object is to be deleted; do NOT do script calls (like in Cursor->UnSelect(true))
2010-03-27 16:05:02 +00:00
Cursor = NULL ; AdjustCursorCommand ( ) ; // also selects and eventually does a script call!
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// View-Cursor
if ( ViewCursor = = pObj ) ViewCursor = NULL ;
// View
if ( ViewTarget = = pObj ) ViewTarget = NULL ;
2009-05-08 13:28:41 +00:00
// Menu
Menu . ClearPointers ( pObj ) ;
// messageboard-queries
RemoveMessageBoardQuery ( pObj ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : ScenarioAndTeamInit ( int32_t idTeam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4PlayerInfo * pInfo = GetInfo ( ) ;
if ( ! pInfo ) return false ;
C4Team * pTeam ;
if ( idTeam = = TEAMID_New )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// creation of a new team only if allowed by scenario
if ( ! Game . Teams . IsAutoGenerateTeams ( ) )
pTeam = NULL ;
else
2010-03-28 18:58:01 +00:00
{
2010-01-25 04:00:59 +00:00
if ( ( pTeam = Game . Teams . GetGenerateTeamByID ( idTeam ) ) ) idTeam = pTeam - > GetID ( ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// uage of an existing team
2010-03-28 18:58:01 +00:00
pTeam = Game . Teams . GetTeamByID ( idTeam ) ;
}
2009-05-08 13:28:41 +00:00
C4Team * pPrevTeam = Game . Teams . GetTeamByID ( Team ) ;
// check if join to team is possible; e.g. not too many players
if ( pPrevTeam ! = pTeam & & idTeam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Game . Teams . IsJoin2TeamAllowed ( idTeam ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pTeam = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! pTeam & & idTeam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
OnTeamSelectionFailed ( ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// team selection OK; execute it!
if ( pPrevTeam ) pPrevTeam - > RemovePlayerByID ( pInfo - > GetID ( ) ) ;
if ( pTeam ) pTeam - > AddPlayer ( * pInfo , true ) ;
if ( ! ScenarioInit ( ) ) return false ;
2009-08-15 18:50:32 +00:00
if ( ! FinalInit ( false ) ) return false ;
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Execute ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Status ) return ;
// Open/refresh team menu if desired
if ( Status = = PS_TeamSelection )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t idSelectedTeam ;
2010-01-25 04:00:59 +00:00
if ( ( idSelectedTeam = Game . Teams . GetForcedTeamSelection ( ID ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// There's only one team left to join? Join there immediately.
if ( Menu . IsActive ( ) & & Menu . GetIdentification ( ) = = C4MN_TeamSelection ) Menu . TryClose ( false , false ) ;
2009-06-15 22:06:37 +00:00
if ( LocalControl & & ! : : Control . isReplay ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// team selection done through queue because TeamSelection-status may not be in sync (may be TeamSelectionPending!)
DoTeamSelection ( idSelectedTeam ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( ! Menu . IsActive ( ) ) ActivateMenuTeamSelection ( false ) ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// during team selection: Update view to selected team, if it has a position assigned
C4MenuItem * pSelectedTeamItem ;
2010-01-25 04:00:59 +00:00
if ( ( pSelectedTeamItem = Menu . GetSelectedItem ( ) ) )
2010-03-28 18:58:01 +00:00
{
2010-01-25 15:57:57 +00:00
int32_t idSelectedTeam = pSelectedTeamItem - > GetValue ( ) ;
2009-05-08 13:28:41 +00:00
if ( idSelectedTeam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Team * pSelectedTeam ;
2010-01-25 04:00:59 +00:00
if ( ( pSelectedTeam = Game . Teams . GetTeamByID ( idSelectedTeam ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iPlrStartIndex = pSelectedTeam - > GetPlrStartIndex ( ) ;
if ( iPlrStartIndex & & Inside < int32_t > ( iPlrStartIndex , 1 , C4S_MaxPlayer ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Game . C4S . PlrStart [ iPlrStartIndex - 1 ] . Position [ 0 ] > - 1 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// player has selected a team that has a valid start position assigned
// set view to this position!
2009-06-05 15:20:41 +00:00
ViewX = Game . C4S . PlrStart [ iPlrStartIndex - 1 ] . Position [ 0 ] * : : Landscape . MapZoom ;
ViewY = Game . C4S . PlrStart [ iPlrStartIndex - 1 ] . Position [ 1 ] * : : Landscape . MapZoom ;
2009-05-08 13:28:41 +00:00
}
}
}
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( Menu . IsActive ( ) & & Menu . GetIdentification ( ) = = C4MN_TeamSelection )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Menu . TryClose ( false , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Tick1
UpdateView ( ) ;
ExecuteControl ( ) ;
Menu . Execute ( ) ;
2009-06-12 18:52:21 +00:00
// ::Game.iTick35
if ( ! : : Game . iTick35 & & Status = = PS_Normal )
2010-03-28 18:58:01 +00:00
{
2014-04-16 12:06:30 +00:00
ExecBaseProduction ( ) ;
2009-05-08 13:28:41 +00:00
CheckElimination ( ) ;
if ( pMsgBoardQuery & & LocalControl ) ExecMsgBoardQueries ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Delays
if ( MessageStatus > 0 ) MessageStatus - - ;
if ( RetireDelay > 0 ) RetireDelay - - ;
if ( CursorFlash > 0 ) CursorFlash - - ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : Init ( int32_t iNumber , int32_t iAtClient , const char * szAtClientName ,
2011-03-26 22:59:35 +00:00
const char * szFilename , bool fScenarioInit , class C4PlayerInfo * pInfo , C4ValueNumbers * numbers )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! pInfo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
LogF ( " ERROR: Init player %s failed: No info! " , szFilename ) ;
assert ( false ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Status init
2010-03-27 16:05:02 +00:00
Status = PS_Normal ;
2009-05-08 13:28:41 +00:00
Number = iNumber ;
ID = pInfo - > GetID ( ) ;
Team = pInfo - > GetTeam ( ) ;
NoEliminationCheck = pInfo - > IsNoEliminationCheck ( ) ;
// At client
AtClient = iAtClient ; SCopy ( szAtClientName , AtClientName , C4MaxTitle ) ;
2011-01-06 20:18:13 +00:00
if ( szFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Load core & crew info list
2011-08-05 12:58:16 +00:00
if ( ! Load ( szFilename , ! fScenarioInit ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no core file present: Keep defaults
// This can happen for script players only
assert ( pInfo - > GetType ( ) = = C4PT_Script ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Take player name from player info; forcing overloads by the league or because of doubled player names
Name . Copy ( pInfo - > GetName ( ) ) ;
// view pos init: Start at center pos
ViewX = GBackWdt / 2 ; ViewY = GBackHgt / 2 ;
// Scenario init
if ( fScenarioInit )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// mark player join in player info list
// for non-scenarioinit, player should already be marked as joined
pInfo - > SetJoined ( iNumber ) ;
// Number might have changed: Recheck list sorting before scenarioinit, which will do script calls
2009-06-12 23:09:32 +00:00
: : Players . RecheckPlayerSort ( this ) ;
2009-05-08 13:28:41 +00:00
// check for a postponed scenario init, if no team is specified (post-lobby-join in network, or simply non-network)
C4Team * pTeam = NULL ;
if ( Team )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Game . Teams . IsAutoGenerateTeams ( ) )
pTeam = Game . Teams . GetGenerateTeamByID ( Team ) ;
else
pTeam = Game . Teams . GetTeamByID ( Team ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! pTeam & & Game . Teams . IsRuntimeJoinTeamChoice ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pInfo - > GetType ( ) = = C4PT_Script )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// script player without team: This can usually not happen, because RecheckPlayerInfoTeams should have been executed
// just leave this player without the team
assert ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// postponed init: Chose team first
Status = PS_TeamSelection ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Init control method before scenario init, because script callbacks may need to know it!
2011-09-22 18:00:17 +00:00
ClearControl ( ) ;
2009-05-08 13:28:41 +00:00
InitControl ( ) ;
2010-03-26 13:48:28 +00:00
// defaultdisabled controls
Control . Init ( ) ;
2009-05-08 13:28:41 +00:00
// Special: Script players may skip scenario initialization altogether, and just desire a single callback to all objects
// of a given ID
if ( ! pInfo - > IsScenarioInitDesired ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// only initialization that's done anyway is team hostility
if ( Team ) SetTeamHostility ( ) ;
// callback definition passed?
C4ID idCallback = pInfo - > GetScriptPlayerExtraID ( ) ;
C4Def * pDefCallback ;
if ( idCallback & & ( pDefCallback = C4Id2Def ( idCallback ) ) )
2010-03-28 18:58:01 +00:00
{
2011-10-15 00:03:04 +00:00
pDefCallback - > Call ( PSF_InitializeScriptPlayer , & C4AulParSet ( C4VInt ( Number ) , C4VInt ( Team ) ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// player preinit: In case a team needs to be chosen first, no InitializePlayer-broadcast is done
// this callback shall give scripters a chance to do stuff like starting an intro or enabling FoW, which might need to be done
2011-01-08 16:04:20 +00:00
: : GameScript . GRBroadcast ( PSF_PreInitializePlayer , & C4AulParSet ( C4VInt ( Number ) ) ) ;
2009-05-08 13:28:41 +00:00
// direct init
2009-08-15 18:50:32 +00:00
if ( Status ! = PS_TeamSelection ) if ( ! ScenarioInit ( ) ) return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Load runtime data
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pInfo - > IsJoined ( ) ) ;
2011-03-26 22:59:35 +00:00
assert ( numbers ) ;
2009-05-08 13:28:41 +00:00
// (compile using DefaultRuntimeData) - also check if compilation returned sane results, i.e. ID assigned
2011-03-26 22:59:35 +00:00
if ( ! LoadRuntimeData ( Game . ScenarioFile , numbers ) | | ! ID )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// for script players in non-savegames, this is OK - it means they get restored using default values
// this happens when the users saves a scenario using the "Save scenario"-option while a script player
// was joined
if ( ! Game . C4S . Head . SaveGame & & pInfo - > GetType ( ) = = C4PT_Script )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Number = pInfo - > GetInGameNumber ( ) ;
ColorDw = pInfo - > GetColor ( ) ;
ID = pInfo - > GetID ( ) ;
Team = pInfo - > GetTeam ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Reset values default-overriden by old runtime data load (safety?)
if ( Number = = C4P_Number_None ) Number = iNumber ;
if ( szFilename ) SCopy ( Config . AtUserDataPath ( szFilename ) , Filename ) ; else * Filename = ' \0 ' ;
// NET2: Direct joins always send accurate client IDs and names in params
// do not overwrite them with savegame data, because players might as well
// change clients
// (only call should be savegame recreation by C4PlayerInfoList::RecreatePlayers)
AtClient = iAtClient ;
SCopy ( szAtClientName , AtClientName , C4MaxTitle ) ;
// Number might have changed: Recheck list sorting
2009-06-12 23:09:32 +00:00
: : Players . RecheckPlayerSort ( this ) ;
2009-05-08 13:28:41 +00:00
// Init control after loading runtime data, because control init will overwrite some of the values
InitControl ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// store game joining time
GameJoinTime = Game . Time ;
// Init FoW-viewobjects: NO_OWNER-FoW-repellers might need to be added
2014-10-24 20:50:14 +00:00
for ( C4Object * pObj : Objects )
2010-03-28 18:58:01 +00:00
{
2015-01-02 00:06:00 +00:00
if ( ( pObj - > lightRange | | pObj - > lightFadeoutRange ) & & pObj - > Owner = = NO_OWNER )
pObj - > UpdateLight ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// init graphs
if ( Game . pNetworkStatistics ) CreateGraphs ( ) ;
2015-08-28 01:44:23 +00:00
// init sound mod
2015-12-02 15:38:22 +00:00
SetSoundModifier ( SoundModifier . getPropList ( ) ) ;
2015-08-28 01:44:23 +00:00
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : Save ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Group hGroup ;
2009-05-08 13:28:41 +00:00
// Regular player saving need not be done for script players
2009-08-15 18:50:32 +00:00
if ( GetType ( ) = = C4PT_Script ) return false ;
2009-05-08 13:28:41 +00:00
// Log
LogF ( LoadResStr ( " IDS_PRC_SAVEPLR " ) , Config . AtRelativePath ( Filename ) ) ;
2009-06-05 15:14:20 +00:00
: : GraphicsSystem . MessageBoard . EnsureLastMessage ( ) ;
2009-05-08 13:28:41 +00:00
// copy player to save somewhere else
2010-03-27 16:05:02 +00:00
char szPath [ _MAX_PATH + 1 ] ;
SCopy ( Config . AtTempPath ( C4CFN_TempPlayer ) , szPath , _MAX_PATH ) ;
MakeTempFilename ( szPath ) ;
2011-08-15 09:25:37 +00:00
// For local players, we save over the old player file, as there might
// be all kinds of non-essential stuff in it. For non-local players, we
// just re-create it every time (it's temporary anyway).
if ( LocalControl )
{
// But make sure to copy it first so full hard (flgr stupid) disks
// won't corrupt any player files...
C4Group_CopyItem ( Filename , szPath ) ;
}
else
{
// For non-local players, we can actually use the loaded definition
// list to strip out all non-existant definitions. This is only valid
// because we know the file to be temporary.
CrewInfoList . Strip ( : : Definitions ) ;
}
2009-05-08 13:28:41 +00:00
// Open group
2010-03-27 16:05:02 +00:00
if ( ! hGroup . Open ( szPath , true ) )
return false ;
2009-05-08 13:28:41 +00:00
// Save
if ( ! Save ( hGroup , false , ! LocalControl ) )
2010-03-27 16:05:02 +00:00
{ hGroup . Close ( ) ; return false ; }
2009-05-08 13:28:41 +00:00
// Close group
2010-03-27 16:05:02 +00:00
if ( ! hGroup . Close ( ) ) return false ;
// resource
2009-06-05 15:19:46 +00:00
C4Network2Res : : Ref pRes = : : Network . ResList . getRefRes ( Filename ) ,
2010-03-28 18:58:01 +00:00
pDRes = NULL ;
2010-03-27 16:05:02 +00:00
bool fOfficial = pRes & & : : Control . isCtrlHost ( ) ;
2010-03-28 18:58:01 +00:00
if ( pRes ) pDRes = pRes - > Derive ( ) ;
2009-05-08 13:28:41 +00:00
// move back
if ( ItemExists ( Filename ) ) EraseItem ( Filename ) ;
2010-03-27 16:05:02 +00:00
if ( ! C4Group_MoveItem ( szPath , Filename ) ) return false ;
// finish update
2010-03-28 18:58:01 +00:00
if ( pDRes & & fOfficial ) pDRes - > FinishDerive ( ) ;
2009-05-08 13:28:41 +00:00
// Success
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : Save ( C4Group & hGroup , bool fSavegame , bool fStoreTiny )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Save core
2010-03-27 16:05:02 +00:00
if ( ! C4PlayerInfoCore : : Save ( hGroup ) )
return false ;
2009-05-08 13:28:41 +00:00
// Save crew
2009-06-05 16:46:37 +00:00
C4DefList * pDefs = & : : Definitions ;
2009-05-08 13:28:41 +00:00
if ( ! CrewInfoList . Save ( hGroup , fSavegame , fStoreTiny , pDefs ) )
2010-03-27 16:05:02 +00:00
{ hGroup . Close ( ) ; return false ; }
2009-05-08 13:28:41 +00:00
// Sort
hGroup . Sort ( C4FLS_Player ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : PlaceReadyCrew ( int32_t tx1 , int32_t tx2 , int32_t ty , C4Object * FirstBase )
2010-03-28 18:58:01 +00:00
{
2013-01-13 14:45:01 +00:00
int32_t cnt , ctx , cty ;
2010-03-27 16:05:02 +00:00
C4Object * nobj ;
C4ObjectInfo * pInfo ;
C4Def * pDef ;
2009-05-08 13:28:41 +00:00
2013-01-13 14:45:01 +00:00
// Place crew
int32_t iCount ;
C4ID id ;
for ( cnt = 0 ; ( id = Game . C4S . PlrStart [ PlrStartIndex ] . ReadyCrew . GetID ( cnt , & iCount ) ) ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2013-01-13 14:45:01 +00:00
// Minimum one clonk if empty id
2015-11-15 12:53:01 +00:00
iCount = std : : max < int32_t > ( iCount , 1 ) ;
2013-01-13 14:45:01 +00:00
for ( int32_t cnt2 = 0 ; cnt2 < iCount ; cnt2 + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Select member from home crew, add new if necessary
2013-01-13 14:45:01 +00:00
while ( ! ( pInfo = CrewInfoList . GetIdle ( id , : : Definitions ) ) )
if ( ! CrewInfoList . New ( id , & : : Definitions ) )
2009-05-08 13:28:41 +00:00
break ;
2013-01-13 14:45:01 +00:00
// Safety
2009-05-08 13:28:41 +00:00
if ( ! pInfo | | ! ( pDef = C4Id2Def ( pInfo - > id ) ) ) continue ;
2013-01-13 14:45:01 +00:00
// Crew placement location
2009-05-08 13:28:41 +00:00
ctx = tx1 + Random ( tx2 - tx1 ) ; cty = ty ;
if ( ! Game . C4S . PlrStart [ PlrStartIndex ] . EnforcePosition )
FindSolidGround ( ctx , cty , pDef - > Shape . Wdt * 3 ) ;
// Create object
2010-01-25 04:00:59 +00:00
if ( ( nobj = Game . CreateInfoObject ( pInfo , Number , ctx , cty ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Add object to crew
2013-01-13 14:45:51 +00:00
Crew . Add ( nobj , C4ObjectList : : stNone ) ;
2009-05-08 13:28:41 +00:00
// add visibility range
2015-01-02 00:06:00 +00:00
nobj - > SetLightRange ( C4FOW_DefLightRangeX , C4FOW_DefLightFadeoutRangeX ) ;
2009-05-08 13:28:41 +00:00
// If base is present, enter base
if ( FirstBase ) { nobj - > Enter ( FirstBase ) ; nobj - > SetCommand ( C4CMD_Exit ) ; }
// OnJoinCrew callback
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# if !defined(DEBUGREC_RECRUITMENT)
2013-01-13 14:45:01 +00:00
C4DebugRecOff DbgRecOff ;
2009-05-08 13:28:41 +00:00
# endif
2013-01-13 14:45:01 +00:00
C4AulParSet parset ( C4VInt ( Number ) ) ;
nobj - > Call ( PSF_OnJoinCrew , & parset ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : PlaceReadyBase ( int32_t & tx , int32_t & ty , C4Object * * pFirstBase )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cnt , cnt2 , ctx , cty ;
C4Def * def ;
C4ID cid ;
2011-01-02 23:03:28 +00:00
C4Object * cbase ;
2010-03-27 16:05:02 +00:00
// Create ready base structures
for ( cnt = 0 ; ( cid = Game . C4S . PlrStart [ PlrStartIndex ] . ReadyBase . GetID ( cnt ) ) ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ( def = C4Id2Def ( cid ) ) )
for ( cnt2 = 0 ; cnt2 < Game . C4S . PlrStart [ PlrStartIndex ] . ReadyBase . GetCount ( cnt ) ; cnt2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
ctx = tx ; cty = ty ;
2009-05-08 13:28:41 +00:00
if ( Game . C4S . PlrStart [ PlrStartIndex ] . EnforcePosition
2010-12-27 19:15:55 +00:00
| | FindConSiteSpot ( ctx , cty , def - > Shape . Wdt , def - > Shape . Hgt , def - > GetPlane ( ) , 20 ) )
2010-03-27 16:05:02 +00:00
if ( ( cbase = Game . CreateObjectConstruction ( C4Id2Def ( cid ) , NULL , Number , ctx , cty , FullCon , true ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// FirstBase
2010-03-27 16:05:02 +00:00
if ( ! ( * pFirstBase ) ) if ( ( cbase - > Def - > Entrance . Wdt > 0 ) & & ( cbase - > Def - > Entrance . Hgt > 0 ) )
2010-03-28 18:58:01 +00:00
{ * pFirstBase = cbase ; tx = ( * pFirstBase ) - > GetX ( ) ; ty = ( * pFirstBase ) - > GetY ( ) ; }
}
}
}
}
2009-05-08 13:28:41 +00:00
void C4Player : : PlaceReadyVehic ( int32_t tx1 , int32_t tx2 , int32_t ty , C4Object * FirstBase )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cnt , cnt2 , ctx , cty ;
C4Def * def ; C4ID cid ; C4Object * cobj ;
for ( cnt = 0 ; ( cid = Game . C4S . PlrStart [ PlrStartIndex ] . ReadyVehic . GetID ( cnt ) ) ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ( def = C4Id2Def ( cid ) ) )
for ( cnt2 = 0 ; cnt2 < Game . C4S . PlrStart [ PlrStartIndex ] . ReadyVehic . GetCount ( cnt ) ; cnt2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
ctx = tx1 + Random ( tx2 - tx1 ) ; cty = ty ;
2009-05-08 13:28:41 +00:00
if ( ! Game . C4S . PlrStart [ PlrStartIndex ] . EnforcePosition )
FindLevelGround ( ctx , cty , def - > Shape . Wdt , 6 ) ;
2010-03-27 16:05:02 +00:00
if ( ( cobj = Game . CreateObject ( cid , NULL , Number , ctx , cty ) ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( FirstBase ) // First base overrides target location
{ cobj - > Enter ( FirstBase ) ; cobj - > SetCommand ( C4CMD_Exit ) ; }
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : PlaceReadyMaterial ( int32_t tx1 , int32_t tx2 , int32_t ty , C4Object * FirstBase )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cnt , cnt2 , ctx , cty ;
C4Def * def ; C4ID cid ;
// In base
if ( FirstBase )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
FirstBase - > CreateContentsByList ( Game . C4S . PlrStart [ PlrStartIndex ] . ReadyMaterial ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Outside
else
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
for ( cnt = 0 ; ( cid = Game . C4S . PlrStart [ PlrStartIndex ] . ReadyMaterial . GetID ( cnt ) ) ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ( def = C4Id2Def ( cid ) ) )
for ( cnt2 = 0 ; cnt2 < Game . C4S . PlrStart [ PlrStartIndex ] . ReadyMaterial . GetCount ( cnt ) ; cnt2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
ctx = tx1 + Random ( tx2 - tx1 ) ; cty = ty ;
2009-05-08 13:28:41 +00:00
if ( ! Game . C4S . PlrStart [ PlrStartIndex ] . EnforcePosition )
FindSolidGround ( ctx , cty , def - > Shape . Wdt ) ;
2010-03-27 16:05:02 +00:00
Game . CreateObject ( cid , NULL , Number , ctx , cty ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : ScenarioInit ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t ptx , pty ;
2009-05-08 13:28:41 +00:00
// player start index by team, if specified. Otherwise by player number
PlrStartIndex = Number % C4S_MaxPlayer ;
C4Team * pTeam ; int32_t i ;
2010-01-25 04:00:59 +00:00
if ( Team & & ( pTeam = Game . Teams . GetTeamByID ( Team ) ) ) if ( ( i = pTeam - > GetPlrStartIndex ( ) ) ) PlrStartIndex = i - 1 ;
2009-05-08 13:28:41 +00:00
C4PlayerInfo * pInfo = GetInfo ( ) ;
2009-08-15 18:50:32 +00:00
if ( ! pInfo ) { assert ( false ) ; LogF ( " Internal error: ScenarioInit for ghost player %s! " , GetName ( ) ) ; return false ; }
2009-05-08 13:28:41 +00:00
// set color by player info class
// re-setting, because runtime team choice may have altered color
ColorDw = pInfo - > GetColor ( ) ;
// any team selection is over now
Status = PS_Normal ;
2010-03-27 16:05:02 +00:00
// Wealth, home base materials, abilities
Wealth = Game . C4S . PlrStart [ PlrStartIndex ] . Wealth . Evaluate ( ) ;
2014-04-16 12:06:30 +00:00
BaseMaterial = Game . C4S . PlrStart [ PlrStartIndex ] . BaseMaterial ;
BaseMaterial . ConsolidateValids ( : : Definitions ) ;
BaseProduction = Game . C4S . PlrStart [ PlrStartIndex ] . BaseProduction ;
BaseProduction . ConsolidateValids ( : : Definitions ) ;
2010-03-27 16:05:02 +00:00
Knowledge = Game . C4S . PlrStart [ PlrStartIndex ] . BuildKnowledge ;
Knowledge . ConsolidateValids ( : : Definitions ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Starting position
ptx = Game . C4S . PlrStart [ PlrStartIndex ] . Position [ 0 ] ;
pty = Game . C4S . PlrStart [ PlrStartIndex ] . Position [ 1 ] ;
2009-05-08 13:28:41 +00:00
// Zoomed position
2015-02-12 22:05:55 +00:00
if ( ptx > - 1 ) ptx = Clamp < int32_t > ( ptx * Game . C4S . Landscape . MapZoom . Evaluate ( ) , 0 , GBackWdt - 1 ) ;
if ( pty > - 1 ) pty = Clamp < int32_t > ( pty * Game . C4S . Landscape . MapZoom . Evaluate ( ) , 0 , GBackHgt - 1 ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Standard position (PrefPosition)
if ( ptx < 0 )
if ( Game . StartupPlayerCount > = 2 )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t iMaxPos = Game . StartupPlayerCount ;
// Map preferred position to available positions
2015-02-12 22:05:55 +00:00
int32_t iStartPos = Clamp ( PrefPosition * iMaxPos / C4P_MaxPosition , 0 , iMaxPos - 1 ) ;
2010-03-27 16:05:02 +00:00
int32_t iPosition = iStartPos ;
// Distribute according to availability
while ( : : Players . PositionTaken ( iPosition ) )
2014-04-15 12:58:54 +00:00
{
+ + iPosition ;
iPosition % = iMaxPos ;
if ( iPosition = = iStartPos )
break ;
}
2009-05-08 13:28:41 +00:00
Position = iPosition ;
2010-03-27 16:05:02 +00:00
// Set x position
2015-02-12 22:05:55 +00:00
ptx = Clamp ( 16 + Position * ( GBackWdt - 32 ) / ( iMaxPos - 1 ) , 0 , GBackWdt - 16 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// All-random position
if ( ptx < 0 ) ptx = 16 + Random ( GBackWdt - 32 ) ;
if ( pty < 0 ) pty = 16 + Random ( GBackHgt - 32 ) ;
2009-05-08 13:28:41 +00:00
// Place to solid ground
if ( ! Game . C4S . PlrStart [ PlrStartIndex ] . EnforcePosition )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Use nearest above-ground...
FindSolidGround ( ptx , pty , 30 ) ;
// Might have hit a small lake, or similar: Seach a real site spot from here
2010-12-27 19:15:55 +00:00
FindConSiteSpot ( ptx , pty , 30 , 50 , C4Plane_Structure , 400 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Place Readies
2009-05-08 13:28:41 +00:00
C4Object * FirstBase = NULL ;
PlaceReadyBase ( ptx , pty , & FirstBase ) ;
PlaceReadyMaterial ( ptx - 10 , ptx + 10 , pty , FirstBase ) ;
PlaceReadyVehic ( ptx - 30 , ptx + 30 , pty , FirstBase ) ;
2010-03-27 16:05:02 +00:00
PlaceReadyCrew ( ptx - 30 , ptx + 30 , pty , FirstBase ) ;
2009-05-08 13:28:41 +00:00
// set initial hostility by team info
if ( Team ) SetTeamHostility ( ) ;
// Scenario script initialization
2011-01-08 16:04:20 +00:00
: : GameScript . GRBroadcast ( PSF_InitializePlayer , & C4AulParSet ( C4VInt ( Number ) ,
2010-03-28 18:58:01 +00:00
C4VInt ( ptx ) ,
C4VInt ( pty ) ,
C4VObj ( FirstBase ) ,
C4VInt ( Team ) ,
2011-02-05 22:09:09 +00:00
C4VPropList ( C4Id2Def ( GetInfo ( ) - > GetScriptPlayerExtraID ( ) ) ) ) ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-04-21 19:12:49 +00:00
bool C4Player : : FinalInit ( bool fInitialScore )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! Status ) return true ;
2009-05-08 13:28:41 +00:00
// Init player's mouse control
if ( LocalControl )
if ( MouseControl )
2009-06-05 15:20:07 +00:00
: : MouseControl . Init ( Number ) ;
2009-05-08 13:28:41 +00:00
2010-04-21 19:12:49 +00:00
// Set initial score
if ( fInitialScore )
{
InitialScore = CurrentScore ;
}
2009-05-08 13:28:41 +00:00
// Cursor
if ( ! Cursor ) AdjustCursorCommand ( ) ;
2010-04-21 19:12:49 +00:00
// Update counts, pointers, views
2010-03-27 16:05:02 +00:00
Execute ( ) ;
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : SetFoW ( bool fEnable )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set flag
2014-12-29 22:09:31 +00:00
fFogOfWar = fEnable ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : DoWealth ( int32_t iChange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( LocalControl )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( iChange > 0 ) StartSoundEffect ( " Cash " ) ;
if ( iChange < 0 ) StartSoundEffect ( " UnCash " ) ;
2010-03-28 18:58:01 +00:00
}
2009-12-15 19:30:00 +00:00
SetWealth ( Wealth + iChange ) ;
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-12-15 19:30:00 +00:00
bool C4Player : : SetWealth ( int32_t iVal )
2010-03-28 18:58:01 +00:00
{
if ( iVal = = Wealth ) return true ;
2009-12-15 19:30:00 +00:00
2015-02-12 22:05:55 +00:00
Wealth = Clamp < int32_t > ( iVal , 0 , 10000 ) ;
2009-12-15 19:30:00 +00:00
2011-01-08 16:04:20 +00:00
: : GameScript . GRBroadcast ( PSF_OnWealthChanged , & C4AulParSet ( C4VInt ( Number ) ) ) ;
2009-12-15 19:30:00 +00:00
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : SetViewMode ( int32_t iMode , C4Object * pTarget )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safe back
2010-03-27 16:05:02 +00:00
ViewMode = iMode ; ViewTarget = pTarget ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ResetCursorView ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// reset view to cursor if any cursor exists
if ( ! ViewCursor & & ! Cursor ) return ;
SetViewMode ( C4PVM_Cursor ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Evaluate ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do not evaluate twice
if ( Evaluated ) return ;
2010-03-27 16:05:02 +00:00
const int32_t SuccessBonus = 100 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Set last round
LastRound . Title = Game . ScenarioTitle ;
time ( reinterpret_cast < time_t * > ( & LastRound . Date ) ) ;
LastRound . Duration = Game . Time ;
LastRound . Won = ! Eliminated ;
2009-06-15 21:47:26 +00:00
// Melee: personal value gain score ...check ::Objects(C4D_Goal)
2015-11-15 12:53:01 +00:00
if ( Game . C4S . Game . IsMelee ( ) ) LastRound . Score = std : : max < int32_t > ( CurrentScore - InitialScore , 0 ) ;
2009-05-08 13:28:41 +00:00
// Cooperative: shared score
2015-11-15 12:53:01 +00:00
else LastRound . Score = std : : max ( : : Players . AverageScoreGain ( ) , 0 ) ;
2009-05-08 13:28:41 +00:00
LastRound . Level = 0 ; // unknown...
LastRound . Bonus = SuccessBonus * LastRound . Won ;
LastRound . FinalScore = LastRound . Score + LastRound . Bonus ;
2010-04-21 19:12:49 +00:00
LastRound . TotalScore = TotalScore + LastRound . FinalScore ;
2009-05-08 13:28:41 +00:00
// Update player
2010-03-27 16:05:02 +00:00
Rounds + + ;
if ( LastRound . Won ) RoundsWon + + ; else RoundsLost + + ;
2010-04-21 19:12:49 +00:00
TotalScore = LastRound . TotalScore ;
2010-03-27 16:05:02 +00:00
TotalPlayingTime + = Game . Time - GameJoinTime ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Crew
2009-05-08 13:28:41 +00:00
CrewInfoList . Evaluate ( ) ;
// league
if ( Game . Parameters . isLeague ( ) )
2010-03-27 16:05:02 +00:00
EvaluateLeague ( false , Game . GameOver & & ! Eliminated ) ;
2009-05-08 13:28:41 +00:00
// Player is now evaluated
Evaluated = true ;
// round results
Game . RoundResults . EvaluatePlayer ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Surrender ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Surrendered ) return ;
2010-03-27 16:05:02 +00:00
Surrendered = true ;
Eliminated = true ;
2009-05-08 13:28:41 +00:00
RetireDelay = C4RetireDelay ;
2010-03-27 16:05:02 +00:00
StartSoundEffect ( " Eliminated " ) ;
2009-05-08 13:28:41 +00:00
Log ( FormatString ( LoadResStr ( " IDS_PRC_PLRSURRENDERED " ) , GetName ( ) ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-01-25 15:57:57 +00:00
bool C4Player : : SetHostility ( int32_t iOpponent , int32_t hostile , bool fSilent )
2010-03-28 18:58:01 +00:00
{
2010-01-25 15:57:57 +00:00
assert ( hostile = = 0 | | hostile = = 1 ) ;
2009-05-08 13:28:41 +00:00
// Check opponent valid
2010-01-25 15:57:57 +00:00
C4Player * opponent = : : Players . Get ( iOpponent ) ;
if ( ! opponent | | opponent = = this )
return false ;
2009-05-08 13:28:41 +00:00
// Set hostility
2010-01-25 15:57:57 +00:00
if ( hostile )
Hostility . insert ( opponent ) ;
else
Hostility . erase ( opponent ) ;
2009-05-08 13:28:41 +00:00
// no announce in first frame, or if specified
2009-08-15 18:50:32 +00:00
if ( ! Game . FrameCounter | | fSilent ) return true ;
2009-05-08 13:28:41 +00:00
// Announce
StartSoundEffect ( " Trumpet " ) ;
2010-01-25 15:57:57 +00:00
Log ( FormatString ( LoadResStr ( hostile ? " IDS_PLR_HOSTILITY " : " IDS_PLR_NOHOSTILITY " ) ,
2010-03-28 18:58:01 +00:00
GetName ( ) , opponent - > GetName ( ) ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
// Success
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-01-25 15:57:57 +00:00
bool C4Player : : IsHostileTowards ( const C4Player * plr ) const
{
assert ( plr ) ;
if ( ! plr ) return false ;
return Hostility . find ( plr ) ! = Hostility . end ( ) ;
}
2010-07-30 20:38:21 +00:00
C4Object * C4Player : : GetHiExpActiveCrew ( )
2010-03-28 18:58:01 +00:00
{
2014-10-24 20:50:14 +00:00
C4Object * hiexp = NULL ;
2009-05-08 13:28:41 +00:00
int32_t iHighestExp = - 2 , iExp ;
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : Crew )
{
2009-05-08 13:28:41 +00:00
if ( ! cobj - > CrewDisabled )
2010-07-30 20:38:21 +00:00
{
if ( cobj - > Info ) iExp = cobj - > Info - > Experience ; else iExp = - 1 ;
if ( ! hiexp | | ( iExp > iHighestExp ) )
2010-03-28 18:58:01 +00:00
{
2010-07-30 20:38:21 +00:00
hiexp = cobj ;
iHighestExp = iExp ;
2010-03-28 18:58:01 +00:00
}
2010-07-30 20:38:21 +00:00
}
2014-10-24 20:50:14 +00:00
}
2009-05-08 13:28:41 +00:00
return hiexp ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-07-30 20:38:21 +00:00
C4Object * C4Player : : GetHiRankActiveCrew ( )
2010-03-28 18:58:01 +00:00
{
2014-10-24 20:50:14 +00:00
C4Object * hirank = NULL ;
2009-05-08 13:28:41 +00:00
int32_t iHighestRank = - 2 , iRank ;
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : Crew )
{
2009-05-08 13:28:41 +00:00
if ( ! cobj - > CrewDisabled )
2010-07-30 20:38:21 +00:00
{
if ( cobj - > Info ) iRank = cobj - > Info - > Rank ; else iRank = - 1 ;
if ( ! hirank | | ( iRank > iHighestRank ) )
2010-03-28 18:58:01 +00:00
{
2010-07-30 20:38:21 +00:00
hirank = cobj ;
iHighestRank = iRank ;
2010-03-28 18:58:01 +00:00
}
2010-07-30 20:38:21 +00:00
}
2014-10-24 20:50:14 +00:00
}
2009-05-08 13:28:41 +00:00
return hirank ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CheckCrewExPromotion ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Object * hirank ;
2010-07-30 20:38:21 +00:00
if ( ( hirank = GetHiRankActiveCrew ( ) ) )
2009-05-08 13:28:41 +00:00
if ( hirank - > Info )
2010-09-09 20:38:18 +00:00
if ( hirank - > Info - > Rank < 1 ) // No Fähnrich -> except. promo.
2010-07-30 20:38:21 +00:00
if ( ( hirank = GetHiExpActiveCrew ( ) ) )
2009-08-15 18:50:32 +00:00
hirank - > Promote ( 1 , true , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : SetTeamHostility ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// team only
if ( ! Team ) return ;
// set hostilities
2009-06-12 23:09:32 +00:00
for ( C4Player * pPlr = : : Players . First ; pPlr ; pPlr = pPlr - > Next )
2009-05-08 13:28:41 +00:00
if ( pPlr ! = this )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
bool fHostile = ( pPlr - > Team ! = Team ) ;
SetHostility ( pPlr - > Number , fHostile , true ) ;
pPlr - > SetHostility ( Number , fHostile , true ) ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : Message ( const char * szMsg )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( ! szMsg ) return false ;
2009-05-08 13:28:41 +00:00
SCopy ( szMsg , MessageBuf , 256 ) ;
MessageStatus = SLen ( szMsg ) * 2 ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ClearGraphs ( ) ;
Crew . Clear ( ) ;
CrewInfoList . Clear ( ) ;
Menu . Clear ( ) ;
BigIcon . Clear ( ) ;
2015-08-28 01:44:23 +00:00
SetSoundModifier ( NULL ) ;
2009-05-08 13:28:41 +00:00
fFogOfWar = true ;
while ( pMsgBoardQuery )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4MessageBoardQuery * pNext = pMsgBoardQuery - > pNext ;
delete pMsgBoardQuery ;
pMsgBoardQuery = pNext ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( pGamepad ) delete pGamepad ;
pGamepad = NULL ;
Status = 0 ;
2009-10-16 21:07:43 +00:00
ClearControl ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Default ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Filename [ 0 ] = 0 ;
2009-10-14 16:46:22 +00:00
Number = C4P_Number_None ;
2009-05-08 13:28:41 +00:00
ID = 0 ;
Team = 0 ;
DefaultRuntimeData ( ) ;
Menu . Default ( ) ;
Crew . Default ( ) ;
CrewInfoList . Default ( ) ;
2009-08-15 18:50:32 +00:00
LocalControl = false ;
2009-05-08 13:28:41 +00:00
BigIcon . Default ( ) ;
Next = NULL ;
2014-12-29 22:09:31 +00:00
fFogOfWar = true ;
2009-08-15 18:50:32 +00:00
LeagueEvaluated = false ;
2009-05-08 13:28:41 +00:00
GameJoinTime = 0 ; // overwritten in Init
pstatControls = pstatActions = NULL ;
ControlCount = ActionCount = 0 ;
LastControlType = PCID_None ;
LastControlID = 0 ;
pMsgBoardQuery = NULL ;
pGamepad = NULL ;
NoEliminationCheck = false ;
Evaluated = false ;
2010-09-08 21:49:42 +00:00
ZoomLimitMinWdt = ZoomLimitMinHgt = ZoomLimitMaxWdt = ZoomLimitMaxHgt = ZoomWdt = ZoomHgt = 0 ;
2014-04-21 17:38:05 +00:00
ZoomLimitMinVal = ZoomLimitMaxVal = ZoomVal = Fix0 ;
2013-05-23 16:33:24 +00:00
ViewLock = true ;
2015-08-28 01:44:23 +00:00
SoundModifier . Set0 ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-08-05 12:58:16 +00:00
bool C4Player : : Load ( const char * szFilename , bool fSavegame )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Group hGroup ;
// Open group
2011-01-06 20:18:13 +00:00
if ( ! Reloc . Open ( hGroup , szFilename ) ) return false ;
2011-03-12 12:55:05 +00:00
// Remember filename
SCopy ( hGroup . GetFullName ( ) . getData ( ) , Filename , _MAX_PATH ) ;
2009-05-08 13:28:41 +00:00
// Load core
2010-03-27 16:05:02 +00:00
if ( ! C4PlayerInfoCore : : Load ( hGroup ) )
2009-08-15 18:50:32 +00:00
{ hGroup . Close ( ) ; return false ; }
2009-05-08 13:28:41 +00:00
// Load BigIcon
2015-09-19 01:10:39 +00:00
if ( hGroup . FindEntry ( C4CFN_BigIcon ) ) BigIcon . Load ( hGroup , C4CFN_BigIcon , C4FCT_Full , C4FCT_Full , false , 0 ) ;
2010-03-27 16:05:02 +00:00
// Load crew info list
2011-08-05 12:58:16 +00:00
CrewInfoList . Load ( hGroup ) ;
2009-05-08 13:28:41 +00:00
// Close group
hGroup . Close ( ) ;
// Success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : Strip ( const char * szFilename , bool fAggressive )
2010-03-28 18:58:01 +00:00
{
2012-01-29 02:17:11 +00:00
// Open group
2009-05-08 13:28:41 +00:00
C4Group Grp ;
2010-03-28 18:58:01 +00:00
if ( ! Grp . Open ( szFilename ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Which type of stripping?
2010-03-28 18:58:01 +00:00
if ( ! fAggressive )
{
2009-05-08 13:28:41 +00:00
// remove bigicon, if the file size is too large
size_t iBigIconSize = 0 ;
if ( Grp . FindEntry ( C4CFN_BigIcon , NULL , & iBigIconSize ) )
if ( iBigIconSize > C4NetResMaxBigicon * 1024 )
Grp . Delete ( C4CFN_BigIcon ) ;
Grp . Close ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Load info core and crew info list
C4PlayerInfoCore PlrInfoCore ;
C4ObjectInfoList CrewInfoList ;
2011-08-05 12:58:16 +00:00
if ( ! PlrInfoCore . Load ( Grp ) | | ! CrewInfoList . Load ( Grp ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Strip crew info list (remove object infos that are invalid for this scenario)
2009-06-05 16:46:37 +00:00
CrewInfoList . Strip ( : : Definitions ) ;
2009-05-08 13:28:41 +00:00
// Create a new group that receives the bare essentials
Grp . Close ( ) ;
2010-03-28 18:58:01 +00:00
if ( ! EraseItem ( szFilename ) | |
! Grp . Open ( szFilename , true ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Save info core & crew info list to newly-created file
2010-03-28 18:58:01 +00:00
if ( ! PlrInfoCore . Save ( Grp ) | | ! CrewInfoList . Save ( Grp , true , true , & : : Definitions ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
Grp . Close ( ) ;
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
void C4Player : : DrawHostility ( C4Facet & cgo , int32_t iIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Player * pPlr ;
2010-01-25 04:00:59 +00:00
if ( ( pPlr = : : Players . GetByIndex ( iIndex ) ) )
2010-03-28 18:58:01 +00:00
{
2010-02-22 17:35:51 +00:00
: : GraphicsResource . fctCrewClr . DrawClr ( cgo , true , pPlr - > ColorDw ) ;
2009-05-08 13:28:41 +00:00
// Other player and hostile
if ( pPlr ! = this )
2010-01-25 15:57:57 +00:00
if ( Hostility . find ( pPlr ) ! = Hostility . end ( ) )
2009-06-05 15:19:15 +00:00
: : GraphicsResource . fctMenu . GetPhase ( 7 ) . Draw ( cgo ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : MakeCrewMember ( C4Object * pObj , bool fForceInfo , bool fDoCalls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4ObjectInfo * cInf = NULL ;
2009-08-15 18:50:32 +00:00
if ( ! pObj | | ! pObj - > Def - > CrewMember | | ! pObj - > Status ) return false ;
2009-05-08 13:28:41 +00:00
// only if info is not yet assigned
if ( ! pObj - > Info & & fForceInfo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Find crew info by name
if ( pObj - > nInfo )
cInf = CrewInfoList . GetIdle ( pObj - > nInfo . getData ( ) ) ;
// Find crew info by id
if ( ! cInf )
2009-06-05 16:46:37 +00:00
while ( ! ( cInf = CrewInfoList . GetIdle ( pObj - > id , : : Definitions ) ) )
if ( ! CrewInfoList . New ( pObj - > id , & : : Definitions ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Set object info
pObj - > Info = cInf ;
2009-04-03 19:06:29 +00:00
pObj - > SetName ( cInf - > Name ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Add to crew
if ( ! Crew . GetLink ( pObj ) )
2013-01-13 14:45:51 +00:00
Crew . Add ( pObj , C4ObjectList : : stNone ) ;
2009-05-08 13:28:41 +00:00
2015-01-02 00:06:00 +00:00
// add light
if ( ! pObj - > lightRange )
pObj - > SetLightRange ( C4FOW_DefLightRangeX , C4FOW_DefLightFadeoutRangeX ) ;
else
pObj - > UpdateLight ( ) ;
2009-05-08 13:28:41 +00:00
// controlled by the player
pObj - > Controller = Number ;
// OnJoinCrew callback
if ( fDoCalls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4AulParSet parset ( C4VInt ( Number ) ) ;
pObj - > Call ( PSF_OnJoinCrew , & parset ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ExecuteControl ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Control . Execute ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : AdjustCursorCommand ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Reset view
ResetCursorView ( ) ;
2010-07-30 20:38:21 +00:00
// Default cursor to hirank clonk
if ( ! Cursor | | Cursor - > CrewDisabled )
2009-05-08 13:28:41 +00:00
{
2010-07-30 20:38:21 +00:00
C4Object * pHiRank = GetHiRankActiveCrew ( ) ;
if ( ! pHiRank )
return ;
2010-07-31 16:38:23 +00:00
SetCursor ( pHiRank , true ) ;
2009-05-08 13:28:41 +00:00
UpdateView ( ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : ObjectCommand ( int32_t iCommand , C4Object * pTarget , int32_t iX , int32_t iY , C4Object * pTarget2 , C4Value iData , int32_t iMode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Eliminated
2010-03-27 16:05:02 +00:00
if ( Eliminated ) return false ;
// Hide startup
if ( ShowStartup ) ShowStartup = false ;
2009-05-08 13:28:41 +00:00
// Always apply to cursor, even if it's not in the crew
2010-07-30 20:38:21 +00:00
if ( Cursor & & Cursor - > Status & & Cursor ! = pTarget )
ObjectCommand2Obj ( Cursor , iCommand , pTarget , iX , iY , pTarget2 , iData , iMode ) ;
2009-05-08 13:28:41 +00:00
// Success
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-07-20 20:42:38 +00:00
void C4Player : : ObjectCommand2Obj ( C4Object * cObj , int32_t iCommand , C4Object * pTarget , int32_t iX , int32_t iY , C4Object * pTarget2 , C4Value iData , int32_t iMode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// forward to object
2009-08-15 18:50:32 +00:00
if ( iMode & C4P_Command_Append ) cObj - > AddCommand ( iCommand , pTarget , iX , iY , 0 , pTarget2 , true , iData , true , 0 , NULL , C4CMD_Mode_Base ) ; // append: by Shift-click and for dragging of multiple objects (all independant; thus C4CMD_Mode_Base)
else if ( iMode & C4P_Command_Add ) cObj - > AddCommand ( iCommand , pTarget , iX , iY , 0 , pTarget2 , true , iData , false , 0 , NULL , C4CMD_Mode_Base ) ; // append: by context menu and keyboard throw command (all independant; thus C4CMD_Mode_Base)
else if ( iMode & C4P_Command_Set ) cObj - > SetCommand ( iCommand , pTarget , iX , iY , pTarget2 , true , iData ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-03-26 22:59:35 +00:00
void C4Player : : CompileFunc ( StdCompiler * pComp , C4ValueNumbers * numbers )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( ID ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingAdapt ( Status , " Status " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( AtClient , " AtClient " , C4ClientIDUnknown ) ) ;
pComp - > Value ( mkNamingAdapt ( toC4CStr ( AtClientName ) , " AtClientName " , " Local " ) ) ;
pComp - > Value ( mkNamingAdapt ( Number , " Index " , C4P_Number_None ) ) ;
pComp - > Value ( mkNamingAdapt ( ID , " ID " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Eliminated , " Eliminated " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Surrendered , " Surrendered " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Evaluated , " Evaluated " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( ColorDw , " ColorDw " , 0u ) ) ;
pComp - > Value ( mkNamingAdapt ( Position , " Position " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ViewMode , " ViewMode " , C4PVM_Cursor ) ) ;
pComp - > Value ( mkNamingAdapt ( ViewX , " ViewX " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ViewY , " ViewY " , 0 ) ) ;
2013-05-23 23:03:29 +00:00
pComp - > Value ( mkNamingAdapt ( ViewLock , " ViewLock " , true ) ) ;
2010-09-08 21:49:42 +00:00
pComp - > Value ( mkNamingAdapt ( ZoomLimitMinWdt , " ZoomLimitMinWdt " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomLimitMinHgt , " ZoomLimitMinHgt " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomLimitMaxWdt , " ZoomLimitMaxWdt " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomLimitMaxHgt , " ZoomLimitMaxHgt " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomWdt , " ZoomWdt " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomHgt , " ZoomHgt " , 0 ) ) ;
2014-04-21 17:38:05 +00:00
pComp - > Value ( mkNamingAdapt ( ZoomLimitMinVal , " ZoomLimitMinVal " , Fix0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomLimitMaxVal , " ZoomLimitMaxVal " , Fix0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ZoomVal , " ZoomVal " , Fix0 ) ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingAdapt ( fFogOfWar , " FogOfWar " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( ShowStartup , " ShowStartup " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( Wealth , " Wealth " , 0 ) ) ;
2010-04-21 19:12:49 +00:00
pComp - > Value ( mkNamingAdapt ( CurrentScore , " Score " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( InitialScore , " InitialScore " , 0 ) ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingAdapt ( ObjectsOwned , " ObjectsOwned " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Hostility , " Hostile " ) ) ;
pComp - > Value ( mkNamingAdapt ( ProductionDelay , " ProductionDelay " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( ProductionUnit , " ProductionUnit " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( CursorFlash , " CursorFlash " , 0 ) ) ;
2010-03-30 21:08:15 +00:00
pComp - > Value ( mkNamingAdapt ( Cursor , " Cursor " , C4ObjectPtr : : Null ) ) ;
pComp - > Value ( mkNamingAdapt ( ViewCursor , " ViewCursor " , C4ObjectPtr : : Null ) ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingAdapt ( MessageStatus , " MessageStatus " , 0 ) ) ;
2010-03-30 21:08:15 +00:00
pComp - > Value ( mkNamingAdapt ( toC4CStr ( MessageBuf ) , " MessageBuf " , " " ) ) ;
2014-04-16 12:06:30 +00:00
pComp - > Value ( mkNamingAdapt ( BaseMaterial , " BaseMaterial " ) ) ;
pComp - > Value ( mkNamingAdapt ( BaseProduction , " BaseProduction " ) ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingAdapt ( Knowledge , " Knowledge " ) ) ;
2011-03-26 22:59:35 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( Crew , numbers ) , " Crew " ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( CrewInfoList . iNumCreated , " CrewCreated " , 0 ) ) ;
2009-10-14 16:46:22 +00:00
pComp - > Value ( mkNamingPtrAdapt ( pMsgBoardQuery , " MsgBoardQueries " ) ) ;
2015-08-28 01:44:23 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( SoundModifier , numbers ) , " SoundModifier " , C4Value ( ) ) ) ;
2015-12-02 15:38:22 +00:00
if ( pComp - > isCompiler ( ) )
{
SoundModifier . Denumerate ( numbers ) ;
}
2009-06-16 00:38:39 +00:00
// Keys held down
pComp - > Value ( Control ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-03-26 22:59:35 +00:00
bool C4Player : : LoadRuntimeData ( C4Group & hGroup , C4ValueNumbers * numbers )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const char * pSource ;
// Use loaded game text component
2009-08-15 18:50:32 +00:00
if ( ! ( pSource = Game . GameText . GetData ( ) ) ) return false ;
2011-09-22 18:00:17 +00:00
// safety: Do nothing if player section is not even present (could kill initialized values)
2009-08-15 18:50:32 +00:00
if ( ! SSearch ( pSource , FormatString ( " [Player%i] " , ID ) . getData ( ) ) ) return false ;
2009-05-08 13:28:41 +00:00
// Compile (Search player section - runtime data is stored by unique player ID)
2009-06-16 00:38:39 +00:00
// Always compile exact. Exact data will not be present for savegame load, so it does not matter
2009-05-08 13:28:41 +00:00
assert ( ID ) ;
2010-03-28 18:58:01 +00:00
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > (
2011-03-26 22:59:35 +00:00
mkNamingAdapt ( mkParAdapt ( * this , numbers ) , FormatString ( " Player%i " , ID ) . getData ( ) ) ,
2010-03-28 18:58:01 +00:00
StdStrBuf ( pSource ) ,
Game . GameText . GetFilePath ( ) ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Denumerate pointers
DenumeratePointers ( ) ;
// Success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-04-16 12:06:30 +00:00
void C4Player : : ExecBaseProduction ( )
2010-03-28 18:58:01 +00:00
{
2014-04-16 12:06:30 +00:00
const int32_t MaxBaseProduction = 25 ;
2010-03-27 16:05:02 +00:00
ProductionDelay + + ;
if ( ProductionDelay > = 60 ) // Minute Production Unit
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
ProductionDelay = 0 ; ProductionUnit + + ;
2014-04-16 12:06:30 +00:00
for ( int32_t cnt = 0 ; BaseProduction . GetID ( cnt ) ; cnt + + )
if ( BaseProduction . GetCount ( cnt ) > 0 )
2015-02-12 22:05:55 +00:00
if ( ProductionUnit % Clamp < int32_t > ( 11 - BaseProduction . GetCount ( cnt ) , 1 , 10 ) = = 0 )
2014-04-16 12:06:30 +00:00
if ( BaseMaterial . GetIDCount ( BaseProduction . GetID ( cnt ) ) < MaxBaseProduction )
BaseMaterial . IncreaseIDCount ( BaseProduction . GetID ( cnt ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CheckElimination ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Standard elimination: no crew
2015-01-25 15:16:06 +00:00
if ( ! Crew . GetFirstObject ( ) )
2009-05-08 13:28:41 +00:00
// Already eliminated safety
if ( ! Eliminated )
// No automatic elimination desired?
if ( ! NoEliminationCheck )
// Do elimination!
Eliminate ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : UpdateView ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// view target/cursor
2010-03-27 16:05:02 +00:00
switch ( ViewMode )
2010-03-28 18:58:01 +00:00
{
case C4PVM_Cursor :
{
C4Object * pViewObj ;
if ( ! ( pViewObj = ViewCursor ) ) pViewObj = Cursor ;
if ( pViewObj )
2010-03-27 16:05:02 +00:00
{
2010-03-28 18:58:01 +00:00
ViewX = pViewObj - > GetX ( ) ; ViewY = pViewObj - > GetY ( ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
case C4PVM_Target :
if ( ViewTarget )
{
ViewX = ViewTarget - > GetX ( ) ; ViewY = ViewTarget - > GetY ( ) ;
}
break ;
case C4PVM_Scrolling :
break ;
}
}
2009-05-08 13:28:41 +00:00
void C4Player : : DefaultRuntimeData ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Status = 0 ;
2009-10-14 16:46:22 +00:00
Eliminated = 0 ;
Surrendered = 0 ;
2009-05-08 13:28:41 +00:00
AtClient = C4ClientIDUnknown ;
SCopy ( " Local " , AtClientName ) ;
2009-10-14 16:46:22 +00:00
ControlSet = NULL ;
ControlSetName . Clear ( ) ;
2009-08-15 18:50:32 +00:00
MouseControl = false ;
2009-10-14 16:46:22 +00:00
Position = - 1 ;
2009-05-08 13:28:41 +00:00
PlrStartIndex = 0 ;
RetireDelay = 0 ;
2009-10-14 16:46:22 +00:00
ViewMode = C4PVM_Cursor ;
ViewX = ViewY = 0 ;
ViewTarget = NULL ;
ShowStartup = true ;
2009-05-08 13:28:41 +00:00
Wealth = 0 ;
2010-04-21 19:12:49 +00:00
CurrentScore = InitialScore = 0 ;
2009-10-14 16:46:22 +00:00
ObjectsOwned = 0 ;
2009-05-08 13:28:41 +00:00
ProductionDelay = ProductionUnit = 0 ;
Cursor = ViewCursor = NULL ;
2010-07-30 20:38:21 +00:00
CursorFlash = 30 ;
2009-05-08 13:28:41 +00:00
MessageStatus = 0 ;
MessageBuf [ 0 ] = 0 ;
2010-01-25 15:57:57 +00:00
Hostility . clear ( ) ;
2014-04-16 12:06:30 +00:00
BaseMaterial . Default ( ) ;
BaseProduction . Default ( ) ;
2009-10-14 16:46:22 +00:00
Knowledge . Default ( ) ;
2009-05-08 13:28:41 +00:00
FlashCom = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : ActivateMenuTeamSelection ( bool fFromMain )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Menu symbol/init
bool fSwitch = ! ( Status = = PS_TeamSelection ) ;
Menu . InitRefSym ( C4GUI : : Icon : : GetIconFacet ( C4GUI : : Ico_Team ) , LoadResStr ( " IDS_MSG_SELTEAM " ) , Number , C4MN_Extra_None , 0 , fSwitch ? C4MN_TeamSwitch : C4MN_TeamSelection ) ;
Menu . SetAlignment ( fSwitch ? C4MN_Align_Left | C4MN_Align_Bottom : 0 ) ;
Menu . Refill ( ) ;
// Go back to options menu on close
if ( fFromMain ) Menu . SetCloseCommand ( " ActivateMenu:Main " ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : DoTeamSelection ( int32_t idTeam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// stop team selection. This might close the menu forever if the control gets lost
// let's hope it doesn't!
Status = PS_TeamSelectionPending ;
2013-09-02 20:22:29 +00:00
: : Control . DoInput ( CID_PlrAction , C4ControlPlayerAction : : InitScenarioPlayer ( this , idTeam ) , CDT_Queue ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : DenumeratePointers ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Crew
2011-09-19 19:02:28 +00:00
Crew . DenumeratePointers ( ) ;
2009-05-08 13:28:41 +00:00
// Cursor
2010-03-30 21:08:15 +00:00
Cursor . DenumeratePointers ( ) ;
2009-05-08 13:28:41 +00:00
// ViewCursor
2010-03-30 21:08:15 +00:00
ViewCursor . DenumeratePointers ( ) ;
2009-05-08 13:28:41 +00:00
// messageboard-queries
for ( C4MessageBoardQuery * pCheck = pMsgBoardQuery ; pCheck ; pCheck = pCheck - > pNext )
2010-03-30 21:08:15 +00:00
pCheck - > CallbackObj . DenumeratePointers ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : RemoveCrewObjects ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Object * pCrew ;
2009-05-08 13:28:41 +00:00
// Remove all crew objects
2010-01-25 04:00:59 +00:00
while ( ( pCrew = Crew . GetObject ( ) ) ) pCrew - > AssignRemoval ( true ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-04-01 20:06:43 +00:00
int32_t C4Player : : FindNewOwner ( ) const
{
int32_t iNewOwner = NO_OWNER ;
C4Team * pTeam ;
if ( Team ) if ( ( pTeam = Game . Teams . GetTeamByID ( Team ) ) )
{
for ( int32_t i = 0 ; i < pTeam - > GetPlayerCount ( ) ; + + i )
{
int32_t iPlrID = pTeam - > GetIndexedPlayer ( i ) ;
if ( iPlrID & & iPlrID ! = ID )
{
C4PlayerInfo * pPlrInfo = Game . PlayerInfos . GetPlayerInfoByID ( iPlrID ) ;
if ( pPlrInfo ) if ( pPlrInfo - > IsJoined ( ) )
{
// this looks like a good new owner
iNewOwner = pPlrInfo - > GetInGameNumber ( ) ;
break ;
}
}
}
}
// if noone from the same team was found, try to find another non-hostile player
// (necessary for cooperative rounds without teams)
if ( iNewOwner = = NO_OWNER )
for ( C4Player * pOtherPlr = : : Players . First ; pOtherPlr ; pOtherPlr = pOtherPlr - > Next )
if ( pOtherPlr ! = this ) if ( ! pOtherPlr - > Eliminated )
if ( ! : : Players . Hostile ( pOtherPlr - > Number , Number ) )
iNewOwner = pOtherPlr - > Number ;
return iNewOwner ;
}
2009-05-08 13:28:41 +00:00
void C4Player : : NotifyOwnedObjects ( )
2010-03-28 18:58:01 +00:00
{
2012-04-01 20:06:43 +00:00
int32_t iNewOwner = FindNewOwner ( ) ;
2009-05-08 13:28:41 +00:00
// notify objects in all object lists
2009-06-15 21:47:26 +00:00
for ( C4ObjectList * pList = & : : Objects ; pList ; pList = ( ( pList = = & : : Objects ) ? & : : Objects . InactiveObjects : NULL ) )
2012-04-01 20:06:43 +00:00
{
2014-10-24 20:50:14 +00:00
for ( C4Object * cobj : * pList )
2012-04-01 20:06:43 +00:00
{
if ( cobj - > Status & & cobj - > Owner = = Number )
{
C4AulFunc * pFn = cobj - > GetFunc ( PSF_OnOwnerRemoved ) ;
if ( pFn )
2010-03-28 18:58:01 +00:00
{
2013-03-02 22:38:29 +00:00
C4AulParSet pars ( C4VInt ( iNewOwner ) ) ;
pFn - > Exec ( cobj , & pars ) ;
2010-03-28 18:58:01 +00:00
}
2012-04-01 20:06:43 +00:00
else
{
// crew members: Those are removed later (AFTER the player has been removed, for backwards compatiblity with relaunch scripting)
if ( Crew . IsContained ( cobj ) )
continue ;
// Regular objects: Try to find a new, suitable owner from the same team
2013-03-02 22:38:29 +00:00
// Ignore StaticBack, because this would not be compatible with many internal objects such as team account
2015-05-25 14:17:58 +00:00
if ( ( cobj - > Category & C4D_StaticBack ) = = 0 )
2012-04-01 20:06:43 +00:00
cobj - > SetOwner ( iNewOwner ) ;
}
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-04-21 19:12:49 +00:00
bool C4Player : : DoScore ( int32_t iChange )
2010-03-28 18:58:01 +00:00
{
2015-02-12 22:05:55 +00:00
CurrentScore = Clamp < int32_t > ( CurrentScore + iChange , - 100000 , 100000 ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-07-30 20:38:21 +00:00
void C4Player : : SetCursor ( C4Object * pObj , bool fSelectArrow )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check disabled
if ( pObj ) if ( pObj - > CrewDisabled ) return ;
bool fChanged = pObj ! = Cursor ;
C4Object * pPrev = Cursor ;
// Set cursor
2010-03-27 16:05:02 +00:00
Cursor = pObj ;
2009-05-08 13:28:41 +00:00
// unselect previous
2010-07-30 20:38:21 +00:00
if ( pPrev & & fChanged ) pPrev - > UnSelect ( ) ;
2009-05-08 13:28:41 +00:00
// Select object
2010-07-31 16:38:23 +00:00
if ( fChanged & & Cursor ) { Cursor - > DoSelect ( ) ; }
2009-05-08 13:28:41 +00:00
// View flash
2010-03-27 16:05:02 +00:00
if ( fSelectArrow ) CursorFlash = 30 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-09-24 17:52:20 +00:00
void C4Player : : ScrollView ( float iX , float iY , float ViewWdt , float ViewHgt )
2010-03-28 18:58:01 +00:00
{
2010-09-08 21:49:42 +00:00
if ( ViewLock ) return ;
2009-05-08 13:28:41 +00:00
SetViewMode ( C4PVM_Scrolling ) ;
2010-09-28 18:16:33 +00:00
float ViewportScrollBorder = Application . isEditor ? 0 : C4ViewportScrollBorder ;
2015-02-12 22:05:55 +00:00
ViewX = Clamp < C4Real > ( ViewX + ftofix ( iX ) , ftofix ( ViewWdt / 2.0f - ViewportScrollBorder ) , ftofix ( GBackWdt + ViewportScrollBorder - ViewWdt / 2.0f ) ) ;
ViewY = Clamp < C4Real > ( ViewY + ftofix ( iY ) , ftofix ( ViewHgt / 2.0f - ViewportScrollBorder ) , ftofix ( GBackHgt + ViewportScrollBorder - ViewHgt / 2.0f ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-10-16 21:07:43 +00:00
void C4Player : : ClearControl ( )
2009-10-13 20:02:44 +00:00
{
2009-10-16 21:07:43 +00:00
// Mark any control set as unused
Control . Clear ( ) ;
2009-10-14 16:46:22 +00:00
// Reset control
2009-10-16 21:07:43 +00:00
LocalControl = false ;
2009-10-14 16:46:22 +00:00
ControlSetName . Clear ( ) ;
ControlSet = NULL ;
2009-05-08 13:28:41 +00:00
if ( pGamepad ) { delete pGamepad ; pGamepad = NULL ; }
2009-10-14 16:46:22 +00:00
MouseControl = false ;
2009-05-08 13:28:41 +00:00
// no controls issued yet
ControlCount = ActionCount = 0 ;
LastControlType = PCID_None ;
LastControlID = 0 ;
2009-10-16 21:07:43 +00:00
}
void C4Player : : InitControl ( )
{
// Check local control
if ( AtClient = = : : Control . ClientID ( ) )
if ( ! GetInfo ( ) | | GetInfo ( ) - > GetType ( ) = = C4PT_User )
if ( ! : : Control . isReplay ( ) )
LocalControl = true ;
2009-10-14 16:46:22 +00:00
// needs to init control for local players only
if ( LocalControl )
2009-10-13 20:02:44 +00:00
{
2009-10-14 16:46:22 +00:00
// Preferred control
ControlSetName = PrefControl ;
2011-03-30 20:11:47 +00:00
ControlSet = Game . PlayerControlUserAssignmentSets . GetSetByName ( ControlSetName . getData ( ) ) ;
2009-10-14 16:46:22 +00:00
// control set unassigned/not known? fallback to some default then (=first defined control set)
2011-03-30 20:11:47 +00:00
if ( ! ControlSet ) ControlSet = Game . PlayerControlUserAssignmentSets . GetDefaultSet ( ) ;
2009-10-14 16:46:22 +00:00
// gamepad control safety (assuming the default control set is not using gamepad)
if ( ControlSet & & ControlSet - > HasGamepad ( ) & & ! Config . General . GamepadEnabled )
2009-10-13 20:02:44 +00:00
{
2011-03-30 20:11:47 +00:00
ControlSet = Game . PlayerControlUserAssignmentSets . GetDefaultSet ( ) ;
2009-10-13 20:02:44 +00:00
}
2009-10-14 16:46:22 +00:00
// Choose next while control taken
// TODO
// init gamepad
if ( ControlSet & & ControlSet - > HasGamepad ( ) )
2009-10-13 20:02:44 +00:00
{
2009-10-14 16:46:22 +00:00
pGamepad = new C4GamePadOpener ( ControlSet - > GetGamepadIndex ( ) ) ;
2009-10-13 20:02:44 +00:00
}
2009-10-14 16:46:22 +00:00
// Mouse
if ( ControlSet & & ControlSet - > HasMouse ( ) & & PrefMouse )
2010-02-18 23:03:53 +00:00
if ( ! : : Players . MouseControlTaken ( ) )
MouseControl = true ;
2010-03-22 15:49:51 +00:00
// Some controls such as gamepad control need special synced GUI elements
// Do a script callback for selected control
2013-09-04 13:45:00 +00:00
: : Control . DoInput ( CID_PlrAction , C4ControlPlayerAction : : InitPlayerControl ( this , ControlSet ) , CDT_Queue ) ;
2009-05-08 13:28:41 +00:00
}
2009-10-14 16:46:22 +00:00
// clear old control method and register new
Control . RegisterKeyset ( Number , ControlSet ) ;
2009-10-13 20:02:44 +00:00
}
2009-05-08 13:28:41 +00:00
int igOffX , igOffY ;
int VisibilityCheck ( int iVis , int sx , int sy , int cx , int cy )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sx - = igOffX ; sy - = igOffY ; cx - = igOffX ; cy - = igOffY ;
2015-11-15 12:53:01 +00:00
int st = std : : max ( 1 , std : : max ( Abs ( sx - cx ) , Abs ( sy - cy ) ) ) ;
2010-03-28 18:58:01 +00:00
for ( int i = 0 ; i < = st ; i + + )
2009-05-08 13:28:41 +00:00
{
int x = ( sx * ( st - i ) + cx * i ) / st , y = ( sy * ( st - i ) + cy * i ) / st ;
2010-03-28 18:58:01 +00:00
if ( GBackSolid ( x , y ) )
{
if ( ( iVis - = 2 ) < = 0 )
2010-03-21 18:34:22 +00:00
return 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
}
return iVis ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CloseMenu ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// cancel all player menus
Menu . Close ( false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : Eliminate ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Eliminated ) return ;
2010-03-27 16:05:02 +00:00
Eliminated = true ;
2009-05-08 13:28:41 +00:00
RetireDelay = C4RetireDelay ;
2010-03-27 16:05:02 +00:00
StartSoundEffect ( " Eliminated " ) ;
2009-05-08 13:28:41 +00:00
Log ( FormatString ( LoadResStr ( " IDS_PRC_PLRELIMINATED " ) , GetName ( ) ) . getData ( ) ) ;
// Early client deactivation check
2010-03-28 18:58:01 +00:00
if ( : : Control . isCtrlHost ( ) & & AtClient > C4ClientIDHost )
{
2009-05-08 13:28:41 +00:00
// Check: Any player left at this client?
C4Player * pPlr = NULL ;
2010-03-28 18:58:01 +00:00
for ( int i = 0 ; ( pPlr = : : Players . GetAtClient ( AtClient , i ) ) ; i + + )
if ( ! pPlr - > Eliminated )
2009-05-08 13:28:41 +00:00
break ;
// If not, deactivate the client
2010-03-28 18:58:01 +00:00
if ( ! pPlr )
2009-06-15 22:06:37 +00:00
: : Control . DoInput ( CID_ClientUpdate ,
2010-03-28 18:58:01 +00:00
new C4ControlClientUpdate ( AtClient , CUT_Activate , false ) ,
CDT_Sync ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4Player : : ActiveCrewCount ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get number of objects in crew that is not disabled
int32_t iNum = 0 ;
2014-10-24 20:50:14 +00:00
for ( C4Object * cObj : Crew )
if ( cObj )
2009-05-08 13:28:41 +00:00
if ( ! cObj - > CrewDisabled )
+ + iNum ;
// return it
return iNum ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4Player : : GetSelectedCrewCount ( )
2010-03-28 18:58:01 +00:00
{
2010-07-30 20:38:21 +00:00
if ( Cursor & & ! Cursor - > CrewDisabled )
return 1 ;
return 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : EvaluateLeague ( bool fDisconnected , bool fWon )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// already evaluated?
2009-08-15 18:50:32 +00:00
if ( LeagueEvaluated ) return ; LeagueEvaluated = true ;
2010-03-27 16:05:02 +00:00
// set fate
C4PlayerInfo * pInfo = GetInfo ( ) ;
2010-03-28 18:58:01 +00:00
if ( pInfo )
{
if ( fDisconnected )
2010-03-27 16:05:02 +00:00
pInfo - > SetDisconnected ( ) ;
2010-03-28 18:58:01 +00:00
if ( fWon )
2010-03-27 16:05:02 +00:00
pInfo - > SetWinner ( ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : LocalSync ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// local sync not necessary for script players
2009-08-15 18:50:32 +00:00
if ( GetType ( ) = = C4PT_Script ) return true ;
2009-05-08 13:28:41 +00:00
// evaluate total playing time
TotalPlayingTime + = Game . Time - GameJoinTime ;
GameJoinTime = Game . Time ;
// evaluate total playing time of all the crew
for ( C4ObjectInfo * pInf = CrewInfoList . GetFirst ( ) ; pInf ; pInf = pInf - > Next )
if ( pInf - > InAction )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pInf - > TotalPlayingTime + = ( Game . Time - pInf - > InActionTime ) ;
pInf - > InActionTime = Game . Time ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// save player
if ( ! Save ( ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4PlayerInfo * C4Player : : GetInfo ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return Game . PlayerInfos . GetPlayerInfoByID ( ID ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Player : : SetObjectCrewStatus ( C4Object * pCrew , bool fNewStatus )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// either add...
if ( fNewStatus )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// is in crew already?
2009-08-15 18:50:32 +00:00
if ( Crew . IsContained ( pCrew ) ) return true ;
2009-05-08 13:28:41 +00:00
return MakeCrewMember ( pCrew , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// already outside?
2009-08-15 18:50:32 +00:00
if ( ! Crew . IsContained ( pCrew ) ) return true ;
2009-05-08 13:28:41 +00:00
// ...or remove
Crew . Remove ( pCrew ) ;
2009-12-14 21:44:55 +00:00
C4AulParSet parset ( C4VInt ( Number ) ) ;
pCrew - > Call ( PSF_OnRemoveCrew , & parset ) ;
2009-05-08 13:28:41 +00:00
// remove info, if assigned to this player
// theoretically, info objects could remain when the player is deleted
// but then they would be reassigned to the player crew when loaded in a savegame
// by the crew-assignment code kept for backwards compatibility with pre-4.95.2-savegames
if ( pCrew - > Info & & CrewInfoList . IsElement ( pCrew - > Info ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCrew - > Info - > Retire ( ) ;
pCrew - > Info = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CreateGraphs ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// del prev
ClearGraphs ( ) ;
// create graphs
if ( Game . pNetworkStatistics )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DWORD dwGraphClr = ColorDw ;
C4PlayerInfo * pInfo ;
if ( ID & & ( pInfo = Game . PlayerInfos . GetPlayerInfoByID ( ID ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set color by player info class
dwGraphClr = pInfo - > GetColor ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4GUI : : MakeColorReadableOnBlack ( dwGraphClr ) ; dwGraphClr & = 0xffffff ;
pstatControls = new C4TableGraph ( C4TableGraph : : DefaultBlockLength * 20 , Game . pNetworkStatistics - > ControlCounter ) ;
pstatControls - > SetColorDw ( dwGraphClr ) ;
pstatControls - > SetTitle ( GetName ( ) ) ;
pstatActions = new C4TableGraph ( C4TableGraph : : DefaultBlockLength * 20 , Game . pNetworkStatistics - > ControlCounter ) ;
pstatActions - > SetColorDw ( dwGraphClr ) ;
pstatActions - > SetTitle ( GetName ( ) ) ;
// register into
Game . pNetworkStatistics - > statControls . AddGraph ( pstatControls ) ;
Game . pNetworkStatistics - > statActions . AddGraph ( pstatActions ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ClearGraphs ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// del all assigned graphs
if ( pstatControls )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Game . pNetworkStatistics ) Game . pNetworkStatistics - > statControls . RemoveGraph ( pstatControls ) ;
delete pstatControls ;
pstatControls = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( pstatActions )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Game . pNetworkStatistics ) Game . pNetworkStatistics - > statActions . RemoveGraph ( pstatActions ) ;
delete pstatActions ;
pstatActions = NULL ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CountControl ( ControlType eType , int32_t iID , int32_t iCntAdd )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// count it
ControlCount + = iCntAdd ;
// catch doubles
if ( eType = = LastControlType & & iID = = LastControlID ) return ;
// no double: count as action
LastControlType = eType ;
LastControlID = iID ;
ActionCount + = iCntAdd ;
// and give experience
if ( Cursor & & Cursor - > Info )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( Cursor - > Info )
2010-03-28 18:58:01 +00:00
{
Cursor - > Info - > ControlCount + + ; if ( ( Cursor - > Info - > ControlCount % 5 ) = = 0 ) Cursor - > DoExperience ( + 1 ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ExecMsgBoardQueries ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// already active?
2009-06-05 15:18:45 +00:00
if ( : : MessageInput . IsTypeIn ( ) ) return ;
2009-05-08 13:28:41 +00:00
// find an un-evaluated query
C4MessageBoardQuery * pCheck = pMsgBoardQuery ;
2010-03-28 18:58:01 +00:00
while ( pCheck ) if ( ! pCheck - > fAnswered ) break ; else pCheck = pCheck - > pNext ;
2009-05-08 13:28:41 +00:00
if ( ! pCheck ) return ;
// open it
2010-03-30 21:08:15 +00:00
: : MessageInput . StartTypeIn ( true , pCheck - > CallbackObj , pCheck - > fIsUppercase , false , Number , pCheck - > sInputQuery ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : CallMessageBoard ( C4Object * pForObj , const StdStrBuf & sQueryString , bool fIsUppercase )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// remove any previous query for the same object
RemoveMessageBoardQuery ( pForObj ) ;
// sort new query to end of list
C4MessageBoardQuery * * ppTarget = & pMsgBoardQuery ;
while ( * ppTarget ) ppTarget = & ( ( * ppTarget ) - > pNext ) ;
* ppTarget = new C4MessageBoardQuery ( pForObj , sQueryString , fIsUppercase ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : RemoveMessageBoardQuery ( C4Object * pForObj )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get matching query
C4MessageBoardQuery * * ppCheck = & pMsgBoardQuery , * pFound ;
2010-03-30 21:08:15 +00:00
while ( * ppCheck ) if ( ( * ppCheck ) - > CallbackObj = = pForObj ) break ; else ppCheck = & ( ( * ppCheck ) - > pNext ) ;
2009-05-08 13:28:41 +00:00
pFound = * ppCheck ;
if ( ! pFound ) return false ;
// remove it
* ppCheck = ( * ppCheck ) - > pNext ;
delete pFound ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : MarkMessageBoardQueryAnswered ( C4Object * pForObj )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get matching query
C4MessageBoardQuery * pCheck = pMsgBoardQuery ;
2010-03-30 21:08:15 +00:00
while ( pCheck ) if ( pCheck - > CallbackObj = = pForObj & & ! pCheck - > fAnswered ) break ; else pCheck = pCheck - > pNext ;
2009-05-08 13:28:41 +00:00
if ( ! pCheck ) return false ;
// mark it
pCheck - > fAnswered = true ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : HasMessageBoardQuery ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// return whether any object has a messageboard-query
return ! ! pMsgBoardQuery ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : OnTeamSelectionFailed ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// looks like a selected team was not available: Go back to team selection if this is not a mislead call
if ( Status = = PS_TeamSelectionPending )
Status = PS_TeamSelection ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : SetPlayerColor ( uint32_t dwNewClr )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no change?
if ( dwNewClr = = ColorDw ) return ;
// reflect change in all active, player-owned objects
// this can never catch everything (thinking of overlays, etc.); scenarios that allow team changes should take care of the rest
uint32_t dwOldClr = ColorDw ;
ColorDw = dwNewClr ;
2014-10-24 20:50:14 +00:00
for ( C4Object * pObj : Objects )
if ( pObj & & pObj - > Status & & pObj - > Owner = = Number )
{
if ( ( pObj - > Color & 0xffffff ) = = ( dwOldClr & 0xffffff ) )
pObj - > Color = ( pObj - > Color & 0xff000000u ) | ( dwNewClr & 0xffffff ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4PlayerType C4Player : : GetType ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// type by info
C4PlayerInfo * pInfo = Game . PlayerInfos . GetPlayerInfoByID ( ID ) ;
if ( pInfo ) return pInfo - > GetType ( ) ; else { assert ( false ) ; return C4PT_User ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Player : : IsInvisible ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// invisible by info
C4PlayerInfo * pInfo = Game . PlayerInfos . GetPlayerInfoByID ( ID ) ;
if ( pInfo ) return pInfo - > IsInvisible ( ) ; else { assert ( false ) ; return false ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Player : : ToggleMouseControl ( )
{
// Activate mouse control if it's available
2009-06-12 23:09:32 +00:00
if ( ! MouseControl & & ! : : Players . MouseControlTaken ( ) )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:20:07 +00:00
: : MouseControl . Init ( Number ) ;
2009-08-15 18:50:32 +00:00
MouseControl = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Deactivate mouse control
else if ( MouseControl )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:20:07 +00:00
: : MouseControl . Clear ( ) ;
: : MouseControl . Default ( ) ;
2009-05-08 13:28:41 +00:00
MouseControl = 0 ;
// Scrolling isn't possible any more
if ( ViewMode = = C4PVM_Scrolling )
SetViewMode ( C4PVM_Cursor ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
}
bool C4Player : : ActivateMenuMain ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Not during game over dialog
if ( C4GameOverDlg : : IsShown ( ) ) return false ;
// Open menu
return ! ! Menu . ActivateMain ( Number ) ;
2010-03-28 18:58:01 +00:00
}
2010-01-25 15:57:57 +00:00
void C4Player : : HostilitySet : : CompileFunc ( StdCompiler * pComp )
{
int entries = size ( ) ;
if ( pComp - > isCompiler ( ) )
{
clear ( ) ;
pComp - > Value ( entries ) ;
while ( entries - - )
{
int number ;
pComp - > Value ( number ) ;
assert ( : : Players . Valid ( number ) ) ;
C4Player * plr = : : Players . Get ( number ) ;
if ( plr )
insert ( plr ) ;
}
}
else
{
pComp - > Value ( entries ) ;
for ( const_iterator it = begin ( ) ; it ! = end ( ) ; + + it )
{
int32_t num = ( * it ) - > Number ;
pComp - > Value ( num ) ; // Can't use (*it)->Number directly because StdCompiler is dumb about constness
}
}
}
2010-09-08 21:49:42 +00:00
void C4Player : : SetZoomByViewRange ( int32_t range_wdt , int32_t range_hgt , bool direct , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomWdt , range_wdt , no_increase , no_decrease ) ;
AdjustZoomParameter ( & ZoomHgt , range_hgt , no_increase , no_decrease ) ;
2010-12-12 21:38:19 +00:00
ZoomToViewports ( direct , no_decrease , no_increase ) ; // inc/dec swapped for zoom, because it's inversely proportional to range
2010-09-08 21:49:42 +00:00
}
void C4Player : : SetMinZoomByViewRange ( int32_t range_wdt , int32_t range_hgt , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomLimitMinWdt , range_wdt , no_increase , no_decrease ) ;
AdjustZoomParameter ( & ZoomLimitMinHgt , range_hgt , no_increase , no_decrease ) ;
2010-12-12 21:38:19 +00:00
ZoomLimitsToViewports ( ) ;
2010-09-08 21:49:42 +00:00
}
void C4Player : : SetMaxZoomByViewRange ( int32_t range_wdt , int32_t range_hgt , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomLimitMaxWdt , range_wdt , no_increase , no_decrease ) ;
AdjustZoomParameter ( & ZoomLimitMaxHgt , range_hgt , no_increase , no_decrease ) ;
2010-12-12 21:38:19 +00:00
ZoomLimitsToViewports ( ) ;
2010-09-08 21:49:42 +00:00
}
2014-04-21 17:38:05 +00:00
void C4Player : : SetZoom ( C4Fixed zoom , bool direct , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomVal , zoom , no_increase , no_decrease ) ;
ZoomToViewports ( direct , no_increase , no_decrease ) ;
}
void C4Player : : SetMinZoom ( C4Fixed zoom , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomLimitMinVal , zoom , no_increase , no_decrease ) ;
ZoomLimitsToViewports ( ) ;
}
void C4Player : : SetMaxZoom ( C4Fixed zoom , bool no_increase , bool no_decrease )
{
AdjustZoomParameter ( & ZoomLimitMaxVal , zoom , no_increase , no_decrease ) ;
ZoomLimitsToViewports ( ) ;
}
2010-12-12 21:38:19 +00:00
void C4Player : : ZoomToViewports ( bool direct , bool no_increase , bool no_decrease )
{
C4Viewport * vp = NULL ;
while ( ( vp = : : Viewports . GetViewport ( Number , vp ) ) ! = NULL )
ZoomToViewport ( vp , direct , no_increase , no_decrease ) ;
}
void C4Player : : ZoomToViewport ( C4Viewport * vp , bool direct , bool no_increase , bool no_decrease )
2010-09-08 21:49:42 +00:00
{
2014-04-21 17:38:05 +00:00
float new_zoom = ZoomVal ? fixtof ( ZoomVal ) : vp - > GetZoomByViewRange ( ( ZoomWdt | | ZoomHgt ) ? ZoomWdt : C4VP_DefViewRangeX , ZoomHgt ) ;
2010-09-08 21:49:42 +00:00
float old_zoom = vp - > GetZoomTarget ( ) ;
if ( new_zoom > old_zoom & & no_increase ) return ;
if ( new_zoom < old_zoom & & no_decrease ) return ;
vp - > SetZoom ( new_zoom , direct ) ;
}
2010-12-12 21:38:19 +00:00
void C4Player : : ZoomLimitsToViewports ( )
{
C4Viewport * vp = NULL ;
while ( ( vp = : : Viewports . GetViewport ( Number , vp ) ) ! = NULL )
ZoomLimitsToViewport ( vp ) ;
}
void C4Player : : ZoomLimitsToViewport ( C4Viewport * vp )
2010-09-08 21:49:42 +00:00
{
2014-04-21 17:38:05 +00:00
float zoom_max = ZoomLimitMaxVal ? fixtof ( ZoomLimitMaxVal ) : vp - > GetZoomByViewRange ( ( ZoomLimitMinWdt | | ZoomLimitMinHgt ) ? ZoomLimitMinWdt : C4VP_DefMinViewRangeX , ZoomLimitMinHgt ) ;
float zoom_min = ZoomLimitMinVal ? fixtof ( ZoomLimitMinVal ) : vp - > GetZoomByViewRange ( ( ZoomLimitMaxWdt | | ZoomLimitMaxHgt ) ? ZoomLimitMaxWdt : C4VP_DefMaxViewRangeX , ZoomLimitMaxHgt ) ;
2010-09-08 21:49:42 +00:00
vp - > SetZoomLimits ( zoom_min , zoom_max ) ;
}
bool C4Player : : AdjustZoomParameter ( int32_t * range_par , int32_t new_val , bool no_increase , bool no_decrease )
{
// helper function: Adjust *range_par to new_val if increase/decrease not forbidden
if ( new_val < * range_par )
{
if ( ! no_decrease ) * range_par = new_val ;
return ! no_decrease ;
}
else if ( new_val > * range_par )
{
if ( ! no_increase ) * range_par = new_val ;
return ! no_increase ;
}
return true ;
}
2014-04-21 17:38:05 +00:00
bool C4Player : : AdjustZoomParameter ( C4Fixed * zoom_par , C4Fixed new_val , bool no_increase , bool no_decrease )
{
// helper function: Adjust *zoom_par to new_val if increase/decrease not forbidden
if ( new_val < * zoom_par )
{
if ( ! no_decrease ) * zoom_par = new_val ;
return ! no_decrease ;
}
else if ( new_val > * zoom_par )
{
if ( ! no_increase ) * zoom_par = new_val ;
return ! no_increase ;
}
return true ;
}
2010-09-08 21:49:42 +00:00
void C4Player : : SetViewLocked ( bool to_val )
{
if ( ( ViewLock = to_val ) )
{
// view was locked - cancel any scrolling
if ( ViewMode = = C4PVM_Scrolling ) SetViewMode ( C4PVM_Cursor ) ;
}
2010-09-09 20:38:18 +00:00
}
2014-09-24 21:08:40 +00:00
bool C4Player : : GainScenarioAchievement ( const char * achievement_id , int32_t value , const char * scen_name_override )
{
// Determine full ID of achievement
if ( ! scen_name_override )
2015-01-25 15:16:06 +00:00
{
2014-09-24 21:08:40 +00:00
if ( : : Game . C4S . Head . Origin . getLength ( ) )
scen_name_override = : : Game . C4S . Head . Origin . getData ( ) ;
else
scen_name_override = : : Game . ScenarioFilename ;
2015-01-25 15:16:06 +00:00
}
2014-09-24 21:08:40 +00:00
StdStrBuf sAchvID = C4ScenarioParameters : : AddFilename2ID ( scen_name_override , achievement_id ) ;
// Gain achievement iff it's an improvement
Achievements . SetValue ( sAchvID . getData ( ) , value , true ) ;
return true ;
}
2015-08-28 01:44:23 +00:00
void C4Player : : SetSoundModifier ( C4PropList * new_modifier )
{
// set modifier to be applied to all new sounds being played in a player's viewport
// update prop list parameter
C4SoundModifier * mod ;
if ( new_modifier )
{
SoundModifier . SetPropList ( new_modifier ) ;
mod = : : Application . SoundSystem . Modifiers . Get ( new_modifier , true ) ;
}
else
{
SoundModifier . Set0 ( ) ;
mod = NULL ;
}
// update in sound system
: : Application . SoundSystem . Modifiers . SetGlobalModifier ( mod , Number ) ;
}