2020-05-27 12:16:20 -07:00
//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/*
* * DLLInterfac . cpp
* *
* * This is where we implement the API expected by the Instance Server .
* *
* * The Instance Server will pass in requests for loading and starting maps , control input from players ,
* * and requests for game simulation and rendering states .
* *
* *
*/
// Exception handling isn't enabled
# pragma warning (disable : 4530) //warning C4530: C++ exception handler used, but unwind semantics are not enabled.
# include <string>
# include <vector>
# include <set>
# include "function.h"
# include "externs.h"
# include "DLLInterface.h"
# include "Gadget.h"
# include "defines.h" // VOC_COUNT, VOX_COUNT
# include "SidebarGlyphx.h"
# include <chrono>
/*
* * Externs
*/
extern int DLL_Startup ( const char * command_line ) ;
extern void Reallocate_Big_Shape_Buffer ( void ) ;
extern bool ProgEndCalled ;
extern int Write_PCX_File ( char * name , GraphicViewPortClass & pic , unsigned char * palette ) ;
extern void Color_Cycle ( void ) ;
bool Debug_Write_Shape_Type ( const ObjectTypeClass * type , int shapenum ) ;
bool Debug_Write_Shape ( const char * file_name , void const * shapefile , int shapenum , int flags = 0 , void const * ghostdata = NULL ) ;
typedef void ( __cdecl * CNC_Event_Callback_Type ) ( const EventCallbackStruct & event ) ;
typedef unsigned __int64 uint64 ;
typedef __int64 int64 ;
/*
* * Audio defines
* *
* *
* *
* *
* *
*/
// For compatibility with Watcom in audio enums
# pragma warning (disable : 4091)
// From RedAlert\Audio.cpp
enum ContextType ;
extern struct SoundEffectNameStruct {
char const * Name ; // Digitized voice file name.
int Priority ; // Playback priority of this sample.
ContextType Where ; // In what game context does this sample exist.
} SoundEffectName [ VOC_COUNT ] ;
// From RedAlert\Audio.cpp
extern char const * Speech [ VOX_COUNT ] ;
// From RedAlert\Audio.cpp
typedef enum {
IN_NOVAR , // No variation or alterations allowed.
IN_VAR // Infantry variance response modification.
} ;
/*
* * Misc defines
* *
* *
* *
* *
* *
*/
# define GAME_TO_PLAY Session.Type
# define MULTIPLAYER_COUNT Session.Players.Count()
# define KEYBOARD Keyboard
# define RANDOM_START_POSITION 0x7f
2020-06-22 09:43:21 -07:00
# define KILL_PLAYER_ON_DISCONNECT 1
2020-05-27 12:16:20 -07:00
/*
* * DLL Interface
* *
* *
* *
* *
* *
*/
extern " C " __declspec ( dllexport ) unsigned int __cdecl CNC_Version ( unsigned int version_in ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Init ( const char * command_line , CNC_Event_Callback_Type event_callback ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Config ( const CNCRulesDataStruct & rules ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Add_Mod_Path ( const char * mod_path ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Visible_Page ( unsigned char * buffer_in , unsigned int & width , unsigned int & height ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Palette ( unsigned char ( & palette_in ) [ 256 ] [ 3 ] ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Instance ( int scenario_index , int build_level , const char * faction , const char * game_type , const char * content_directory , int sabotaged_structure , const char * override_map_name ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Instance_Variation ( int scenario_index , int scenario_variation , int scenario_direction , int build_level , const char * faction , const char * game_type , const char * content_directory , int sabotaged_structure , const char * override_map_name ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Custom_Instance ( const char * content_directory , const char * directory_path , const char * scenario_name , int build_level , bool multiplayer ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Advance_Instance ( uint64 player_id ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Game_State ( GameStateRequestEnum state_type , uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Read_INI ( int scenario_index , int scenario_variation , int scenario_direction , const char * content_directory , const char * override_map_name , char * ini_buffer , int _ini_buffer_size ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Set_Home_Cell ( int x , int y , uint64 player_id ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Game_Request ( GameRequestEnum request_type ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Game_Settings_Request ( int health_bar_display_mode , int resource_bar_display_mode ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Input ( InputRequestEnum mouse_event , unsigned char special_key_flags , uint64 player_id , int x1 , int y1 , int x2 , int y2 ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Structure_Request ( StructureRequestEnum request_type , uint64 player_id , int object_id ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Unit_Request ( UnitRequestEnum request_type , uint64 player_id ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Sidebar_Request ( SidebarRequestEnum request_type , uint64 player_id , int buildable_type , int buildable_id , short cell_x , short cell_y ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_SuperWeapon_Request ( SuperWeaponRequestEnum request_type , uint64 player_id , int buildable_type , int buildable_id , int x1 , int y1 ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_ControlGroup_Request ( ControlGroupRequestEnum request_type , uint64 player_id , unsigned char control_group_index ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Debug_Request ( DebugRequestEnum debug_request_type , uint64 player_id , const char * object_name , int x , int y , bool unshroud , bool enemy ) ;
2020-09-16 10:03:04 -07:00
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Beacon_Request ( BeaconRequestEnum beacon_request_type , uint64 player_id , int pixel_x , int pixel_y ) ;
2020-05-27 12:16:20 -07:00
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Set_Multiplayer_Data ( int scenario_index , CNCMultiplayerOptionsStruct & game_options , int num_players , CNCPlayerInfoStruct * player_list , int max_players ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Clear_Object_Selection ( uint64 player_id ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Select_Object ( uint64 player_id , int object_type_id , int object_to_select_id ) ;
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Save_Load ( bool save , const char * file_path_and_name , const char * game_type ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Set_Difficulty ( int difficulty ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Restore_Carryover_Objects ( const CarryoverObjectStruct * objects ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Player_Switch_To_AI ( uint64 player_id ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Human_Team_Wins ( uint64 player_id ) ;
extern " C " __declspec ( dllexport ) void __cdecl CNC_Start_Mission_Timer ( int time ) ;
2020-09-16 10:03:04 -07:00
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Start_Game_Info ( uint64 player_id , int & start_location_waypoint_index ) ;
2020-05-27 12:16:20 -07:00
/*
* * Class to implement the interface , and contain additional game state required by the conversion from peer / peer to client / server
* *
* *
* *
* *
* *
*/
class DLLExportClass {
public :
static void Init ( void ) ;
static void Shutdown ( void ) ;
static void Config ( const CNCRulesDataStruct & rules ) ;
static void Add_Mod_Path ( const char * mod_path ) ;
static void Set_Home_Cell ( int x , int y , uint64 player_id ) ;
static void Set_Content_Directory ( const char * dir ) ;
static bool Get_Layer_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static bool Get_Sidebar_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static bool Start_Construction ( uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Hold_Construction ( uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Cancel_Construction ( uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Start_Placement ( uint64 player_id , int buildable_type , int buildable_id ) ;
static BuildingClass * Get_Pending_Placement_Object ( uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Get_Placement_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static void Convert_Type ( const ObjectClass * object , CNCObjectStruct & object_out ) ;
static void DLL_Draw_Intercept ( int shape_number , int x , int y , int width , int height , int flags , const ObjectClass * object , DirType rotation , long scale , const char * shape_file_name = NULL , char override_owner = HOUSE_NONE ) ;
static void DLL_Draw_Pip_Intercept ( const ObjectClass * object , int pip ) ;
static bool Place ( uint64 player_id , int buildable_type , int buildable_id , short cell_x , short cell_y ) ;
static bool Cancel_Placement ( uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Place_Super_Weapon ( uint64 player_id , int buildable_type , int buildable_id , int x , int y ) ;
static bool Create_Control_Group ( unsigned char control_group_index ) ;
static bool Add_To_Control_Group ( unsigned char control_group_index ) ;
static bool Toggle_Control_Group_Selection ( unsigned char control_group_index ) ;
static bool Construction_Action ( SidebarRequestEnum construction_action , uint64 player_id , int buildable_type , int buildable_id ) ;
static bool MP_Construction_Action ( SidebarRequestEnum construction_action , uint64 player_id , int buildable_type , int buildable_id ) ;
static bool Passes_Proximity_Check ( CELL cell_in , BuildingTypeClass * placement_type , unsigned char * placement_distance ) ;
static void Calculate_Start_Positions ( void ) ;
static void Computer_Message ( bool last_player_taunt ) ;
static void Repair_Mode ( uint64 player_id ) ;
static void Repair ( uint64 player_id , int object_id ) ;
static void Sell_Mode ( uint64 player_id ) ;
static void Sell ( uint64 player_id , int object_id ) ;
static void Repair_Sell_Cancel ( uint64 player_id ) ;
static void Scatter_Selected ( uint64 player_id ) ;
static void Select_Next_Unit ( uint64 player_id ) ;
static void Select_Previous_Unit ( uint64 player_id ) ;
static void Selected_Guard_Mode ( uint64 player_id ) ;
static void Selected_Stop ( uint64 player_id ) ;
static void Team_Units_Formation_Toggle_On ( uint64 player_id ) ;
static void Units_Queued_Movement_Toggle ( uint64 player_id , bool toggle ) ;
static void Cell_Class_Draw_It ( CNCDynamicMapStruct * dynamic_map , int & entry_index , CellClass * cell_ptr , int xpixel , int ypixel , bool debug_output ) ;
static bool Get_Dynamic_Map_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static bool Get_Shroud_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static bool Get_Occupier_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static bool Get_Player_Info_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size ) ;
static void Set_Event_Callback ( CNC_Event_Callback_Type event_callback ) { EventCallback = event_callback ; }
static void Debug_Spawn_Unit ( const char * object_name , int x , int y , bool enemy = false ) ;
static void Debug_Spawn_All ( int x , int y ) ;
static bool Try_Debug_Spawn_Unlimbo ( TechnoClass * techno , int & cell_x , int & cell_y ) ;
static void Debug_Kill_Unit ( int x , int y ) ;
static void Debug_Heal_Unit ( int x , int y ) ;
static void On_Play_Movie ( const char * movie_name , ThemeType theme , bool immediate ) ;
static void On_Display_Briefing_Text ( ) ;
static void On_Sound_Effect ( const HouseClass * player_ptr , int sound_effect_index , const char * extension , int variation , COORDINATE coord ) ;
static void On_Speech ( const HouseClass * player_ptr , int speech_index ) ;
static void On_Message ( const HouseClass * player_ptr , const char * message , float timeout_seconds , EventCallbackMessageEnum message_type , int64 message_id ) ;
static void On_Update_Map_Cell ( int cell_x , int cell_y , const char * template_type_name ) ;
static void On_Special_Weapon_Targetting ( const HouseClass * player_ptr , SpecialWeaponType weapon_type ) ;
static void On_Ping ( const HouseClass * player_ptr , COORDINATE coord ) ;
static void On_Game_Over ( uint64 glyphx_player_id , bool player_wins ) ;
static void On_Multiplayer_Game_Over ( void ) ;
static void On_Debug_Output ( const char * debug_text ) ;
static void On_Achievement ( const HouseClass * player_ptr , const char * achievement_type , const char * achievement_reason ) ;
static void On_Center_Camera ( const HouseClass * player_ptr , int coord_x , int coord_y ) ;
static void Glyphx_Queue_AI ( ) ;
static void Store_Carryover_Objects ( ) ;
static void Force_Human_Team_Wins ( uint64 quitting_player_id ) ;
/*
* * Player context switching for input / output
*/
static bool Set_Player_Context ( uint64 glyphx_player , bool force = false ) ;
static void Reset_Player_Context ( void ) ;
static void Adjust_Internal_View ( bool force_ignore_view_constraints = false ) ;
static void Logic_Switch_Player_Context ( ObjectClass * object ) ;
static void Logic_Switch_Player_Context ( HouseClass * house ) ;
static void Refresh_Player_Control_Flags ( void ) ;
static __int64 Get_GlyphX_Player_ID ( const HouseClass * house ) ;
static void Recalculate_Placement_Distances ( ) ;
static void Reset_Sidebars ( void ) ;
static SidebarGlyphxClass * Get_Current_Context_Sidebar ( HouseClass * player_ptr = NULL ) ;
static uint64 GlyphxPlayerIDs [ MAX_PLAYERS ] ;
static const void * Get_Shadow_Shapes ( void ) { return Map . ShadowShapes ; }
static const unsigned char * Get_Shadow_Trans ( void ) { return & Map . ShadowTrans [ 0 ] ; }
static bool Legacy_Render_Enabled ( void ) ;
static bool Get_Input_Key_State ( KeyNumType key ) ;
static void Set_Special_Key_Flags ( unsigned char special_key_flags ) ;
static void Clear_Special_Key_Flags ( ) ;
static bool Load ( Straw & file ) ;
static bool Save ( Pipe & file ) ;
static void Code_Pointers ( void ) ;
static void Decode_Pointers ( void ) ;
static bool Get_Game_Over ( ) { return GameOver ; }
private :
static void Calculate_Single_Player_Score ( EventCallbackStruct & ) ;
static int RA_Calculate_Leadership ( HousesType player_house , int units_lost , int buildings_lost ) ;
static int RA_Calculate_Economy ( long available_money , int stolen_buildings_credits , unsigned harvested_credits , long initial_credits ) ;
static int RA_Calculate_Score ( int uspoints , int leadership , int economy ) ;
static void Convert_Action_Type ( ActionType type , ObjectClass * object , TARGET target , DllActionTypeEnum & dll_type ) ;
static void Convert_Special_Weapon_Type ( SpecialWeaponType weapon_type , DllSuperweaponTypeEnum & dll_weapon_type , char * weapon_name ) ;
static void Fill_Sidebar_Entry_From_Special_Weapon ( CNCSidebarEntryStruct & sidebar_entry_out , SuperClass * & super_weapon_out , SpecialWeaponType weapon_type ) ;
static void Calculate_Placement_Distances ( BuildingTypeClass * placement_type , unsigned char * placement_distance ) ;
static int CurrentDrawCount ;
static int TotalObjectCount ;
static int SortOrder ;
2020-08-12 11:32:36 -07:00
static int ExportLayer ;
2020-05-27 12:16:20 -07:00
static CNCObjectListStruct * ObjectList ;
static CNC_Event_Callback_Type EventCallback ;
static int CurrentLocalPlayerIndex ;
static bool GameOver ;
static std : : set < int64 > MessagesSent ;
/*
* * Pseudo sidebars for players in multiplayer
*/
static SidebarGlyphxClass MultiplayerSidebars [ MAX_PLAYERS ] ;
static CELL MultiplayerStartPositions [ MAX_PLAYERS ] ;
static BuildingTypeClass * PlacementType [ MAX_PLAYERS ] ;
static unsigned char PlacementDistance [ MAX_PLAYERS ] [ MAP_CELL_TOTAL ] ;
static unsigned char SpecialKeyFlags [ MAX_PLAYERS ] ;
/*
* * Mod directories
*/
static DynamicVectorClass < char * > ModSearchPaths ;
} ;
/*
* * DLLExportClass static data
* *
* *
* *
* *
* *
*/
int DLLExportClass : : CurrentDrawCount = 0 ;
int DLLExportClass : : TotalObjectCount = 0 ;
int DLLExportClass : : SortOrder = 0 ;
2020-08-12 11:32:36 -07:00
int DLLExportClass : : ExportLayer = 0 ;
2020-05-27 12:16:20 -07:00
CNCObjectListStruct * DLLExportClass : : ObjectList = NULL ;
SidebarGlyphxClass DLLExportClass : : MultiplayerSidebars [ MAX_PLAYERS ] ;
uint64 DLLExportClass : : GlyphxPlayerIDs [ MAX_PLAYERS ] = { 0xffffffffl } ;
int DLLExportClass : : CurrentLocalPlayerIndex = - 1 ;
CELL DLLExportClass : : MultiplayerStartPositions [ MAX_PLAYERS ] ;
BuildingTypeClass * DLLExportClass : : PlacementType [ MAX_PLAYERS ] ;
unsigned char DLLExportClass : : PlacementDistance [ MAX_PLAYERS ] [ MAP_CELL_TOTAL ] ;
unsigned char DLLExportClass : : SpecialKeyFlags [ MAX_PLAYERS ] = { 0U } ;
DynamicVectorClass < char * > DLLExportClass : : ModSearchPaths ;
std : : set < int64 > DLLExportClass : : MessagesSent ;
bool DLLExportClass : : GameOver = false ;
/*
* * Global variables
* *
* *
* *
* *
* *
*/
int DLLForceMouseX = 0 ;
int DLLForceMouseY = 0 ;
CNC_Event_Callback_Type DLLExportClass : : EventCallback = NULL ;
// Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
int GlyphXClientSidebarWidthInLeptons = 0 ;
bool MPlayerIsHuman [ MAX_PLAYERS ] ;
int MPlayerTeamIDs [ MAX_PLAYERS ] ;
int MPlayerStartLocations [ MAX_PLAYERS ] ;
bool MPSuperWeaponDisable = false ;
bool ShareAllyVisibility = true ;
bool UseGlyphXStartLocations = true ;
2020-08-06 09:44:54 -07:00
SpecialClass * SpecialBackup = NULL ;
2020-05-27 12:16:20 -07:00
int GetRandSeed ( )
{
using namespace std : : chrono ;
time_point < system_clock > time_since_epoch = system_clock : : now ( ) ;
auto microseconds_since_epoch = floor < std : : chrono : : microseconds > ( time_since_epoch ) ;
return abs ( static_cast < int > ( microseconds_since_epoch . time_since_epoch ( ) . count ( ) ) ) ;
}
void Play_Movie_GlyphX ( const char * movie_name , ThemeType theme , bool immediate = false )
{
if ( ( movie_name [ 0 ] = = ' x ' | | movie_name [ 0 ] = = ' X ' ) & & movie_name [ 1 ] = = 0 ) {
return ;
}
DLLExportClass : : On_Play_Movie ( movie_name , theme , immediate ) ;
}
void Display_Briefing_Text_GlyphX ( )
{
DLLExportClass : : On_Display_Briefing_Text ( ) ;
}
void On_Sound_Effect ( int sound_index , int variation , COORDINATE coord , int house )
{
int voc = sound_index ;
if ( voc = = VOC_NONE )
{
return ;
}
2020-09-16 10:03:04 -07:00
// Borrowed from RedAlert\AUDIO.CPP Sound_Effect()
2020-05-27 12:16:20 -07:00
//
# if 1
/*
* * Fetch a pointer to the sound effect data . Modify the sound as appropriate and desired .
*/
char const * ext = " " ; // ".AUD";
if ( SoundEffectName [ voc ] . Where = = IN_VAR ) {
/*
* * If there is no forced house , then use the current player
* * act like house .
*/
if ( house = = HOUSE_NONE ) {
house = PlayerPtr - > ActLike ;
}
/*
* * Change the extension based on the variation and house accent requested .
*/
if ( ( ( 1 < < house ) & HOUSEF_ALLIES ) ! = 0 ) {
/*
* * For infantry , use a variation on the response . For vehicles , always
* * use the vehicle response table .
*/
if ( variation < 0 ) {
if ( ABS ( variation ) % 2 ) {
ext = " .V00 " ;
} else {
ext = " .V02 " ;
}
} else {
if ( variation % 2 ) {
ext = " .V01 " ;
} else {
ext = " .V03 " ;
}
}
} else {
if ( variation < 0 ) {
if ( ABS ( variation ) % 2 ) {
ext = " .R00 " ;
} else {
ext = " .R02 " ;
}
} else {
if ( variation % 2 ) {
ext = " .R01 " ;
} else {
ext = " .R03 " ;
}
}
}
}
# endif
// END MBL
DLLExportClass : : On_Sound_Effect ( PlayerPtr , sound_index , ext , variation , coord ) ;
#if 0
int voc = sound_index ;
if ( voc = = VOC_NONE )
{
return ;
}
2020-09-16 10:03:04 -07:00
// Borrowed from AUDIO.CPP Sound_Effect()
2020-05-27 12:16:20 -07:00
//
char const * ext = " " ; // ".AUD";
# ifdef TIBERIAN_DAWN
if ( Special . IsJuvenile & & SoundEffectName [ voc ] . Where = = IN_JUV ) {
ext = " .JUV " ;
} else {
# endif
if ( SoundEffectName [ voc ] . Where = = IN_VAR ) {
/*
* * For infantry , use a variation on the response . For vehicles , always
* * use the vehicle response table .
*/
if ( variation < 0 ) {
if ( ABS ( variation ) % 2 ) {
ext = " .V00 " ;
} else {
ext = " .V02 " ;
}
} else {
if ( variation % 2 ) {
ext = " .V01 " ;
} else {
ext = " .V03 " ;
}
}
}
# ifdef TIBERIAN_DAWN
}
# endif
// END MBL
DLLExportClass : : On_Sound_Effect ( PlayerPtr , sound_index , ext , variation , coord ) ;
# endif
}
void On_Speech ( int speech_index , HouseClass * house )
{
if ( house = = NULL ) {
DLLExportClass : : On_Speech ( PlayerPtr , speech_index ) ;
}
else
{
DLLExportClass : : On_Speech ( house , speech_index ) ;
}
}
void On_Message ( const char * message , float timeout_seconds , int64 id )
{
DLLExportClass : : On_Message ( PlayerPtr , message , timeout_seconds , MESSAGE_TYPE_DIRECT , id ) ;
}
void On_Update_Map_Cell ( int cell_x , int cell_y , const char * template_type_name )
{
DLLExportClass : : On_Update_Map_Cell ( cell_x , cell_y , template_type_name ) ;
}
void On_Special_Weapon_Targetting ( const HouseClass * player_ptr , SpecialWeaponType weapon_type )
{
DLLExportClass : : On_Special_Weapon_Targetting ( player_ptr , weapon_type ) ;
}
void On_Ping ( const HouseClass * player_ptr , COORDINATE coord )
{
DLLExportClass : : On_Ping ( player_ptr , coord ) ;
}
void On_Defeated_Message ( const char * message , float timeout_seconds )
{
DLLExportClass : : On_Message ( PlayerPtr , message , timeout_seconds , MESSAGE_TYPE_PLAYER_DEFEATED , - 1 ) ;
}
void GlyphX_Debug_Print ( const char * debug_text )
{
DLLExportClass : : On_Debug_Output ( debug_text ) ;
}
void On_Achievement_Event ( const HouseClass * player_ptr , const char * achievement_type , const char * achievement_reason )
{
DLLExportClass : : On_Achievement ( player_ptr , achievement_type , achievement_reason ) ;
}
/**************************************************************************************************
* CNC_Version - - Check DLL / Server version
*
* In : Version expected
*
* Out : Actual version
*
*
*
* History : 4 / 9 / 2020 2 : 12 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) unsigned int __cdecl CNC_Version ( unsigned int version_in )
{
// Unreferenced, but potentially useful to know which version the server is expecting
version_in ;
return CNC_DLL_API_VERSION ;
}
/**************************************************************************************************
* CNC_Init - - Initialize the . DLL
*
* In : Command line
*
* Out :
*
*
*
* History : 1 / 3 / 2019 11 : 33 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Init ( const char * command_line , CNC_Event_Callback_Type event_callback )
{
DLLExportClass : : Set_Content_Directory ( NULL ) ;
DLL_Startup ( command_line ) ;
DLLExportClass : : Set_Event_Callback ( event_callback ) ;
DLLExportClass : : Init ( ) ;
}
/**************************************************************************************************
* DLL_Shutdown - - Shutdown the . DLL
*
* In :
*
* Out :
*
*
*
* History : 2 / 20 / 2020 1 : 58 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLL_Shutdown ( void )
{
DLLExportClass : : Shutdown ( ) ;
}
/**************************************************************************************************
* CNC_Config - - Configure the plugin
*
* In : Configuration data
*
* Out :
*
*
*
* History : 10 / 03 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Config ( const CNCRulesDataStruct & rules )
{
DLLExportClass : : Config ( rules ) ;
}
/**************************************************************************************************
* CNC_Add_Mod_Path - - Add a path to load mod files from
*
* In : Path to load mods from
*
* Out :
*
*
*
* History : 2 / 20 / 2020 2 : 04 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Add_Mod_Path ( const char * mod_path )
{
DLLExportClass : : Add_Mod_Path ( mod_path ) ;
}
/**************************************************************************************************
* CNC_Get_Visible_Page - - Get the screen buffer ' SeenBuff ' from the game
*
* In : If buffer_in is null , just return info about page
*
* Out : false if not changed since last call
*
*
*
* History : 1 / 3 / 2019 11 : 33 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Visible_Page ( unsigned char * buffer_in , unsigned int & width , unsigned int & height )
{
if ( ! DLLExportClass : : Legacy_Render_Enabled ( ) | | ( buffer_in = = NULL ) ) {
return false ;
}
/*
* * Assume the seen page viewport is the same size as the page
*/
GraphicBufferClass * gbuffer = HidPage . Get_Graphic_Buffer ( ) ;
if ( gbuffer = = NULL ) {
return false ;
}
int view_port_width = Map . MapCellWidth * CELL_PIXEL_W ;
int view_port_height = Map . MapCellHeight * CELL_PIXEL_H ;
if ( view_port_width = = 0 | | view_port_height = = 0 ) {
return false ;
}
unsigned char * raw_buffer = ( unsigned char * ) gbuffer - > Get_Buffer ( ) ;
long raw_size = gbuffer - > Get_Size ( ) ;
if ( raw_buffer = = NULL | | gbuffer - > Get_Width ( ) < view_port_width | | gbuffer - > Get_Height ( ) < view_port_height ) {
return false ;
}
width = view_port_width ;
height = view_port_height ;
int pitch = gbuffer - > Get_Width ( ) ;
for ( int i = 0 ; i < view_port_height ; + + i , buffer_in + = view_port_width , raw_buffer + = pitch ) {
memcpy ( buffer_in , raw_buffer , view_port_width ) ;
}
return true ;
}
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Palette ( unsigned char ( & palette_in ) [ 256 ] [ 3 ] )
{
memcpy ( palette_in , CurrentPalette , sizeof ( palette_in ) ) ;
return true ;
}
/**************************************************************************************************
* CNC_Set_Multiplayer_Data - - Set up for a multiplayer match
*
* In : Multiplayer data
*
* Out : false if data is bad
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Set_Multiplayer_Data ( int scenario_index , CNCMultiplayerOptionsStruct & game_options , int num_players , CNCPlayerInfoStruct * player_list , int max_players )
{
if ( num_players < = 0 ) {
return false ;
}
if ( num_players > min ( MAX_PLAYERS , max_players ) ) {
return false ;
}
DLLExportClass : : Init ( ) ;
Session . Options . Bases = game_options . MPlayerBases ; // 1 = bases are on for this scenario
Session . Options . Credits = game_options . MPlayerCredits ; // # credits everyone gets
Session . Options . Tiberium = game_options . MPlayerTiberium ; // 1 = tiberium enabled for this scenario
Session . Options . Goodies = game_options . MPlayerGoodies ; // 1 = goodies enabled for this scenario
Session . Options . Ghosts = game_options . MPlayerGhosts ; // 1 = houses with no players will still play
//MPlayerSolo = game_options.MPlayerSolo; // 1 = allows a single-player net game
Session . Options . UnitCount = game_options . MPlayerUnitCount ; // # units for non-base multiplayer scenarios
Special . IsShadowGrow = game_options . MPlayerShadowRegrow ;
Special . IsCaptureTheFlag = game_options . CaptureTheFlag ;
if ( Session . Options . Tiberium ) {
Special . IsTGrowth = 1 ;
Special . IsTSpread = 1 ;
} else {
Special . IsTGrowth = 0 ;
Special . IsTSpread = 0 ;
}
Session . Options . ScenarioIndex = scenario_index ;
Special . IsMCVDeploy = game_options . IsMCVDeploy ;
Special . UseMCVDeploy = true ;
MPSuperWeaponDisable = ! game_options . EnableSuperweapons ; // Are superweapons available
//Session.Options.AIPlayers = WWGetPrivateProfileInt("Options", "AI", 0, buffer); //Number of AI players
Special . IsEarlyWin = game_options . DestroyStructures ;
2020-08-06 09:44:54 -07:00
Special . ModernBalance = game_options . ModernBalance ;
2020-05-27 12:16:20 -07:00
/*
* * Enable Counterstrike / Aftermath units
*/
OverrideNewUnitsEnabled = game_options . MPlayerAftermathUnits ;
while ( Session . Players . Count ( ) > 0 ) {
delete Session . Players [ 0 ] ;
Session . Players . Delete ( Session . Players [ 0 ] ) ;
}
for ( int i = 0 ; i < num_players ; i + + ) {
CNCPlayerInfoStruct & player_info = player_list [ i ] ;
NodeNameType * who = new NodeNameType ;
strncpy ( who - > Name , player_info . Name , MPLAYER_NAME_MAX ) ;
who - > Name [ MPLAYER_NAME_MAX - 1 ] = 0 ; // Make sure it's terminated
who - > Player . House = ( HousesType ) player_info . House ;
who - > Player . Color = ( PlayerColorType ) player_info . ColorIndex ;
Session . Players . Add ( who ) ;
/*
* * Player IDs are done differently in Red Alert vs . TD .
* * In TD , the ID is created from the house / color combination
* * In RA , the ID is HOUSE_MULTI1 + the index into the Session . Players vector
*/
DLLExportClass : : GlyphxPlayerIDs [ i ] = player_info . GlyphxPlayerID ;
MPlayerIsHuman [ i ] = ! player_info . IsAI ;
MPlayerTeamIDs [ i ] = player_info . Team ;
MPlayerStartLocations [ i ] = player_info . StartLocationIndex ;
/*
* * Temp fix for custom maps that don ' t have valid start positions set from matchmaking
*/
if ( i > 0 & & MPlayerStartLocations [ i ] = = 0 & & MPlayerStartLocations [ 0 ] = = 0 ) {
MPlayerStartLocations [ i ] = i ;
}
}
/*
* * Force smart defense always on for multiplayer / skirmish
*/
Rule . IsSmartDefense = true ;
2020-08-06 09:44:54 -07:00
/*
* * Backup special
*/
if ( SpecialBackup ! = NULL ) {
memcpy ( SpecialBackup , & Special , sizeof ( SpecialClass ) ) ;
}
2020-05-27 12:16:20 -07:00
return true ;
}
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Clear_Object_Selection ( uint64 player_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
Unselect_All ( ) ;
return true ;
}
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Select_Object ( uint64 player_id , int object_type_id , int object_to_select_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
switch ( object_type_id )
{
case INFANTRY :
{
for ( int index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * obj = Infantry . Ptr ( index ) ;
if ( obj
& & ! obj - > IsInLimbo
& & obj - > House - > IsPlayerControl
& & Infantry . ID ( ( InfantryClass * ) obj ) = = object_to_select_id )
{
if ( ! obj - > Is_Selected_By_Player ( ) )
{
obj - > Select ( ) ;
AllowVoice = false ;
}
return true ;
}
}
}
break ;
case UNIT :
{
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj
& & ! obj - > IsInLimbo
& & obj - > House - > IsPlayerControl
& & Units . ID ( ( UnitClass * ) obj ) = = object_to_select_id )
{
if ( ! obj - > Is_Selected_By_Player ( ) )
{
obj - > Select ( ) ;
AllowVoice = false ;
}
return true ;
}
}
}
break ;
case AIRCRAFT :
{
for ( int index = 0 ; index < Aircraft . Count ( ) ; index + + ) {
AircraftClass * obj = Aircraft . Ptr ( index ) ;
if ( obj
& & ! obj - > IsInLimbo
& & obj - > House - > IsPlayerControl
& & Aircraft . ID ( ( AircraftClass * ) obj ) = = object_to_select_id )
{
if ( ! obj - > Is_Selected_By_Player ( ) )
{
obj - > Select ( ) ;
AllowVoice = false ;
}
return true ;
}
}
}
break ;
case BUILDING :
{
for ( int index = 0 ; index < Buildings . Count ( ) ; index + + ) {
BuildingClass * obj = Buildings . Ptr ( index ) ;
if ( obj
& & ! obj - > IsInLimbo
& & obj - > House - > IsPlayerControl
& & Buildings . ID ( ( BuildingClass * ) obj ) = = object_to_select_id )
{
if ( ! obj - > Is_Selected_By_Player ( ) )
{
obj - > Select ( ) ;
AllowVoice = false ;
}
return true ;
}
}
}
break ;
case VESSEL :
{
for ( int index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass * obj = Vessels . Ptr ( index ) ;
if ( obj
& & ! obj - > IsInLimbo
& & obj - > House - > IsPlayerControl
& & Vessels . ID ( ( VesselClass * ) obj ) = = object_to_select_id )
{
if ( ! obj - > Is_Selected_By_Player ( ) )
{
obj - > Select ( ) ;
AllowVoice = false ;
}
return true ;
}
}
}
break ;
}
return false ;
}
/**************************************************************************************************
* GlyphX_Assign_Houses - - Replacement for Assign_Houses in INI . CPP / SCNEARIO . CPP
*
* In :
*
* Out :
*
*
*
* History : 8 / 8 / 2019 12 : 37 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void GlyphX_Assign_Houses ( void )
{
/*
* * RA version
*/
extern int _build_tech [ 11 ] ;
int assigned [ MAX_PLAYERS ] ;
bool preassigned ;
int i , j , random_start_location ;
HousesType house , house2 ;
HouseClass * housep , * housep2 ;
int lowest_color ;
int index ;
srand ( timeGetTime ( ) ) ;
/*
* * Use pre - selected start locations as long as at least one has been defined , otherwise let the original code
* * in SCENARIO . CPP figure it out
*/
UseGlyphXStartLocations = false ;
/*
* * Assign random start positions if needed .
*/
int random_start_locations [ 26 ] ;
int num_start_locations = 0 ;
int num_random_start_locations = 0 ;
for ( i = 0 ; i < 26 ; i + + ) {
if ( Scen . Waypoint [ i ] ! = - 1 ) {
preassigned = false ;
for ( j = 0 ; ! preassigned & & ( j < Session . Players . Count ( ) ) ; j + + ) {
if ( MPlayerStartLocations [ j ] = = num_start_locations ) {
preassigned = true ;
UseGlyphXStartLocations = true ;
}
}
2020-09-16 10:03:04 -07:00
if ( ! preassigned & & i < MAX_PLAYERS ) {
2020-05-27 12:16:20 -07:00
random_start_locations [ num_random_start_locations ] = num_start_locations ;
num_random_start_locations + + ;
}
num_start_locations + + ;
}
}
if ( num_random_start_locations > 1 ) {
for ( i = 0 ; i < num_random_start_locations - 1 ; i + + ) {
j = i + rand ( ) / ( RAND_MAX / ( num_random_start_locations - i ) + 1 ) ;
int t = random_start_locations [ j ] ;
random_start_locations [ j ] = random_start_locations [ i ] ;
random_start_locations [ i ] = t ;
}
}
//------------------------------------------------------------------------
// Initialize
//------------------------------------------------------------------------
for ( i = 0 ; i < MAX_PLAYERS ; i + + ) {
assigned [ i ] = 0 ;
}
random_start_location = 0 ;
// debugprint( "Assign_Houses()\n" );
//------------------------------------------------------------------------
// Assign each player in 'Players' to a multiplayer house. Players will
// be sorted by their chosen color value (this value must be unique among
// all the players).
//------------------------------------------------------------------------
for ( i = 0 ; i < Session . Players . Count ( ) ; i + + ) {
//.....................................................................
// Find the player with the lowest color index
//.....................................................................
index = 0 ;
lowest_color = 255 ;
for ( j = 0 ; j < Session . Players . Count ( ) ; j + + ) {
//..................................................................
// If we've already assigned this house, skip it.
//..................................................................
if ( assigned [ j ] ) {
continue ;
}
if ( Session . Players [ j ] - > Player . Color < lowest_color ) {
lowest_color = Session . Players [ j ] - > Player . Color ;
index = j ;
}
}
//.....................................................................
// Mark this player as having been assigned.
//.....................................................................
assigned [ index ] = 1 ;
//.....................................................................
// Assign the lowest-color'd player to the next available slot in the
// HouseClass array.
//.....................................................................
house = ( HousesType ) ( i + HOUSE_MULTI1 ) ;
housep = HouseClass : : As_Pointer ( house ) ;
memset ( ( char * ) housep - > IniName , 0 , MPLAYER_NAME_MAX ) ;
strncpy ( ( char * ) housep - > IniName , Session . Players [ index ] - > Name , MPLAYER_NAME_MAX - 1 ) ;
# ifdef WOLAPI_INTEGRATION
// Make another copy of name, permanent throughout entire game.
strncpy ( ( char * ) housep - > InitialName , Session . Players [ index ] - > Name , MPLAYER_NAME_MAX - 1 ) ;
# endif
housep - > IsHuman = MPlayerIsHuman [ index ] ;
housep - > IsPlayerControl = housep - > IsHuman ;
if ( ! housep - > IsHuman ) {
housep - > IsStarted = true ;
strncpy ( housep - > IniName , Text_String ( TXT_COMPUTER ) , HOUSE_NAME_MAX ) ;
housep - > IQ = Rule . MaxIQ ;
//housep->Control.TechLevel = _build_tech[BuildLevel];
2020-08-12 11:32:36 -07:00
} else {
housep - > IQ = 0 ;
2020-05-27 12:16:20 -07:00
}
housep - > Init_Data ( ( PlayerColorType ) ( Session . Players [ index ] - > Player . Color ) ,
Session . Players [ index ] - > Player . House , Session . Options . Credits ) ;
/*
* * Set the start location override
*/
if ( MPlayerStartLocations [ index ] ! = RANDOM_START_POSITION ) {
housep - > StartLocationOverride = MPlayerStartLocations [ index ] ;
} else {
if ( random_start_location < num_random_start_locations ) {
housep - > StartLocationOverride = random_start_locations [ random_start_location + + ] ;
} else {
housep - > StartLocationOverride = - 1 ;
}
}
if ( index = = 0 ) {
PlayerPtr = housep ;
}
/*
* * Convert the build level into an actual tech level to assign to the house .
* * There isn ' t a one - to - one correspondence .
*/
housep - > Control . TechLevel = _build_tech [ BuildLevel ] ;
housep - > Assign_Handicap ( Scen . Difficulty ) ;
//.....................................................................
// Record where we placed this player
//.....................................................................
Session . Players [ index ] - > Player . ID = house ;
// debugprint( "Assigned ID of %i to %s\n", house, Session.Players[index]->Name );
}
for ( i = Session . Players . Count ( ) ; i < Rule . MaxPlayers ; i + + ) {
house = ( HousesType ) ( i + HOUSE_MULTI1 ) ;
housep = HouseClass : : As_Pointer ( house ) ;
if ( housep ! = NULL ) {
housep - > IsDefeated = true ;
}
}
for ( i = 0 ; i < Session . Players . Count ( ) ; i + + ) {
house = Session . Players [ i ] - > Player . ID ;
housep = HouseClass : : As_Pointer ( house ) ;
if ( housep ) {
int team = MPlayerTeamIDs [ i ] ;
for ( int j = 0 ; j < Session . Players . Count ( ) ; j + + ) {
if ( i ! = j ) {
if ( team = = MPlayerTeamIDs [ j ] ) {
house2 = Session . Players [ j ] - > Player . ID ;
housep2 = HouseClass : : As_Pointer ( house2 ) ;
if ( housep2 ) {
housep - > Make_Ally ( house2 ) ;
}
}
}
}
}
}
}
/**************************************************************************************************
* CNC_Set_Home_Cell - - Allows overriding the start position for the camera
*
*
* History : 2 / 14 / 2020 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Set_Home_Cell ( int x , int y , uint64 player_id )
{
DLLExportClass : : Set_Home_Cell ( x , y , player_id ) ;
}
/**************************************************************************************************
* CNC_Start_Instance - - Load and start a cnc map - > WITHOUT SPECIFYING A SCENARIO VARIATION ( SCEN_VAR )
*
* In : Map initialization parameters
*
* Out : false if map load failed
*
*
*
* History : 7 / 10 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Instance ( int scenario_index , int build_level , const char * faction , const char * game_type , const char * content_directory , int sabotaged_structure , const char * override_map_name )
{
return CNC_Start_Instance_Variation ( scenario_index , ( int ) SCEN_VAR_NONE , ( int ) SCEN_DIR_EAST , build_level , faction , game_type , content_directory , sabotaged_structure , override_map_name ) ;
}
/**************************************************************************************************
* CNC_Start_Instance - - Load and start a cnc map
*
* In : Map initialization parameters
*
* Out : false if map load failed
*
*
* Renamed and modified to accept a scenario variation 7 / 10 / 2019 - LLL
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Instance_Variation ( int scenario_index , int scenario_variation , int scenario_direction , int build_level , const char * faction , const char * game_type , const char * content_directory , int sabotaged_structure , const char * override_map_name )
{
if ( game_type = = NULL ) {
return false ;
}
if ( faction = = NULL ) {
return false ;
}
if ( content_directory = = NULL ) {
return false ;
}
ScenarioPlayerType scen_player = SCEN_PLAYER_NONE ;
if ( stricmp ( faction , " SPAIN " ) = = 0 ) {
scen_player = SCEN_PLAYER_SPAIN ;
Whom = HOUSE_GOOD ;
}
if ( stricmp ( faction , " GREECE " ) = = 0 | | stricmp ( faction , " ALLY " ) = = 0 ) {
scen_player = SCEN_PLAYER_GREECE ;
Whom = HOUSE_GOOD ;
}
if ( stricmp ( faction , " USSR " ) = = 0 ) {
scen_player = SCEN_PLAYER_USSR ;
Whom = HOUSE_BAD ;
}
DLLExportClass : : Set_Content_Directory ( content_directory ) ;
BuildLevel = build_level ;
Scen . Scenario = scenario_index ;
ScenarioDirType scen_dir = ( ScenarioDirType ) scenario_direction ;
if ( stricmp ( game_type , " GAME_NORMAL " ) = = 0 ) {
GAME_TO_PLAY = GAME_NORMAL ;
if ( scen_player = = SCEN_PLAYER_NONE ) {
return false ;
}
} else {
if ( stricmp ( game_type , " GAME_GLYPHX_MULTIPLAYER " ) = = 0 ) {
GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER ;
scen_player = SCEN_PLAYER_MPLAYER ;
} else {
return false ;
}
}
/*
* * Load the scenario . Specify variation ' A ' for the editor ; for the game ,
* * don ' t specify a variation , to make ' Set_Scenario_Name ( ) ' pick a random one .
* * Skip this if we ' ve already loaded a save - game .
*/
Force_CD_Available ( ALWAYS_RELOAD_CD ) ;
if ( override_map_name & & strlen ( override_map_name ) ) {
strcpy ( Scen . ScenarioName , override_map_name ) ;
} else {
Scen . Set_Scenario_Name ( Scen . Scenario , scen_player , scen_dir , ( ScenarioVarType ) scenario_variation ) ;
}
HiddenPage . Clear ( ) ;
VisiblePage . Clear ( ) ;
/*
* * Set the mouse to some position where it ' s not going to scroll , or do something else wierd .
*/
DLLForceMouseX = 100 ;
DLLForceMouseY = 100 ;
KEYBOARD - > MouseQX = 100 ;
KEYBOARD - > MouseQY = 100 ;
GlyphXClientSidebarWidthInLeptons = 0 ;
Seed = GetRandSeed ( ) ;
Scen . RandomNumber = Seed ;
if ( ! Start_Scenario ( Scen . ScenarioName ) ) {
return ( false ) ;
}
DLLExportClass : : Reset_Sidebars ( ) ;
DLLExportClass : : Reset_Player_Context ( ) ;
DLLExportClass : : Calculate_Start_Positions ( ) ;
/*
* * Make sure the scroll constraints are applied . This is important for GDI 1 where the map isn ' t wide enough for the screen
*/
COORDINATE origin_coord = Coord_Add ( Map . TacticalCoord , XY_Coord ( 1 , 0 ) ) ;
Map . Set_Tactical_Position ( origin_coord ) ;
origin_coord = Coord_Add ( Map . TacticalCoord , XY_Coord ( - 1 , 0 ) ) ;
Map . Set_Tactical_Position ( origin_coord ) ;
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
MPSuperWeaponDisable = false ;
} else {
if ( MPSuperWeaponDisable ) {
/*
* * Write over the tecb level settings we just loaded from the Rules ini
*/
Rule . GPSTechLevel = 100 ;
Rule . ParaInfantryTechLevel = 100 ;
Rule . SpyPlaneTechLevel = 100 ;
Rule . ParaBombTechLevel = 100 ;
Rule . ChronoTechLevel = 100 ;
}
}
/*
* * Hide the SeenBuff ; force the map to render one frame . The caller can
* * then fade the palette in .
* * ( If we loaded a game , this step will fade out the title screen . If we
* * started a scenario , Start_Scenario ( ) will have played a couple of VQ
* * movies , which will have cleared the screen to black already . )
*/
//Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
HiddenPage . Clear ( ) ;
VisiblePage . Clear ( ) ;
Set_Logic_Page ( SeenBuff ) ;
/*
* * Sidebar is always active in hi - res .
*/
if ( ! Debug_Map ) {
Map . SidebarClass : : Activate ( 1 ) ;
}
Map . Flag_To_Redraw ( true ) ;
Set_Palette ( GamePalette . Get_Data ( ) ) ;
Map . Render ( ) ;
Set_Palette ( GamePalette . Get_Data ( ) ) ;
return true ;
}
/**************************************************************************************************
* CNC_Read_INI - - Load an ini file into the supplied buffer
*
* In : Map initialization parameters
*
* Out : false if ini load failed
*
*
* History : 12 / 16 / 2019 11 : 44 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Read_INI ( int scenario_index , int scenario_variation , int scenario_direction , const char * content_directory , const char * override_map_name , char * ini_buffer , int _ini_buffer_size )
{
if ( content_directory = = NULL ) {
return false ;
}
DLLExportClass : : Set_Content_Directory ( content_directory ) ;
Scen . Scenario = scenario_index ;
ScenarioDirType scen_dir = ( ScenarioDirType ) scenario_direction ;
GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER ;
ScenarioPlayerType scen_player = SCEN_PLAYER_MPLAYER ;
Force_CD_Available ( ALWAYS_RELOAD_CD ) ;
if ( override_map_name & & strlen ( override_map_name ) ) {
strcpy ( Scen . ScenarioName , override_map_name ) ;
} else {
Scen . Set_Scenario_Name ( Scen . Scenario , scen_player , scen_dir , ( ScenarioVarType ) scenario_variation ) ;
}
if ( _ini_buffer_size < _ShapeBufferSize ) {
GlyphX_Debug_Print ( " INI file buffer may be too small " ) ;
return false ;
}
if ( ! ini_buffer ) {
GlyphX_Debug_Print ( " No INI file buffer " ) ;
return false ;
}
memset ( ini_buffer , _ini_buffer_size , 0 ) ;
CCFileClass file ( Scen . ScenarioName ) ;
if ( ! file . Is_Available ( ) ) {
GlyphX_Debug_Print ( " Failed to find scenario file " ) ;
GlyphX_Debug_Print ( Scen . ScenarioName ) ;
return ( false ) ;
} else {
GlyphX_Debug_Print ( " Opened scenario file " ) ;
GlyphX_Debug_Print ( Scen . ScenarioName ) ;
int bytes_read = file . Read ( ini_buffer , _ini_buffer_size - 1 ) ;
if ( bytes_read = = _ini_buffer_size - 1 ) {
GlyphX_Debug_Print ( " INI file buffer is too small " ) ;
return false ;
}
}
/*
* * Ini buffer should be zero terminated
*/
if ( ( int ) strlen ( ini_buffer ) > = _ini_buffer_size ) {
GlyphX_Debug_Print ( " INI file buffer overrun " ) ;
return false ;
}
return true ;
}
/**************************************************************************************************
* CNC_Start_Custom_Instance - - Load and start a custom map
*
* In : Map initialization parameters
*
* Out : false if map load failed
*
*
*
* History : 2019 / 10 / 28 - JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Start_Custom_Instance ( const char * content_directory , const char * directory_path , const char * scenario_name , int build_level , bool multiplayer )
{
DLLExportClass : : Set_Content_Directory ( content_directory ) ;
char fullname [ _MAX_FNAME + _MAX_EXT ] ;
snprintf ( fullname , _MAX_FNAME + _MAX_EXT , " %s%s.mpr " , directory_path , scenario_name ) ;
char name_buffer [ 128 ] ;
char digest_buffer [ 32 ] ;
CCFileClass file ( fullname ) ;
INIClass ini ;
ini . Load ( file ) ;
ini . Get_String ( " Basic " , " Name " , " No Name " , name_buffer , sizeof ( name_buffer ) ) ;
ini . Get_String ( " Digest " , " 1 " , " No Digest " , digest_buffer , sizeof ( digest_buffer ) ) ;
Session . Scenarios . Add ( new MultiMission ( fullname , name_buffer , digest_buffer , ini . Get_Bool ( " Basic " , " Official " , false ) , false ) ) ;
BuildLevel = build_level ;
ScenarioPlayerType scen_player ;
strncpy ( Scen . ScenarioName , fullname , _MAX_FNAME + _MAX_EXT ) ;
if ( multiplayer ) {
GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER ;
} else {
GAME_TO_PLAY = GAME_NORMAL ;
}
scen_player = SCEN_PLAYER_MPLAYER ;
//Scen.Scenario = scenario_index;
//ScenarioDirType scen_dir = (ScenarioDirType)scenario_direction;
//if (stricmp(game_type, "GAME_NORMAL") == 0) {
// GAME_TO_PLAY = GAME_NORMAL;
//}
//else {
// if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
// GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
// scen_player = SCEN_PLAYER_MPLAYER;
// }
// else {
// return false;
// }
//}
///*
//** Load the scenario. Specify variation 'A' for the editor; for the game,
//** don't specify a variation, to make 'Set_Scenario_Name()' pick a random one.
//** Skip this if we've already loaded a save-game.
//*/
//Force_CD_Available(ALWAYS_RELOAD_CD);
//if (override_map_name && strlen(override_map_name)) {
// strcpy(Scen.ScenarioName, override_map_name);
//}
//else {
// Scen.Set_Scenario_Name(Scen.Scenario, scen_player, scen_dir, (ScenarioVarType)scenario_variation);
//}
HiddenPage . Clear ( ) ;
VisiblePage . Clear ( ) ;
/*
* * Set the mouse to some position where it ' s not going to scroll , or do something else wierd .
*/
DLLForceMouseX = 100 ;
DLLForceMouseY = 100 ;
KEYBOARD - > MouseQX = 100 ;
KEYBOARD - > MouseQY = 100 ;
GlyphXClientSidebarWidthInLeptons = 0 ;
Seed = GetRandSeed ( ) ;
Scen . RandomNumber = Seed ;
if ( ! Start_Scenario ( Scen . ScenarioName ) ) {
return ( false ) ;
}
DLLExportClass : : Reset_Sidebars ( ) ;
DLLExportClass : : Reset_Player_Context ( ) ;
DLLExportClass : : Calculate_Start_Positions ( ) ;
/*
* * Make sure the scroll constraints are applied . This is important for GDI 1 where the map isn ' t wide enough for the screen
*/
COORDINATE origin_coord = Coord_Add ( Map . TacticalCoord , XY_Coord ( 1 , 0 ) ) ;
Map . Set_Tactical_Position ( origin_coord ) ;
origin_coord = Coord_Add ( Map . TacticalCoord , XY_Coord ( - 1 , 0 ) ) ;
Map . Set_Tactical_Position ( origin_coord ) ;
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
MPSuperWeaponDisable = false ;
}
else {
if ( MPSuperWeaponDisable ) {
/*
* * Write over the tecb level settings we just loaded from the Rules ini
*/
Rule . GPSTechLevel = 100 ;
Rule . ParaInfantryTechLevel = 100 ;
Rule . SpyPlaneTechLevel = 100 ;
Rule . ParaBombTechLevel = 100 ;
Rule . ChronoTechLevel = 100 ;
}
}
/*
* * Hide the SeenBuff ; force the map to render one frame . The caller can
* * then fade the palette in .
* * ( If we loaded a game , this step will fade out the title screen . If we
* * started a scenario , Start_Scenario ( ) will have played a couple of VQ
* * movies , which will have cleared the screen to black already . )
*/
//Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
HiddenPage . Clear ( ) ;
VisiblePage . Clear ( ) ;
Set_Logic_Page ( SeenBuff ) ;
/*
* * Sidebar is always active in hi - res .
*/
if ( ! Debug_Map ) {
Map . SidebarClass : : Activate ( 1 ) ;
}
Map . Flag_To_Redraw ( true ) ;
Set_Palette ( GamePalette . Get_Data ( ) ) ;
Map . Render ( ) ;
Set_Palette ( GamePalette . Get_Data ( ) ) ;
return true ;
}
bool Debug_Write_Shape_Type ( const ObjectTypeClass * type , int shapenum )
{
char fullname [ _MAX_FNAME + _MAX_EXT ] ;
char buffer [ _MAX_FNAME ] ;
CCFileClass file ;
if ( type - > ImageData ! = NULL ) {
sprintf ( buffer , " %s_%d " , type - > IniName , shapenum ) ;
_makepath ( fullname , NULL , NULL , buffer , " .PCX " ) ;
return Debug_Write_Shape ( fullname , type - > ImageData , shapenum ) ;
}
return false ;
}
bool Debug_Write_Shape ( const char * file_name , void const * shapefile , int shapenum , int flags , void const * ghostdata )
{
/*
* * Build frame returns a pointer now instead of the shapes length
*/
char * shape_pointer = ( char * ) Build_Frame ( shapefile , shapenum , _ShapeBuffer ) ;
if ( shape_pointer = = NULL ) {
return false ; ;
}
if ( Get_Last_Frame_Length ( ) > _ShapeBufferSize ) {
return false ; ;
}
int width = Get_Build_Frame_Width ( shapefile ) ;
int height = Get_Build_Frame_Height ( shapefile ) ;
GraphicBufferClass temp_gbuffer ( width , height ) ;
GraphicViewPortClass temp_viewport ( & temp_gbuffer , 0 , 0 , width , height ) ;
WindowList [ WINDOW_CUSTOM ] [ WINDOWX ] = 0 ;
WindowList [ WINDOW_CUSTOM ] [ WINDOWY ] = 0 ;
WindowList [ WINDOW_CUSTOM ] [ WINDOWWIDTH ] = width ;
WindowList [ WINDOW_CUSTOM ] [ WINDOWHEIGHT ] = height ;
static const char _shape_trans = 0x40 ;
if ( flags = = 0 ) {
Buffer_Frame_To_Page ( 0 , 0 , width , height , shape_pointer , temp_viewport , SHAPE_NORMAL | SHAPE_WIN_REL | _shape_trans ) ; //, ghostdata, predoffset);
} else {
Buffer_Frame_To_Page ( 0 , 0 , width , height , shape_pointer , temp_viewport , flags , ghostdata ) ;
}
Write_PCX_File ( ( char * ) file_name , temp_viewport , ( unsigned char * ) GamePalette . Get_Data ( ) ) ;
return true ;
}
/**************************************************************************************************
* CNC_Advance_Instance - - Process one logic frame
*
* In :
*
* Out : Is game still playing ?
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Advance_Instance ( uint64 player_id )
{
//DLLExportClass::Set_Event_Callback(event_callback);
if ( Frame < = 10 ) { // Don't spam forever, but useful to know that we actually started advancing
GlyphX_Debug_Print ( " CNC_Advance_Instance - RA " ) ;
}
2020-08-06 09:44:54 -07:00
2020-05-27 12:16:20 -07:00
/*
* * Shouldn ' t really need to do this , but I like the idea of always running the main loop in the context of the same player .
* * Might make tbe bugs more repeatable and consistent . ST - 3 / 15 / 2019 11 : 58 AM
*/
if ( player_id ! = 0 ) {
DLLExportClass : : Set_Player_Context ( player_id ) ;
} else {
DLLExportClass : : Set_Player_Context ( DLLExportClass : : GlyphxPlayerIDs [ 0 ] ) ;
}
2020-08-06 09:44:54 -07:00
/*
* * Restore special from backup
*/
if ( SpecialBackup ! = NULL ) {
memcpy ( & Special , SpecialBackup , sizeof ( SpecialClass ) ) ;
}
2020-05-27 12:16:20 -07:00
# ifdef FIXIT_CSII // checked - ajw 9/28/98
TimeQuake = PendingTimeQuake ;
PendingTimeQuake = false ;
# else
TimeQuake = false ;
# endif
/*
* * Allocate extra memory for uncompressed shapes as needed
*/
Reallocate_Big_Shape_Buffer ( ) ;
/*
* * If there is no theme playing , but it looks like one is required , then start one
* * playing . This is usually the symptom of there being no transition score .
*/
//if (SampleType && Theme.What_Is_Playing() == THEME_NONE) {
// Theme.Queue_Song(THEME_PICK_ANOTHER);
//}
/*
* * Update the display , unless we ' re inside a dialog .
*/
//if (SpecialDialog == SDLG_NONE && GameInFocus) {
//WWMouse->Erase_Mouse(&HidPage, TRUE);
//Map.Input(input, x, y);
//if (input) {
// Keyboard_Process(input);
//}
/*
* * The main loop passes these in uninitialized . ST - 2 / 7 / 2019 4 : 36 PM
*/
KeyNumType input = KN_NONE ; // Player input.
int x = 0 ;
int y = 0 ;
Map . Input ( input , x , y ) ;
//if (input) {
// Keyboard_Process(input);
//}
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
/*
* * Process the sidebar . ST - 4 / 18 / 2019 11 : 59 AM
*/
HouseClass * old_player_ptr = PlayerPtr ;
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
DLLExportClass : : Logic_Switch_Player_Context ( player_ptr ) ;
Sidebar_Glyphx_AI ( player_ptr , input ) ;
}
DLLExportClass : : Logic_Switch_Player_Context ( old_player_ptr ) ;
}
//}
/*
* * Sort the map ' s ground layer by y - coordinate value . This is done
* * outside the IsToRedraw check , for the purposes of game sync ' ing
* * between machines ; this way , all machines will sort the Map ' s
* * layer in the same way , and any processing done that ' s based on
* * the order of this layer will sync on different machines .
*/
Map . Layer [ LAYER_GROUND ] . Sort ( ) ;
/*
* * AI logic operations are performed here .
*/
//Skip this block of code on first update of single-player games. This helps prevents trigger generated messages on the first update from being lost during loading screen or movie. - LLL
static bool FirstUpdate = GAME_TO_PLAY ! = GAME_GLYPHX_MULTIPLAYER ; ;
if ( ! FirstUpdate ) {
HouseClass * old_player_ptr = PlayerPtr ;
Logic . Clear_Recently_Created_Bits ( ) ;
Logic . AI ( ) ;
DLLExportClass : : Logic_Switch_Player_Context ( old_player_ptr ) ;
}
FirstUpdate = false ;
TimeQuake = false ;
# ifdef FIXIT_CSII // checked - ajw 9/28/98
if ( ! PendingTimeQuake ) {
TimeQuakeCenter = 0 ;
}
# endif
/*
* * Manage the inter - player message list . If Manage ( ) returns true , it means
* * a message has expired & been removed , and the entire map must be updated .
*/
if ( Session . Messages . Manage ( ) ) {
# ifdef WIN32
HiddenPage . Clear ( ) ;
# else //WIN32
HidPage . Clear ( ) ;
# endif //WIN32
Map . Flag_To_Redraw ( true ) ;
}
/*
* * Process all commands that are ready to be processed .
*/
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
Queue_AI ( ) ;
} else {
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
DLLExportClass : : Glyphx_Queue_AI ( ) ;
/*
* * Process the sidebar . ST - 3 / 22 / 2019 2 : 07 PM
*/
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
Sidebar_Glyphx_Recalc ( player_ptr ) ;
}
}
}
/*
* * Keep track of elapsed time in the game .
*/
//Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND;
/*
* * Perform any win / lose code as indicated by the global control flags .
*/
/*
* * Check for player wins or loses according to global event flag .
*/
if ( PlayerWins ) {
//WWMouse->Erase_Mouse(&HidPage, TRUE);
PlayerLoses = false ;
PlayerWins = false ;
PlayerRestarts = false ;
Map . Help_Text ( TXT_NONE ) ;
GlyphX_Debug_Print ( " PlayerWins = true " ) ;
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
DLLExportClass : : On_Multiplayer_Game_Over ( ) ;
} else {
DLLExportClass : : On_Game_Over ( player_id , true ) ;
}
//DLLExportClass::Set_Event_Callback(NULL);
return false ;
}
if ( PlayerLoses ) {
//WWMouse->Erase_Mouse(&HidPage, TRUE);
PlayerWins = false ;
PlayerLoses = false ;
PlayerRestarts = false ;
Map . Help_Text ( TXT_NONE ) ;
GlyphX_Debug_Print ( " PlayerLoses = true " ) ;
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
DLLExportClass : : On_Multiplayer_Game_Over ( ) ;
} else {
DLLExportClass : : On_Game_Over ( player_id , false ) ;
}
//DLLExportClass::Set_Event_Callback(NULL);
return false ;
}
/*
* * The frame logic has been completed . Increment the frame
* * counter .
*/
Frame + + ;
/*
* * Very rarely , the human players will get a message from the computer .
* *
* * This was disabled in the RA source code , so copying over the functionality from TD
*/
if ( GAME_TO_PLAY ! = GAME_NORMAL & & Session . Options . Ghosts & & IRandom ( 0 , 10000 ) = = 1 ) {
DLLExportClass : : Computer_Message ( false ) ;
}
if ( ProgEndCalled ) {
GlyphX_Debug_Print ( " ProgEndCalled - GameActive = false " ) ;
GameActive = false ;
}
if ( DLLExportClass : : Legacy_Render_Enabled ( ) ) {
Map . Render ( ) ;
}
//Sync_Delay();
//DLLExportClass::Set_Event_Callback(NULL);
Color_Cycle ( ) ;
2020-08-06 09:44:54 -07:00
/*
* * Don ' t respect GameActive . Game will end in multiplayer on win / loss
*/
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
return true ;
}
2020-05-27 12:16:20 -07:00
return ( GameActive ) ;
}
/**************************************************************************************************
* CNC_Save_Load - - Process a save or load game action
*
* In :
*
* Out : Success ?
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Save_Load ( bool save , const char * file_path_and_name , const char * game_type )
{
bool result = false ;
if ( save ) {
result = Save_Game ( file_path_and_name , " internal " ) ;
} else {
if ( game_type = = NULL ) {
return false ;
}
if ( stricmp ( game_type , " GAME_NORMAL " ) = = 0 ) {
GAME_TO_PLAY = GAME_NORMAL ;
} else {
if ( stricmp ( game_type , " GAME_GLYPHX_MULTIPLAYER " ) = = 0 ) {
GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER ;
//ScenPlayer = SCEN_PLAYER_MPLAYER;
} else {
return false ;
}
}
while ( Session . Players . Count ( ) > 0 ) {
delete Session . Players [ 0 ] ;
Session . Players . Delete ( Session . Players [ 0 ] ) ;
}
result = Load_Game ( file_path_and_name ) ;
2020-08-06 09:44:54 -07:00
if ( result = = false )
{
return false ;
}
2020-05-27 12:16:20 -07:00
DLLExportClass : : Set_Player_Context ( DLLExportClass : : GlyphxPlayerIDs [ 0 ] , true ) ;
2020-09-16 10:03:04 -07:00
DLLExportClass : : Cancel_Placement ( DLLExportClass : : GlyphxPlayerIDs [ 0 ] , - 1 , - 1 ) ;
2020-05-27 12:16:20 -07:00
Set_Logic_Page ( SeenBuff ) ;
VisiblePage . Clear ( ) ;
Map . Flag_To_Redraw ( true ) ;
if ( DLLExportClass : : Legacy_Render_Enabled ( ) ) {
Map . Render ( ) ;
}
Set_Palette ( GamePalette . Get_Data ( ) ) ;
}
return result ;
}
/**************************************************************************************************
* CNC_Set_Difficulty - - Set game difficulty
*
* In :
*
* Out :
*
*
*
* History : 10 / 02 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Set_Difficulty ( int difficulty )
{
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
Set_Scenario_Difficulty ( difficulty ) ;
}
}
/**************************************************************************************************
* CNC_Restore_Carryover_Objects
*
* History : 11 / 15 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Restore_Carryover_Objects ( const CarryoverObjectStruct * objects )
{
//Delete the list
while ( Carryover ) {
CarryoverClass * cptr = ( CarryoverClass * ) Carryover - > Get_Next ( ) ;
delete Carryover ;
Carryover = cptr ;
}
//Populate the list
const CarryoverObjectStruct * next_object = objects ;
while ( next_object ) {
CarryoverClass * cptr = new CarryoverClass ( ) ;
cptr - > RTTI = ( RTTIType ) next_object - > RTTI ;
cptr - > Type . Building = ( StructType ) next_object - > Type ; //This works regardless of what the RTTI-type and the enum type, because they're all enums. - LLL
cptr - > Cell = ( CELL ) next_object - > Cell ;
cptr - > House = ( HousesType ) next_object - > House ;
cptr - > Strength = next_object - > Strength ;
next_object = next_object - > Next ;
if ( Carryover = = NULL ) {
Carryover = cptr ;
}
else {
cptr - > Add_Tail ( * Carryover ) ;
}
}
}
/**************************************************************************************************
* CNC_Handle_Player_Switch_To_AI - - Renamed 3 / 9 / 2020 - LLL
* CNC_Handle_Player_Disconnect - - Handle player disconnected during multiplayer game
*
* In :
*
* Out :
*
*
*
* History : 12 / 3 / 2019 1 : 46 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Player_Switch_To_AI ( uint64 player_id )
{
if ( PlayerWins | | PlayerLoses | | DLLExportClass : : Get_Game_Over ( ) ) {
return ;
}
GlyphX_Debug_Print ( " CNC_Handle_Player_Switch_To_AI " ) ;
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
return ;
}
2020-06-22 09:43:21 -07:00
# ifdef KILL_PLAYER_ON_DISCONNECT
/*
* * Kill player ' s units on disconnect .
*/
if ( player_id ! = 0 ) {
DLLExportClass : : Set_Player_Context ( player_id ) ;
if ( PlayerPtr ) {
PlayerPtr - > Flag_To_Die ( ) ;
}
}
# else //KILL_PLAYER_ON_DISCONNECT
2020-05-27 12:16:20 -07:00
if ( player_id ! = 0 ) {
2020-06-22 09:43:21 -07:00
HousesType house ;
HouseClass * ptr ;
2020-05-27 12:16:20 -07:00
DLLExportClass : : Set_Player_Context ( player_id ) ;
if ( PlayerPtr ) {
PlayerPtr - > WasHuman = true ;
PlayerPtr - > IsHuman = false ;
PlayerPtr - > IQ = Rule . MaxIQ ;
strcpy ( PlayerPtr - > IniName , Text_String ( TXT_COMPUTER ) ) ;
PlayerPtr - > IsBaseBuilding = true ;
/*
* * Start the unload mission for MCVs
*/
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr ) {
if ( * obj = = UNIT_MCV ) {
obj - > Assign_Mission ( MISSION_GUARD ) ;
obj - > Assign_Target ( TARGET_NONE ) ;
obj - > Assign_Destination ( TARGET_NONE ) ;
obj - > Assign_Mission ( MISSION_UNLOAD ) ;
obj - > Commence ( ) ;
}
}
}
DLLExportClass : : On_Message ( PlayerPtr , " " , 60.0f , MESSAGE_TYPE_PLAYER_DISCONNECTED , - 1 ) ;
/*
* * Send the disconnect taunt message
*/
int human_count = 0 ;
for ( house = HOUSE_MULTI1 ; house < ( HOUSE_MULTI1 + MULTIPLAYER_COUNT ) ; house + + ) {
ptr = HouseClass : : As_Pointer ( house ) ;
if ( ptr & & ptr - > IsHuman & & ! ptr - > IsDefeated ) {
human_count + + ;
}
}
if ( human_count = = 1 ) {
DLLExportClass : : Computer_Message ( true ) ;
}
}
}
2020-06-22 09:43:21 -07:00
# endif //KILL_PLAYER_ON_DISCONNECT
2020-05-27 12:16:20 -07:00
}
/**************************************************************************************************
* CNC_Handle_Human_Team_Wins
*
* History : 3 / 10 / 2020 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Human_Team_Wins ( uint64 quitting_player_id )
{
GlyphX_Debug_Print ( " CNC_Handle_Human_Team_Wins " ) ;
DLLExportClass : : Force_Human_Team_Wins ( quitting_player_id ) ;
}
/**************************************************************************************************
* CNC_Start_Mission_Timer
*
* History : 11 / 25 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Start_Mission_Timer ( int time )
{
if ( GameActive )
{
Scen . MissionTimer = time ;
if ( ! Scen . MissionTimer . Is_Active ( ) ) {
Scen . MissionTimer . Start ( ) ;
}
Map . Redraw_Tab ( ) ;
}
}
2020-09-16 10:03:04 -07:00
/**************************************************************************************************
* CNC_Get_Start_Game_Info
*
* History : 8 / 31 / 2020 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Start_Game_Info ( uint64 player_id , int & start_location_waypoint_index )
{
start_location_waypoint_index = 0 ;
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
start_location_waypoint_index = PlayerPtr - > StartLocationOverride ;
return true ;
}
/**************************************************************************************************
* Is_Legacy_Render_Enabled - - Is the legacy rendering enabled ?
*
* In :
*
* Out : True if only one human player
*
*
*
* History : 8 / 25 / 2020 5 : 55 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool Is_Legacy_Render_Enabled ( void )
{
return DLLExportClass : : Legacy_Render_Enabled ( ) ;
}
2020-05-27 12:16:20 -07:00
/**************************************************************************************************
* DLLExportClass : : Init - - Init the class
*
* In :
*
* Out :
*
*
*
* History : 3 / 12 / 2019 10 : 52 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Init ( void )
{
for ( int i = 0 ; i < MAX_PLAYERS ; i + + ) {
GlyphxPlayerIDs [ i ] = 0xffffffffull ;
}
CurrentLocalPlayerIndex = 0 ;
MessagesSent . clear ( ) ;
2020-08-06 09:44:54 -07:00
if ( SpecialBackup = = NULL ) {
SpecialBackup = new SpecialClass ;
}
memcpy ( SpecialBackup , & Special , sizeof ( SpecialClass ) ) ;
2020-05-27 12:16:20 -07:00
}
/**************************************************************************************************
* DLLExportClass : : Shutdown - - Shutdown
*
* In :
*
* Out :
*
*
*
* History : 2 / 20 / 2020 1 : 59 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Shutdown ( void )
{
2020-08-06 09:44:54 -07:00
delete SpecialBackup ;
SpecialBackup = NULL ;
2020-05-27 12:16:20 -07:00
for ( int i = 0 ; i < ModSearchPaths . Count ( ) ; i + + ) {
delete [ ] ModSearchPaths [ i ] ;
}
ModSearchPaths . Clear ( ) ;
}
/**************************************************************************************************
* DLLExportClass : : Add_Mod_Path - - Add a path to load mod files from
*
* In : Mod path
*
* Out :
*
*
*
* History : 2 / 20 / 2020 2 : 03 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Add_Mod_Path ( const char * mod_path )
{
char * copy_path = strdup ( mod_path ) ;
ModSearchPaths . Add ( copy_path ) ;
}
/**************************************************************************************************
* DLLExportClass : : Set_Content_Directory - - Update the locations that the original code will load from
*
* In : Main ( official ) content directory
*
* Out :
*
*
*
* History : 2 / 20 / 2020 2 : 03 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Set_Content_Directory ( const char * content_directory )
{
CCFileClass : : Clear_Search_Drives ( ) ;
CCFileClass : : Reset_Raw_Path ( ) ;
if ( ( content_directory = = NULL | | strlen ( content_directory ) = = 0 ) & & ModSearchPaths . Count ( ) = = 0 ) {
return ;
}
char * all_paths = new char [ _MAX_PATH * 100 ] ;
* all_paths = 0 ;
for ( int i = 0 ; i < ModSearchPaths . Count ( ) ; i + + ) {
if ( i ! = 0 ) {
strcat ( all_paths , " ; " ) ;
}
strcat ( all_paths , ModSearchPaths [ i ] ) ;
}
if ( ModSearchPaths . Count ( ) & & content_directory & & strlen ( content_directory ) ) {
strcat ( all_paths , " ; " ) ;
}
if ( content_directory ) {
strcat ( all_paths , content_directory ) ;
}
CCFileClass : : Set_Search_Drives ( all_paths ) ;
delete [ ] all_paths ;
}
/**************************************************************************************************
* DLLExportClass : : Config
*
* History : 1 / 16 / 2020 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Config ( const CNCRulesDataStruct & rules )
{
for ( int i = 0 ; i < 3 ; + + i )
{
Rule . Diff [ i ] . FirepowerBias = rules . Difficulties [ i ] . FirepowerBias ;
Rule . Diff [ i ] . GroundspeedBias = rules . Difficulties [ i ] . GroundspeedBias ;
Rule . Diff [ i ] . AirspeedBias = rules . Difficulties [ i ] . AirspeedBias ;
Rule . Diff [ i ] . ArmorBias = rules . Difficulties [ i ] . ArmorBias ;
Rule . Diff [ i ] . ROFBias = rules . Difficulties [ i ] . ROFBias ;
Rule . Diff [ i ] . CostBias = rules . Difficulties [ i ] . CostBias ;
Rule . Diff [ i ] . BuildSpeedBias = rules . Difficulties [ i ] . BuildSpeedBias ;
Rule . Diff [ i ] . RepairDelay = rules . Difficulties [ i ] . RepairDelay ;
Rule . Diff [ i ] . BuildDelay = rules . Difficulties [ i ] . BuildDelay ;
Rule . Diff [ i ] . IsBuildSlowdown = rules . Difficulties [ i ] . IsBuildSlowdown ? 1 : 0 ;
Rule . Diff [ i ] . IsWallDestroyer = rules . Difficulties [ i ] . IsWallDestroyer ? 1 : 0 ;
Rule . Diff [ i ] . IsContentScan = rules . Difficulties [ i ] . IsContentScan ? 1 : 0 ;
}
}
/**************************************************************************************************
* DLLExportClass : : Set_Home_Cell
*
* History : 2 / 14 / 2020 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Set_Home_Cell ( int x , int y , uint64 player_id )
{
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
MultiplayerStartPositions [ 0 ] = XY_Cell ( x , y ) ;
}
else {
for ( int i = 0 ; i < MAX_PLAYERS & & i < 4 ; i + + ) {
if ( GlyphxPlayerIDs [ i ] = = player_id ) {
MultiplayerStartPositions [ i ] = XY_Cell ( x , y ) ;
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : On_Play_Movie
*
* History : 7 / 23 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Play_Movie ( const char * movie_name , ThemeType theme , bool immediate )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_MOVIE ;
new_event . Movie . MovieName = movie_name ;
new_event . Movie . Theme = ( int ) theme ;
new_event . Movie . Immediate = immediate ;
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Display_Briefing_Text
*
* Called when Red Alert wants to display the mission breifing screen before a mission .
*
* History : 12 / 04 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Display_Briefing_Text ( )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_BRIEFING_SCREEN ;
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Sound_Effect - - Called when C & C wants to play a sound effect
*
* In :
*
* Out :
*
*
*
* History : 2 / 20 / 2019 2 : 39 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Sound_Effect ( const HouseClass * player_ptr , int sound_effect_index , const char * extension , int variation , COORDINATE coord )
{
// player_ptr could be NULL
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_SOUND_EFFECT ;
new_event . SoundEffect . SFXIndex = sound_effect_index ;
new_event . SoundEffect . Variation = variation ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL )
{
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
if ( coord = = 0 )
{
new_event . SoundEffect . PixelX = - 1 ;
new_event . SoundEffect . PixelY = - 1 ;
}
else
{
// Use world pixel coordinates
new_event . SoundEffect . PixelX = Lepton_To_Pixel ( Coord_X ( coord ) ) ;
new_event . SoundEffect . PixelY = Lepton_To_Pixel ( Coord_Y ( coord ) ) ;
}
if ( sound_effect_index > = VOC_FIRST & & sound_effect_index < VOC_COUNT )
{
strncpy ( new_event . SoundEffect . SoundEffectName , SoundEffectName [ sound_effect_index ] . Name , 16 ) ;
if ( extension ! = NULL )
{
strncat ( new_event . SoundEffect . SoundEffectName , extension , 16 ) ;
}
new_event . SoundEffect . SoundEffectPriority = SoundEffectName [ sound_effect_index ] . Priority ;
new_event . SoundEffect . SoundEffectContext = SoundEffectName [ sound_effect_index ] . Where ;
}
else
{
strncpy ( new_event . SoundEffect . SoundEffectName , " BADINDEX " , 16 ) ;
new_event . SoundEffect . SoundEffectPriority = - 1 ;
new_event . SoundEffect . SoundEffectContext = - 1 ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Speech - - Called when C & C wants to play a speech line
*
* In :
*
* Out :
*
*
*
* History : 2 / 20 / 2019 2 : 39 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Speech ( const HouseClass * player_ptr , int speech_index )
{
// player_ptr could be NULL
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_SPEECH ;
new_event . Speech . SpeechIndex = speech_index ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL )
{
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
if ( speech_index > = VOX_FIRST & & speech_index < VOX_COUNT )
{
strncpy ( new_event . Speech . SpeechName , Speech [ speech_index ] , 16 ) ;
}
else
{
strncpy ( new_event . Speech . SpeechName , " BAD_SPEECH_INDEX " , 16 ) ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : RA_Calculate_Leadership - -
*
* History : 10.30 .2019 MBL ( Based on LLL ' s Calculate_Single_Player_Score ( ) )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int DLLExportClass : : RA_Calculate_Leadership ( HousesType player_house , int units_lost , int buildings_lost )
{
int house = ( player_house = = HOUSE_USSR | | player_house = = HOUSE_UKRAINE ) ; // 0 or 1
int leadership = 0 ;
for ( int index = 0 ; index < Logic . Count ( ) ; index + + ) {
ObjectClass * object = Logic [ index ] ;
HousesType owner = object - > Owner ( ) ;
if ( ( house ) & & ( owner = = HOUSE_USSR | | owner = = HOUSE_BAD | | owner = = HOUSE_UKRAINE ) ) {
leadership + + ;
}
else {
if ( ( ! house ) & & ( object - > Owner ( ) = = HOUSE_GREECE ) ) {
leadership + + ;
}
}
}
if ( ! leadership ) leadership + + ;
leadership = 100 * fixed ( leadership , ( units_lost + buildings_lost + leadership ) ) ;
leadership = min ( 150 , leadership ) ;
return leadership ;
}
/**************************************************************************************************
* DLLExportClass : : RA_Calculate_Economy - -
*
* History : 10.30 .2019 MBL ( Based on LLL ' s Calculate_Single_Player_Score ( ) )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int DLLExportClass : : RA_Calculate_Economy ( long available_money , int stolen_buildings_credits , unsigned harvested_credits , long initial_credits )
{
int economy = 100 * fixed ( ( unsigned ) available_money + 1 + stolen_buildings_credits , harvested_credits + ( unsigned ) initial_credits + 1 ) ;
economy = min ( economy , 150 ) ;
return economy ;
}
/**************************************************************************************************
* DLLExportClass : : RA_Calculate_Score - -
*
* History : 10.30 .2019 MBL ( Based on LLL ' s Calculate_Single_Player_Score ( ) )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int DLLExportClass : : RA_Calculate_Score ( int uspoints , int leadership , int economy )
{
int score_total = ( ( uspoints * leadership ) / 100 ) + ( ( uspoints * economy ) / 100 ) ;
if ( score_total < - 9999 ) score_total = - 9999 ;
score_total = min ( score_total , 99999 ) ;
return score_total ;
}
/**************************************************************************************************
* DLLExportClass : : CalculateScore *
*
* History : 10 / 16 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Calculate_Single_Player_Score ( EventCallbackStruct & event )
{
//Adapted from Red Alert SCORE.CPP Presentation() - LLL
int house = ( PlayerPtr - > Class - > House = = HOUSE_USSR | | PlayerPtr - > Class - > House = = HOUSE_UKRAINE ) ; // 0 or 1
int good_units_lost = ( HouseClass : : As_Pointer ( HOUSE_GOOD ) ) - > UnitsLost ;
int bad_units_lost = ( HouseClass : : As_Pointer ( HOUSE_BAD ) ) - > UnitsLost ;
int neutral_units_lost = ( HouseClass : : As_Pointer ( HOUSE_NEUTRAL ) ) - > UnitsLost ;
int good_buildings_lost = ( HouseClass : : As_Pointer ( HOUSE_GOOD ) ) - > BuildingsLost ;
int bad_buildings_lost = ( HouseClass : : As_Pointer ( HOUSE_BAD ) ) - > BuildingsLost ;
int neutral_buildings_lost = ( HouseClass : : As_Pointer ( HOUSE_NEUTRAL ) ) - > BuildingsLost ;
int good_credits_harvested = ( HouseClass : : As_Pointer ( HOUSE_GOOD ) ) - > HarvestedCredits ;
int bad_credits_harvested = ( HouseClass : : As_Pointer ( HOUSE_BAD ) ) - > HarvestedCredits ;
int uspoints = 0 ;
for ( HousesType hous = HOUSE_SPAIN ; hous < = HOUSE_BAD ; hous + + ) {
HouseClass * hows = HouseClass : : As_Pointer ( hous ) ;
if ( hous = = HOUSE_USSR | | hous = = HOUSE_BAD | | hous = = HOUSE_UKRAINE ) {
bad_units_lost + = hows - > UnitsLost ;
bad_buildings_lost + = hows - > BuildingsLost ;
}
else {
good_units_lost + = hows - > UnitsLost ;
good_buildings_lost + = hows - > BuildingsLost ;
}
if ( PlayerPtr - > Is_Ally ( hous ) ) {
uspoints + = hows - > PointTotal ;
}
}
// if(uspoints < 0) uspoints = 0;
// uspoints += 1000; //BG 1000 bonus points for winning mission
/*
* * Bias the base score upward according to the difficulty level .
*/
switch ( PlayerPtr - > Difficulty ) {
case DIFF_EASY :
uspoints + = 500 ;
break ;
case DIFF_NORMAL :
uspoints + = 1500 ;
break ;
case DIFF_HARD :
uspoints + = 3500 ;
break ;
}
/*
* * Determine leadership rating .
*/
int leadership = 0 ;
for ( int index = 0 ; index < Logic . Count ( ) ; index + + ) {
ObjectClass * object = Logic [ index ] ;
HousesType owner = object - > Owner ( ) ;
if ( ( house ) & & ( owner = = HOUSE_USSR | | owner = = HOUSE_BAD | | owner = = HOUSE_UKRAINE ) ) {
leadership + + ;
}
else {
if ( ( ! house ) & & ( object - > Owner ( ) = = HOUSE_GREECE ) ) {
leadership + + ;
}
}
}
if ( ! leadership ) leadership + + ;
leadership = 100 * fixed ( leadership , ( house ? bad_units_lost + bad_buildings_lost + leadership : good_units_lost + good_buildings_lost + leadership ) ) ;
leadership = min ( 150 , leadership ) ;
/*
* * Determine economy rating .
*/
// int init = PlayerPtr->Control.InitialCredits;
// int cred = PlayerPtr->Available_Money();
int economy = 100 * fixed ( ( unsigned ) PlayerPtr - > Available_Money ( ) + 1 + PlayerPtr - > StolenBuildingsCredits , PlayerPtr - > HarvestedCredits + ( unsigned ) PlayerPtr - > Control . InitialCredits + 1 ) ;
economy = min ( economy , 150 ) ;
int score_total = ( ( uspoints * leadership ) / 100 ) + ( ( uspoints * economy ) / 100 ) ;
if ( score_total < - 9999 ) score_total = - 9999 ;
score_total = min ( score_total , 99999 ) ;
//Score Stats
event . GameOver . Leadership = leadership ;
event . GameOver . Efficiency = economy ;
event . GameOver . Score = score_total ;
event . GameOver . CategoryTotal = uspoints ;
event . GameOver . NODKilled = bad_units_lost ;
event . GameOver . GDIKilled = good_units_lost ;
event . GameOver . CiviliansKilled = neutral_units_lost ;
event . GameOver . NODBuildingsDestroyed = bad_buildings_lost ;
event . GameOver . GDIBuildingsDestroyed = good_buildings_lost ;
event . GameOver . CiviliansBuildingsDestroyed = neutral_buildings_lost ;
event . GameOver . RemainingCredits = PlayerPtr - > Available_Money ( ) ;
if ( Scen . IsSkipScore ) {
event . GameOver . Score = - 1 ;
}
}
/**************************************************************************************************
* DLLExportClass : : On_Message - - Called when the game wants to display a message ( ex . tutorial text )
*
* In :
*
* Out :
*
*
*
* History : 10 / 16 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Message ( const HouseClass * player_ptr , const char * message , float timeout_seconds , EventCallbackMessageEnum message_type , int64 message_id )
{
if ( EventCallback = = NULL )
{
return ;
}
const char * p_msg = message ;
std : : string localized_text_name ;
if ( message_id ! = - 1 ) {
if ( message_id = = TXT_INSUFFICIENT_FUNDS ) {
localized_text_name = " TEXT_INSUFFICIENT_FUNDS_MESSAGE " ;
}
else if ( message_id = = TXT_LOW_POWER ) {
localized_text_name = " TEXT_LOW_POWER_MESSAGE_001 " ;
}
else if ( message_id = = TXT_POWER_TESLA ) {
localized_text_name = " TEXT_LOW_POWER_MESSAGE_002 " ;
}
else if ( message_id = = TXT_POWER_AAGUN ) {
localized_text_name = " TEXT_LOW_POWER_MESSAGE_003 " ;
}
else {
if ( MessagesSent . find ( message_id ) ! = MessagesSent . end ( ) ) {
return ;
}
MessagesSent . insert ( message_id ) ;
localized_text_name = " TEXT_RA_TUTORIAL_MESSAGE_ " ;
localized_text_name + = std : : to_string ( message_id ) ;
}
p_msg = localized_text_name . c_str ( ) ;
Sound_Effect ( VOC_INCOMING_MESSAGE ) ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_MESSAGE ;
new_event . Message . Message = p_msg ;
new_event . Message . TimeoutSeconds = timeout_seconds ;
new_event . Message . MessageType = message_type ;
new_event . Message . MessageParam1 = message_id ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL )
{
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Update_Map_Cell - - Called when an individual map cell template is updated
*
*
* History : 11 / 7 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Update_Map_Cell ( int cell_x , int cell_y , const char * template_type_name )
{
if ( EventCallback = = NULL )
{
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_UPDATE_MAP_CELL ;
new_event . UpdateMapCell . CellX = cell_x ;
new_event . UpdateMapCell . CellY = cell_y ;
strncpy ( new_event . UpdateMapCell . TemplateTypeName , template_type_name , 32 ) ;
new_event . UpdateMapCell . TemplateTypeName [ 31 ] = ' \0 ' ;
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Special_Weapon_Targetting - - Called when the server initiates targetting
*
*
* History : 11 / 19 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Special_Weapon_Targetting ( const HouseClass * player_ptr , SpecialWeaponType weapon_type )
{
if ( EventCallback = = NULL )
{
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_SPECIAL_WEAPON_TARGETTING ;
new_event . SpecialWeaponTargetting . Type = RTTI_SPECIAL ;
new_event . SpecialWeaponTargetting . ID = weapon_type ;
Convert_Special_Weapon_Type ( weapon_type , new_event . SpecialWeaponTargetting . WeaponType , new_event . SpecialWeaponTargetting . Name ) ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL )
{
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Ping - - Called when a radar ping is needed
*
*
* History : 05 / 15 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Ping ( const HouseClass * player_ptr , COORDINATE coord )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_PING ;
new_event . Ping . CoordX = Coord_X ( coord ) ;
new_event . Ping . CoordY = Coord_Y ( coord ) ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL )
{
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Game_Over - - Called when the C & C campaign game finishes
*
*
* History : 6 / 19 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Game_Over ( uint64 glyphx_Player_id , bool player_wins )
{
if ( EventCallback = = NULL ) {
return ;
}
GameOver = true ;
SaveTanya = IsTanyaDead ;
Scen . CarryOverTimer = Scen . MissionTimer ;
// int timer = Scen.MissionTimer;
Scen . CarryOverMoney = PlayerPtr - > Credits ;
DLLExportClass : : Store_Carryover_Objects ( ) ;
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_GAME_OVER ;
new_event . GlyphXPlayerID = glyphx_Player_id ;
new_event . GameOver . PlayerWins = player_wins ;
new_event . GameOver . AfterScoreMovieName = " " ;
new_event . GameOver . Multiplayer = false ;
new_event . GameOver . MultiPlayerTotalPlayers = 0 ;
Calculate_Single_Player_Score ( new_event ) ;
VQType movie = player_wins ? Scen . WinMovie : Scen . LoseMovie ;
if ( movie > VQ_NONE & & movie < VQ_COUNT ) {
new_event . GameOver . MovieName = VQName [ movie ] ;
} else {
new_event . GameOver . MovieName = " " ;
}
movie = player_wins ? Scen . WinMovie2 : VQ_NONE ;
if ( movie > VQ_NONE & & movie < VQ_COUNT ) {
new_event . GameOver . MovieName2 = VQName [ movie ] ;
}
else {
new_event . GameOver . MovieName2 = " " ;
}
movie = player_wins ? Scen . WinMovie3 : VQ_NONE ;
if ( movie > VQ_NONE & & movie < VQ_COUNT ) {
new_event . GameOver . MovieName3 = VQName [ movie ] ;
}
else {
new_event . GameOver . MovieName3 = " " ;
}
movie = player_wins ? Scen . WinMovie4 : VQ_NONE ;
if ( movie > VQ_NONE & & movie < VQ_COUNT ) {
new_event . GameOver . MovieName4 = VQName [ movie ] ;
}
else {
new_event . GameOver . MovieName4 = " " ;
}
//Campaign win & credits
if ( Scen . IsEndOfGame ) {
if ( PlayerPtr - > ActLike = = HOUSE_USSR ) {
new_event . GameOver . AfterScoreMovieName = VQName [ VQ_SOVFINAL ] ;
}
else {
new_event . GameOver . AfterScoreMovieName = VQName [ VQ_ALLYEND ] ;
}
}
new_event . GameOver . SabotagedStructureType = - 1 ;
new_event . GameOver . TimerRemaining = Scen . MissionTimer . Was_Started ( ) ? Scen . MissionTimer . Value ( ) : - 1 ;
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Multiplayer_Game_Over - - Called when the C & C multiplayer game finishes
*
*
* History : 6 / 19 / 2019 - LLL
* History : 10 / 31 / 2019 - MBL - Adding the multi - player score stats support for debrief
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Multiplayer_Game_Over ( void )
{
if ( EventCallback = = NULL ) {
return ;
}
GameOver = true ;
EventCallbackStruct event ;
event . EventType = CALLBACK_EVENT_GAME_OVER ;
// Includes AI's for skirmish
int player_count = Session . Players . Count ( ) ;
// Multiplayer players data for debrief stats
event . GameOver . Multiplayer = true ;
event . GameOver . MultiPlayerTotalPlayers = player_count ;
for ( int player_index = 0 ; player_index < player_count ; player_index + + )
{
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ player_index ] - > Player . ID ) ;
if ( player_ptr ! = NULL )
{
HousesType player_house = PlayerPtr - > Class - > House ;
int uspoints = 0 ;
for ( HousesType hous = HOUSE_SPAIN ; hous < = HOUSE_BAD ; hous + + ) {
HouseClass * hows = HouseClass : : As_Pointer ( hous ) ;
if ( player_ptr - > Is_Ally ( hous ) ) {
uspoints + = hows - > PointTotal ;
}
}
// if(uspoints < 0) uspoints = 0;
// uspoints += 1000; //BG 1000 bonus points for winning mission
// N/A for multi-player
#if 0
// Bias the base score upward according to the difficulty level.
switch ( PlayerPtr - > Difficulty ) {
case DIFF_EASY :
uspoints + = 500 ;
break ;
case DIFF_NORMAL :
uspoints + = 1500 ;
break ;
case DIFF_HARD :
uspoints + = 3500 ;
break ;
}
# endif
int leadership = RA_Calculate_Leadership ( player_ptr - > Class - > House , player_ptr - > UnitsLost , player_ptr - > BuildingsLost ) ;
int economy = RA_Calculate_Economy ( player_ptr - > Available_Money ( ) , player_ptr - > StolenBuildingsCredits , player_ptr - > HarvestedCredits , player_ptr - > Control . InitialCredits ) ;
int total_score = RA_Calculate_Score ( uspoints , leadership , economy ) ;
int units_killed = 0 ;
int structures_killed = 0 ;
for ( unsigned int house_index = 0 ; house_index < HOUSE_COUNT ; house_index + + )
{
units_killed + = player_ptr - > UnitsKilled [ house_index ] ;
structures_killed + = player_ptr - > BuildingsKilled [ house_index ] ;
}
// Populate and copy the multiplayer player data structure
GameOverMultiPlayerStatsStruct multi_player_data ;
multi_player_data . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
multi_player_data . IsHuman = ( player_ptr - > IsHuman | | player_ptr - > WasHuman ) ;
multi_player_data . WasHuman = player_ptr - > WasHuman ;
multi_player_data . IsWinner = ! player_ptr - > IsDefeated ;
multi_player_data . Efficiency = economy ;
multi_player_data . Score = total_score ;
multi_player_data . ResourcesGathered = player_ptr - > HarvestedCredits ;
multi_player_data . TotalUnitsKilled = units_killed ;
multi_player_data . TotalStructuresKilled = structures_killed ;
if ( player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED )
{
event . GameOver . MultiPlayerPlayersData [ player_index ] = multi_player_data ;
}
}
}
for ( int player_index = player_count ; player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED ; player_index + + )
{
memset ( & event . GameOver . MultiPlayerPlayersData [ player_index ] , 0 , sizeof ( GameOverMultiPlayerStatsStruct ) ) ;
}
// Single-player N/A stuff
event . GameOver . MovieName = " " ;
event . GameOver . MovieName2 = " " ;
event . GameOver . MovieName3 = " " ;
event . GameOver . MovieName4 = " " ;
event . GameOver . AfterScoreMovieName = " " ;
event . GameOver . Leadership = 0 ;
event . GameOver . Efficiency = 0 ;
event . GameOver . Score = 0 ;
event . GameOver . NODKilled = 0 ;
event . GameOver . GDIKilled = 0 ;
event . GameOver . CiviliansKilled = 0 ;
event . GameOver . NODBuildingsDestroyed = 0 ;
event . GameOver . GDIBuildingsDestroyed = 0 ;
event . GameOver . CiviliansBuildingsDestroyed = 0 ;
event . GameOver . RemainingCredits = 0 ;
event . GameOver . SabotagedStructureType = 0 ;
event . GameOver . TimerRemaining = - 1 ;
2020-06-22 09:43:21 -07:00
// Trigger an event for each human player, winner first (even if it's an AI)
for ( int i = 0 ; i < player_count ; i + + ) {
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
if ( ! player_ptr - > IsDefeated ) {
event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
event . GameOver . IsHuman = player_ptr - > IsHuman ;
event . GameOver . PlayerWins = true ;
event . GameOver . RemainingCredits = player_ptr - > Available_Money ( ) ;
EventCallback ( event ) ;
}
}
for ( int i = 0 ; i < player_count ; i + + ) {
2020-05-27 12:16:20 -07:00
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
2020-06-22 09:43:21 -07:00
if ( player_ptr - > IsHuman & & player_ptr - > IsDefeated ) {
2020-05-27 12:16:20 -07:00
event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
2020-06-22 09:43:21 -07:00
event . GameOver . IsHuman = true ;
event . GameOver . PlayerWins = false ;
2020-05-27 12:16:20 -07:00
event . GameOver . RemainingCredits = player_ptr - > Available_Money ( ) ;
EventCallback ( event ) ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : On_Achievement - - Called when something achievement - related happens
*
* In : Type of achievement , reason this happened
*
* Out :
*
*
*
* History : 11 / 11 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Achievement ( const HouseClass * player_ptr , const char * achievement_type , const char * achievement_reason )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_ACHIEVEMENT ;
new_event . Achievement . AchievementType = achievement_type ;
new_event . Achievement . AchievementReason = achievement_reason ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL ) {
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
EventCallback ( new_event ) ;
}
void DLLExportClass : : On_Center_Camera ( const HouseClass * player_ptr , int coord_x , int coord_y )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_CENTER_CAMERA ;
new_event . CenterCamera . CoordX = coord_x ;
new_event . CenterCamera . CoordY = coord_y ;
new_event . GlyphXPlayerID = 0 ;
if ( player_ptr ! = NULL ) {
new_event . GlyphXPlayerID = Get_GlyphX_Player_ID ( player_ptr ) ;
}
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : On_Debug_Output - - Called when C & C wants to print debug output
*
* In : String to print to GlyphX log system
*
* Out :
*
*
*
* History : 2 / 20 / 2019 2 : 39 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : On_Debug_Output ( const char * debug_text )
{
if ( EventCallback = = NULL ) {
return ;
}
EventCallbackStruct new_event ;
new_event . EventType = CALLBACK_EVENT_DEBUG_PRINT ;
new_event . DebugPrint . PrintString = debug_text ;
EventCallback ( new_event ) ;
}
/**************************************************************************************************
* DLLExportClass : : Force_Human_Team_Wins
*
* History : 3 / 10 / 2020 - LL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Force_Human_Team_Wins ( uint64 quitting_player_id )
{
int winning_team = - 1 ;
//Find the first human's multiplayer team.
for ( int i = 0 ; i < Session . Players . Count ( ) ; i + + )
{
if ( GlyphxPlayerIDs [ i ] ! = quitting_player_id ) {
HousesType house_type = Session . Players [ i ] - > Player . ID ;
HouseClass * house_class = HouseClass : : As_Pointer ( house_type ) ;
if ( house_class & & house_class - > IsHuman & & ! house_class - > IsDefeated ) {
winning_team = MPlayerTeamIDs [ i ] ;
break ;
}
}
}
//Mark all players not on that team as defeated.
for ( int i = 0 ; i < Session . Players . Count ( ) ; i + + )
{
HousesType house_type = Session . Players [ i ] - > Player . ID ;
HouseClass * house_class = HouseClass : : As_Pointer ( house_type ) ;
if ( house_class ) {
house_class - > IsDefeated = MPlayerTeamIDs [ i ] ! = winning_team ;
}
}
PlayerWins = true ;
}
/**************************************************************************************************
* CNC_Get_Game_State - - Get game state
*
* In : Type of state requested
* Player perspective
* Buffer to contain game state
* Size of buffer
*
* Out : Game state returned in buffer
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) bool __cdecl CNC_Get_Game_State ( GameStateRequestEnum state_type , uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
bool got_state = false ;
switch ( state_type ) {
case GAME_STATE_LAYERS :
{
got_state = DLLExportClass : : Get_Layer_State ( player_id , buffer_in , buffer_size ) ;
break ;
}
case GAME_STATE_SIDEBAR :
{
got_state = DLLExportClass : : Get_Sidebar_State ( player_id , buffer_in , buffer_size ) ;
break ;
}
case GAME_STATE_PLACEMENT :
{
got_state = DLLExportClass : : Get_Placement_State ( player_id , buffer_in , buffer_size ) ;
break ;
}
case GAME_STATE_DYNAMIC_MAP :
got_state = DLLExportClass : : Get_Dynamic_Map_State ( player_id , buffer_in , buffer_size ) ;
break ;
case GAME_STATE_SHROUD :
got_state = DLLExportClass : : Get_Shroud_State ( player_id , buffer_in , buffer_size ) ;
break ;
case GAME_STATE_OCCUPIER :
got_state = DLLExportClass : : Get_Occupier_State ( player_id , buffer_in , buffer_size ) ;
break ;
case GAME_STATE_PLAYER_INFO :
got_state = DLLExportClass : : Get_Player_Info_State ( player_id , buffer_in , buffer_size ) ;
break ;
case GAME_STATE_STATIC_MAP :
{
if ( buffer_size < sizeof ( CNCMapDataStruct ) ) {
got_state = false ;
break ;
}
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
CNCMapDataStruct * map_data = ( CNCMapDataStruct * ) buffer_in ;
map_data - > OriginalMapCellX = map_cell_x ;
map_data - > OriginalMapCellY = map_cell_y ;
map_data - > OriginalMapCellWidth = map_cell_width ;
map_data - > OriginalMapCellHeight = map_cell_height ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_HEIGHT ) {
map_cell_height + + ;
}
map_data - > MapCellX = map_cell_x ;
map_data - > MapCellY = map_cell_y ;
map_data - > MapCellWidth = map_cell_width ;
map_data - > MapCellHeight = map_cell_height ;
map_data - > Theater = ( CnCTheaterType ) Scen . Theater ;
char * dot_ptr = strchr ( Scen . ScenarioName , ' . ' ) ;
const int count = ( dot_ptr ! = nullptr ) ? ( dot_ptr - Scen . ScenarioName ) : sizeof ( Scen . ScenarioName ) ;
memset ( map_data - > ScenarioName , 0 , sizeof ( map_data - > ScenarioName ) ) ;
strncpy ( map_data - > ScenarioName , Scen . ScenarioName , min ( sizeof ( map_data - > ScenarioName ) - 1 , count ) ) ;
int cell_index = 0 ;
char cell_name [ _MAX_PATH ] ;
char icon_number [ 32 ] ;
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + ) {
CELL cell = XY_Cell ( map_cell_x + x , map_cell_y + y ) ;
CellClass * cellptr = & Map [ cell ] ;
cell_name [ 0 ] = 0 ;
int icon = 0 ;
void * image_data = 0 ;
if ( cellptr - > Get_Template_Info ( cell_name , icon , image_data ) ) {
itoa ( icon , icon_number , 10 ) ;
strncat ( cell_name , " _i " , 32 ) ;
strncat ( cell_name , icon_number , 32 ) ;
strncat ( cell_name , " .tga " , 32 ) ;
CNCStaticCellStruct & cell_info = map_data - > StaticCells [ cell_index + + ] ;
strncpy ( cell_info . TemplateTypeName , cell_name , 32 ) ;
cell_info . IconNumber = icon ;
}
}
}
got_state = true ;
break ;
}
default :
{
got_state = false ;
break ;
}
}
return got_state ;
}
/**************************************************************************************************
* CNC_Handle_Game_Request
*
* Callback for when the requested movie is done playing .
*
* 7 / 23 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Game_Request ( GameRequestEnum request_type )
{
switch ( request_type )
{
case INPUT_GAME_MOVIE_DONE :
break ;
}
}
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Game_Settings_Request ( int health_bar_display_mode , int resource_bar_display_mode )
{
if ( ! DLLExportClass : : Legacy_Render_Enabled ( ) ) {
return ;
}
RulesClass : : eHealthBarDisplayMode new_hb_mode = ( RulesClass : : eHealthBarDisplayMode ) health_bar_display_mode ;
if ( new_hb_mode ! = Rule . HealthBarDisplayMode ) {
Rule . HealthBarDisplayMode = new_hb_mode ;
Map . Flag_To_Redraw ( true ) ;
}
RulesClass : : eResourceBarDisplayMode new_rb_mode = ( RulesClass : : eResourceBarDisplayMode ) resource_bar_display_mode ;
if ( new_rb_mode ! = Rule . ResourceBarDisplayMode ) {
Rule . ResourceBarDisplayMode = new_rb_mode ;
Map . Flag_To_Redraw ( true ) ;
}
}
void DLL_Draw_Intercept ( int shape_number , int x , int y , int width , int height , int flags , const ObjectClass * object , DirType rotation , long scale , const char * shape_file_name , char override_owner )
{
DLLExportClass : : DLL_Draw_Intercept ( shape_number , x , y , width , height , flags , object , rotation , scale , shape_file_name , override_owner ) ;
}
void DLL_Draw_Pip_Intercept ( const ObjectClass * object , int pip )
{
DLLExportClass : : DLL_Draw_Pip_Intercept ( object , pip ) ;
}
void DLLExportClass : : DLL_Draw_Intercept ( int shape_number , int x , int y , int width , int height , int flags , const ObjectClass * object , DirType rotation , long scale , const char * shape_file_name , char override_owner )
{
CNCObjectStruct & new_object = ObjectList - > Objects [ TotalObjectCount + CurrentDrawCount ] ;
2020-08-06 09:44:54 -07:00
memset ( & new_object , 0 , sizeof ( new_object ) ) ;
2020-05-27 12:16:20 -07:00
Convert_Type ( object , new_object ) ;
if ( new_object . Type = = UNKNOWN ) {
return ;
}
CNCObjectStruct * base_object = NULL ;
char sub_object = 0 ;
for ( int i = 0 ; i < CurrentDrawCount ; + + i ) {
CNCObjectStruct & draw_object = ObjectList - > Objects [ TotalObjectCount + i ] ;
if ( draw_object . CNCInternalObjectPointer = = object ) {
if ( base_object = = NULL ) {
base_object = & draw_object ;
}
sub_object + + ;
}
}
new_object . CNCInternalObjectPointer = ( void * ) object ;
new_object . OccupyListLength = 0 ;
2020-08-12 11:32:36 -07:00
if ( CurrentDrawCount = = 0 ) {
new_object . SortOrder = ( ExportLayer < < 29 ) + ( object - > Sort_Y ( ) > > 3 ) ;
} else {
new_object . SortOrder = ObjectList - > Objects [ TotalObjectCount ] . SortOrder + CurrentDrawCount ;
}
2020-05-27 12:16:20 -07:00
strncpy ( new_object . TypeName , object - > Class_Of ( ) . IniName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
if ( shape_file_name ! = NULL ) {
strncpy ( new_object . AssetName , shape_file_name , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
}
else {
strncpy ( new_object . AssetName , object - > Class_Of ( ) . Graphic_Name ( ) , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
}
new_object . Owner = ( base_object ! = NULL ) ? ( ( override_owner ! = HOUSE_NONE ) ? override_owner : base_object - > Owner ) : ( char ) object - > Owner ( ) ;
HouseClass * owner_house = nullptr ;
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
HouseClass * hptr = Houses . Ptr ( i ) ;
if ( ( hptr ! = nullptr ) & & ( hptr - > Class - > House = = new_object . Owner ) ) {
owner_house = hptr ;
break ;
}
}
new_object . RemapColor = ( owner_house ! = nullptr ) ? owner_house - > RemapColor : - 1 ;
if ( base_object = = NULL ) {
CNCObjectStruct & root_object = ObjectList - > Objects [ TotalObjectCount ] ;
if ( new_object . Type = = BUILDING ) {
BuildingClass * building = ( BuildingClass * ) object ;
if ( building - > BState = = BSTATE_CONSTRUCTION ) {
strncat ( new_object . AssetName , " MAKE " , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
}
const BuildingTypeClass * building_type = building - > Class ;
short const * occupy_list = building_type - > Occupy_List ( ) ;
if ( occupy_list ) {
while ( * occupy_list ! = REFRESH_EOL & & new_object . OccupyListLength < MAX_OCCUPY_CELLS ) {
new_object . OccupyList [ new_object . OccupyListLength ] = * occupy_list ;
new_object . OccupyListLength + + ;
occupy_list + + ;
}
}
}
COORDINATE coord = object - > Render_Coord ( ) ;
CELL cell = Coord_Cell ( coord ) ;
int dimx , dimy ;
object - > Class_Of ( ) . Dimensions ( dimx , dimy ) ;
new_object . PositionX = x ;
new_object . PositionY = y ;
new_object . Width = width ;
new_object . Height = height ;
new_object . Altitude = object - > Height ;
new_object . DrawFlags = flags ;
new_object . SubObject = 0 ;
new_object . ShapeIndex = ( unsigned short ) shape_number ;
new_object . IsTheaterSpecific = IsTheaterShape ;
new_object . Rotation = ( unsigned char ) rotation ;
new_object . Scale = scale ;
new_object . FlashingFlags = 0 ;
new_object . Cloak = ( CurrentDrawCount > 0 ) ? root_object . Cloak : UNCLOAKED ;
new_object . VisibleFlags = CNCObjectStruct : : VISIBLE_FLAGS_ALL ;
new_object . SpiedByFlags = 0U ;
new_object . IsSelectable = object - > Class_Of ( ) . IsSelectable ;
new_object . IsSelectedMask = object - > IsSelectedMask ;
new_object . MaxStrength = object - > Class_Of ( ) . MaxStrength ;
new_object . Strength = object - > Strength ;
new_object . CellX = ( CurrentDrawCount > 0 ) ? root_object . CellX : Cell_X ( cell ) ;
new_object . CellY = ( CurrentDrawCount > 0 ) ? root_object . CellY : Cell_Y ( cell ) ;
new_object . CenterCoordX = Coord_X ( object - > Center_Coord ( ) ) ;
new_object . CenterCoordY = Coord_Y ( object - > Center_Coord ( ) ) ;
new_object . DimensionX = dimx ;
new_object . DimensionY = dimy ;
new_object . SimLeptonX = ( CurrentDrawCount > 0 ) ? root_object . SimLeptonX : 0 ;
new_object . SimLeptonY = ( CurrentDrawCount > 0 ) ? root_object . SimLeptonY : 0 ;
new_object . BaseObjectID = ( ( CurrentDrawCount > 0 ) & & ( root_object . Type ! = BUILDING ) & & ( root_object . Type ! = VESSEL ) ) ? root_object . ID : 0 ;
new_object . BaseObjectType = ( ( CurrentDrawCount > 0 ) & & ( root_object . Type ! = BUILDING ) & & ( root_object . Type ! = VESSEL ) ) ? root_object . Type : UNKNOWN ;
new_object . NumLines = 0 ;
new_object . RecentlyCreated = object - > IsRecentlyCreated ;
new_object . NumPips = 0 ;
new_object . MaxPips = 0 ;
new_object . CanDemolish = object - > Can_Demolish ( ) ;
new_object . CanDemolishUnit = object - > Can_Demolish_Unit ( ) ;
new_object . CanRepair = object - > Can_Repair ( ) ;
memset ( new_object . CanMove , false , sizeof ( new_object . CanMove ) ) ;
memset ( new_object . CanFire , false , sizeof ( new_object . CanFire ) ) ;
memset ( new_object . ActionWithSelected , DAT_NONE , sizeof ( new_object . ActionWithSelected ) ) ;
HouseClass * old_player_ptr = PlayerPtr ;
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
HouseClass * hptr = Houses . Ptr ( i ) ;
if ( ( hptr ! = nullptr ) & & hptr - > IsActive & & hptr - > IsHuman ) {
HousesType house = hptr - > Class - > House ;
DynamicVectorClass < ObjectClass * > & selected_objects = CurrentObject . Raw ( house ) ;
if ( selected_objects . Count ( ) > 0 ) {
Logic_Switch_Player_Context ( hptr ) ;
Convert_Action_Type ( Best_Object_Action ( selected_objects , object ) , ( selected_objects . Count ( ) = = 1 ) ? selected_objects [ 0 ] : NULL , object - > As_Target ( ) , new_object . ActionWithSelected [ house ] ) ;
}
}
}
Logic_Switch_Player_Context ( old_player_ptr ) ;
RTTIType what_is_object = object - > What_Am_I ( ) ;
new_object . IsRepairing = false ;
new_object . IsDumping = false ;
new_object . IsALoaner = false ;
new_object . IsFactory = false ;
new_object . IsPrimaryFactory = false ;
new_object . IsNominal = false ;
new_object . IsDog = false ;
new_object . IsIronCurtain = false ;
new_object . IsAntiGround = false ;
new_object . IsAntiAircraft = false ;
new_object . IsSubSurface = false ;
new_object . IsFake = false ;
new_object . ProductionAssetName [ 0 ] = ' \0 ' ;
new_object . OverrideDisplayName = " \0 " ;
bool is_building = what_is_object = = RTTI_BUILDING ;
if ( is_building ) {
const BuildingClass * building = static_cast < const BuildingClass * > ( object ) ;
new_object . IsRepairing = building - > IsRepairing ;
new_object . IsFactory = building - > Class - > Is_Factory ( ) ;
new_object . IsPrimaryFactory = building - > IsLeader ;
new_object . IsFake = building - > Class - > IsFake ;
}
if ( object - > Is_Techno ( ) ) {
const TechnoClass * techno_object = static_cast < const TechnoClass * > ( object ) ;
const TechnoTypeClass * ttype = techno_object - > Techno_Type_Class ( ) ;
new_object . MaxSpeed = ( unsigned char ) ttype - > MaxSpeed ;
new_object . IsALoaner = techno_object - > IsALoaner ;
new_object . IsNominal = ttype - > IsNominal ;
new_object . MaxPips = ttype - > Max_Pips ( ) ;
new_object . IsAntiGround = ( ttype - > PrimaryWeapon ! = NULL ) & & ( ttype - > PrimaryWeapon - > Bullet ! = NULL ) & & ttype - > PrimaryWeapon - > Bullet - > IsAntiGround ;
new_object . IsAntiAircraft = ( ttype - > PrimaryWeapon ! = NULL ) & & ( ttype - > PrimaryWeapon - > Bullet ! = NULL ) & & ttype - > PrimaryWeapon - > Bullet - > IsAntiAircraft ;
new_object . IsSubSurface = ( ttype - > PrimaryWeapon ! = NULL ) & & ( ttype - > PrimaryWeapon - > Bullet ! = NULL ) & & ttype - > PrimaryWeapon - > Bullet - > IsSubSurface ;
new_object . IsIronCurtain = techno_object - > IronCurtainCountDown > 0 ;
int full_name = techno_object - > Full_Name ( ) ;
if ( full_name < 0 )
{
new_object . OverrideDisplayName = Text_String ( full_name ) ;
}
HouseClass * old_player_ptr = PlayerPtr ;
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
HouseClass * hptr = Houses . Ptr ( i ) ;
if ( ( hptr ! = nullptr ) & & hptr - > IsActive & & hptr - > IsHuman ) {
Logic_Switch_Player_Context ( hptr ) ;
HousesType house = hptr - > Class - > House ;
new_object . CanMove [ house ] = techno_object - > Can_Player_Move ( ) ;
new_object . CanFire [ house ] = techno_object - > Can_Player_Fire ( ) ;
}
}
Logic_Switch_Player_Context ( old_player_ptr ) ;
}
new_object . ControlGroup = ( unsigned char ) ( - 1 ) ;
new_object . IsInFormation = false ;
new_object . CanPlaceBombs = false ;
if ( object - > Is_Foot ( ) ) {
const FootClass * foot = static_cast < const FootClass * > ( object ) ;
new_object . ControlGroup = foot - > Group ;
new_object . IsInFormation = foot - > XFormOffset ! = 0x80000000UL ;
}
bool is_infantry = what_is_object = = RTTI_INFANTRY ;
if ( is_infantry ) {
const InfantryClass * infantry = static_cast < const InfantryClass * > ( object ) ;
new_object . IsDog = infantry - > Class - > IsDog ;
new_object . CanPlaceBombs = infantry - > Class - > IsBomber ;
}
new_object . CanHarvest = false ;
bool is_unit = what_is_object = = RTTI_UNIT ;
if ( is_unit ) {
const UnitClass * unit = static_cast < const UnitClass * > ( object ) ;
if ( unit - > Class - > Type = = UNIT_HARVESTER )
{
new_object . CanHarvest = true ;
}
new_object . IsDumping = unit - > IsDumping ;
}
new_object . IsFixedWingedAircraft = false ;
bool is_aircraft = what_is_object = = RTTI_AIRCRAFT ;
if ( is_aircraft ) {
const AircraftClass * aircraft = static_cast < const AircraftClass * > ( object ) ; ;
new_object . IsFixedWingedAircraft = aircraft - > Class - > IsFixedWing ;
}
switch ( what_is_object )
{
case RTTI_INFANTRY :
case RTTI_INFANTRYTYPE :
case RTTI_UNIT :
case RTTI_UNITTYPE :
case RTTI_AIRCRAFT :
case RTTI_AIRCRAFTTYPE :
case RTTI_BUILDING :
case RTTI_BUILDINGTYPE :
case RTTI_VESSEL :
case RTTI_VESSELTYPE :
{
const TechnoClass * techno_object = static_cast < const TechnoClass * > ( object ) ;
new_object . FlashingFlags = techno_object - > Get_Flashing_Flags ( ) ;
new_object . Cloak = techno_object - > Cloak ;
new_object . SpiedByFlags = techno_object - > Spied_By ( ) ;
if ( techno_object - > Techno_Type_Class ( ) - > IsInvisible ) {
// Hide for enemy players
HouseClass * owner = HouseClass : : As_Pointer ( object - > Owner ( ) ) ;
if ( owner ! = nullptr ) {
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
HouseClass * hptr = Houses . Ptr ( i ) ;
if ( ( hptr ! = nullptr ) & & hptr - > IsActive & & ! owner - > Is_Ally ( hptr ) ) {
new_object . VisibleFlags & = ~ ( 1 < < hptr - > Class - > House ) ;
}
}
}
}
}
break ;
case RTTI_ANIM :
case RTTI_ANIMTYPE :
{
const AnimClass * anim_object = static_cast < const AnimClass * > ( object ) ;
new_object . Owner = anim_object - > OwnerHouse ;
new_object . RemapColor = - 1 ;
new_object . VisibleFlags = anim_object - > Get_Visible_Flags ( ) ;
const AnimTypeClass & anim_type = static_cast < const AnimTypeClass & > ( anim_object - > Class_Of ( ) ) ;
if ( anim_type . VirtualName ! = NULL ) {
strncpy ( new_object . AssetName , anim_type . VirtualName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
}
}
break ;
case RTTI_TERRAIN :
case RTTI_TERRAINTYPE :
{
if ( strncmp ( new_object . AssetName , " MINE " , CNC_OBJECT_ASSET_NAME_LENGTH ) = = 0 ) {
strncpy ( new_object . AssetName , " OREMINE " , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
}
}
break ;
}
}
else {
new_object . MaxStrength = 0 ;
new_object . MaxSpeed = 0 ;
new_object . Strength = 0 ;
new_object . CellX = base_object - > CellX ;
new_object . CellY = base_object - > CellY ;
new_object . CenterCoordX = base_object - > CenterCoordX ;
new_object . CenterCoordY = base_object - > CenterCoordY ;
new_object . DimensionX = base_object - > DimensionX ;
new_object . DimensionY = base_object - > DimensionY ;
new_object . IsSelectable = false ;
new_object . IsSelectedMask = 0U ;
new_object . SimLeptonX = base_object - > SimLeptonX ;
new_object . SimLeptonY = base_object - > SimLeptonY ;
new_object . PositionX = x ;
new_object . PositionY = y ;
new_object . Width = width ;
new_object . Height = height ;
new_object . Altitude = base_object - > Altitude ;
new_object . DrawFlags = flags ;
new_object . ShapeIndex = ( unsigned short ) shape_number ;
new_object . IsTheaterSpecific = IsTheaterShape ;
new_object . Rotation = ( unsigned char ) rotation ;
new_object . Scale = scale ;
new_object . SubObject = sub_object ;
new_object . BaseObjectID = base_object - > ID ;
new_object . BaseObjectType = base_object - > Type ;
new_object . FlashingFlags = base_object - > FlashingFlags ;
new_object . Cloak = base_object - > Cloak ;
new_object . OccupyListLength = 0 ;
new_object . NumPips = 0 ;
new_object . MaxPips = 0 ;
new_object . NumLines = 0 ;
new_object . IsRepairing = false ;
new_object . IsDumping = false ;
new_object . IsALoaner = base_object - > IsALoaner ;
new_object . CanDemolish = base_object - > CanDemolish ;
new_object . CanDemolishUnit = base_object - > CanDemolishUnit ;
new_object . CanRepair = base_object - > CanRepair ;
new_object . RecentlyCreated = base_object - > RecentlyCreated ;
new_object . IsFactory = base_object - > IsFactory ;
new_object . IsPrimaryFactory = base_object - > IsPrimaryFactory ;
new_object . IsAntiGround = base_object - > IsAntiGround ;
new_object . IsAntiAircraft = base_object - > IsAntiAircraft ;
new_object . IsSubSurface = base_object - > IsSubSurface ;
new_object . IsNominal = base_object - > IsNominal ;
new_object . IsDog = base_object - > IsDog ;
new_object . IsIronCurtain = base_object - > IsIronCurtain ;
new_object . IsInFormation = false ;
new_object . CanHarvest = base_object - > CanHarvest ;
new_object . CanPlaceBombs = base_object - > CanPlaceBombs ;
new_object . ControlGroup = base_object - > ControlGroup ;
new_object . VisibleFlags = base_object - > VisibleFlags ;
new_object . SpiedByFlags = base_object - > SpiedByFlags ;
new_object . IsFixedWingedAircraft = base_object - > IsFixedWingedAircraft ;
new_object . IsFake = base_object - > IsFake ;
new_object . ProductionAssetName [ 0 ] = ' \0 ' ;
new_object . OverrideDisplayName = " \0 " ;
memset ( new_object . CanMove , false , sizeof ( new_object . CanMove ) ) ;
memset ( new_object . CanFire , false , sizeof ( new_object . CanFire ) ) ;
memset ( new_object . ActionWithSelected , DAT_NONE , sizeof ( new_object . ActionWithSelected ) ) ;
}
CurrentDrawCount + + ;
}
void DLLExportClass : : DLL_Draw_Pip_Intercept ( const ObjectClass * object , int pip )
{
CNCObjectStruct * base_object = NULL ;
for ( int i = 0 ; i < CurrentDrawCount ; + + i ) {
CNCObjectStruct & draw_object = ObjectList - > Objects [ TotalObjectCount + i ] ;
if ( draw_object . CNCInternalObjectPointer = = object ) {
base_object = & draw_object ;
break ;
}
}
if ( ( base_object ! = NULL ) & & ( base_object - > NumPips < MAX_OBJECT_PIPS ) ) {
base_object - > Pips [ base_object - > NumPips ] = pip ;
base_object - > NumPips + + ;
base_object - > MaxPips = max ( base_object - > MaxPips , base_object - > NumPips ) ;
}
}
/**************************************************************************************************
* DLLExportClass : : Get_Layer_State - - Get game objects from the layers
*
* In :
*
* Out :
*
*
*
* History : 1 / 29 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Layer_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
player_id ;
static int _export_count = 0 ;
bool got_state = false ;
ObjectList = ( CNCObjectListStruct * ) buffer_in ;
TotalObjectCount = 0 ;
/*
* * Get a reference draw coordinate for cells
*/
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
}
SortOrder = 0 ;
/*
* * Get the ground layer first and then followed by all the layers in increasing altitude .
*/
for ( int layer = 0 ; layer < DLL_LAYER_COUNT ; layer + + ) {
2020-08-12 11:32:36 -07:00
ExportLayer = layer ;
2020-05-27 12:16:20 -07:00
for ( int index = 0 ; index < Map . Layer [ layer ] . Count ( ) ; index + + ) {
ObjectClass * object = Map . Layer [ layer ] [ index ] ;
if ( object - > IsActive ) {
unsigned int memory_needed = sizeof ( CNCObjectListStruct ) ;
memory_needed + = ( TotalObjectCount + 10 ) * sizeof ( CNCObjectStruct ) ;
if ( memory_needed > = buffer_size ) {
return false ;
}
if ( object - > Is_Techno ( ) ) {
/*
* * Skip units tethered to buildings , since the building will draw them itself
*/
TechnoClass * techno_object = static_cast < TechnoClass * > ( object ) ;
TechnoClass * contact_object = techno_object - > In_Radio_Contact ( ) ? techno_object - > Contact_With_Whom ( ) : nullptr ;
if ( ( object - > What_Am_I ( ) ! = RTTI_BUILDING ) & & ( contact_object ! = nullptr ) & & ( contact_object - > What_Am_I ( ) = = RTTI_BUILDING ) & & contact_object - > IsTethered & & * ( ( BuildingClass * ) contact_object ) = = STRUCT_WEAP ) {
continue ;
}
/*
* * Skip units tethered to vessels , since the vessel will draw them itself
*/
if ( ( contact_object ! = nullptr ) & & ( contact_object - > What_Am_I ( ) = = RTTI_VESSEL ) & & ! contact_object - > Is_Door_Closed ( ) & & contact_object - > IsTethered & & ! techno_object - > IsInLimbo ) {
continue ;
}
}
if ( Debug_Map | | Debug_Unshroud | | ( object - > IsDown & & ! object - > IsInLimbo ) ) {
int x , y ;
Map . Coord_To_Pixel ( object - > Render_Coord ( ) , x , y ) ;
/*
* * Call to Draw_It can result in multiple callbacks to the draw intercept
*/
CurrentDrawCount = 0 ;
object - > Draw_It ( x , y , WINDOW_VIRTUAL ) ;
/*
* * If the root object is a factory , then the last base object is the object in production ( rendered after infiltrated buildings when selected ) .
* * The root object is updated with the production asset name , but otherwise a separate object isn ' t created .
* * This only occurs in skirmish and multiplayer .
*/
if ( ( GAME_TO_PLAY ! = GAME_NORMAL ) & & ( CurrentDrawCount > 0 ) ) {
CNCObjectStruct & root_object = ObjectList - > Objects [ TotalObjectCount ] ;
if ( root_object . IsFactory ) {
BuildingClass * building = ( BuildingClass * ) root_object . CNCInternalObjectPointer ;
FactoryClass * factory = building - > House - > IsHuman ? building - > House - > Fetch_Factory ( building - > Class - > ToBuild ) : building - > Factory ;
if ( factory ! = nullptr ) {
for ( int i = CurrentDrawCount - 1 ; i > 0 ; - - i ) {
CNCObjectStruct & base_object = ObjectList - > Objects [ TotalObjectCount + i ] ;
if ( base_object . SubObject ) {
continue ;
}
strncpy ( root_object . ProductionAssetName , base_object . TypeName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
void * production_object = base_object . CNCInternalObjectPointer ;
int new_draw_count = i ;
for ( int j = i + 1 ; j < CurrentDrawCount ; + + j ) {
CNCObjectStruct & cnc_object = ObjectList - > Objects [ TotalObjectCount + j ] ;
if ( cnc_object . CNCInternalObjectPointer ! = production_object ) {
memcpy ( ObjectList - > Objects + TotalObjectCount + new_draw_count , & cnc_object , sizeof ( CNCObjectStruct ) ) ;
new_draw_count + + ;
}
}
memset ( ObjectList - > Objects + TotalObjectCount + new_draw_count , 0 , ( CurrentDrawCount - new_draw_count ) * sizeof ( CNCObjectStruct ) ) ;
CurrentDrawCount = new_draw_count ;
break ;
}
}
}
}
/*
* * Shadows need to be rendered before the base object so they appear underneath ,
* * even though they get drawn as sub - objects ( after the base object )
*/
for ( int i = 1 ; i < CurrentDrawCount ; + + i ) {
CNCObjectStruct & sub_object = ObjectList - > Objects [ TotalObjectCount + i ] ;
if ( ! sub_object . SubObject ) {
continue ;
}
static const int shadow_flags = SHAPE_PREDATOR | SHAPE_FADING ;
if ( ( ( sub_object . DrawFlags & shadow_flags ) = = shadow_flags ) | | ( strncmp ( sub_object . AssetName , " WAKE " , CNC_OBJECT_ASSET_NAME_LENGTH ) = = 0 ) ) {
if ( ( strncmp ( sub_object . AssetName , " RROTOR " , CNC_OBJECT_ASSET_NAME_LENGTH ) ! = 0 ) & &
( strncmp ( sub_object . AssetName , " LROTOR " , CNC_OBJECT_ASSET_NAME_LENGTH ) ! = 0 ) ) {
for ( int j = i - 1 ; j > = 0 ; - - j ) {
CNCObjectStruct & base_object = ObjectList - > Objects [ TotalObjectCount + j ] ;
if ( ! base_object . SubObject & & ( base_object . CNCInternalObjectPointer = = sub_object . CNCInternalObjectPointer ) ) {
int sort_order = base_object . SortOrder ;
base_object . SortOrder = sub_object . SortOrder ;
sub_object . SortOrder = sort_order ;
break ;
}
}
}
}
}
TotalObjectCount + = CurrentDrawCount ;
}
}
}
}
ObjectList - > Count = TotalObjectCount ;
if ( ObjectList - > Count ) {
_export_count + + ;
return true ;
}
return false ;
}
void DLLExportClass : : Convert_Type ( const ObjectClass * object , CNCObjectStruct & object_out )
{
object_out . Type = UNKNOWN ;
object_out . ID = - 1 ;
if ( object = = NULL ) {
return ;
}
RTTIType type = object - > What_Am_I ( ) ;
switch ( type ) {
default :
break ;
case RTTI_VESSEL :
object_out . Type = VESSEL ;
object_out . ID = Vessels . ID ( ( VesselClass * ) object ) ;
break ;
case RTTI_INFANTRY :
object_out . Type = INFANTRY ;
object_out . ID = Infantry . ID ( ( InfantryClass * ) object ) ;
break ;
case RTTI_UNIT :
object_out . Type = UNIT ;
object_out . ID = Units . ID ( ( UnitClass * ) object ) ;
break ;
case RTTI_AIRCRAFT :
object_out . Type = AIRCRAFT ;
object_out . ID = Aircraft . ID ( ( AircraftClass * ) object ) ;
break ;
case RTTI_BUILDING :
object_out . Type = BUILDING ;
object_out . ID = Buildings . ID ( ( BuildingClass * ) object ) ;
break ;
case RTTI_BULLET :
object_out . Type = BULLET ;
object_out . ID = Bullets . ID ( ( BulletClass * ) object ) ;
break ;
case RTTI_ANIM :
object_out . Type = ANIM ;
object_out . ID = Anims . ID ( ( AnimClass * ) object ) ;
break ;
case RTTI_SMUDGE :
object_out . Type = SMUDGE ;
object_out . ID = Smudges . ID ( ( SmudgeClass * ) object ) ;
break ;
case RTTI_TERRAIN :
object_out . Type = TERRAIN ;
object_out . ID = Terrains . ID ( ( TerrainClass * ) object ) ;
break ;
}
}
/**************************************************************************************************
* CNC_Handle_Input - - Process input to the game
*
* In :
*
*
*
*
* Out : Game state returned in buffer
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Input ( InputRequestEnum input_event , unsigned char special_key_flags , uint64 player_id , int x1 , int y1 , int x2 , int y2 )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( input_event ) {
/*
* * Special keys have changed
*/
case INPUT_REQUEST_SPECIAL_KEYS :
{
DLLExportClass : : Set_Special_Key_Flags ( special_key_flags ) ;
break ;
}
/*
* * The mouse is moving
*/
case INPUT_REQUEST_MOUSE_MOVE :
{
if ( ! DLLExportClass : : Legacy_Render_Enabled ( ) ) {
break ;
}
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
KEYBOARD - > MouseQX = x1 ;
KEYBOARD - > MouseQY = y1 ;
COORDINATE coord = Map . Pixel_To_Coord ( x1 , y1 ) ;
CELL cell = Coord_Cell ( coord ) ;
if ( coord ) {
//x -= Map.TacPixelX;
//y -= Map.TacPixelY;
/*
* * Cause any displayed cursor to move along with the mouse cursor .
*/
if ( cell ! = Map . ZoneCell ) {
Map . Set_Cursor_Pos ( cell ) ;
}
}
break ;
}
/*
* * Player left - clicked
*/
case INPUT_REQUEST_MOUSE_LEFT_CLICK :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
KEYBOARD - > MouseQX = x1 ;
KEYBOARD - > MouseQY = y1 ;
KeyNumType key = ( KeyNumType ) ( KN_LMOUSE | KN_RLSE_BIT ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) ) {
//DisplayClass::TacButton.Clicked_On(key, GadgetClass::LEFTRELEASE, x1, y1);
DisplayClass : : TacButton . Clicked_On ( key , GadgetClass : : LEFTRELEASE , 100 , 100 ) ;
}
break ;
}
/*
* * Player right - clicked ( on up )
*/
case INPUT_REQUEST_MOUSE_RIGHT_CLICK :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
KEYBOARD - > MouseQX = x1 ;
KEYBOARD - > MouseQY = y1 ;
KeyNumType key = ( KeyNumType ) ( KN_RMOUSE | KN_RLSE_BIT ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) ) {
//DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTRELEASE, x1, y1);
DisplayClass : : TacButton . Clicked_On ( key , GadgetClass : : RIGHTRELEASE , 100 , 100 ) ;
}
break ;
}
/*
* * Player right button down
*/
case INPUT_REQUEST_MOUSE_RIGHT_DOWN :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
KEYBOARD - > MouseQX = x1 ;
KEYBOARD - > MouseQY = y1 ;
KeyNumType key = ( KeyNumType ) ( KN_RMOUSE ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) ) {
//DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTPRESS, x1, y1);
DisplayClass : : TacButton . Clicked_On ( key , GadgetClass : : RIGHTPRESS , 100 , 100 ) ;
}
break ;
}
/*
* * Player drag selected
*/
case INPUT_REQUEST_MOUSE_AREA :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
Map . Select_These ( XYP_Coord ( x1 , y1 ) , XYP_Coord ( x2 , y2 ) , false ) ;
break ;
}
case INPUT_REQUEST_MOUSE_AREA_ADDITIVE :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
Map . Select_These ( XYP_Coord ( x1 , y1 ) , XYP_Coord ( x2 , y2 ) , true ) ;
break ;
}
case INPUT_REQUEST_SELL_AT_POSITION :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
KEYBOARD - > MouseQX = x1 ;
KEYBOARD - > MouseQY = y1 ;
COORDINATE coord = Map . Pixel_To_Coord ( x1 , y1 ) ;
CELL cell = Coord_Cell ( coord ) ;
PlayerPtr - > Sell_Wall ( cell ) ;
break ;
}
case INPUT_REQUEST_SELECT_AT_POSITION :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
Keyboard - > MouseQX = x1 ;
Keyboard - > MouseQY = y1 ;
COORDINATE coord = Map . Pixel_To_Coord ( x1 , y1 ) ;
CELL cell = Coord_Cell ( coord ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) )
{
KeyNumType key = ( KeyNumType ) ( KN_LMOUSE | KN_RLSE_BIT ) ;
DisplayClass : : TacButton . Selection_At_Mouse ( GadgetClass : : LEFTRELEASE , key ) ;
}
break ;
}
case INPUT_REQUEST_COMMAND_AT_POSITION :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
Keyboard - > MouseQX = x1 ;
Keyboard - > MouseQY = y1 ;
COORDINATE coord = Map . Pixel_To_Coord ( x1 , y1 ) ;
CELL cell = Coord_Cell ( coord ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) )
{
KeyNumType key = ( KeyNumType ) ( KN_LMOUSE | KN_RLSE_BIT ) ;
DisplayClass : : TacButton . Command_Object ( GadgetClass : : LEFTRELEASE , key ) ;
}
break ;
}
2020-09-16 10:03:04 -07:00
// MBL 09.08.2020 - Mod Support
case INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION :
case INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION :
case INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION :
case INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION :
{
DLLExportClass : : Adjust_Internal_View ( ) ;
DLLForceMouseX = x1 ;
DLLForceMouseY = y1 ;
Keyboard - > MouseQX = x1 ;
Keyboard - > MouseQY = y1 ;
COORDINATE coord = Map . Pixel_To_Coord ( x1 , y1 ) ;
CELL cell = Coord_Cell ( coord ) ;
if ( Map . Pixel_To_Coord ( x1 , y1 ) )
{
// TBD: For our ever-awesome Community Modders!
//
// PlayerPtr->Handle_Mod_Game_Command(cell, input_event - INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION);
}
break ;
}
2020-05-27 12:16:20 -07:00
default :
break ;
}
}
/**************************************************************************************************
* CNC_Handle_Structure_Request - - Process requests to repair and sell structures .
*
* In :
*
*
* Out :
*
*
*
* History : 4 / 29 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Structure_Request ( StructureRequestEnum request_type , uint64 player_id , int object_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( request_type )
{
case INPUT_STRUCTURE_REPAIR_START :
DLLExportClass : : Repair_Mode ( player_id ) ;
break ;
case INPUT_STRUCTURE_REPAIR :
DLLExportClass : : Repair ( player_id , object_id ) ;
break ;
case INPUT_STRUCTURE_SELL_START :
DLLExportClass : : Sell_Mode ( player_id ) ;
break ;
case INPUT_STRUCTURE_SELL :
DLLExportClass : : Sell ( player_id , object_id ) ;
break ;
case INPUT_STRUCTURE_CANCEL :
DLLExportClass : : Repair_Sell_Cancel ( player_id ) ;
break ;
default :
break ;
}
}
/**************************************************************************************************
* CNC_Handle_Unit_Request - - Process requests on selected units .
*
* In :
*
*
* Out :
*
*
*
* History : 10 / 15 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Unit_Request ( UnitRequestEnum request_type , uint64 player_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( request_type )
{
case INPUT_UNIT_SCATTER :
DLLExportClass : : Scatter_Selected ( player_id ) ;
break ;
case INPUT_UNIT_SELECT_NEXT :
DLLExportClass : : Select_Next_Unit ( player_id ) ;
break ;
case INPUT_UNIT_SELECT_PREVIOUS :
DLLExportClass : : Select_Previous_Unit ( player_id ) ;
break ;
case INPUT_UNIT_GUARD_MODE :
DLLExportClass : : Selected_Guard_Mode ( player_id ) ;
break ;
case INPUT_UNIT_STOP :
DLLExportClass : : Selected_Stop ( player_id ) ;
break ;
case INPUT_UNIT_FORMATION_TOGGLE :
DLLExportClass : : Team_Units_Formation_Toggle_On ( player_id ) ;
break ;
case INPUT_UNIT_QUEUED_MOVEMENT_ON :
// Red Alert Only
DLLExportClass : : Units_Queued_Movement_Toggle ( player_id , true ) ;
break ;
case INPUT_UNIT_QUEUED_MOVEMENT_OFF :
// Red Alert Only
DLLExportClass : : Units_Queued_Movement_Toggle ( player_id , false ) ;
break ;
default :
break ;
}
}
/**************************************************************************************************
* CNC_Handle_Sidebar_Request - - Process an input request to the sidebar
*
* In :
*
*
* Out :
*
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Sidebar_Request ( SidebarRequestEnum request_type , uint64 player_id , int buildable_type , int buildable_id , short cell_x , short cell_y )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( request_type ) {
2020-09-16 10:03:04 -07:00
// Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold
2020-06-22 09:43:21 -07:00
// Handle and fall through to start construction (from hold state) below
case SIDEBAR_REQUEST_START_CONSTRUCTION_MULTI :
2020-05-27 12:16:20 -07:00
case SIDEBAR_REQUEST_START_CONSTRUCTION :
DLLExportClass : : Start_Construction ( player_id , buildable_type , buildable_id ) ;
break ;
case SIDEBAR_REQUEST_HOLD_CONSTRUCTION :
DLLExportClass : : Hold_Construction ( player_id , buildable_type , buildable_id ) ;
break ;
case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION :
DLLExportClass : : Cancel_Construction ( player_id , buildable_type , buildable_id ) ;
break ;
case SIDEBAR_REQUEST_START_PLACEMENT :
DLLExportClass : : Start_Placement ( player_id , buildable_type , buildable_id ) ;
break ;
case SIDEBAR_REQUEST_PLACE :
DLLExportClass : : Place ( player_id , buildable_type , buildable_id , cell_x , cell_y ) ;
break ;
case SIDEBAR_CANCEL_PLACE :
DLLExportClass : : Cancel_Placement ( player_id , buildable_type , buildable_id ) ;
break ;
default :
break ;
}
}
/**************************************************************************************************
* CNC_Handle_SuperWeapon_Request
*
* In :
*
*
* Out :
*
*
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_SuperWeapon_Request ( SuperWeaponRequestEnum request_type , uint64 player_id , int buildable_type , int buildable_id , int x1 , int y1 )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( request_type )
{
case SUPERWEAPON_REQUEST_PLACE_SUPER_WEAPON :
DLLExportClass : : Place_Super_Weapon ( player_id , buildable_type , buildable_id , x1 , y1 ) ;
break ;
}
}
/**************************************************************************************************
* CNC_Handle_ControlGroup_Request
*
* In :
*
*
* Out :
*
*
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_ControlGroup_Request ( ControlGroupRequestEnum request_type , uint64 player_id , unsigned char control_group_index )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( request_type )
{
case CONTROL_GROUP_REQUEST_CREATE :
DLLExportClass : : Create_Control_Group ( control_group_index ) ;
break ;
case CONTROL_GROUP_REQUEST_TOGGLE :
DLLExportClass : : Toggle_Control_Group_Selection ( control_group_index ) ;
break ;
case CONTROL_GROUP_REQUEST_ADDITIVE_SELECTION :
DLLExportClass : : Add_To_Control_Group ( control_group_index ) ;
break ;
}
}
/**************************************************************************************************
* DLLExportClass : : Get_Layer_State - - Get a snapshot of the sidebar state
*
* In :
*
* Out :
*
*
*
* History : 1 / 29 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Sidebar_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
CNCSidebarStruct * sidebar = ( CNCSidebarStruct * ) buffer_in ;
unsigned int memory_needed = sizeof ( * sidebar ) ; // Base amount needed. Will need more depending on how many entries there are
int entry_index = 0 ;
sidebar - > Credits = 0 ;
sidebar - > CreditsCounter = 0 ;
sidebar - > Tiberium = 0 ;
sidebar - > MaxTiberium = 0 ;
sidebar - > PowerProduced = 0 ;
sidebar - > PowerDrained = 0 ;
sidebar - > RepairBtnEnabled = false ;
sidebar - > SellBtnEnabled = false ;
sidebar - > RadarMapActive = false ;
sidebar - > MissionTimer = Scen . MissionTimer . Is_Active ( ) ? ( Scen . MissionTimer / TICKS_PER_SECOND ) : - 1 ;
sidebar - > UnitsKilled = 0 ;
sidebar - > BuildingsKilled = 0 ;
sidebar - > UnitsLost = 0 ;
sidebar - > BuildingsLost = 0 ;
sidebar - > TotalHarvestedCredits = 0 ;
if ( PlayerPtr ) {
sidebar - > Credits = PlayerPtr - > Credits ;
sidebar - > CreditsCounter = PlayerPtr - > VisibleCredits . Current ; // Timed display
// sidebar->CreditsCounter = PlayerPtr->VisibleCredits.Credits; // Actual
sidebar - > Tiberium = PlayerPtr - > Tiberium ;
sidebar - > MaxTiberium = PlayerPtr - > Capacity ;
sidebar - > PowerProduced = PlayerPtr - > Power ;
sidebar - > PowerDrained = PlayerPtr - > Drain ;
sidebar - > RepairBtnEnabled = PlayerPtr - > BScan > 0 ;
sidebar - > SellBtnEnabled = PlayerPtr - > BScan > 0 ;
sidebar - > RadarMapActive = PlayerPtr - > Radar = = RADAR_ON ;
// A. Get the DestroyedBuildings and DestroyedInfantry stats if they are available at this point
if ( PlayerPtr - > DestroyedBuildings ) {
for ( int index = 0 ; index < PlayerPtr - > DestroyedBuildings - > Get_Unit_Count ( ) ; index + + )
{
unsigned int count = ( unsigned int ) PlayerPtr - > DestroyedBuildings - > Get_Unit_Total ( index ) ;
sidebar - > BuildingsKilled + = count ;
}
}
if ( PlayerPtr - > DestroyedInfantry ) {
for ( int index = 0 ; index < PlayerPtr - > DestroyedInfantry - > Get_Unit_Count ( ) ; index + + )
{
unsigned int count = ( unsigned int ) PlayerPtr - > DestroyedInfantry - > Get_Unit_Total ( index ) ;
sidebar - > UnitsKilled + = count ; // Includes Infantry, Vehicles, Aircraft
}
}
if ( PlayerPtr - > DestroyedUnits ) {
for ( int index = 0 ; index < PlayerPtr - > DestroyedUnits - > Get_Unit_Count ( ) ; index + + )
{
unsigned int count = ( unsigned int ) PlayerPtr - > DestroyedUnits - > Get_Unit_Total ( index ) ;
sidebar - > UnitsKilled + = count ; // Includes Infantry, Vehicles, Aircraft
}
}
if ( PlayerPtr - > DestroyedAircraft ) {
for ( int index = 0 ; index < PlayerPtr - > DestroyedAircraft - > Get_Unit_Count ( ) ; index + + )
{
unsigned int count = ( unsigned int ) PlayerPtr - > DestroyedAircraft - > Get_Unit_Total ( index ) ;
sidebar - > UnitsKilled + = count ; // Includes Infantry, Vehicles, Aircraft
}
}
// B. If the DestroyedBuildings and DestroyedInfantry stats seemed to be unvailable, this is another way to do it
// Note that we need to do both of these depending on which type of match we are running, as well as for Replays/Observer and live stats reporting
// We can't just do it this way for everything, as it does not work for all cases
if ( sidebar - > BuildingsKilled = = 0 )
{
for ( unsigned int house_index = 0 ; house_index < HOUSE_COUNT ; house_index + + )
{
sidebar - > BuildingsKilled + = PlayerPtr - > BuildingsKilled [ house_index ] ;
}
}
if ( sidebar - > UnitsKilled = = 0 )
{
for ( unsigned int house_index = 0 ; house_index < HOUSE_COUNT ; house_index + + )
{
sidebar - > UnitsKilled + = PlayerPtr - > UnitsKilled [ house_index ] ; // Includes Infantry, Vehicles, Aircraft
}
}
sidebar - > UnitsLost = PlayerPtr - > UnitsLost ;
sidebar - > BuildingsLost = PlayerPtr - > BuildingsLost ;
sidebar - > TotalHarvestedCredits = PlayerPtr - > HarvestedCredits ;
}
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
/*
* * Get each sidebar column
*/
for ( int c = 0 ; c < 2 ; c + + ) {
sidebar - > EntryCount [ c ] = Map . Column [ c ] . BuildableCount ;
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < Map . Column [ c ] . BuildableCount ; b + + ) {
CNCSidebarEntryStruct & sidebar_entry = sidebar - > Entries [ entry_index + + ] ;
if ( ( entry_index + 1 ) * sizeof ( CNCSidebarEntryStruct ) + memory_needed > buffer_size ) {
return false ;
}
2020-08-06 09:44:54 -07:00
memset ( & sidebar_entry , 0 , sizeof ( sidebar_entry ) ) ;
2020-05-27 12:16:20 -07:00
sidebar_entry . AssetName [ 0 ] = 0 ;
sidebar_entry . Type = UNKNOWN ;
sidebar_entry . BuildableID = Map . Column [ c ] . Buildables [ b ] . BuildableID ;
sidebar_entry . BuildableType = Map . Column [ c ] . Buildables [ b ] . BuildableType ;
sidebar_entry . BuildableViaCapture = Map . Column [ c ] . Buildables [ b ] . BuildableViaCapture ;
sidebar_entry . Fake = false ;
TechnoTypeClass const * tech = Fetch_Techno_Type ( Map . Column [ c ] . Buildables [ b ] . BuildableType , Map . Column [ c ] . Buildables [ b ] . BuildableID ) ;
sidebar_entry . SuperWeaponType = SW_NONE ;
if ( tech ) {
2020-09-16 10:03:04 -07:00
sidebar_entry . Cost = tech - > Cost * PlayerPtr - > CostBias ; // If this gets modified, also modify below for skirmish and multiplayer
2020-05-27 12:16:20 -07:00
sidebar_entry . PowerProvided = 0 ;
2020-06-22 09:43:21 -07:00
sidebar_entry . BuildTime = tech - > Time_To_Build ( PlayerPtr - > Class - > House ) ; // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
2020-05-27 12:16:20 -07:00
strncpy ( sidebar_entry . AssetName , tech - > IniName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
} else {
sidebar_entry . Cost = 0 ;
sidebar_entry . AssetName [ 0 ] = 0 ;
}
SuperClass * super_weapon = nullptr ;
bool isbusy = false ;
switch ( Map . Column [ c ] . Buildables [ b ] . BuildableType ) {
case RTTI_INFANTRYTYPE :
sidebar_entry . Type = INFANTRY_TYPE ;
isbusy = ( PlayerPtr - > InfantryFactory ! = - 1 ) ;
isbusy | = Infantry . Avail ( ) < = 0 ;
break ;
case RTTI_UNITTYPE :
isbusy = ( PlayerPtr - > UnitFactory ! = - 1 ) ;
isbusy | = Units . Avail ( ) < = 0 ;
sidebar_entry . Type = UNIT_TYPE ;
break ;
case RTTI_AIRCRAFTTYPE :
isbusy = ( PlayerPtr - > AircraftFactory ! = - 1 ) ;
isbusy | = Aircraft . Avail ( ) < = 0 ;
sidebar_entry . Type = AIRCRAFT_TYPE ;
break ;
case RTTI_BUILDINGTYPE :
{
isbusy = ( PlayerPtr - > BuildingFactory ! = - 1 ) ;
isbusy | = Buildings . Avail ( ) < = 0 ;
sidebar_entry . Type = BUILDING_TYPE ;
const BuildingTypeClass * build_type = static_cast < const BuildingTypeClass * > ( tech ) ;
sidebar_entry . PowerProvided = build_type - > Power - build_type - > Drain ;
sidebar_entry . Fake = build_type - > IsFake ;
}
break ;
case RTTI_VESSELTYPE :
sidebar_entry . Type = VESSEL_TYPE ;
isbusy = ( PlayerPtr - > VesselFactory ! = - 1 ) ;
isbusy | = Vessels . Avail ( ) < = 0 ;
break ;
default :
sidebar_entry . Type = UNKNOWN ;
break ;
case RTTI_SPECIAL :
Fill_Sidebar_Entry_From_Special_Weapon ( sidebar_entry , super_weapon , ( SpecialWeaponType ) Map . Column [ c ] . Buildables [ b ] . BuildableID ) ;
break ;
}
if ( super_weapon ! = nullptr )
{
sidebar_entry . Progress = ( float ) super_weapon - > Anim_Stage ( ) / ( float ) SuperClass : : ANIMATION_STAGES ;
sidebar_entry . Completed = super_weapon - > Is_Ready ( ) ;
sidebar_entry . Constructing = super_weapon - > Anim_Stage ( ) ! = SuperClass : : ANIMATION_STAGES ;
sidebar_entry . ConstructionOnHold = false ;
sidebar_entry . PlacementListLength = 0 ;
sidebar_entry . PowerProvided = 0 ;
sidebar_entry . BuildTime = super_weapon - > Get_Recharge_Time ( ) ;
}
else
{
int fnumber = Map . Column [ c ] . Buildables [ b ] . Factory ;
FactoryClass * factory = NULL ;
if ( tech & & fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
sidebar_entry . Completed = false ;
sidebar_entry . Constructing = false ;
sidebar_entry . ConstructionOnHold = false ;
sidebar_entry . Progress = 0.0f ;
sidebar_entry . Busy = isbusy ;
sidebar_entry . PlacementListLength = 0 ;
if ( factory ) {
if ( factory - > Is_Building ( ) ) {
sidebar_entry . Constructing = true ;
sidebar_entry . Progress = ( float ) factory - > Completion ( ) / ( float ) FactoryClass : : STEP_COUNT ;
sidebar_entry . Completed = factory - > Has_Completed ( ) ;
}
else {
sidebar_entry . Completed = factory - > Has_Completed ( ) ;
if ( ! sidebar_entry . Completed )
{
sidebar_entry . ConstructionOnHold = true ;
sidebar_entry . Progress = ( float ) factory - > Completion ( ) / ( float ) FactoryClass : : STEP_COUNT ;
}
if ( sidebar_entry . Completed & & sidebar_entry . Type = = BUILDING_TYPE ) {
if ( tech ) {
BuildingTypeClass * building_type = ( BuildingTypeClass * ) tech ;
short const * occupy_list = building_type - > Occupy_List ( true ) ;
if ( occupy_list ) {
while ( * occupy_list ! = REFRESH_EOL & & sidebar_entry . PlacementListLength < MAX_OCCUPY_CELLS ) {
sidebar_entry . PlacementList [ sidebar_entry . PlacementListLength ] = * occupy_list ;
sidebar_entry . PlacementListLength + + ;
occupy_list + + ;
}
}
}
}
}
}
}
}
}
} else {
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
SidebarGlyphxClass * context_sidebar = DLLExportClass : : Get_Current_Context_Sidebar ( ) ;
/*
* * Get each sidebar column
*/
for ( int c = 0 ; c < 2 ; c + + ) {
sidebar - > EntryCount [ c ] = context_sidebar - > Column [ c ] . BuildableCount ;
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < context_sidebar - > Column [ c ] . BuildableCount ; b + + ) {
CNCSidebarEntryStruct & sidebar_entry = sidebar - > Entries [ entry_index + + ] ;
if ( ( entry_index + 1 ) * sizeof ( CNCSidebarEntryStruct ) + memory_needed > buffer_size ) {
return false ;
}
2020-08-06 09:44:54 -07:00
memset ( & sidebar_entry , 0 , sizeof ( sidebar_entry ) ) ;
2020-05-27 12:16:20 -07:00
sidebar_entry . AssetName [ 0 ] = 0 ;
sidebar_entry . Type = UNKNOWN ;
sidebar_entry . BuildableID = context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableID ;
sidebar_entry . BuildableType = context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableType ;
sidebar_entry . BuildableViaCapture = context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableViaCapture ;
sidebar_entry . Fake = false ;
TechnoTypeClass const * tech = Fetch_Techno_Type ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableType , context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableID ) ;
sidebar_entry . SuperWeaponType = SW_NONE ;
if ( tech ) {
2020-08-06 09:44:54 -07:00
2020-09-16 10:03:04 -07:00
// Updated to apply and difficulty abd/or faction price modifier; See https://jaas.ea.com/browse/TDRA-6864
2020-08-06 09:44:54 -07:00
// If this gets modified, also modify above for non-skirmish / non-multiplayer
//
// sidebar_entry.Cost = tech->Cost;
sidebar_entry . Cost = tech - > Cost * PlayerPtr - > CostBias ;
2020-05-27 12:16:20 -07:00
sidebar_entry . PowerProvided = 0 ;
2020-06-22 09:43:21 -07:00
sidebar_entry . BuildTime = tech - > Time_To_Build ( PlayerPtr - > Class - > House ) ; // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
2020-05-27 12:16:20 -07:00
strncpy ( sidebar_entry . AssetName , tech - > IniName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
} else {
sidebar_entry . Cost = 0 ;
sidebar_entry . AssetName [ 0 ] = 0 ;
}
SuperClass * super_weapon = nullptr ;
bool isbusy = false ;
switch ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableType ) {
case RTTI_INFANTRYTYPE :
sidebar_entry . Type = INFANTRY_TYPE ;
isbusy = ( PlayerPtr - > InfantryFactory ! = - 1 ) ;
isbusy | = Infantry . Avail ( ) < = 0 ;
break ;
case RTTI_UNITTYPE :
isbusy = ( PlayerPtr - > UnitFactory ! = - 1 ) ;
isbusy | = Units . Avail ( ) < = 0 ;
sidebar_entry . Type = UNIT_TYPE ;
break ;
case RTTI_AIRCRAFTTYPE :
isbusy = ( PlayerPtr - > AircraftFactory ! = - 1 ) ;
isbusy | = Aircraft . Avail ( ) < = 0 ;
sidebar_entry . Type = AIRCRAFT_TYPE ;
break ;
case RTTI_BUILDINGTYPE :
{
isbusy = ( PlayerPtr - > BuildingFactory ! = - 1 ) ;
isbusy | = Buildings . Avail ( ) < = 0 ;
sidebar_entry . Type = BUILDING_TYPE ;
const BuildingTypeClass * build_type = static_cast < const BuildingTypeClass * > ( tech ) ;
sidebar_entry . PowerProvided = build_type - > Power - build_type - > Drain ;
sidebar_entry . Fake = build_type - > IsFake ;
break ;
}
case RTTI_VESSELTYPE :
isbusy = ( PlayerPtr - > VesselFactory ! = - 1 ) ;
isbusy | = Vessels . Avail ( ) < = 0 ;
sidebar_entry . Type = VESSEL_TYPE ;
break ;
default :
sidebar_entry . Type = UNKNOWN ;
break ;
case RTTI_SPECIAL :
Fill_Sidebar_Entry_From_Special_Weapon ( sidebar_entry , super_weapon , ( SpecialWeaponType ) sidebar_entry . BuildableID ) ;
break ;
}
if ( super_weapon ! = nullptr )
{
sidebar_entry . Progress = ( float ) super_weapon - > Anim_Stage ( ) / ( float ) SuperClass : : ANIMATION_STAGES ;
sidebar_entry . Completed = super_weapon - > Is_Ready ( ) ;
sidebar_entry . Constructing = super_weapon - > Anim_Stage ( ) ! = SuperClass : : ANIMATION_STAGES ;
sidebar_entry . ConstructionOnHold = false ;
sidebar_entry . PlacementListLength = 0 ;
sidebar_entry . PowerProvided = 0 ;
sidebar_entry . BuildTime = super_weapon - > Get_Recharge_Time ( ) ;
}
else
{
int fnumber = context_sidebar - > Column [ c ] . Buildables [ b ] . Factory ;
FactoryClass * factory = NULL ;
if ( tech & & fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
sidebar_entry . Completed = false ;
sidebar_entry . Constructing = false ;
sidebar_entry . ConstructionOnHold = false ;
sidebar_entry . Progress = 0.0f ;
sidebar_entry . Busy = isbusy ;
sidebar_entry . PlacementListLength = 0 ;
if ( factory ) {
if ( factory - > Is_Building ( ) ) {
sidebar_entry . Constructing = true ;
sidebar_entry . Progress = ( float ) factory - > Completion ( ) / ( float ) FactoryClass : : STEP_COUNT ;
sidebar_entry . Completed = factory - > Has_Completed ( ) ;
}
else {
sidebar_entry . Completed = factory - > Has_Completed ( ) ;
if ( ! sidebar_entry . Completed )
{
sidebar_entry . ConstructionOnHold = true ;
sidebar_entry . Progress = ( float ) factory - > Completion ( ) / ( float ) FactoryClass : : STEP_COUNT ;
}
if ( sidebar_entry . Completed & & sidebar_entry . Type = = BUILDING_TYPE ) {
if ( tech ) {
BuildingTypeClass * building_type = ( BuildingTypeClass * ) tech ;
short const * occupy_list = building_type - > Occupy_List ( true ) ;
if ( occupy_list ) {
while ( * occupy_list ! = REFRESH_EOL & & sidebar_entry . PlacementListLength < MAX_OCCUPY_CELLS ) {
sidebar_entry . PlacementList [ sidebar_entry . PlacementListLength ] = * occupy_list ;
sidebar_entry . PlacementListLength + + ;
occupy_list + + ;
}
}
}
}
}
}
}
}
}
}
}
return true ;
}
void DLLExportClass : : Convert_Action_Type ( ActionType type , ObjectClass * object , TARGET target , DllActionTypeEnum & dll_type )
{
switch ( type )
{
case ACTION_NONE :
default :
dll_type = DAT_NONE ;
break ;
case ACTION_MOVE :
dll_type = DAT_MOVE ;
break ;
case ACTION_NOMOVE :
dll_type = DAT_NOMOVE ;
break ;
case ACTION_ENTER :
dll_type = DAT_ENTER ;
break ;
case ACTION_SELF :
dll_type = DAT_SELF ;
break ;
case ACTION_ATTACK :
if ( Target_Legal ( target ) & & ( object ! = NULL ) & & object - > Is_Techno ( ) & & ( ( TechnoClass * ) object ) - > In_Range ( target , 0 ) ) {
dll_type = DAT_ATTACK ;
}
else {
dll_type = DAT_ATTACK_OUT_OF_RANGE ;
}
break ;
case ACTION_GUARD_AREA :
dll_type = DAT_GUARD ;
break ;
case ACTION_HARVEST :
dll_type = DAT_ATTACK ;
break ;
case ACTION_SELECT :
case ACTION_TOGGLE_SELECT :
dll_type = DAT_SELECT ;
break ;
case ACTION_CAPTURE :
dll_type = DAT_CAPTURE ;
break ;
case ACTION_DAMAGE :
dll_type = DAT_DAMAGE ;
break ;
case ACTION_SABOTAGE :
dll_type = DAT_SABOTAGE ;
break ;
case ACTION_HEAL :
dll_type = DAT_HEAL ;
break ;
case ACTION_TOGGLE_PRIMARY :
dll_type = DAT_TOGGLE_PRIMARY ;
break ;
case ACTION_NO_DEPLOY :
dll_type = DAT_CANT_DEPLOY ;
break ;
case ACTION_GREPAIR :
dll_type = DAT_REPAIR ;
break ;
case ACTION_NO_GREPAIR :
dll_type = DAT_CANT_REPAIR ;
break ;
}
}
void DLLExportClass : : Convert_Special_Weapon_Type ( SpecialWeaponType weapon_type , DllSuperweaponTypeEnum & dll_weapon_type , char * weapon_name )
{
switch ( weapon_type )
{
case SPC_SONAR_PULSE :
dll_weapon_type = SW_SONAR_PULSE ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_SonarPulse " , 16 ) ;
}
break ;
case SPC_NUCLEAR_BOMB :
dll_weapon_type = SW_NUKE ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_Nuke " , 16 ) ;
}
break ;
case SPC_CHRONOSPHERE :
dll_weapon_type = SW_CHRONOSPHERE ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_Chrono " , 16 ) ;
}
break ;
case SPC_PARA_BOMB :
dll_weapon_type = SW_PARA_BOMB ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_ParaBomb " , 16 ) ;
}
break ;
case SPC_PARA_INFANTRY :
dll_weapon_type = SW_PARA_INFANTRY ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_ParaInfantry " , 16 ) ;
}
break ;
case SPC_SPY_MISSION :
dll_weapon_type = SW_SPY_MISSION ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_SpyMission " , 16 ) ;
}
break ;
case SPC_IRON_CURTAIN :
dll_weapon_type = SW_IRON_CURTAIN ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_IronCurtain " , 16 ) ;
}
break ;
case SPC_GPS :
dll_weapon_type = SW_GPS ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_GPS " , 16 ) ;
}
break ;
case SPC_CHRONO2 :
dll_weapon_type = SW_CHRONOSPHERE_DESTINATION ;
if ( weapon_name ! = NULL )
{
strncpy ( weapon_name , " SW_Chrono2 " , 16 ) ;
}
break ;
default :
dll_weapon_type = SW_UNKNOWN ;
if ( weapon_name ! = NULL )
{
weapon_name [ 0 ] = ' \0 ' ;
}
break ;
}
}
void DLLExportClass : : Fill_Sidebar_Entry_From_Special_Weapon ( CNCSidebarEntryStruct & sidebar_entry_out , SuperClass * & super_weapon_out , SpecialWeaponType weapon_type )
{
sidebar_entry_out . Type = SPECIAL ;
switch ( weapon_type )
{
case SPC_SONAR_PULSE :
case SPC_NUCLEAR_BOMB :
case SPC_CHRONOSPHERE :
case SPC_PARA_BOMB :
case SPC_PARA_INFANTRY :
case SPC_SPY_MISSION :
case SPC_IRON_CURTAIN :
case SPC_GPS :
case SPC_CHRONO2 :
Convert_Special_Weapon_Type ( weapon_type , sidebar_entry_out . SuperWeaponType , sidebar_entry_out . AssetName ) ;
break ;
default :
sidebar_entry_out . SuperWeaponType = SW_UNKNOWN ;
sidebar_entry_out . Type = UNKNOWN ;
super_weapon_out = nullptr ;
return ;
}
super_weapon_out = & ( PlayerPtr - > SuperWeapon [ weapon_type ] ) ;
}
static const int _map_width_shift_bits = 7 ;
void DLLExportClass : : Calculate_Placement_Distances ( BuildingTypeClass * placement_type , unsigned char * placement_distance )
{
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_WIDTH ) {
map_cell_height + + ;
}
static const FacingType _scan_facings [ ] = {
FACING_E ,
FACING_S ,
FACING_W ,
FACING_N
} ;
memset ( placement_distance , 255U , MAP_CELL_TOTAL ) ;
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + ) {
CELL cell = ( CELL ) map_cell_x + x + ( ( map_cell_y + y ) < < _map_width_shift_bits ) ;
BuildingClass * base = ( BuildingClass * ) Map [ cell ] . Cell_Find_Object ( RTTI_BUILDING ) ;
if ( ( base & & base - > House - > Class - > House = = PlayerPtr - > Class - > House & & base - > Class - > IsBase ) | |
( ( placement_type - > IsWall | | ( ( Map [ cell ] . Smudge ! = SMUDGE_NONE ) & & SmudgeTypeClass : : As_Reference ( Map [ cell ] . Smudge ) . IsBib ) ) & &
Map [ cell ] . Owner = = PlayerPtr - > Class - > House ) ) {
placement_distance [ cell ] = 0U ;
CELL startcell = cell ;
for ( unsigned char distance = 1U ; distance < = ( placement_type - > Adjacent + 1U ) ; distance + + ) {
startcell = Adjacent_Cell ( startcell , FACING_NW ) ;
CELL scancell = startcell ;
for ( int i = 0 ; i < ARRAY_SIZE ( _scan_facings ) ; i + + ) {
CELL nextcell = scancell ;
for ( unsigned char scan = 0U ; scan < = ( distance * 2U ) ; scan + + ) {
scancell = nextcell ;
if ( Map . In_Radar ( scancell ) ) {
placement_distance [ scancell ] = min ( placement_distance [ scancell ] , distance ) ;
}
nextcell = Adjacent_Cell ( scancell , _scan_facings [ i ] ) ;
}
}
}
}
}
}
}
void Recalculate_Placement_Distances ( )
{
DLLExportClass : : Recalculate_Placement_Distances ( ) ;
}
void DLLExportClass : : Recalculate_Placement_Distances ( )
{
if ( PlacementType [ CurrentLocalPlayerIndex ] ! = NULL ) {
Calculate_Placement_Distances ( PlacementType [ CurrentLocalPlayerIndex ] , PlacementDistance [ CurrentLocalPlayerIndex ] ) ;
}
}
/**************************************************************************************************
* DLLExportClass : : Get_Placement_State - - Get a snapshot of legal validity of placing a structure on all map cells
*
* In :
*
* Out :
*
*
*
* History : 2 / 4 / 2019 3 : 11 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Placement_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
if ( PlacementType [ CurrentLocalPlayerIndex ] = = NULL ) {
return false ;
}
CNCPlacementInfoStruct * placement_info = ( CNCPlacementInfoStruct * ) buffer_in ;
unsigned int memory_needed = sizeof ( * placement_info ) ; // Base amount needed. Will need more depending on how many entries there are
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_WIDTH ) {
map_cell_height + + ;
}
memory_needed + = map_cell_width * map_cell_height * sizeof ( CNCPlacementCellInfoStruct ) ;
if ( memory_needed + 128 > = buffer_size ) {
return false ;
}
placement_info - > Count = map_cell_width * map_cell_height ;
int index = 0 ;
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + ) {
CELL cell = ( CELL ) map_cell_x + x + ( ( map_cell_y + y ) < < _map_width_shift_bits ) ;
bool pass = Passes_Proximity_Check ( cell , PlacementType [ CurrentLocalPlayerIndex ] , PlacementDistance [ CurrentLocalPlayerIndex ] ) ;
CellClass * cellptr = & Map [ cell ] ;
bool clear = cellptr - > Is_Clear_To_Build ( PlacementType [ CurrentLocalPlayerIndex ] - > Speed ) ;
CNCPlacementCellInfoStruct & placement_cell_info = placement_info - > CellInfo [ index + + ] ;
placement_cell_info . PassesProximityCheck = pass ;
placement_cell_info . GenerallyClear = clear ;
}
}
Map . ZoneOffset = 0 ;
return true ;
}
bool DLLExportClass : : Passes_Proximity_Check ( CELL cell_in , BuildingTypeClass * placement_type , unsigned char * placement_distance )
{
/*
* * Scan through all cells that the building foundation would cover . If any adjacent
* * cells to these are of friendly persuasion , then consider the proximity check to
* * have been a success .
*/
short const * occupy_list = placement_type - > Occupy_List ( true ) ;
while ( * occupy_list ! = REFRESH_EOL ) {
CELL center_cell = cell_in + * occupy_list + + ;
if ( ! Map . In_Radar ( center_cell ) ) {
return false ;
}
if ( placement_distance [ center_cell ] < = ( placement_type - > Adjacent + 1 ) ) {
return true ;
}
}
return false ;
}
/**************************************************************************************************
* DLLExportClass : : Start_Construction - - Start sidebar construction
*
* In :
*
* Out :
*
*
*
* History : 1 / 29 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Start_Construction ( uint64 player_id , int buildable_type , int buildable_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
return Construction_Action ( SIDEBAR_REQUEST_START_CONSTRUCTION , player_id , buildable_type , buildable_id ) ;
}
return MP_Construction_Action ( SIDEBAR_REQUEST_START_CONSTRUCTION , player_id , buildable_type , buildable_id ) ;
}
/**************************************************************************************************
* DLLExportClass : : Hold_Construction - - Pause sidebar construction
*
* In :
*
* Out :
*
*
*
* History : 6 / 12 / 2019 JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Hold_Construction ( uint64 player_id , int buildable_type , int buildable_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) )
{
return false ;
}
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
return Construction_Action ( SIDEBAR_REQUEST_HOLD_CONSTRUCTION , player_id , buildable_type , buildable_id ) ;
}
return MP_Construction_Action ( SIDEBAR_REQUEST_HOLD_CONSTRUCTION , player_id , buildable_type , buildable_id ) ;
}
/**************************************************************************************************
* DLLExportClass : : Cancel_Construction - - Stop sidebar construction
*
* In :
*
* Out :
*
*
*
* History : 6 / 12 / 2019 JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Cancel_Construction ( uint64 player_id , int buildable_type , int buildable_id )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) )
{
return false ;
}
return Cancel_Placement ( player_id , buildable_type , buildable_id ) & &
( ( GAME_TO_PLAY = = GAME_NORMAL ) ?
Construction_Action ( SIDEBAR_REQUEST_CANCEL_CONSTRUCTION , player_id , buildable_type , buildable_id ) :
MP_Construction_Action ( SIDEBAR_REQUEST_CANCEL_CONSTRUCTION , player_id , buildable_type , buildable_id ) ) ;
}
/**************************************************************************************************
* DLLExportClass : : Construction_Action - - Reproduce actions on the sidebar
*
* In :
*
* Out :
*
*
*
* History : 1 / 29 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Construction_Action ( SidebarRequestEnum construction_action , uint64 player_id , int buildable_type , int buildable_id )
{
/*
* *
* * Based on SidebarClass : : StripClass : : SelectClass : : Action
* *
* * Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
* *
*/
for ( int c = 0 ; c < 2 ; c + + ) {
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < Map . Column [ c ] . BuildableCount ; b + + ) {
if ( Map . Column [ c ] . Buildables [ b ] . BuildableID = = buildable_id ) {
if ( Map . Column [ c ] . Buildables [ b ] . BuildableType = = buildable_type ) {
int fnumber = Map . Column [ c ] . Buildables [ b ] . Factory ;
int spc = 0 ;
ObjectTypeClass const * choice = NULL ;
if ( buildable_type ! = RTTI_SPECIAL ) {
choice = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
} else {
spc = buildable_id ;
}
FactoryClass * factory = PlayerPtr - > Fetch_Factory ( ( RTTIType ) buildable_type ) ;
if ( fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
if ( spc = = 0 & & choice ) {
if ( fnumber = = - 1 & & factory ! = NULL ) {
return ( false ) ;
}
if ( factory ) {
switch ( construction_action )
{
case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION :
On_Speech ( PlayerPtr , VOX_CANCELED ) ; // Speak(VOX_CANCELED);
OutList . Add ( EventClass ( EventClass : : ABANDON , ( RTTIType ) buildable_type , buildable_id ) ) ;
break ;
case SIDEBAR_REQUEST_HOLD_CONSTRUCTION :
if ( factory - > Is_Building ( ) )
{
On_Speech ( PlayerPtr , VOX_SUSPENDED ) ; // Speak(VOX_SUSPENDED);
OutList . Add ( EventClass ( EventClass : : SUSPEND , ( RTTIType ) buildable_type , buildable_id ) ) ;
}
break ;
default :
/*
* * If this object is currently being built , then give a scold sound and text and then
* * bail .
*/
if ( factory - > Is_Building ( ) ) {
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; //Speak(VOX_NO_FACTORY); // "Cannot Comply"
return false ;
}
else {
/*
* * If production has completed , then attempt to have the object exit
* * the factory or go into placement mode .
*/
if ( factory - > Has_Completed ( ) ) {
TechnoClass * pending = factory - > Get_Object ( ) ;
if ( ! pending & & factory - > Get_Special_Item ( ) ) {
// TO_DO
//Map.IsTargettingMode = true;
}
else {
BuildingClass * builder = pending - > Who_Can_Build_Me ( false , false ) ;
if ( ! builder ) {
OutList . Add ( EventClass ( EventClass : : ABANDON , ( RTTIType ) buildable_type , buildable_id ) ) ;
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; //Speak(VOX_NO_FACTORY); // "Cannot Comply"
}
else {
/*
* * If the completed object is a building , then change the
* * game state into building placement mode . This fact is
* * not transmitted to any linked computers until the moment
* * the building is actually placed down .
*/
if ( pending - > What_Am_I ( ) = = RTTI_BUILDING ) {
if ( construction_action = = SIDEBAR_REQUEST_START_PLACEMENT ) {
PlayerPtr - > Manual_Place ( builder , ( BuildingClass * ) pending ) ;
}
}
else {
/*
* * For objects that can leave the factory under their own
* * power , queue this event and process through normal house
* * production channels .
*/
//OutList.Add(EventClass(EventClass::PLACE, otype, -1));
}
}
}
}
else {
/*
* * The factory must have been in a suspended state . Resume construction
* * normally .
*/
if ( construction_action = = SIDEBAR_REQUEST_START_CONSTRUCTION ) {
if ( ( RTTIType ) buildable_type = = RTTI_INFANTRYTYPE )
{
On_Speech ( PlayerPtr , VOX_TRAINING ) ; // Speak(VOX_TRAINING);
}
else
{
On_Speech ( PlayerPtr , VOX_BUILDING ) ; // Speak(VOX_BUILDING);
}
OutList . Add ( EventClass ( EventClass : : PRODUCE , ( RTTIType ) buildable_type , buildable_id ) ) ;
return true ;
}
}
}
}
} else {
switch ( construction_action )
{
case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION :
case SIDEBAR_REQUEST_HOLD_CONSTRUCTION :
break ;
default :
/*
* * If this side strip is already busy with production , then ignore the
* * input and announce this fact .
*/
if ( ( RTTIType ) buildable_type = = RTTI_INFANTRYTYPE )
{
On_Speech ( PlayerPtr , VOX_TRAINING ) ; // Speak(VOX_TRAINING);
}
else
{
On_Speech ( PlayerPtr , VOX_BUILDING ) ; // Speak(VOX_BUILDING);
}
OutList . Add ( EventClass ( EventClass : : PRODUCE , ( RTTIType ) buildable_type , buildable_id ) ) ;
/*
* * Execute immediately so we get the sidebar feedback
*/
Queue_AI ( ) ;
return true ;
}
}
}
}
}
}
}
return false ;
}
/**************************************************************************************************
* DLLExportClass : : MP_Construction_Action - - Reproduce actions on the sidebar
*
* In :
*
* Out :
*
*
*
* History : 3 / 26 / 2019 1 : 02 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : MP_Construction_Action ( SidebarRequestEnum construction_action , uint64 player_id , int buildable_type , int buildable_id )
{
/*
* *
* * Based on SidebarClass : : StripClass : : SelectClass : : Action
* *
* * Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
* *
*/
SidebarGlyphxClass * context_sidebar = DLLExportClass : : Get_Current_Context_Sidebar ( ) ;
for ( int c = 0 ; c < 2 ; c + + ) {
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < context_sidebar - > Column [ c ] . BuildableCount ; b + + ) {
if ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableID = = buildable_id ) {
if ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableType = = buildable_type ) {
int genfactory = - 1 ;
switch ( buildable_type ) {
case RTTI_INFANTRYTYPE :
genfactory = PlayerPtr - > InfantryFactory ;
break ;
case RTTI_UNITTYPE :
genfactory = PlayerPtr - > UnitFactory ;
break ;
case RTTI_AIRCRAFTTYPE :
genfactory = PlayerPtr - > AircraftFactory ;
break ;
case RTTI_BUILDINGTYPE :
genfactory = PlayerPtr - > BuildingFactory ;
break ;
default :
genfactory = - 1 ;
break ;
}
int fnumber = context_sidebar - > Column [ c ] . Buildables [ b ] . Factory ;
int spc = 0 ;
ObjectTypeClass const * choice = NULL ;
if ( buildable_type ! = RTTI_SPECIAL ) {
choice = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
} else {
spc = buildable_id ;
}
FactoryClass * factory = NULL ;
if ( fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
if ( spc = = 0 & & choice ) {
/*
* * If there is already a factory attached to this strip but the player didn ' t click
* * on the icon that has the attached factory , then say that the factory is busy and
* * ignore the click .
*/
if ( fnumber = = - 1 & & genfactory ! = - 1 ) {
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; //Speak(VOX_NO_FACTORY); // "Cannot Comply"
return ( false ) ;
}
if ( factory ) {
switch ( construction_action )
{
case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION :
On_Speech ( PlayerPtr , VOX_CANCELED ) ; // Speak(VOX_CANCELED);
OutList . Add ( EventClass ( EventClass : : ABANDON , ( RTTIType ) buildable_type , buildable_id ) ) ;
break ;
case SIDEBAR_REQUEST_HOLD_CONSTRUCTION :
if ( factory - > Is_Building ( ) )
{
On_Speech ( PlayerPtr , VOX_SUSPENDED ) ; // Speak(VOX_SUSPENDED);
OutList . Add ( EventClass ( EventClass : : SUSPEND , ( RTTIType ) buildable_type , buildable_id ) ) ;
}
break ;
default :
/*
* * If this object is currently being built , then give a scold sound and text and then
* * bail .
*/
if ( factory - > Is_Building ( ) ) {
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; //Speak(VOX_NO_FACTORY); // "Cannot Comply"
return false ;
}
else {
/*
* * If production has completed , then attempt to have the object exit
* * the factory or go into placement mode .
*/
if ( factory - > Has_Completed ( ) ) {
TechnoClass * pending = factory - > Get_Object ( ) ;
if ( ! pending & & factory - > Get_Special_Item ( ) ) {
// TO_DO
//Map.IsTargettingMode = true;
}
else {
BuildingClass * builder = pending - > Who_Can_Build_Me ( false , false ) ;
if ( ! builder ) {
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; //Speak(VOX_NO_FACTORY); // "Cannot Comply"
OutList . Add ( EventClass ( EventClass : : ABANDON , ( RTTIType ) buildable_type , buildable_id ) ) ;
//Speak(VOX_NO_FACTORY);
}
else {
/*
* * If the completed object is a building , then change the
* * game state into building placement mode . This fact is
* * not transmitted to any linked computers until the moment
* * the building is actually placed down .
*/
if ( pending - > What_Am_I ( ) = = RTTI_BUILDING ) {
if ( construction_action = = SIDEBAR_REQUEST_START_PLACEMENT ) {
if ( DLLExportClass : : Legacy_Render_Enabled ( ) ) {
PlayerPtr - > Manual_Place ( builder , ( BuildingClass * ) pending ) ;
} else {
Unselect_All ( ) ;
}
}
}
else {
/*
* * For objects that can leave the factory under their own
* * power , queue this event and process through normal house
* * production channels .
*/
//OutList.Add(EventClass(EventClass::PLACE, otype, -1));
}
}
}
}
else {
/*
* * The factory must have been in a suspended state . Resume construction
* * normally .
*/
if ( construction_action = = SIDEBAR_REQUEST_START_CONSTRUCTION ) {
if ( ( RTTIType ) buildable_type = = RTTI_INFANTRYTYPE )
{
On_Speech ( PlayerPtr , VOX_TRAINING ) ; // Speak(VOX_TRAINING);
}
else
{
On_Speech ( PlayerPtr , VOX_BUILDING ) ; // Speak(VOX_BUILDING);
}
OutList . Add ( EventClass ( EventClass : : PRODUCE , ( RTTIType ) buildable_type , buildable_id ) ) ;
return true ;
}
}
}
break ;
}
} else {
switch ( construction_action )
{
case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION :
case SIDEBAR_REQUEST_HOLD_CONSTRUCTION :
break ;
default :
/*
* *
*/
if ( ( RTTIType ) buildable_type = = RTTI_INFANTRYTYPE )
{
On_Speech ( PlayerPtr , VOX_TRAINING ) ; // Speak(VOX_TRAINING);
}
else
{
On_Speech ( PlayerPtr , VOX_BUILDING ) ; // Speak(VOX_BUILDING);
}
OutList . Add ( EventClass ( EventClass : : PRODUCE , ( RTTIType ) buildable_type , buildable_id ) ) ;
/*
* * Execute immediately so we get the sidebar feedback
*/
DLLExportClass : : Glyphx_Queue_AI ( ) ;
return true ;
}
}
}
}
}
}
}
return false ;
}
/**************************************************************************************************
* DLLExportClass : : Start_Placement - - Start placing a completed structure
*
* In :
*
* Out :
*
*
*
* History : 1 / 29 / 2019 11 : 37 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Start_Placement ( uint64 player_id , int buildable_type , int buildable_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
BuildingClass * building = Get_Pending_Placement_Object ( player_id , buildable_type , buildable_id ) ;
if ( building ) {
TechnoTypeClass const * tech = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
if ( tech ) {
BuildingTypeClass * building_type = ( BuildingTypeClass * ) tech ;
//short const *occupy_list = building_type->Get_Occupy_List(true);
PlacementType [ CurrentLocalPlayerIndex ] = building_type ;
Recalculate_Placement_Distances ( ) ;
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
return Construction_Action ( SIDEBAR_REQUEST_START_PLACEMENT , player_id , buildable_type , buildable_id ) ;
}
return MP_Construction_Action ( SIDEBAR_REQUEST_START_PLACEMENT , player_id , buildable_type , buildable_id ) ;
}
}
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Cancel_Placement - - Cancel placing a completed structure
*
* In :
*
* Out :
*
*
*
* History : 2 / 7 / 2019 10 : 52 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Cancel_Placement ( uint64 player_id , int buildable_type , int buildable_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
PlacementType [ CurrentLocalPlayerIndex ] = NULL ;
Map . PendingObjectPtr = 0 ;
Map . PendingObject = 0 ;
Map . PendingHouse = HOUSE_NONE ;
Map . IsTargettingMode = SPC_NONE ;
Map . Set_Cursor_Shape ( 0 ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Place - - Place a completed structure down
*
* In :
*
* Out :
*
*
*
* History : 2 / 6 / 2019 11 : 51 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Place ( uint64 player_id , int buildable_type , int buildable_id , short cell_x , short cell_y )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
static const int _map_width_shift_bits = 7 ;
BuildingClass * building = Get_Pending_Placement_Object ( player_id , buildable_type , buildable_id ) ;
if ( building ) {
TechnoTypeClass const * tech = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
if ( tech ) {
BuildingTypeClass * building_type = ( BuildingTypeClass * ) tech ;
//short const *occupy_list = building_type->Get_Occupy_List(true);
PlacementType [ CurrentLocalPlayerIndex ] = building_type ;
/*
* * The cell coordinates passed in will be relative to the playable area that the client knows about
*/
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
CELL cell = ( CELL ) ( map_cell_x + cell_x ) + ( ( map_cell_y + cell_y ) < < _map_width_shift_bits ) ;
/*
* * Call the place directly instead of queueing it , so we can evaluate the return code .
*/
if ( PlayerPtr - > Place_Object ( building - > What_Am_I ( ) , cell + Map . ZoneOffset ) ) {
PlacementType [ CurrentLocalPlayerIndex ] = NULL ;
}
}
}
return true ;
}
BuildingClass * DLLExportClass : : Get_Pending_Placement_Object ( uint64 player_id , int buildable_type , int buildable_id )
{
/*
* *
* * Based on SidebarClass : : StripClass : : SelectClass : : Action
* *
* *
*/
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
for ( int c = 0 ; c < 2 ; c + + ) {
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < Map . Column [ c ] . BuildableCount ; b + + ) {
if ( Map . Column [ c ] . Buildables [ b ] . BuildableID = = buildable_id ) {
if ( Map . Column [ c ] . Buildables [ b ] . BuildableType = = buildable_type ) {
int genfactory = - 1 ;
switch ( buildable_type ) {
case RTTI_INFANTRYTYPE :
genfactory = PlayerPtr - > InfantryFactory ;
break ;
case RTTI_UNITTYPE :
genfactory = PlayerPtr - > UnitFactory ;
break ;
case RTTI_AIRCRAFTTYPE :
genfactory = PlayerPtr - > AircraftFactory ;
break ;
case RTTI_BUILDINGTYPE :
genfactory = PlayerPtr - > BuildingFactory ;
break ;
default :
genfactory = - 1 ;
break ;
}
int fnumber = Map . Column [ c ] . Buildables [ b ] . Factory ;
int spc = 0 ;
ObjectTypeClass const * choice = NULL ;
if ( buildable_type ! = RTTI_SPECIAL ) {
choice = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
} else {
spc = buildable_id ;
}
FactoryClass * factory = NULL ;
if ( fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
if ( spc = = 0 & & choice ) {
if ( fnumber = = - 1 & & genfactory ! = - 1 ) {
return ( NULL ) ;
}
if ( factory ) {
/*
* * If production has completed , then attempt to have the object exit
* * the factory or go into placement mode .
*/
if ( factory - > Has_Completed ( ) ) {
TechnoClass * pending = factory - > Get_Object ( ) ;
if ( ! pending & & factory - > Get_Special_Item ( ) ) {
//Map.IsTargettingMode = true;
} else {
BuildingClass * builder = pending - > Who_Can_Build_Me ( false , false ) ;
if ( ! builder ) {
OutList . Add ( EventClass ( EventClass : : ABANDON , buildable_type , buildable_id ) ) ;
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; // Speak(VOX_NO_FACTORY);
} else {
/*
* * If the completed object is a building , then change the
* * game state into building placement mode . This fact is
* * not transmitted to any linked computers until the moment
* * the building is actually placed down .
*/
if ( pending - > What_Am_I ( ) = = RTTI_BUILDING ) {
return ( BuildingClass * ) pending ;
//PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
}
}
}
}
}
}
}
}
}
}
} else {
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
SidebarGlyphxClass * context_sidebar = DLLExportClass : : Get_Current_Context_Sidebar ( ) ;
for ( int c = 0 ; c < 2 ; c + + ) {
/*
* * Each production slot in the column
*/
for ( int b = 0 ; b < context_sidebar - > Column [ c ] . BuildableCount ; b + + ) {
if ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableID = = buildable_id ) {
if ( context_sidebar - > Column [ c ] . Buildables [ b ] . BuildableType = = buildable_type ) {
int genfactory = - 1 ;
switch ( buildable_type ) {
case RTTI_INFANTRYTYPE :
genfactory = PlayerPtr - > InfantryFactory ;
break ;
case RTTI_UNITTYPE :
genfactory = PlayerPtr - > UnitFactory ;
break ;
case RTTI_AIRCRAFTTYPE :
genfactory = PlayerPtr - > AircraftFactory ;
break ;
case RTTI_BUILDINGTYPE :
genfactory = PlayerPtr - > BuildingFactory ;
break ;
default :
genfactory = - 1 ;
break ;
}
int fnumber = context_sidebar - > Column [ c ] . Buildables [ b ] . Factory ;
int spc = 0 ;
ObjectTypeClass const * choice = NULL ;
if ( buildable_type ! = RTTI_SPECIAL ) {
choice = Fetch_Techno_Type ( ( RTTIType ) buildable_type , buildable_id ) ;
} else {
spc = buildable_id ;
}
FactoryClass * factory = NULL ;
if ( fnumber ! = - 1 ) {
factory = Factories . Raw_Ptr ( fnumber ) ;
}
if ( spc = = 0 & & choice ) {
if ( fnumber = = - 1 & & genfactory ! = - 1 ) {
return ( NULL ) ;
}
if ( factory ) {
/*
* * If production has completed , then attempt to have the object exit
* * the factory or go into placement mode .
*/
if ( factory - > Has_Completed ( ) ) {
TechnoClass * pending = factory - > Get_Object ( ) ;
if ( ! pending & & factory - > Get_Special_Item ( ) ) {
//Map.IsTargettingMode = true;
} else {
BuildingClass * builder = pending - > Who_Can_Build_Me ( false , false ) ;
if ( ! builder ) {
OutList . Add ( EventClass ( EventClass : : ABANDON , buildable_type , buildable_id ) ) ;
On_Speech ( PlayerPtr , VOX_NO_FACTORY ) ; // Speak(VOX_NO_FACTORY);
} else {
/*
* * If the completed object is a building , then change the
* * game state into building placement mode . This fact is
* * not transmitted to any linked computers until the moment
* * the building is actually placed down .
*/
if ( pending - > What_Am_I ( ) = = RTTI_BUILDING ) {
return ( BuildingClass * ) pending ;
//PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
}
}
}
}
}
}
}
}
}
}
}
}
return NULL ;
}
/**************************************************************************************************
* DLLExportClass : : Place_Super_Weapon
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Place_Super_Weapon ( uint64 player_id , int buildable_type , int buildable_id , int x , int y )
{
if ( buildable_type ! = RTTI_SPECIAL )
{
return false ;
}
COORDINATE coord = Map . Pixel_To_Coord ( x , y ) ;
CELL cell = Coord_Cell ( coord ) ;
SpecialWeaponType weapon_type = ( SpecialWeaponType ) buildable_id ;
OutList . Add ( EventClass ( EventClass : : SPECIAL_PLACE , weapon_type , cell ) ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Create_Control_Group
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Create_Control_Group ( unsigned char control_group_index )
{
Handle_Team ( control_group_index , 2 ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Add_To_Control_Group
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Add_To_Control_Group ( unsigned char control_group_index )
{
Handle_Team ( control_group_index , 1 ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Toggle_Control_Group_Selection
*
* History :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Toggle_Control_Group_Selection ( unsigned char control_group_index )
{
Handle_Team ( control_group_index , 0 ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Get_Shroud_State - - Get a snapshot of the shroud for the given player
*
* In :
*
* Out :
*
*
*
* History : 4 / 12 / 2019 3 : 44 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Shroud_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
2020-09-16 10:03:04 -07:00
/*
* * Apply mobile gap generators
*/
static unsigned int _shroud_bits [ UNIT_MAX ] ;
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj - > Class - > IsGapper & & obj - > IsActive & & obj - > Strength ) {
if ( ! obj - > House - > Is_Ally ( PlayerPtr ) ) {
_shroud_bits [ index ] = obj - > Apply_Temporary_Jamming_Shroud ( PlayerPtr ) ;
}
}
}
}
2020-05-27 12:16:20 -07:00
CNCShroudStruct * shroud = ( CNCShroudStruct * ) buffer_in ;
unsigned int memory_needed = sizeof ( * shroud ) + 256 ; // Base amount needed. Will need more depending on how many entries there are
int entry_index = 0 ;
/*
* *
* * Based loosely on DisplayClass : : Redraw_Icons
* *
* *
*/
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_HEIGHT ) {
map_cell_height + + ;
}
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + ) {
CELL cell = XY_Cell ( map_cell_x + x , map_cell_y + y ) ;
COORDINATE coord = Cell_Coord ( cell ) & 0xFF00FF00L ;
memory_needed + = sizeof ( CNCShroudEntryStruct ) ;
if ( memory_needed > = buffer_size ) {
return false ;
}
int xpixel ;
int ypixel ;
Map . Coord_To_Pixel ( coord , xpixel , ypixel ) ;
CellClass * cellptr = & Map [ Coord_Cell ( coord ) ] ;
CNCShroudEntryStruct & shroud_entry = shroud - > Entries [ entry_index ] ;
shroud_entry . IsVisible = cellptr - > Is_Visible ( PlayerPtr ) ;
shroud_entry . IsMapped = cellptr - > Is_Mapped ( PlayerPtr ) ;
shroud_entry . IsJamming = cellptr - > Is_Jamming ( PlayerPtr ) ;
//shroud_entry.IsVisible = cellptr->IsVisible;
//shroud_entry.IsMapped = cellptr->IsMapped;
shroud_entry . ShadowIndex = - 1 ;
if ( shroud_entry . IsMapped ) {
if ( ! shroud_entry . IsVisible ) {
shroud_entry . ShadowIndex = ( char ) Map . Cell_Shadow ( cell , PlayerPtr ) ;
}
}
entry_index + + ;
}
}
shroud - > Count = entry_index ;
2020-09-16 10:03:04 -07:00
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
for ( int index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj - > Class - > IsGapper & & obj - > IsActive & & obj - > Strength ) {
if ( ! obj - > House - > Is_Ally ( PlayerPtr ) ) {
obj - > Unapply_Temporary_Jamming_Shroud ( PlayerPtr , _shroud_bits [ index ] ) ;
}
}
}
}
2020-05-27 12:16:20 -07:00
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Get_Occupier_State - - Get the occupier state for this player
*
* In :
*
* Out :
*
*
*
* History : 10 / 25 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Occupier_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
UNREFERENCED_PARAMETER ( player_id ) ;
CNCOccupierHeaderStruct * occupiers = ( CNCOccupierHeaderStruct * ) buffer_in ;
CNCOccupierEntryHeaderStruct * entry = reinterpret_cast < CNCOccupierEntryHeaderStruct * > ( occupiers + 1U ) ;
occupiers - > Count = 0 ;
unsigned int memory_needed = sizeof ( CNCOccupierHeaderStruct ) ;
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_HEIGHT ) {
map_cell_height + + ;
}
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + , occupiers - > Count + + ) {
CELL cell = XY_Cell ( map_cell_x + x , map_cell_y + y ) ;
CellClass * cellptr = & Map [ cell ] ;
int occupier_count = 0 ;
ObjectClass * optr = cellptr - > Cell_Occupier ( ) ;
while ( optr ! = NULL ) {
occupier_count + + ;
optr = optr - > Next ;
}
memory_needed + = sizeof ( CNCOccupierEntryHeaderStruct ) + ( sizeof ( CNCOccupierObjectStruct ) * occupier_count ) ;
if ( memory_needed > = buffer_size ) {
return false ;
}
CNCOccupierObjectStruct * occupier = reinterpret_cast < CNCOccupierObjectStruct * > ( entry + 1U ) ;
entry - > Count = 0 ;
optr = cellptr - > Cell_Occupier ( ) ;
for ( int i = 0 ; i < occupier_count ; i + + , occupier + + , entry - > Count + + ) {
CNCObjectStruct object ;
Convert_Type ( optr , object ) ;
occupier - > Type = object . Type ;
occupier - > ID = object . ID ;
optr = optr - > Next ;
}
entry = reinterpret_cast < CNCOccupierEntryHeaderStruct * > ( occupier + 1U ) ;
}
}
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Get_Player_Info_State - - Get the multiplayer info for this player
*
* In :
*
* Out :
*
*
*
* History : 4 / 22 / 2019 10 : 33 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Player_Info_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return false ;
}
CNCPlayerInfoStruct * player_info = ( CNCPlayerInfoStruct * ) buffer_in ;
unsigned int memory_needed = sizeof ( * player_info ) + 32 ; // A little extra for no reason
if ( memory_needed > = buffer_size ) {
return false ;
}
player_info - > GlyphxPlayerID = 0 ;
if ( PlayerPtr = = NULL ) {
return false ; ;
}
if ( Session . Players . Count ( ) > CurrentLocalPlayerIndex ) {
strncpy ( & player_info - > Name [ 0 ] , Session . Players [ CurrentLocalPlayerIndex ] - > Name , MPLAYER_NAME_MAX ) ;
}
player_info - > Name [ MPLAYER_NAME_MAX - 1 ] = 0 ; // Make sure it's terminated
player_info - > House = PlayerPtr - > Class - > House ;
player_info - > AllyFlags = PlayerPtr - > Get_Ally_Flags ( ) ;
if ( Session . Players . Count ( ) > CurrentLocalPlayerIndex ) {
player_info - > ColorIndex = Session . Players [ CurrentLocalPlayerIndex ] - > Player . Color ;
} else {
player_info - > ColorIndex = ( PlayerPtr - > Class - > House = = HOUSE_USSR ) ? 2 : 1 ; // Fudge to a sensible color in campaign; 2 = red, 1 = blue
}
player_info - > GlyphxPlayerID = player_id ;
player_info - > HomeCellX = Cell_X ( MultiplayerStartPositions [ CurrentLocalPlayerIndex ] ) ;
player_info - > HomeCellY = Cell_Y ( MultiplayerStartPositions [ CurrentLocalPlayerIndex ] ) ;
player_info - > IsDefeated = PlayerPtr - > IsDefeated ;
// Can see other players' power if ally (except for the player themself) or spying on a power plant
// Can see other players' money if spying on a resource building
player_info - > SpiedPowerFlags = 0U ;
player_info - > SpiedMoneyFlags = 0U ;
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
HouseClass * house = Houses . Ptr ( i ) ;
if ( ( house ! = nullptr ) & & house - > IsActive & & ( house ! = PlayerPtr ) & & house - > Is_Ally ( PlayerPtr ) ) {
player_info - > SpiedPowerFlags | = 1U < < house - > Class - > House ;
}
}
for ( int i = 0 ; i < Buildings . Count ( ) ; + + i ) {
BuildingClass * building = Buildings . Ptr ( i ) ;
if ( ( building ! = nullptr ) & & building - > IsActive & & ( building - > Spied_By ( ) & ( 1U < < PlayerPtr - > Class - > House ) ) ) {
if ( ( * building = = STRUCT_POWER ) | | ( * building = = STRUCT_ADVANCED_POWER ) ) {
player_info - > SpiedPowerFlags | = 1U < < building - > House - > Class - > House ;
} else if ( ( * building = = STRUCT_REFINERY ) | | ( * building = = STRUCT_STORAGE ) ) {
player_info - > SpiedMoneyFlags | = 1U < < building - > House - > Class - > House ;
}
}
}
// Populate spied data
for ( char house = 0 ; house < MAX_HOUSES ; + + house ) {
HouseClass * hptr = HouseClass : : As_Pointer ( ( HousesType ) house ) ;
if ( ( hptr ! = nullptr ) & & hptr - > IsActive ) {
if ( player_info - > SpiedPowerFlags & ( 1U < < house ) ) {
player_info - > SpiedInfo [ house ] . Power = hptr - > Power ;
player_info - > SpiedInfo [ house ] . Drain = hptr - > Drain ;
}
if ( player_info - > SpiedMoneyFlags & ( 1U < < house ) ) {
player_info - > SpiedInfo [ house ] . Money = hptr - > Available_Money ( ) ;
}
}
}
// Populate selection info
if ( CurrentObject . Count ( ) > 0 ) {
CNCObjectStruct object ;
Convert_Type ( CurrentObject [ 0 ] , object ) ;
player_info - > SelectedID = object . ID ;
player_info - > SelectedType = object . Type ;
const int left = Map . MapCellX ;
const int right = Map . MapCellX + Map . MapCellWidth - 1 ;
const int top = Map . MapCellY ;
const int bottom = Map . MapCellY + Map . MapCellHeight - 1 ;
// Use first object with a weapon, or first object if none
ObjectClass * action_object = nullptr ;
for ( int i = 0 ; i < CurrentObject . Count ( ) ; + + i ) {
ObjectClass * object = CurrentObject [ i ] ;
if ( object - > Is_Techno ( ) ) {
TechnoClass * techno = ( TechnoClass * ) object ;
if ( techno - > Techno_Type_Class ( ) - > PrimaryWeapon ! = NULL | | techno - > Techno_Type_Class ( ) - > SecondaryWeapon ! = NULL ) {
action_object = object ;
break ;
}
}
}
if ( action_object = = nullptr ) {
action_object = CurrentObject [ 0 ] ;
}
int index = 0 ;
for ( int y = top ; y < = bottom ; + + y ) {
for ( int x = left ; x < = right ; + + x , + + index ) {
Convert_Action_Type ( action_object - > What_Action ( XY_Cell ( x , y ) ) , ( CurrentObject . Count ( ) = = 1 ) ? action_object : NULL , As_Target ( XY_Cell ( x , y ) ) , player_info - > ActionWithSelected [ index ] ) ;
}
}
player_info - > ActionWithSelectedCount = Map . MapCellWidth * Map . MapCellHeight ;
}
else {
player_info - > SelectedID = - 1 ;
player_info - > SelectedType = UNKNOWN ;
player_info - > ActionWithSelectedCount = 0U ;
}
// Screen shake
player_info - > ScreenShake = PlayerPtr - > ScreenShakeTime ;
// Radar jammed
player_info - > IsRadarJammed = Map . Get_Jammed ( PlayerPtr ) ;
return true ;
} ;
/**************************************************************************************************
* DLLExportClass : : Get_Dynamic_Map_State - - Get a snapshot of the smudges and overlays on the terrain
*
* In :
*
* Out :
*
*
*
* History : 2 / 8 / 2019 10 : 45 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Dynamic_Map_State ( uint64 player_id , unsigned char * buffer_in , unsigned int buffer_size )
{
/*
* * Get the player for this . . .
*/
player_id ;
static int _call_count = 0 ;
CNCDynamicMapStruct * dynamic_map = ( CNCDynamicMapStruct * ) buffer_in ;
unsigned int memory_needed = sizeof ( * dynamic_map ) + 256 ; // Base amount needed. Will need more depending on how many entries there are
int entry_index = 0 ;
/*
* *
* * Based loosely on DisplayClass : : Redraw_Icons
* *
* *
*/
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_width = Map . MapCellWidth ;
int map_cell_height = Map . MapCellHeight ;
if ( map_cell_x > 0 ) {
map_cell_x - - ;
map_cell_width + + ;
}
if ( map_cell_width < MAP_MAX_CELL_WIDTH ) {
map_cell_width + + ;
}
if ( map_cell_y > 0 ) {
map_cell_y - - ;
map_cell_height + + ;
}
if ( map_cell_height < MAP_MAX_CELL_WIDTH ) {
map_cell_height + + ;
}
int cell_index = 0 ;
bool debug_output = false ;
//if (_call_count == 20) {
//debug_output = true;
//}
// Need to ignore view constraints for dynamic map updates, so the radar map
// has the latest tiberium state for cells outside the tactical view
DLLExportClass : : Adjust_Internal_View ( true ) ;
for ( int y = 0 ; y < map_cell_height ; y + + ) {
for ( int x = 0 ; x < map_cell_width ; x + + ) {
CELL cell = XY_Cell ( map_cell_x + x , map_cell_y + y ) ;
COORDINATE coord = Cell_Coord ( cell ) & 0xFF00FF00L ;
memory_needed + = sizeof ( CNCDynamicMapEntryStruct ) * 2 ;
if ( memory_needed > = buffer_size ) {
return false ;
}
/*
* * Only cells flagged to be redraw are examined .
*/
//if (In_View(cell) && Is_Cell_Flagged(cell)) {
int xpixel ;
int ypixel ;
if ( Map . Coord_To_Pixel ( coord , xpixel , ypixel ) ) {
CellClass * cellptr = & Map [ Coord_Cell ( coord ) ] ;
/*
* * If there is a portion of the underlying icon that could be visible ,
* * then draw it . Also draw the cell if the shroud is off .
*/
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER | | cellptr - > IsMapped | | Debug_Unshroud ) {
Cell_Class_Draw_It ( dynamic_map , entry_index , cellptr , xpixel , ypixel , debug_output ) ;
}
/*
* * If any cell is not fully mapped , then flag it so that the shadow drawing
* * process will occur . Only draw the shadow if Debug_Unshroud is false .
*/
//if (!cellptr->IsMapped && !Debug_Unshroud) {
// IsShadowPresent = true;
//}
}
//}
}
}
if ( entry_index ) {
_call_count + + ;
}
dynamic_map - > Count = entry_index ;
dynamic_map - > VortexActive = ChronalVortex . Is_Active ( ) ;
dynamic_map - > VortexX = Coord_X ( ChronalVortex . Get_Position ( ) ) ;
dynamic_map - > VortexY = Coord_Y ( ChronalVortex . Get_Position ( ) ) ;
dynamic_map - > VortexWidth = Pixel_To_Lepton ( 64 ) ;
dynamic_map - > VortexHeight = Pixel_To_Lepton ( 64 ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Cell_Class_Draw_It - - Go through the motions of drawing a cell to get the smudge and overlay info
*
* In :
*
* Out :
*
*
*
* History : 2 / 8 / 2019 11 : 09 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Cell_Class_Draw_It ( CNCDynamicMapStruct * dynamic_map , int & entry_index , CellClass * cell_ptr , int xpixel , int ypixel , bool debug_output )
{
/*
* *
* * Based on CellClass : : Draw_It and SmudgeTypeClass : : Draw_It
* *
* *
*/
CELL cell = cell_ptr - > Cell_Number ( ) ;
/*
* * Redraw any smudge .
*/
if ( cell_ptr - > Smudge ! = SMUDGE_NONE ) {
//SmudgeTypeClass::As_Reference(Smudge).Draw_It(x, y, SmudgeData);
const SmudgeTypeClass & smudge_type = SmudgeTypeClass : : As_Reference ( cell_ptr - > Smudge ) ;
if ( smudge_type . Get_Image_Data ( ) ! = NULL ) {
if ( debug_output ) {
IsTheaterShape = true ;
Debug_Write_Shape_Type ( & smudge_type , 0 ) ;
IsTheaterShape = false ;
}
CNCDynamicMapEntryStruct & smudge_entry = dynamic_map - > Entries [ entry_index + + ] ;
strncpy ( smudge_entry . AssetName , smudge_type . IniName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
smudge_entry . Type = ( short ) cell_ptr - > Smudge ;
smudge_entry . Owner = ( char ) cell_ptr - > Owner ;
smudge_entry . DrawFlags = SHAPE_WIN_REL ; // Looks like smudges are drawn top left
smudge_entry . PositionX = xpixel ;
smudge_entry . PositionY = ypixel ;
smudge_entry . Width = Get_Build_Frame_Width ( smudge_type . Get_Image_Data ( ) ) ;
smudge_entry . Height = Get_Build_Frame_Height ( smudge_type . Get_Image_Data ( ) ) ;
smudge_entry . CellX = Cell_X ( cell ) ;
smudge_entry . CellY = Cell_Y ( cell ) ;
smudge_entry . ShapeIndex = cell_ptr - > SmudgeData ;
smudge_entry . IsSmudge = true ;
smudge_entry . IsOverlay = false ;
smudge_entry . IsResource = false ;
smudge_entry . IsSellable = false ;
smudge_entry . IsTheaterShape = true ; // Smudges are always theater-specific
smudge_entry . IsFlag = false ;
}
}
/*
* * Draw the overlay object .
*/
if ( cell_ptr - > Overlay ! = OVERLAY_NONE ) {
//OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(Overlay);
//IsTheaterShape = (bool)otype.IsTheater;
//CC_Draw_Shape(otype.Get_Image_Data(), OverlayData, (x+(CELL_PIXEL_W>>1)), (y+(CELL_PIXEL_H>>1)), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST, NULL, Map.UnitShadow);
//IsTheaterShape = false;
const OverlayTypeClass & overlay_type = OverlayTypeClass : : As_Reference ( cell_ptr - > Overlay ) ;
if ( overlay_type . Get_Image_Data ( ) ! = NULL ) {
CNCDynamicMapEntryStruct & overlay_entry = dynamic_map - > Entries [ entry_index + + ] ;
if ( debug_output ) {
IsTheaterShape = ( bool ) overlay_type . IsTheater ;
Debug_Write_Shape_Type ( & overlay_type , 0 ) ;
IsTheaterShape = false ;
}
strncpy ( overlay_entry . AssetName , overlay_type . IniName , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
overlay_entry . Type = ( short ) cell_ptr - > Overlay ;
overlay_entry . Owner = ( char ) cell_ptr - > Owner ;
overlay_entry . DrawFlags = SHAPE_CENTER | SHAPE_WIN_REL | SHAPE_GHOST ; // Looks like overlays are drawn centered and translucent
overlay_entry . PositionX = xpixel + ( CELL_PIXEL_W > > 1 ) ;
overlay_entry . PositionY = ypixel + ( CELL_PIXEL_H > > 1 ) ;
overlay_entry . Width = Get_Build_Frame_Width ( overlay_type . Get_Image_Data ( ) ) ;
overlay_entry . Height = Get_Build_Frame_Height ( overlay_type . Get_Image_Data ( ) ) ;
overlay_entry . CellX = Cell_X ( cell ) ;
overlay_entry . CellY = Cell_Y ( cell ) ;
overlay_entry . ShapeIndex = cell_ptr - > OverlayData ;
overlay_entry . IsSmudge = false ;
overlay_entry . IsOverlay = true ;
overlay_entry . IsResource = overlay_entry . Type > = OVERLAY_GOLD1 & & overlay_entry . Type < = OVERLAY_GEMS4 ;
overlay_entry . IsSellable = ( overlay_entry . Type > = OVERLAY_SANDBAG_WALL & & overlay_entry . Type < = OVERLAY_WOOD_WALL ) | | overlay_entry . Type = = OVERLAY_FENCE ;
overlay_entry . IsTheaterShape = ( bool ) overlay_type . IsTheater ;
overlay_entry . IsFlag = false ;
}
}
if ( cell_ptr - > IsFlagged ) {
const void * image_data = MFCD : : Retrieve ( " FLAGFLY.SHP " ) ;
if ( image_data ! = NULL ) {
CNCDynamicMapEntryStruct & flag_entry = dynamic_map - > Entries [ entry_index + + ] ;
strncpy ( flag_entry . AssetName , " FLAGFLY " , CNC_OBJECT_ASSET_NAME_LENGTH ) ;
flag_entry . AssetName [ CNC_OBJECT_ASSET_NAME_LENGTH - 1 ] = 0 ;
flag_entry . Type = - 1 ;
flag_entry . Owner = cell_ptr - > Owner ;
flag_entry . DrawFlags = SHAPE_CENTER | SHAPE_GHOST | SHAPE_FADING ;
flag_entry . PositionX = xpixel + ( ICON_PIXEL_W / 2 ) ;
flag_entry . PositionY = ypixel + ( ICON_PIXEL_H / 2 ) ;
flag_entry . Width = Get_Build_Frame_Width ( image_data ) ;
flag_entry . Height = Get_Build_Frame_Height ( image_data ) ;
flag_entry . CellX = Cell_X ( cell ) ;
flag_entry . CellY = Cell_Y ( cell ) ;
flag_entry . ShapeIndex = Frame % 14 ;
flag_entry . IsSmudge = false ;
flag_entry . IsOverlay = false ;
flag_entry . IsResource = false ;
flag_entry . IsSellable = false ;
flag_entry . IsTheaterShape = false ;
flag_entry . IsFlag = true ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : Glyphx_Queue_AI - - Special queue processing for Glyphx multiplayer mode
*
* In :
*
* Out :
*
*
*
* History : 3 / 12 / 2019 10 : 52 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Glyphx_Queue_AI ( void )
{
//------------------------------------------------------------------------
// Move events from the OutList (events generated by this player) into the
// DoList (the list of events to execute).
//------------------------------------------------------------------------
while ( OutList . Count ) {
OutList . First ( ) . IsExecuted = false ;
if ( ! DoList . Add ( OutList . First ( ) ) ) {
;
}
OutList . Next ( ) ;
}
/*
* * Based on Execute_DoList in queue . cpp
* *
* * The events have the ID of the player encoded in them , so no special per - player processing should be needed .
* * When the event is created , the ' local player ' is assumed to be the originator of the event , so PlayerPtr will need
* * to be swapped out to represent the real originating player prior to any events being created as a result of GlyphX input
* *
* * ST - 3 / 12 / 2019 10 : 51 AM
*/
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
HousesType house ;
HouseClass * housep ;
house = Session . Players [ i ] - > Player . ID ;
housep = HouseClass : : As_Pointer ( house ) ;
//.....................................................................
// If for some reason this house doesn't exist, skip it.
// Also, if this house has exited the game, skip it. (The user can
// generate events after he exits, because the exit event is scheduled
// at least FrameSendRate*3 frames ahead. If one system gets these
// packets & another system doesn't, they'll go out of sync because
// they aren't checking the CommandCount for that house, since that
// house isn't connected any more.)
//.....................................................................
if ( ! housep ) {
continue ;
}
if ( ! housep - > IsHuman ) {
continue ;
}
//.....................................................................
// Loop through all events
//.....................................................................
for ( int j = 0 ; j < DoList . Count ; j + + ) {
if ( ! DoList [ j ] . IsExecuted & & ( unsigned ) Frame > = DoList [ j ] . Frame ) {
DoList [ j ] . Execute ( ) ;
//...............................................................
// Mark this event as executed.
//...............................................................
DoList [ j ] . IsExecuted = 1 ;
}
}
}
//------------------------------------------------------------------------
// Clean out the DoList
//------------------------------------------------------------------------
while ( DoList . Count ) {
//.....................................................................
// Discard events that have been executed, OR it's too late to execute.
// (This happens if another player exits the game; he'll leave FRAMEINFO
// events lying around in my queue. They won't have been "executed",
// because his IPX connection was destroyed.)
//.....................................................................
if ( ( DoList . First ( ) . IsExecuted ) | | ( ( unsigned ) Frame > DoList . First ( ) . Frame ) ) {
DoList . Next ( ) ;
}
else {
break ;
}
}
}
CarryoverClass Test_CC ( CarryoverObjectStruct * cptr )
{
CarryoverClass cc ;
cc . RTTI = ( RTTIType ) cptr - > RTTI ;
cc . Type . Building = ( StructType ) cptr - > Type ; //This works regardless of what the RTTI-type and the enum type, because they're all enums. - LLL
cc . Cell = ( CELL ) cptr - > Cell ;
cc . House = ( HousesType ) cptr - > House ;
cc . Strength = cptr - > Strength ;
return cc ;
}
/**************************************************************************************************
* DLLExportClass : : Reset_Sidebars - - Init the multiplayer sidebars
*
*
*
* History : 11 / 8 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Store_Carryover_Objects ( )
{
if ( EventCallback = = NULL | | Scen . IsToCarryOver = = false ) {
return ;
}
CarryoverObjectStruct * carryover_list = 0 ;
CarryoverObjectStruct * carryover_list_tail = 0 ;
/*
* * Record all objects , that are to be part of the carry over set , into the carry over list .
*/
for ( int building_index = 0 ; building_index < Buildings . Count ( ) ; building_index + + ) {
BuildingClass * building = Buildings . Ptr ( building_index ) ;
if ( building & & ! building - > IsInLimbo & & building - > Strength > 0 ) {
CarryoverClass carryover = CarryoverClass ( building ) ;
CarryoverObjectStruct * cptr = new CarryoverObjectStruct ( ) ;
if ( cptr ) {
cptr - > RTTI = carryover . RTTI ;
cptr - > Type = ( int ) carryover . Type . Building ;
cptr - > House = carryover . House ;
cptr - > Cell = carryover . Cell ;
cptr - > Strength = carryover . Strength ;
CarryoverClass cc = Test_CC ( cptr ) ;
cc ;
if ( ! carryover_list_tail ) {
carryover_list = cptr ;
carryover_list_tail = cptr ;
}
else {
carryover_list_tail - > Next = cptr ;
carryover_list_tail = cptr ;
}
}
}
}
for ( int unit_index = 0 ; unit_index < Units . Count ( ) ; unit_index + + ) {
UnitClass * unit = Units . Ptr ( unit_index ) ;
if ( unit & & ! unit - > IsInLimbo & & unit - > Strength > 0 ) {
CarryoverClass carryover = CarryoverClass ( unit ) ;
CarryoverObjectStruct * cptr = new CarryoverObjectStruct ( ) ;
if ( cptr ) {
cptr - > RTTI = carryover . RTTI ;
cptr - > Type = ( int ) carryover . Type . Unit ;
cptr - > House = carryover . House ;
cptr - > Cell = carryover . Cell ;
cptr - > Strength = carryover . Strength ;
CarryoverClass cc = Test_CC ( cptr ) ;
cc ;
if ( ! carryover_list_tail ) {
carryover_list = cptr ;
carryover_list_tail = cptr ;
}
else {
carryover_list_tail - > Next = cptr ;
carryover_list_tail = cptr ;
}
}
}
}
for ( int infantry_index = 0 ; infantry_index < Infantry . Count ( ) ; infantry_index + + ) {
InfantryClass * infantry = Infantry . Ptr ( infantry_index ) ;
if ( infantry & & ! infantry - > IsInLimbo & & infantry - > Strength > 0 ) {
CarryoverClass carryover = CarryoverClass ( infantry ) ;
CarryoverObjectStruct * cptr = new CarryoverObjectStruct ( ) ;
if ( cptr ) {
cptr - > RTTI = carryover . RTTI ;
cptr - > Type = ( int ) carryover . Type . Building ;
cptr - > House = carryover . House ;
cptr - > Cell = carryover . Cell ;
cptr - > Strength = carryover . Strength ;
CarryoverClass cc = Test_CC ( cptr ) ;
cc ;
if ( ! carryover_list_tail ) {
carryover_list = cptr ;
carryover_list_tail = cptr ;
}
else {
carryover_list_tail - > Next = cptr ;
carryover_list_tail = cptr ;
}
}
}
}
for ( int vessel_index = 0 ; vessel_index < Vessels . Count ( ) ; vessel_index + + ) {
VesselClass * vessel = Vessels . Ptr ( vessel_index ) ;
if ( vessel & & ! vessel - > IsInLimbo & & vessel - > Strength > 0 ) {
CarryoverClass carryover = CarryoverClass ( vessel ) ;
CarryoverObjectStruct * cptr = new CarryoverObjectStruct ( ) ;
if ( cptr ) {
cptr - > RTTI = carryover . RTTI ;
cptr - > Type = ( int ) carryover . Type . Building ;
cptr - > House = carryover . House ;
cptr - > Cell = carryover . Cell ;
cptr - > Strength = carryover . Strength ;
CarryoverClass cc = Test_CC ( cptr ) ;
cc ;
if ( ! carryover_list_tail ) {
carryover_list = cptr ;
carryover_list_tail = cptr ;
}
else {
carryover_list_tail - > Next = cptr ;
carryover_list_tail = cptr ;
}
}
}
}
//Make & Send Event
EventCallbackStruct event ;
event . EventType = CALLBACK_EVENT_STORE_CARRYOVER_OBJECTS ;
event . CarryoverObjects . CarryoverList = carryover_list ;
EventCallback ( event ) ;
//Delete the list
while ( carryover_list ) {
CarryoverObjectStruct * cptr = ( CarryoverObjectStruct * ) carryover_list - > Next ;
delete carryover_list ;
carryover_list = cptr ;
}
}
/**************************************************************************************************
* DLLExportClass : : Reset_Sidebars - - Init the multiplayer sidebars
*
* In :
*
* Out :
*
*
*
* History : 3 / 14 / 2019 3 : 10 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Reset_Sidebars ( void )
{
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
if ( i > = Session . Players . Count ( ) ) {
continue ;
}
if ( Session . Players [ i ] = = NULL ) {
continue ;
}
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
MultiplayerSidebars [ i ] . Init_Clear ( player_ptr ) ;
}
}
/**************************************************************************************************
* DLLExportClass : : Set_Player_Context - - Switch the C & C local player context
*
* In :
*
* Out :
*
*
*
* History : 3 / 14 / 2019 3 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Set_Player_Context ( uint64 glyphx_player_id , bool force )
{
/*
* * Context never needs to change in single player
*/
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
if ( PlayerPtr ) {
CurrentObject . Set_Active_Context ( PlayerPtr - > Class - > House ) ;
}
return true ;
}
/*
* * C & C relies a lot on PlayerPtr , which is a pointer to the ' local ' player ' s house . Historically , in a peer - to - peer
* * multiplayer game , each player ' s PlayerPtr pointed to their own local player .
* *
* * Since much of the IO logic depends on PlayerPtr being the player performing the action , we need to set PlayerPtr
* * correctly depending on which player generated input or needs output
*/
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
if ( GlyphxPlayerIDs [ i ] = = glyphx_player_id ) {
if ( ! force & & i = = CurrentLocalPlayerIndex ) {
return true ;
}
PlayerPtr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
CurrentObject . Set_Active_Context ( PlayerPtr - > Class - > House ) ;
CurrentLocalPlayerIndex = i ;
Refresh_Player_Control_Flags ( ) ;
return true ;
}
}
return false ;
}
/**************************************************************************************************
* DLLExportClass : : Reset_Player_Context - - Clear out old player context data
*
* In :
*
* Out :
*
*
*
* History : 4 / 16 / 2019 10 : 36 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Reset_Player_Context ( void )
{
CurrentLocalPlayerIndex = 0 ;
CurrentObject . Clear_All ( ) ;
}
/**************************************************************************************************
* DLLExportClass : : Refresh_Player_Control_Flags - - Set the IsPlayerControl flags so that the player
* in context has IsPlayerControl
*
* In :
*
* Out :
*
*
*
* History : 4 / 16 / 2019 10 : 36 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Refresh_Player_Control_Flags ( void )
{
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
if ( player_ptr ) {
if ( i = = CurrentLocalPlayerIndex & & player_ptr - > IsHuman ) {
player_ptr - > IsPlayerControl = true ;
} else {
player_ptr - > IsPlayerControl = false ;
}
}
}
}
/**************************************************************************************************
* Logic_Switch_Player_Context - - Called when the internal game locic needs to switch player context
*
* In :
*
* Out :
*
*
*
* History : 4 / 17 / 2019 9 : 45 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Logic_Switch_Player_Context ( ObjectClass * object )
{
DLLExportClass : : Logic_Switch_Player_Context ( object ) ;
}
/**************************************************************************************************
* DLLExportClass : : Logic_Switch_Player_Context - - Called when the internal game locic needs to switch player context
*
* In :
*
* Out :
*
*
*
* History : 4 / 17 / 2019 9 : 45 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Logic_Switch_Player_Context ( ObjectClass * object )
{
if ( object = = NULL ) {
return ;
}
/*
* * If it ' s not a techno , it can ' t be owned .
*/
if ( ! object - > Is_Techno ( ) ) {
return ;
}
TechnoClass * tech = static_cast < TechnoClass * > ( object ) ;
//HousesType house = tech->House->Class->House;
DLLExportClass : : Logic_Switch_Player_Context ( tech - > House ) ;
}
/**************************************************************************************************
* Logic_Switch_Player_Context - - Called when the internal game locic needs to switch player context
*
* In :
*
* Out :
*
*
*
* History : 4 / 17 / 2019 9 : 45 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Logic_Switch_Player_Context ( HouseClass * object )
{
DLLExportClass : : Logic_Switch_Player_Context ( object ) ;
}
/**************************************************************************************************
* DLLExportClass : : Logic_Switch_Player_Context - - Called when the internal game locic needs to switch player context
*
* In :
*
* Out :
*
*
*
* History : 4 / 17 / 2019 9 : 45 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Logic_Switch_Player_Context ( HouseClass * house )
{
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
CurrentObject . Set_Active_Context ( PlayerPtr - > Class - > House ) ;
return ;
}
if ( house = = NULL ) {
return ;
}
/*
* * C & C relies a lot on PlayerPtr , which is a pointer to the ' local ' player ' s house . Historically , in a peer - to - peer
* * multiplayer game , each player ' s PlayerPtr pointed to their own local player .
* *
* * Since much of the IO logic depends on PlayerPtr being the player performing the action , we need to set PlayerPtr
* * correctly depending on which player generated input or needs output
*/
HousesType house_type = house - > Class - > House ;
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
if ( house_type = = Session . Players [ i ] - > Player . ID ) {
if ( i = = CurrentLocalPlayerIndex ) {
return ;
}
PlayerPtr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
CurrentObject . Set_Active_Context ( PlayerPtr - > Class - > House ) ;
CurrentLocalPlayerIndex = i ;
Refresh_Player_Control_Flags ( ) ;
return ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : Calculate_Start_Positions - - Calculate the initial view positions for the players
*
* In :
*
* Out :
*
*
*
* History : 4 / 16 / 2019 6 / 12 / 2019 3 : 00 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Calculate_Start_Positions ( void )
{
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
MultiplayerStartPositions [ 0 ] = Scen . Views [ 0 ] ;
return ;
}
HouseClass * player_ptr = PlayerPtr ;
ScenarioInit + + ;
COORDINATE old_tac = Map . TacticalCoord ;
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
PlayerPtr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
if ( PlayerPtr ) {
long x , y ;
Map . Compute_Start_Pos ( x , y ) ;
MultiplayerStartPositions [ i ] = XY_Cell ( x , y ) ;
}
}
Map . TacticalCoord = old_tac ;
ScenarioInit - - ;
PlayerPtr = player_ptr ;
}
/**************************************************************************************************
* DLLExportClass : : Get_GlyphX_Player_ID - - Get the external GlyphX player ID from the C & C house / player pointer
* Returns 0 in single player or if player ID isn ' t found
*
* In :
*
* Out :
*
*
*
* History : 4 / 22 / 2019 6 : 23 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
__int64 DLLExportClass : : Get_GlyphX_Player_ID ( const HouseClass * house )
{
/*
* * C & C relies a lot on PlayerPtr , which is a pointer to the ' local ' player ' s house . Historically , in a peer - to - peer
* * multiplayer game , each player ' s PlayerPtr pointed to their own local player .
* *
* * Since much of the IO logic depends on PlayerPtr being the player performing the action , we need to set PlayerPtr
* * correctly depending on which player generated input or needs output
*/
if ( GAME_TO_PLAY = = GAME_NORMAL ) {
return 0 ;
}
if ( house = = NULL ) {
return 0 ;
}
HousesType house_type = house - > Class - > House ;
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
if ( house_type = = Session . Players [ i ] - > Player . ID ) {
return GlyphxPlayerIDs [ i ] ;
}
}
/*
* * Failure case .
*/
return 0 ;
}
/**************************************************************************************************
* DLLExportClass : : Adjust_Internal_View - - Set the internal tactical view to encompass the input coordinates
*
* In :
*
* Out :
*
*
*
* History : 4 / 16 / 2019 3 : 00 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Adjust_Internal_View ( bool force_ignore_view_constraints )
{
/*
* * When legacy rendering is disabled ( especially in multiplayer ) we can get input coordinates that
* * fall outside the engine ' s tactical view . In this case , we need to adjust the tactical view before the
* * input will behave as expected .
*/
if ( ! force_ignore_view_constraints & & Legacy_Render_Enabled ( ) ) {
/*
* * Render view should already be tracking the player ' s local view
*/
DisplayClass : : IgnoreViewConstraints = false ;
return ;
}
DisplayClass : : IgnoreViewConstraints = true ;
}
/**************************************************************************************************
* DLLExportClass : : Get_Current_Context_Sidebar - - Get the sidebar data for the current player context
*
* In :
*
* Out :
*
*
*
* History : 3 / 14 / 2019 3 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
SidebarGlyphxClass * DLLExportClass : : Get_Current_Context_Sidebar ( HouseClass * player_ptr )
{
if ( player_ptr ) {
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; i + + ) {
if ( player_ptr = = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ) {
return & MultiplayerSidebars [ i ] ;
}
}
}
return & MultiplayerSidebars [ CurrentLocalPlayerIndex ] ;
}
SidebarGlyphxClass * Get_Current_Context_Sidebar ( HouseClass * player_ptr )
{
return DLLExportClass : : Get_Current_Context_Sidebar ( player_ptr ) ;
}
/**************************************************************************************************
* DLLExportClass : : Repair_Mode - - Starts the player ' s repair mode . All it does here is unselect all units .
*
* In :
*
* Out :
*
*
*
* History : 5 / 1 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Repair_Mode ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
Unselect_All ( ) ;
}
/**************************************************************************************************
* DLLExportClass : : Repair - - Repairs a specific building
*
* In :
*
* Out :
*
*
*
* History : 5 / 1 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Repair ( uint64 player_id , int object_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
TARGET target = Build_Target ( RTTI_BUILDING , object_id ) ;
if ( target ! = TARGET_NONE )
{
BuildingClass * building = As_Building ( target ) ;
if ( building ) {
if ( ! building - > IsActive ) {
GlyphX_Debug_Print ( " DLLExportClass::Repair -- trying to repair a non-active building " ) ;
} else {
if ( building - > Can_Repair ( ) & & building - > House . Is_Valid ( ) & & building - > House - > Class - > House = = PlayerPtr - > Class - > House )
{
building - > Repair ( - 1 ) ;
}
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Sell_Mode - - Starts the player ' s sell mode . All it does here is unselect all units .
*
* In :
*
* Out :
*
*
*
* History : 5 / 1 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Sell_Mode ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
Unselect_All ( ) ;
}
/**************************************************************************************************
* DLLExportClass : : Sell - - Sell ' s a player ' s speceific building .
*
* In :
*
* Out :
*
*
*
* History : 5 / 1 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Sell ( uint64 player_id , int object_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
TARGET target = Build_Target ( RTTI_BUILDING , object_id ) ;
if ( target ! = TARGET_NONE )
{
BuildingClass * building = As_Building ( target ) ;
if ( building ) {
if ( ! building - > IsActive ) {
GlyphX_Debug_Print ( " DLLExportClass::Sell -- trying to sell a non-active building " ) ;
} else {
if ( building - > Can_Demolish ( ) & & building - > House . Is_Valid ( ) & & building - > House - > Class - > House = = PlayerPtr - > Class - > House )
{
building - > Sell_Back ( 1 ) ;
}
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Repair_Sell_Cancel - - Ends the player ' s repair or sell mode . Doesn ' t do anything right now .
*
* In :
*
* Out :
*
*
*
* History : 5 / 1 / 2019 - LLL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Repair_Sell_Cancel ( uint64 player_id )
{
//OutputDebugString("Repair_Sell_Cancel\n");
}
/**************************************************************************************************
* DLLExportClass : : Scatter_Selected - - Scatter the selected units
*
* In :
*
* Out :
*
*
*
* History : 10 / 15 / 2019 - SKY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Scatter_Selected ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
if ( CurrentObject . Count ( ) ) {
for ( int index = 0 ; index < CurrentObject . Count ( ) ; index + + ) {
ObjectClass const * tech = CurrentObject [ index ] ;
if ( tech ! = NULL & & tech - > Can_Player_Move ( ) ) {
OutList . Add ( EventClass ( EventClass : : SCATTER , TargetClass ( tech ) ) ) ;
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Select_Next_Unit
*
* History : 03.02 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Select_Next_Unit ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
ObjectClass * obj = Map . Next_Object ( CurrentObject . Count ( ) ? CurrentObject [ 0 ] : NULL ) ;
if ( obj ) {
Unselect_All ( ) ;
obj - > Select ( ) ;
COORDINATE center = Map . Center_Map ( ) ;
Map . Flag_To_Redraw ( true ) ;
if ( center ) {
On_Center_Camera ( PlayerPtr , Coord_X ( center ) , Coord_Y ( center ) ) ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : Select_Previous_Unit
*
* History : 03.02 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Select_Previous_Unit ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
ObjectClass * obj = Map . Prev_Object ( CurrentObject . Count ( ) ? CurrentObject [ 0 ] : NULL ) ;
if ( obj ) {
Unselect_All ( ) ;
obj - > Select ( ) ;
COORDINATE center = Map . Center_Map ( ) ;
Map . Flag_To_Redraw ( true ) ;
if ( center ) {
On_Center_Camera ( PlayerPtr , Coord_X ( center ) , Coord_Y ( center ) ) ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : Selected_Guard_Mode
*
* History : 03.03 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Selected_Guard_Mode ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
if ( CurrentObject . Count ( ) ) {
for ( int index = 0 ; index < CurrentObject . Count ( ) ; index + + ) {
ObjectClass const * tech = CurrentObject [ index ] ;
2020-06-22 09:43:21 -07:00
if ( tech ! = NULL & & tech - > Can_Player_Fire ( ) ) {
if ( tech - > Can_Player_Move ( ) ) {
OutList . Add ( EventClass ( TargetClass ( tech ) , MISSION_GUARD_AREA ) ) ;
} else {
OutList . Add ( EventClass ( TargetClass ( tech ) , MISSION_GUARD ) ) ;
}
2020-05-27 12:16:20 -07:00
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Selected_Stop
*
* History : 03.03 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Selected_Stop ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
// Copied from RedAlert/Conquer.cpp - Keyboard_Process() with Options.KeyStop (VK_S)
if ( CurrentObject . Count ( ) ) {
for ( int index = 0 ; index < CurrentObject . Count ( ) ; index + + ) {
ObjectClass const * tech = CurrentObject [ index ] ;
if ( tech ! = NULL & & ( tech - > Can_Player_Move ( ) | | ( tech - > Can_Player_Fire ( ) & & tech - > What_Am_I ( ) ! = RTTI_BUILDING ) ) ) {
OutList . Add ( EventClass ( EventClass : : IDLE , TargetClass ( tech ) ) ) ;
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Units_Queued_Movement_Toggle
*
* History : 03.03 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Units_Queued_Movement_Toggle ( uint64 player_id , bool toggle )
{
// Currently Red Alert only
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
if ( PlayerPtr ! = NULL )
{
PlayerPtr - > IsQueuedMovementToggle = toggle ;
}
}
/**************************************************************************************************
* DLLExportClass : : Team_Units_Formation_Toggle_On
*
* History : 03.03 .2020 MBL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// extern void Toggle_Formation(void); // Code\RedAlert\Conquer.cpp
extern char FormationEvent ; // Code\RedAlert\Conquer.cpp
void DLLExportClass : : Team_Units_Formation_Toggle_On ( uint64 player_id )
{
/*
* * Get the player for this . . .
*/
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
//
2020-09-16 10:03:04 -07:00
// Code here copied and modified from Toggle_Formation(), since obj->IsSelected is not supported
2020-05-27 12:16:20 -07:00
// Replacing with ObjectClass::Is_Selected_By_Player(HouseClass *player);
//
int team = MAX_TEAMS ;
long minx = 0x7FFFFFFFL , miny = 0x7FFFFFFFL ;
long maxx = 0 , maxy = 0 ;
int index ;
bool setform = 0 ;
2020-06-22 09:43:21 -07:00
TeamFormDataStruct & team_form_data = TeamFormData [ PlayerPtr - > Class - > House ] ;
2020-05-27 12:16:20 -07:00
//
// Recording support
//
if ( Session . Record ) {
FormationEvent = 1 ;
}
/*
* * Find the first selected object that is a member of a team , and
* * register his group as the team we ' re using . Once we find the team
* * number , update the ' setform ' flag to know whether we should be setting
* * the formation ' s offsets , or clearing them . If they currently have
* * illegal offsets ( as in 0x80000000 ) , then we ' re setting .
*/
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj ) {
if ( obj - > House = = PlayerPtr ) {
if ( ! obj - > IsInLimbo ) {
if ( obj - > Is_Selected_By_Player ( PlayerPtr ) ) {
team = obj - > Group ;
if ( team < MAX_TEAMS ) {
setform = obj - > XFormOffset = = ( int ) 0x80000000 ;
2020-06-22 09:43:21 -07:00
team_form_data . TeamSpeed [ team ] = SPEED_WHEEL ;
team_form_data . TeamMaxSpeed [ team ] = MPH_LIGHT_SPEED ;
2020-05-27 12:16:20 -07:00
break ;
}
}
}
}
}
}
if ( team > = MAX_TEAMS ) {
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * obj = Infantry . Ptr ( index ) ;
if ( obj ) {
if ( obj - > House = = PlayerPtr ) {
if ( ! obj - > IsInLimbo ) {
if ( obj - > Is_Selected_By_Player ( PlayerPtr ) ) {
team = obj - > Group ;
if ( team < MAX_TEAMS ) {
setform = obj - > XFormOffset = = ( int ) 0x80000000 ;
2020-06-22 09:43:21 -07:00
team_form_data . TeamSpeed [ team ] = SPEED_WHEEL ;
team_form_data . TeamMaxSpeed [ team ] = MPH_LIGHT_SPEED ;
2020-05-27 12:16:20 -07:00
break ;
}
}
}
}
}
}
}
if ( team > = MAX_TEAMS ) {
for ( index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass * obj = Vessels . Ptr ( index ) ;
if ( obj ) {
if ( obj - > House = = PlayerPtr ) {
if ( ! obj - > IsInLimbo ) {
if ( obj - > Is_Selected_By_Player ( PlayerPtr ) ) {
team = obj - > Group ;
if ( team < MAX_TEAMS ) {
setform = obj - > XFormOffset = = 0x80000000UL ;
2020-06-22 09:43:21 -07:00
team_form_data . TeamSpeed [ team ] = SPEED_WHEEL ;
team_form_data . TeamMaxSpeed [ team ] = MPH_LIGHT_SPEED ;
2020-05-27 12:16:20 -07:00
break ;
}
}
}
}
}
}
}
if ( team > = MAX_TEAMS ) return ;
/*
* * Now that we have a team , let ' s go set ( or clear ) the formation offsets .
*/
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
obj - > Mark ( MARK_CHANGE ) ;
if ( setform ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
if ( xc < minx ) minx = xc ;
if ( xc > maxx ) maxx = xc ;
if ( yc < miny ) miny = yc ;
if ( yc > maxy ) maxy = yc ;
2020-06-22 09:43:21 -07:00
if ( obj - > Class - > MaxSpeed < team_form_data . TeamMaxSpeed [ team ] ) {
team_form_data . TeamMaxSpeed [ team ] = obj - > Class - > MaxSpeed ;
team_form_data . TeamSpeed [ team ] = obj - > Class - > Speed ;
2020-05-27 12:16:20 -07:00
}
} else {
obj - > XFormOffset = obj - > YFormOffset = ( int ) 0x80000000 ;
}
}
}
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * obj = Infantry . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
obj - > Mark ( MARK_CHANGE ) ;
if ( setform ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
if ( xc < minx ) minx = xc ;
if ( xc > maxx ) maxx = xc ;
if ( yc < miny ) miny = yc ;
if ( yc > maxy ) maxy = yc ;
2020-06-22 09:43:21 -07:00
if ( obj - > Class - > MaxSpeed < team_form_data . TeamMaxSpeed [ team ] ) {
team_form_data . TeamMaxSpeed [ team ] = obj - > Class - > MaxSpeed ;
2020-05-27 12:16:20 -07:00
}
} else {
obj - > XFormOffset = obj - > YFormOffset = ( int ) 0x80000000 ;
}
}
}
for ( index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass * obj = Vessels . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
obj - > Mark ( MARK_CHANGE ) ;
if ( setform ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
if ( xc < minx ) minx = xc ;
if ( xc > maxx ) maxx = xc ;
if ( yc < miny ) miny = yc ;
if ( yc > maxy ) maxy = yc ;
2020-06-22 09:43:21 -07:00
if ( obj - > Class - > MaxSpeed < team_form_data . TeamMaxSpeed [ team ] ) {
team_form_data . TeamMaxSpeed [ team ] = obj - > Class - > MaxSpeed ;
2020-05-27 12:16:20 -07:00
}
} else {
obj - > XFormOffset = obj - > YFormOffset = 0x80000000UL ;
}
}
}
/*
* * All the units have been counted to find the bounding rectangle and
* * center of the formation , or to clear their offsets . Now , if we ' re to
* * set them into formation , proceed to do so . Otherwise , bail .
*/
if ( setform ) {
int centerx = ( int ) ( ( maxx - minx ) / 2 ) + minx ;
int centery = ( int ) ( ( maxy - miny ) / 2 ) + miny ;
for ( index = 0 ; index < Units . Count ( ) ; index + + ) {
UnitClass * obj = Units . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
obj - > XFormOffset = xc - centerx ;
obj - > YFormOffset = yc - centery ;
}
}
for ( index = 0 ; index < Infantry . Count ( ) ; index + + ) {
InfantryClass * obj = Infantry . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
obj - > XFormOffset = xc - centerx ;
obj - > YFormOffset = yc - centery ;
}
}
for ( index = 0 ; index < Vessels . Count ( ) ; index + + ) {
VesselClass * obj = Vessels . Ptr ( index ) ;
if ( obj & & ! obj - > IsInLimbo & & obj - > House = = PlayerPtr & & obj - > Group = = team ) {
long xc = Cell_X ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
long yc = Cell_Y ( Coord_Cell ( obj - > Center_Coord ( ) ) ) ;
obj - > XFormOffset = xc - centerx ;
obj - > YFormOffset = yc - centery ;
}
}
}
}
/**************************************************************************************************
* CNC_Handle_Debug_Request - - Process a debug input request
*
* In :
*
*
* Out :
*
*
* History : 1 / 7 / 2019 5 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Debug_Request ( DebugRequestEnum debug_request_type , uint64 player_id , const char * object_name , int x , int y , bool unshroud , bool enemy )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
switch ( debug_request_type ) {
case DEBUG_REQUEST_SPAWN_OBJECT :
DLLExportClass : : Debug_Spawn_Unit ( object_name , x , y , enemy ) ;
break ;
case DEBUG_REQUEST_FORCE_CRASH :
Debug_Force_Crash = true ;
break ;
case DEBUG_REQUEST_KILL_OBJECT :
if ( strcmp ( object_name , " HEAL " ) = = 0 ) {
DLLExportClass : : Debug_Heal_Unit ( x , y ) ;
}
else {
DLLExportClass : : Debug_Kill_Unit ( x , y ) ;
}
break ;
case DEBUG_REQUEST_END_GAME :
{
bool win = true ;
const char lose [ ] = " LOSE " ;
if ( strcmp ( lose , object_name ) = = 0 ) {
win = false ;
}
PlayerWins = win ;
PlayerLoses = ! win ;
}
break ;
case DEBUG_REQUEST_UNSHROUD :
Debug_Unshroud = unshroud ;
Map . Flag_To_Redraw ( true ) ;
break ;
case DEBUG_REQUEST_SUPERWEAPON_RECHARGE :
for ( int i = 0 ; i < SPC_COUNT ; + + i )
{
PlayerPtr - > SuperWeapon [ i ] . Forced_Charge ( true ) ;
}
break ;
case DEBUG_REQUEST_END_PRODUCTION :
{
for ( int index = 0 ; index < Factories . Count ( ) ; index + + ) {
FactoryClass * factory = Factories . Ptr ( index ) ;
if ( factory - > Get_House ( ) - > IsHuman ) {
Factories . Ptr ( index ) - > Force_Complete ( ) ;
}
}
}
break ;
case DEBUG_REQUEST_ADD_RESOURCES :
{
if ( object_name ) {
int amount = atoi ( object_name ) ;
PlayerPtr - > Credits + = amount ;
if ( PlayerPtr - > Credits < 0 ) {
PlayerPtr - > Credits = 0 ;
}
}
}
break ;
case DEBUG_REQUEST_UNLOCK_BUILDABLES :
PlayerPtr - > DebugUnlockBuildables = ! PlayerPtr - > DebugUnlockBuildables ;
PlayerPtr - > IsRecalcNeeded = true ;
break ;
case DEBUG_REQUEST_SET_GLOBAL_FLAG :
Scen . Set_Global_To ( x , true ) ;
break ;
default :
break ;
}
}
2020-09-16 10:03:04 -07:00
extern " C " __declspec ( dllexport ) void __cdecl CNC_Handle_Beacon_Request ( BeaconRequestEnum beacon_request_type , uint64 player_id , int pixel_x , int pixel_y )
{
if ( ! DLLExportClass : : Set_Player_Context ( player_id ) ) {
return ;
}
// Beacons are only available if legacy rendering is disabled
if ( DLLExportClass : : Legacy_Render_Enabled ( ) ) {
return ;
}
// Only allow one beacon per player
for ( int index = 0 ; index < Anims . Count ( ) ; + + index ) {
AnimClass * anim = Anims . Ptr ( index ) ;
if ( anim ! = NULL & &
( * anim = = ANIM_BEACON | | * anim = = ANIM_BEACON_VIRTUAL ) & &
anim - > OwnerHouse = = PlayerPtr - > Class - > House ) {
delete anim ;
}
}
2020-05-27 12:16:20 -07:00
2020-09-16 10:03:04 -07:00
OutList . Add ( EventClass ( ANIM_BEACON , PlayerPtr - > Class - > House , Map . Pixel_To_Coord ( pixel_x , pixel_y ) , PlayerPtr - > Get_Allies ( ) ) ) ;
// Send sound effect to allies
for ( int index = 0 ; index < Houses . Count ( ) ; + + index ) {
HouseClass * hptr = Houses . Ptr ( index ) ;
if ( hptr ! = NULL & & hptr - > IsActive & & hptr - > IsHuman & & PlayerPtr - > Is_Ally ( hptr ) ) {
DLLExportClass : : On_Sound_Effect ( hptr , VOC_BEACON , " " , 0 , 0 ) ;
}
}
}
2020-05-27 12:16:20 -07:00
/**************************************************************************************************
* DLLExportClass : : Debug_Spawn_All - - Debug spawn all buildable units and structures
*
* In : Object to unlimbo , x & y cell positions
*
*
* Out : True if unlimbo succeeded
*
*
*
* History : 1 / 22 / 2020 2 : 57 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Try_Debug_Spawn_Unlimbo ( TechnoClass * techno , int & cell_x , int & cell_y )
{
if ( techno ) {
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_right = map_cell_x + Map . MapCellWidth ;
int map_cell_bottom = map_cell_y + Map . MapCellHeight ;
map_cell_right = min ( map_cell_right , cell_x + 26 ) ; // Generally try to prevent the objects from spawing off the right of the screen
int try_x = cell_x ;
int try_y = cell_y ;
while ( try_y < map_cell_bottom ) {
CELL cell = XY_Cell ( try_x , try_y ) ;
if ( techno - > Unlimbo ( Cell_Coord ( cell ) ) ) {
try_x + + ;
if ( try_x > map_cell_right - 2 ) {
try_x = cell_x ; //map_cell_x + 2;
try_y + + ;
}
cell_x = try_x ;
cell_y = try_y ;
return true ;
}
try_x + + ;
if ( try_x > map_cell_right - 2 ) {
try_x = cell_x ; //map_cell_x + 2;
try_y + + ;
}
}
cell_x = try_x ;
cell_y = try_y ;
}
return false ;
}
/**************************************************************************************************
* DLLExportClass : : Debug_Spawn_All - - Debug spawn all buildable units and structures
*
* In :
*
* Out :
*
*
*
* History : 1 / 22 / 2020 2 : 57 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Debug_Spawn_All ( int x , int y )
{
int map_cell_x = Map . MapCellX ;
int map_cell_y = Map . MapCellY ;
int map_cell_bottom = map_cell_y + Map . MapCellHeight ;
int origin_x = map_cell_x + 2 ;
int origin_y = map_cell_y + 2 ;
if ( x ! = 0 | | y ! = 0 ) {
CELL screen_cell = Coord_Cell ( Map . Pixel_To_Coord ( x , y ) ) ;
origin_x = Cell_X ( screen_cell ) ;
origin_y = Cell_Y ( screen_cell ) ;
}
int try_x = origin_x ;
int try_y = origin_y ;
HousesType house = PlayerPtr - > Class - > House ;
for ( StructType sindex = STRUCT_FIRST ; sindex < STRUCT_COUNT ; sindex + + ) {
BuildingTypeClass const & building_type = BuildingTypeClass : : As_Reference ( sindex ) ;
if ( building_type . Get_Ownable ( ) & & building_type . Level ! = - 1 ) {
BuildingClass * building = new BuildingClass ( building_type , house ) ;
if ( building ) {
try_x = origin_x ;
try_y = origin_y ;
while ( try_y < map_cell_bottom ) {
if ( Try_Debug_Spawn_Unlimbo ( building , try_x , try_y ) ) {
break ;
}
}
}
}
}
for ( UnitType index = UNIT_FIRST ; index < UNIT_COUNT ; index + + ) {
UnitTypeClass const & unit_type = UnitTypeClass : : As_Reference ( index ) ;
/*
* * Fetch the sidebar cameo image for this building .
*/
if ( unit_type . Get_Ownable ( ) & & unit_type . Level ! = - 1 ) {
UnitClass * unit = ( UnitClass * ) unit_type . Create_One_Of ( PlayerPtr ) ;
if ( unit ) {
try_x = origin_x ;
try_y = origin_y ;
while ( try_y < map_cell_bottom ) {
if ( Try_Debug_Spawn_Unlimbo ( unit , try_x , try_y ) ) {
break ;
}
}
}
}
}
for ( InfantryType index = INFANTRY_FIRST ; index < INFANTRY_COUNT ; index + + ) {
InfantryTypeClass const & infantry_type = InfantryTypeClass : : As_Reference ( index ) ;
/*
* * Fetch the sidebar cameo image for this building .
*/
if ( infantry_type . Get_Ownable ( ) & & infantry_type . Level ! = - 1 ) {
InfantryClass * inf = ( InfantryClass * ) infantry_type . Create_One_Of ( PlayerPtr ) ;
if ( inf ) {
try_x = origin_x ;
try_y = origin_y ;
while ( try_y < map_cell_bottom ) {
if ( Try_Debug_Spawn_Unlimbo ( inf , try_x , try_y ) ) {
break ;
}
}
}
}
}
for ( AircraftType index = AIRCRAFT_FIRST ; index < AIRCRAFT_COUNT ; index + + ) {
AircraftTypeClass const & aircraft_type = AircraftTypeClass : : As_Reference ( index ) ;
/*
* * Fetch the sidebar cameo image for this building .
*/
if ( aircraft_type . Get_Ownable ( ) & & aircraft_type . Level ! = - 1 ) {
AircraftClass * air = ( AircraftClass * ) aircraft_type . Create_One_Of ( PlayerPtr ) ;
if ( air ) {
try_x = origin_x ;
try_y = origin_y ;
while ( try_y < map_cell_bottom ) {
if ( Try_Debug_Spawn_Unlimbo ( air , try_x , try_y ) ) {
break ;
}
}
}
}
}
for ( VesselType index = VESSEL_FIRST ; index < VESSEL_COUNT ; index + + ) {
VesselTypeClass const & vessel_type = VesselTypeClass : : As_Reference ( index ) ;
/*
* * Fetch the sidebar cameo image for this building .
*/
if ( vessel_type . Get_Ownable ( ) & & vessel_type . Level ! = - 1 ) {
VesselClass * boat = ( VesselClass * ) vessel_type . Create_One_Of ( PlayerPtr ) ;
if ( boat ) {
try_x = origin_x ;
try_y = origin_y ;
while ( try_y < map_cell_bottom ) {
if ( Try_Debug_Spawn_Unlimbo ( boat , try_x , try_y ) ) {
break ;
}
}
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Debug_Spawn_Unit - - Debug spawn a unit at the specified location
*
* In :
*
* Out :
*
*
*
* History : 3 / 14 / 2019 3 : 20 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Debug_Spawn_Unit ( const char * object_name , int x , int y , bool enemy )
{
if ( object_name = = NULL ) {
return ;
}
if ( strlen ( object_name ) = = 0 ) {
return ;
}
COORDINATE coord = Map . Pixel_To_Coord ( x , y ) ;
CELL cell = Coord_Cell ( coord ) ;
HousesType house = PlayerPtr - > Class - > House ;
/*
* * Place all ?
*/
if ( stricmp ( object_name , " ALLOBJECTS " ) = = 0 ) {
Debug_Spawn_All ( x , y ) ;
return ;
}
/*
* * If this is for the enemy , find the enemy with the most stuff
*/
if ( enemy ) {
unsigned max_count = 0 ;
for ( int i = 0 ; i < Houses . Count ( ) ; + + i ) {
const HouseClass * player = Houses . Ptr ( i ) ;
const unsigned count = player - > CurUnits + player - > CurBuildings + player - > CurInfantry + player - > CurVessels + player - > CurAircraft ;
if ( ! PlayerPtr - > Is_Ally ( player ) & & ( count > = max_count ) ) {
house = player - > Class - > House ;
max_count = count ;
}
}
}
/*
* * What is this thing ?
*/
StructType structure_type = BuildingTypeClass : : From_Name ( object_name ) ;
if ( structure_type ! = STRUCT_NONE ) {
BuildingClass * building = new BuildingClass ( structure_type , house ) ;
if ( building ) {
if ( ! building - > Unlimbo ( Cell_Coord ( cell ) ) ) {
delete building ;
}
}
# if (0)
Map . PendingObject = & BuildingTypeClass : : As_Reference ( structure_type ) ;
Map . PendingHouse = PlayerPtr - > ActLike ;
Map . PendingObjectPtr = Map . PendingObject - > Create_One_Of ( PlayerPtr ) ;
if ( Map . PendingObjectPtr ) {
Map . Set_Cursor_Pos ( ) ;
Map . Set_Cursor_Shape ( Map . PendingObject - > Occupy_List ( ) ) ;
//OutList.Add(EventClass(EventClass::PLACE, RTTI_BUILDING, (CELL)(cell + Map.ZoneOffset)));
}
# endif
return ;
}
UnitType unit_type = UnitTypeClass : : From_Name ( object_name ) ;
if ( unit_type ! = UNIT_NONE ) {
UnitClass * unit = new UnitClass ( unit_type , house ) ;
if ( unit ) {
unit - > Unlimbo ( Map . Pixel_To_Coord ( x , y ) , DIR_N ) ;
}
return ;
}
InfantryType infantry_type = InfantryTypeClass : : From_Name ( object_name ) ;
if ( infantry_type ! = INFANTRY_NONE ) {
InfantryClass * inf = new InfantryClass ( infantry_type , house ) ;
if ( inf ) {
inf - > Unlimbo ( Map . Pixel_To_Coord ( x , y ) , DIR_N ) ;
}
return ;
}
AircraftType aircraft_type = AircraftTypeClass : : From_Name ( object_name ) ;
if ( aircraft_type ! = AIRCRAFT_NONE ) {
AircraftClass * air = new AircraftClass ( aircraft_type , house ) ;
if ( air ) {
air - > Unlimbo ( Map . Pixel_To_Coord ( x , y ) , DIR_N ) ;
}
return ;
}
VesselType vessel_type = VesselTypeClass : : From_Name ( object_name ) ;
if ( vessel_type ! = VESSEL_NONE ) {
VesselClass * boat = new VesselClass ( vessel_type , house ) ;
if ( boat ! = NULL ) {
if ( boat - > Unlimbo ( Map . Pixel_To_Coord ( x , y ) , DIR_N ) ) {
boat - > Enter_Idle_Mode ( ) ;
} else {
delete boat ;
}
}
}
OverlayType overlay_type = OverlayTypeClass : : From_Name ( object_name ) ;
if ( overlay_type ! = OVERLAY_NONE )
{
new OverlayClass ( overlay_type , cell ) ;
return ;
}
}
/**************************************************************************************************
* DLLExportClass : : Debug_Kill_Unit - - Kill a unit at the specified location
*
* In :
*
* Out :
*
*
*
* History : 8 / 19 / 2019 3 : 09 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Debug_Kill_Unit ( int x , int y )
{
COORDINATE coord = Map . Pixel_To_Coord ( x , y ) ;
CELL cell = Coord_Cell ( coord ) ;
CellClass * cellptr = & Map [ cell ] ;
if ( cellptr ) {
ObjectClass * obj = cellptr - > Cell_Object ( ) ;
static const int debug_damage = 100 ; // 100 = Incremental damage
if ( obj ) {
int damage = debug_damage ;
obj - > Take_Damage ( damage , 0 , WARHEAD_HE , 0 , true ) ;
} else {
if ( cellptr - > Overlay ! = OVERLAY_NONE ) {
OverlayTypeClass const * optr = & OverlayTypeClass : : As_Reference ( cellptr - > Overlay ) ;
if ( optr - > IsTiberium ) {
cellptr - > Reduce_Tiberium ( 1 ) ;
}
if ( optr - > IsWall ) {
Map [ cell ] . Reduce_Wall ( debug_damage ) ;
}
}
if ( cellptr - > TType = = TEMPLATE_BRIDGE1 | | cellptr - > TType = = TEMPLATE_BRIDGE2 | |
cellptr - > TType = = TEMPLATE_BRIDGE1H | | cellptr - > TType = = TEMPLATE_BRIDGE2H | |
cellptr - > TType = = TEMPLATE_BRIDGE_1A | | cellptr - > TType = = TEMPLATE_BRIDGE_1B | |
cellptr - > TType = = TEMPLATE_BRIDGE_2A | | cellptr - > TType = = TEMPLATE_BRIDGE_2B | |
cellptr - > TType = = TEMPLATE_BRIDGE_3A | | cellptr - > TType = = TEMPLATE_BRIDGE_3B ) {
Map . Destroy_Bridge_At ( cell ) ;
}
}
}
}
void DLLExportClass : : Debug_Heal_Unit ( int x , int y )
{
COORDINATE coord = Map . Pixel_To_Coord ( x , y ) ;
CELL cell = Coord_Cell ( coord ) ;
CellClass * cellptr = & Map [ cell ] ;
if ( cellptr ) {
ObjectClass * obj = cellptr - > Cell_Object ( ) ;
if ( obj ) {
obj - > Strength = obj - > Class_Of ( ) . MaxStrength ;
}
else {
if ( cellptr - > Overlay ! = OVERLAY_NONE ) {
OverlayTypeClass const * optr = & OverlayTypeClass : : As_Reference ( cellptr - > Overlay ) ;
if ( optr - > IsTiberium ) {
const int cellcount = ( int ) FACING_COUNT + 1 ;
CellClass * cells [ cellcount ] ;
cells [ 0 ] = cellptr ;
for ( FacingType index = FACING_N ; index < FACING_COUNT ; index + + ) {
2020-06-22 09:43:21 -07:00
cells [ ( int ) index + 1 ] = cellptr - > Adjacent_Cell ( index ) ;
2020-05-27 12:16:20 -07:00
}
for ( int index = 0 ; index < cellcount ; index + + ) {
CellClass * newcell = cells [ index ] ;
if ( newcell ! = NULL ) {
if ( newcell - > Can_Tiberium_Germinate ( ) ) {
switch ( cellptr - > Overlay ) {
case OVERLAY_GOLD1 :
case OVERLAY_GOLD2 :
case OVERLAY_GOLD3 :
case OVERLAY_GOLD4 :
new OverlayClass ( Random_Pick ( OVERLAY_GOLD1 , OVERLAY_GOLD4 ) , newcell - > Cell_Number ( ) ) ;
newcell - > OverlayData = 0 ;
break ;
case OVERLAY_GEMS1 :
case OVERLAY_GEMS2 :
case OVERLAY_GEMS3 :
case OVERLAY_GEMS4 :
new OverlayClass ( Random_Pick ( OVERLAY_GEMS1 , OVERLAY_GEMS4 ) , newcell - > Cell_Number ( ) ) ;
newcell - > OverlayData = 0 ;
break ;
default :
break ;
}
}
else if ( newcell - > Land_Type ( ) = = LAND_TIBERIUM ) {
switch ( newcell - > Overlay ) {
case OVERLAY_GOLD1 :
case OVERLAY_GOLD2 :
case OVERLAY_GOLD3 :
case OVERLAY_GOLD4 :
newcell - > OverlayData = MIN ( newcell - > OverlayData + 1 , 11 ) ;
newcell - > Recalc_Attributes ( ) ;
newcell - > Redraw_Objects ( ) ;
break ;
case OVERLAY_GEMS1 :
case OVERLAY_GEMS2 :
case OVERLAY_GEMS3 :
case OVERLAY_GEMS4 :
newcell - > OverlayData = MIN ( newcell - > OverlayData + 1 , 2 ) ;
newcell - > Recalc_Attributes ( ) ;
newcell - > Redraw_Objects ( ) ;
break ;
default :
break ;
}
}
}
}
}
}
}
}
}
/**************************************************************************************************
* DLLExportClass : : Legacy_Render_Enabled - - Is the legacy rendering enabled ?
*
* In :
*
* Out :
*
*
*
* History : 4 / 15 / 2019 5 : 46 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Legacy_Render_Enabled ( void )
{
if ( GAME_TO_PLAY = = GAME_GLYPHX_MULTIPLAYER ) {
unsigned int num_humans = 0U ;
for ( int i = 0 ; i < MULTIPLAYER_COUNT ; + + i ) {
HouseClass * player_ptr = HouseClass : : As_Pointer ( Session . Players [ i ] - > Player . ID ) ;
if ( player_ptr & & player_ptr - > IsHuman ) {
if ( + + num_humans > 1 ) break ;
}
}
return num_humans < 2 ;
}
//return false;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Computer_Message - - Replacement for original Computer_Message function
*
* In :
*
* Out :
*
*
*
* History : 1 / 27 / 2020 1 : 42 PM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Computer_Message ( bool last_player_taunt )
{
HousesType house ;
HouseClass * ptr ;
HouseClass * ai_players [ MAX_PLAYERS ] ;
int ai_player_count = 0 ;
/*------------------------------------------------------------------------
Find the computer house that the message will be from
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
for ( house = HOUSE_MULTI1 ; house < ( HOUSE_MULTI1 + MULTIPLAYER_COUNT ) ; house + + ) {
ptr = HouseClass : : As_Pointer ( house ) ;
if ( ! ptr | | ptr - > IsHuman | | ptr - > IsDefeated ) {
continue ;
}
ai_players [ ai_player_count + + ] = ptr ;
}
if ( ai_player_count ) {
int ai_player_index = 0 ;
if ( ai_player_count > 1 ) {
ai_player_index = IRandom ( 0 , ai_player_count - 1 ) ;
}
int taunt_index ;
if ( last_player_taunt ) {
taunt_index = 13 ;
} else {
taunt_index = IRandom ( 0 , 12 ) ;
}
On_Message ( ai_players [ ai_player_index ] , " " , 15.0f , MESSAGE_TYPE_COMPUTER_TAUNT , taunt_index ) ;
}
}
/**************************************************************************************************
* DLLExportClass : : Set_Special_Key_Flags - -
*
* In :
*
* Out :
*
*
*
* History : 6 / 27 / 2019 - JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Set_Special_Key_Flags ( unsigned char special_key_flags )
{
SpecialKeyFlags [ CurrentLocalPlayerIndex ] = special_key_flags ;
}
/**************************************************************************************************
* DLLExportClass : : Clear_Special_Key_Flags - -
*
* In :
*
* Out :
*
*
*
* History : 6 / 27 / 2019 - JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Clear_Special_Key_Flags ( )
{
SpecialKeyFlags [ CurrentLocalPlayerIndex ] = 0 ;
}
/**************************************************************************************************
* DLLExportClass : : Get_Input_Key_State - -
*
* In :
*
* Out :
*
*
*
* History : 6 / 27 / 2019 - JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Get_Input_Key_State ( KeyNumType key )
{
switch ( key )
{
case KN_LCTRL :
return ( SpecialKeyFlags [ CurrentLocalPlayerIndex ] & INPUT_SPECIAL_KEY_CTRL ) ! = 0 ;
break ;
case KN_LSHIFT :
return ( SpecialKeyFlags [ CurrentLocalPlayerIndex ] & INPUT_SPECIAL_KEY_SHIFT ) ! = 0 ;
break ;
case KN_LALT :
return ( SpecialKeyFlags [ CurrentLocalPlayerIndex ] & INPUT_SPECIAL_KEY_ALT ) ! = 0 ;
break ;
default :
break ;
} ;
return false ;
}
/**************************************************************************************************
* Get_Input_Key_State
*
* History : 6 / 27 / 2019 - JAS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLL_Export_Get_Input_Key_State ( KeyNumType key )
{
return DLLExportClass : : Get_Input_Key_State ( key ) ;
}
bool DLLSave ( Pipe & file )
{
return DLLExportClass : : Save ( file ) ;
}
bool DLLLoad ( Straw & file )
{
return DLLExportClass : : Load ( file ) ;
}
/**************************************************************************************************
* DLLExportClass : : Save - -
*
* In :
*
* Out :
*
*
*
* History : 9 / 10 / 2019 10 : 24 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Save ( Pipe & pipe )
{
/*
* * Version first
*/
unsigned int version = CNC_DLL_API_VERSION ;
pipe . Put ( & version , sizeof ( version ) ) ;
pipe . Put ( MultiplayerStartPositions , sizeof ( MultiplayerStartPositions ) ) ;
pipe . Put ( GlyphxPlayerIDs , sizeof ( GlyphxPlayerIDs ) ) ;
pipe . Put ( & GlyphXClientSidebarWidthInLeptons , sizeof ( GlyphXClientSidebarWidthInLeptons ) ) ;
pipe . Put ( MPlayerIsHuman , sizeof ( MPlayerIsHuman ) ) ;
pipe . Put ( MultiplayerStartPositions , sizeof ( MultiplayerStartPositions ) ) ;
pipe . Put ( PlacementType , sizeof ( PlacementType ) ) ;
pipe . Put ( & OverrideNewUnitsEnabled , sizeof ( OverrideNewUnitsEnabled ) ) ;
for ( int i = 0 ; i < MAX_PLAYERS ; i + + ) {
Sidebar_Glyphx_Save ( pipe , & MultiplayerSidebars [ i ] ) ;
int has_player = false ;
if ( i < Session . Players . Count ( ) & & Session . Players [ i ] ) {
has_player = true ;
pipe . Put ( & has_player , sizeof ( has_player ) ) ;
pipe . Put ( Session . Players [ i ] , sizeof ( NodeNameType ) ) ;
} else {
pipe . Put ( & has_player , sizeof ( has_player ) ) ;
}
}
pipe . Put ( & Special , sizeof ( Special ) ) ;
2020-08-06 09:44:54 -07:00
/*
* * Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
*/
bool not_allow_super_weapons = ! MPSuperWeaponDisable ;
pipe . Put ( & not_allow_super_weapons , sizeof ( not_allow_super_weapons ) ) ;
2020-05-27 12:16:20 -07:00
/*
* * Room for save game expansion
*/
2020-08-06 09:44:54 -07:00
unsigned char padding [ 4095 ] ;
2020-05-27 12:16:20 -07:00
memset ( padding , 0 , sizeof ( padding ) ) ;
pipe . Put ( padding , sizeof ( padding ) ) ;
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Load - -
*
* In :
*
* Out :
*
*
*
* History : 9 / 10 / 2019 10 : 24 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool DLLExportClass : : Load ( Straw & file )
{
unsigned int version = 0 ;
if ( file . Get ( & version , sizeof ( version ) ) ! = sizeof ( version ) ) {
return false ;
}
if ( file . Get ( MultiplayerStartPositions , sizeof ( MultiplayerStartPositions ) ) ! = sizeof ( MultiplayerStartPositions ) ) {
return false ;
}
if ( file . Get ( GlyphxPlayerIDs , sizeof ( GlyphxPlayerIDs ) ) ! = sizeof ( GlyphxPlayerIDs ) ) {
return false ;
}
if ( file . Get ( & GlyphXClientSidebarWidthInLeptons , sizeof ( GlyphXClientSidebarWidthInLeptons ) ) ! = sizeof ( GlyphXClientSidebarWidthInLeptons ) ) {
return false ;
}
if ( file . Get ( MPlayerIsHuman , sizeof ( MPlayerIsHuman ) ) ! = sizeof ( MPlayerIsHuman ) ) {
return false ;
}
if ( file . Get ( MultiplayerStartPositions , sizeof ( MultiplayerStartPositions ) ) ! = sizeof ( MultiplayerStartPositions ) ) {
return false ;
}
if ( file . Get ( PlacementType , sizeof ( PlacementType ) ) ! = sizeof ( PlacementType ) ) {
return false ;
}
if ( file . Get ( & OverrideNewUnitsEnabled , sizeof ( OverrideNewUnitsEnabled ) ) ! = sizeof ( OverrideNewUnitsEnabled ) ) {
return false ;
}
if ( Is_Aftermath_Installed ( ) ) {
if ( Session . Type = = GAME_SKIRMISH | | Session . Type = = GAME_GLYPHX_MULTIPLAYER ) {
bAftermathMultiplayer = NewUnitsEnabled = OverrideNewUnitsEnabled ;
}
}
Session . NumPlayers = 0 ;
for ( int i = 0 ; i < MAX_PLAYERS ; i + + ) {
Sidebar_Glyphx_Load ( file , & MultiplayerSidebars [ i ] ) ;
int has_player = false ;
file . Get ( & has_player , sizeof ( has_player ) ) ;
if ( has_player ) {
NodeNameType * who = new NodeNameType ;
file . Get ( who , sizeof ( NodeNameType ) ) ;
Session . Players . Add ( who ) ;
Session . NumPlayers + + ;
}
}
if ( file . Get ( & Special , sizeof ( Special ) ) ! = sizeof ( Special ) ) {
return false ;
}
2020-08-06 09:44:54 -07:00
/*
* * Restore backup
*/
if ( SpecialBackup ! = NULL ) {
memcpy ( SpecialBackup , & Special , sizeof ( SpecialClass ) ) ;
}
/*
* * Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
*/
bool not_allow_super_weapons = false ;
if ( file . Get ( & not_allow_super_weapons , sizeof ( not_allow_super_weapons ) ) ! = sizeof ( not_allow_super_weapons ) ) {
return false ;
}
MPSuperWeaponDisable = ! not_allow_super_weapons ;
unsigned char padding [ 4095 ] ;
2020-05-27 12:16:20 -07:00
if ( file . Get ( padding , sizeof ( padding ) ) ! = sizeof ( padding ) ) {
return false ;
}
return true ;
}
/**************************************************************************************************
* DLLExportClass : : Code_Pointers - -
*
* In :
*
* Out :
*
*
*
* History : 9 / 10 / 2019 10 : 24 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Code_Pointers ( void )
{
for ( int i = 0 ; i < MAX_PLAYERS ; i + + ) {
Sidebar_Glyphx_Code_Pointers ( & MultiplayerSidebars [ i ] ) ;
if ( PlacementType [ i ] ) {
PlacementType [ i ] = ( BuildingTypeClass * ) PlacementType [ i ] - > Type ;
}
}
}
/**************************************************************************************************
* DLLExportClass : : Decode_Pointers - -
*
* In :
*
* Out :
*
*
*
* History : 9 / 10 / 2019 10 : 24 AM - ST
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DLLExportClass : : Decode_Pointers ( void )
{
for ( int i = 0 ; i < MAX_PLAYERS ; i + + ) {
Sidebar_Glyphx_Decode_Pointers ( & MultiplayerSidebars [ i ] ) ;
if ( PlacementType [ i ] ) {
StructType type = ( StructType ) reinterpret_cast < unsigned int > ( PlacementType [ i ] ) ;
PlacementType [ i ] = NULL ;
if ( type > = STRUCT_FIRST & & type < STRUCT_COUNT ) {
TechnoTypeClass const * tech = Fetch_Techno_Type ( RTTI_BUILDINGTYPE , type ) ;
if ( tech ) {
BuildingTypeClass * build_type = ( BuildingTypeClass * ) ( tech ) ;
if ( build_type ) {
PlacementType [ i ] = build_type ;
}
}
}
}
}
}
void DLL_Code_Pointers ( void )
{
DLLExportClass : : Code_Pointers ( ) ;
}
void DLL_Decode_Pointers ( void )
{
DLLExportClass : : Decode_Pointers ( ) ;
}