September 16th patch update
DLL version incremented Beacon functionality added Support for loading screen match preview display Placeholder handling of new key-bindable mod commands
This commit is contained in:
parent
e37e174be1
commit
fd05be35c1
68 changed files with 1313 additions and 267 deletions
|
@ -2379,7 +2379,58 @@ static AnimTypeClass const Flag(
|
|||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
-1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE
|
||||
);
|
||||
|
||||
static AnimTypeClass const Beacon(
|
||||
ANIM_BEACON, // Animation number.
|
||||
"MOVEFLSH", // Data name of animation.
|
||||
21, // Maximum dimension of animation.
|
||||
0, // Biggest animation stage.
|
||||
false, // Normalized animation rate?
|
||||
false, // Uses white translucent table?
|
||||
false, // Scorches the ground?
|
||||
false, // Forms a crater?
|
||||
false, // Sticks to unit in square?
|
||||
false, // Ground level animation?
|
||||
false, // Translucent colors in this animation?
|
||||
false, // Is this a flame thrower animation?
|
||||
0x0000, // Damage to apply per tick (fixed point).
|
||||
1, // Delay between frames.
|
||||
0, // Starting frame number.
|
||||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE,
|
||||
-1, // Virtual stages
|
||||
0x100, // Virtual scale
|
||||
ANIM_BEACON_VIRTUAL // Virtual anim
|
||||
);
|
||||
|
||||
static AnimTypeClass const BeaconVirtual(
|
||||
ANIM_BEACON_VIRTUAL, // Animation number.
|
||||
"BEACON", // Data name of animation.
|
||||
21, // Maximum dimension of animation.
|
||||
0, // Biggest animation stage.
|
||||
false, // Normalized animation rate?
|
||||
false, // Uses white translucent table?
|
||||
false, // Scorches the ground?
|
||||
false, // Forms a crater?
|
||||
false, // Sticks to unit in square?
|
||||
false, // Ground level animation?
|
||||
false, // Translucent colors in this animation?
|
||||
false, // Is this a flame thrower animation?
|
||||
0x0000, // Damage to apply per tick (fixed point).
|
||||
1, // Delay between frames.
|
||||
0, // Starting frame number.
|
||||
0, // Loop start frame number.
|
||||
-1, // Ending frame of loop back.
|
||||
1, // Number of animation stages.
|
||||
-1, // Number of times the animation loops.
|
||||
VOC_NONE, // Sound effect to play.
|
||||
ANIM_NONE
|
||||
);
|
||||
|
@ -2484,10 +2535,12 @@ AnimTypeClass const * const AnimTypeClass::Pointers[ANIM_COUNT] = {
|
|||
&RaptDie,
|
||||
&ChemBall,
|
||||
&Flag,
|
||||
&Beacon,
|
||||
&Fire3Virtual,
|
||||
&Fire2Virtual,
|
||||
&Fire1Virtual,
|
||||
&Fire4Virtual
|
||||
&Fire4Virtual,
|
||||
&BeaconVirtual
|
||||
};
|
||||
|
||||
|
||||
|
@ -2570,6 +2623,9 @@ void AnimTypeClass::One_Time(void)
|
|||
((void const *&)As_Reference(index).ImageData) = MixFileClass::Retrieve(fullname);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up beacon image data manually since they're new animations only available in the virtual renderer
|
||||
((void const *&)As_Reference(ANIM_BEACON_VIRTUAL).ImageData) = As_Reference(ANIM_BEACON).ImageData;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2368,6 +2368,11 @@ int AircraftClass::Mission_Attack(void)
|
|||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear second shot flag so fire burst works correctly.
|
||||
*/
|
||||
IsSecondShot = false;
|
||||
|
||||
PrimaryFacing.Set_Desired(Direction(TarCom));
|
||||
SecondaryFacing.Set_Desired(Direction(TarCom));
|
||||
switch (Can_Fire(TarCom, 0)) {
|
||||
|
|
|
@ -249,6 +249,8 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
int shapenum = Class->Start + Fetch_Stage();
|
||||
void const * remap = NULL;
|
||||
ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
/*
|
||||
** Some animations require special fixups.
|
||||
|
@ -276,6 +278,12 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
y += (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
|
||||
transtable = Map.UnitShadow;
|
||||
break;
|
||||
|
||||
case ANIM_BEACON_VIRTUAL:
|
||||
width = 29;
|
||||
height = 39;
|
||||
flags = flags | SHAPE_BOTTOM | SHAPE_COMPACT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -303,7 +311,7 @@ void AnimClass::Draw_It(int x, int y, WindowNumberType window)
|
|||
** Draw the animation shape, but ignore legacy if beyond normal stage count.
|
||||
*/
|
||||
if ((window == WINDOW_VIRTUAL) || (Fetch_Stage() < Class->Stages)) {
|
||||
CC_Draw_Shape(this, shapefile, shapenum, x, y, window, flags, remap, transtable, Class->VirtualScale);
|
||||
CC_Draw_Shape(this, shapefile, shapenum, x, y, window, flags, remap, transtable, Class->VirtualScale, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -571,6 +579,7 @@ AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay
|
|||
Object = 0;
|
||||
SortTarget = TARGET_NONE;
|
||||
OwnerHouse = HOUSE_NONE;
|
||||
KillTime = 0ULL;
|
||||
|
||||
if (Class->Stages == -1) {
|
||||
((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
|
||||
|
@ -732,6 +741,19 @@ void AnimClass::AI(void)
|
|||
IsToDelete = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check the kill time.
|
||||
*/
|
||||
if (KillTime > 0ULL) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
unsigned long long now = (unsigned long long)ft.dwLowDateTime + ((unsigned long long)ft.dwHighDateTime << 32ULL);
|
||||
if (now >= KillTime) {
|
||||
IsToDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete this animation and bail early if the animation is flagged to be deleted
|
||||
** immediately.
|
||||
|
@ -1292,4 +1314,20 @@ void AnimClass::Detach(TARGET target, bool all)
|
|||
IsToDelete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimClass::Set_Owner(HousesType owner)
|
||||
{
|
||||
OwnerHouse = owner;
|
||||
if (VirtualAnim != NULL) {
|
||||
VirtualAnim->Set_Owner(owner);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimClass::Set_Visible_Flags(unsigned flags)
|
||||
{
|
||||
VisibleFlags = flags;
|
||||
if (VirtualAnim != NULL) {
|
||||
VirtualAnim->Set_Visible_Flags(flags);
|
||||
}
|
||||
}
|
|
@ -63,14 +63,16 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
void Sort_Above(TARGET target);
|
||||
void Make_Invisible(void) {IsInvisible = true;};
|
||||
void Make_Visible(void) {IsInvisible = false;};
|
||||
void Kill_At(unsigned long long kill_time) {KillTime = kill_time;}
|
||||
|
||||
/*
|
||||
** 2019/09/19 JAS
|
||||
** Added functions for accessing which players can see this anim
|
||||
*/
|
||||
void Set_Visible_Flags(unsigned flags) { VisibleFlags = flags; }
|
||||
void Set_Visible_Flags(unsigned flags);
|
||||
unsigned Get_Visible_Flags() const { return (Delay == 0) ? VisibleFlags : 0; }
|
||||
|
||||
virtual void Set_Owner(HousesType owner);
|
||||
virtual bool Can_Place_Here(COORDINATE ) const {return true;}
|
||||
virtual bool Mark(MarkType mark=MARK_CHANGE);
|
||||
virtual bool Render(bool forced);
|
||||
|
@ -194,10 +196,15 @@ class AnimClass : public ObjectClass, private StageClass {
|
|||
*/
|
||||
AnimClass * VirtualAnim;
|
||||
|
||||
/*
|
||||
** Real-time point to kill this animation.
|
||||
*/
|
||||
unsigned long long KillTime;
|
||||
|
||||
/*
|
||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||
*/
|
||||
unsigned char SaveLoadPadding[32];
|
||||
unsigned char SaveLoadPadding[24];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ struct SoundEffectNameStruct {
|
|||
{"DINOYES", 10, IN_NOVAR}, // VOC_DINOYES Yes Sir in dino-speak.
|
||||
{"DINOATK1", 10, IN_NOVAR}, // VOC_DINOATK1 Dino attack sound.
|
||||
{"DINODIE1", 10, IN_NOVAR}, // VOC_DINODIE1 Dino die sound.
|
||||
{"BEACON", 10, IN_NOVAR }, // VOC_BEACON Beacon sound.
|
||||
|
||||
#ifdef PETROGLYPH_EXAMPLE_MOD
|
||||
{"NUKE_LOB", 10, IN_NOVAR} // VOC_NUKE_LOB Mod expansion unit firing sound
|
||||
|
|
|
@ -2077,7 +2077,7 @@ void BuildingClass::Active_Click_With(ActionType action, CELL cell)
|
|||
OutList.Add(EventClass(EventClass::SELL, As_Target()));
|
||||
|
||||
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord));
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3872,13 +3872,16 @@ bool BuildingClass::Can_Demolish_Unit(void) const
|
|||
|
||||
bool BuildingClass::Can_Capture(void) const
|
||||
{
|
||||
bool can_capture = Class->IsCaptureable;
|
||||
bool can_capture = Class->IsCaptureable && Mission != MISSION_DECONSTRUCTION;
|
||||
|
||||
// Override capturable state if this building has a capture win trigger
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
if (Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
|
||||
if (!House->IsHuman && Trigger != NULL && Trigger->Action == TriggerClass::ACTION_WINLOSE) {
|
||||
can_capture = true;
|
||||
}
|
||||
} else {
|
||||
// Only allow capturing of multiplayer-owned structures
|
||||
can_capture &= House->Class->House >= HOUSE_MULTI1 && House->Class->House <= HOUSE_MULTI6;
|
||||
}
|
||||
|
||||
return(can_capture);
|
||||
|
@ -4161,6 +4164,7 @@ int BuildingClass::Mission_Deconstruction(void)
|
|||
Status = DURING;
|
||||
Begin_Mode(BSTATE_CONSTRUCTION);
|
||||
IsReadyToCommence = false;
|
||||
IsSurvivorless = true;
|
||||
break;
|
||||
}
|
||||
Transmit_Message(RADIO_RUN_AWAY);
|
||||
|
|
|
@ -473,7 +473,7 @@ void BulletClass::AI(void)
|
|||
//
|
||||
if (newanim && Class->Explosion == ANIM_ATOM_BLAST && newanim->OwnerHouse == HOUSE_NONE) {
|
||||
if (Payback && Payback->House && Payback->House->Class) {
|
||||
newanim->OwnerHouse = Payback->House->Class->House;
|
||||
newanim->Set_Owner(Payback->House->Class->House);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -389,7 +389,9 @@ void CellClass::Redraw_Objects(bool forced)
|
|||
if (Cell_Occupier()) {
|
||||
ObjectClass * optr = Cell_Occupier();
|
||||
while (optr) {
|
||||
optr->Mark(MARK_CHANGE);
|
||||
if (optr->IsActive) {
|
||||
optr->Mark(MARK_CHANGE);
|
||||
}
|
||||
optr = optr->Next;
|
||||
}
|
||||
}
|
||||
|
@ -2448,7 +2450,7 @@ void CellClass::Flag_Create(void)
|
|||
CTFFlag = new AnimClass(ANIM_FLAG, Cell_Coord(), 0, 1, true);
|
||||
}
|
||||
assert(CTFFlag != NULL);
|
||||
CTFFlag->OwnerHouse = Owner;
|
||||
CTFFlag->Set_Owner(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2730,11 +2730,11 @@ extern void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int he
|
|||
extern void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip);
|
||||
extern void DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color, int frame);
|
||||
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata, void const * ghostdata, int scale)
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata, void const * ghostdata, int scale, int width, int height)
|
||||
{
|
||||
if (window == WINDOW_VIRTUAL) {
|
||||
int width = Get_Build_Frame_Width(shapefile);
|
||||
int height = Get_Build_Frame_Height(shapefile);
|
||||
if (width == 0) width = Get_Build_Frame_Width(shapefile);
|
||||
if (height == 0) height = Get_Build_Frame_Height(shapefile);
|
||||
DLL_Draw_Intercept(shapenum, x, y, width, height, (int)flags, object, NULL, -1, scale);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1510,11 +1510,13 @@ typedef enum AnimType : char {
|
|||
ANIM_RAPT_DIE,
|
||||
ANIM_CHEM_BALL, // Chemical warrior explosion.
|
||||
ANIM_FLAG, // CTF flag.
|
||||
ANIM_BEACON, // Beacon.
|
||||
|
||||
ANIM_FIRE_SMALL_VIRTUAL, // Small flame animation (virtual).
|
||||
ANIM_FIRE_MED_VIRTUAL, // Medium flame animation (virtual).
|
||||
ANIM_FIRE_MED2_VIRTUAL, // Medium flame animation (oranger) (virtual).
|
||||
ANIM_FIRE_TINY_VIRTUAL, // Very tiny flames (virtual).
|
||||
ANIM_FIRE_SMALL_VIRTUAL, // Small flame animation (virtual).
|
||||
ANIM_FIRE_MED_VIRTUAL, // Medium flame animation (virtual).
|
||||
ANIM_FIRE_MED2_VIRTUAL, // Medium flame animation (oranger) (virtual).
|
||||
ANIM_FIRE_TINY_VIRTUAL, // Very tiny flames (virtual).
|
||||
ANIM_BEACON_VIRTUAL, // Beacon (virtual).
|
||||
|
||||
ANIM_COUNT,
|
||||
ANIM_FIRST=0
|
||||
|
@ -2309,6 +2311,8 @@ typedef enum VocType : char{
|
|||
VOC_DINOATK1, // Dino attack sound.
|
||||
VOC_DINODIE1, // Dino die sound.
|
||||
|
||||
VOC_BEACON, // Beacon sound.
|
||||
|
||||
#ifdef PETROGLYPH_EXAMPLE_MOD
|
||||
VOC_NUKE_LOB, // Modded unit firing sound
|
||||
#endif
|
||||
|
|
|
@ -1107,7 +1107,7 @@ void DisplayClass::Cursor_Mark(CELL pos, bool on)
|
|||
CELL const *ptr;
|
||||
CellClass *cellptr;
|
||||
|
||||
if (pos == -1) return;
|
||||
if ((unsigned)pos >= MAP_CELL_TOTAL) return;
|
||||
|
||||
/*
|
||||
** For every cell in the CursorSize list, invoke its Redraw_Objects and
|
||||
|
@ -2965,6 +2965,7 @@ void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool addit
|
|||
*/
|
||||
if ( obj->Class_Of().IsSelectable &&
|
||||
obj->What_Am_I() != RTTI_BUILDING &&
|
||||
(!obj->Is_Techno() || !((TechnoClass*)obj)->Is_Cloaked(PlayerPtr)) &&
|
||||
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
|
||||
bool old_allow_voice = AllowVoice;
|
||||
bool is_player_controlled = obj->Owner() == PlayerPtr->Class->House;
|
||||
|
@ -2992,6 +2993,7 @@ void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool addit
|
|||
** selected, and are within the bounding box.
|
||||
*/
|
||||
if ( aircraft->Class_Of().IsSelectable &&
|
||||
!aircraft->Is_Cloaked(PlayerPtr) &&
|
||||
!aircraft->Is_Selected_By_Player() &&
|
||||
x >= x1 && x <= x2 && y >= y1 && y <= y2) {
|
||||
bool old_allow_voice = AllowVoice;
|
||||
|
|
|
@ -140,6 +140,7 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
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);
|
||||
extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y);
|
||||
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);
|
||||
|
@ -148,7 +149,7 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty)
|
|||
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);
|
||||
|
||||
extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -390,14 +391,13 @@ void Play_Movie_GlyphX(const char * movie_name, ThemeType theme)
|
|||
|
||||
void On_Sound_Effect(int sound_index, int variation, COORDINATE coord)
|
||||
{
|
||||
// MBL 02.26.2019
|
||||
int voc = sound_index;
|
||||
if (voc == VOC_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// MBL 02.26.2019 - Borrowed from AUDIO.CPP Sound_Effect()
|
||||
// Borrowed from AUDIO.CPP Sound_Effect()
|
||||
//
|
||||
#if 1
|
||||
char const * ext = ""; // ".AUD";
|
||||
|
@ -425,16 +425,12 @@ void On_Sound_Effect(int sound_index, int variation, COORDINATE coord)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
// END MBL
|
||||
|
||||
DLLExportClass::On_Sound_Effect(PlayerPtr, sound_index, ext, variation, coord);
|
||||
}
|
||||
|
||||
// MBL 02.06.2020
|
||||
// void On_Speech(int speech_index)
|
||||
void On_Speech(int speech_index, HouseClass *house)
|
||||
{
|
||||
// DLLExportClass::On_Speech(PlayerPtr, speech_index); // MBL 02.06.2020
|
||||
if (house == NULL) {
|
||||
DLLExportClass::On_Speech(PlayerPtr, speech_index);
|
||||
}
|
||||
|
@ -504,7 +500,6 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line,
|
|||
|
||||
DLL_Startup(command_line);
|
||||
|
||||
// MBL
|
||||
DLLExportClass::Set_Event_Callback( event_callback );
|
||||
|
||||
DLLExportClass::Init();
|
||||
|
@ -879,7 +874,7 @@ void GlyphX_Assign_Houses(void)
|
|||
preassigned = true;
|
||||
}
|
||||
}
|
||||
if (!preassigned) {
|
||||
if (!preassigned && i < MAX_PLAYERS) {
|
||||
random_start_locations[num_random_start_locations] = num_start_locations;
|
||||
num_random_start_locations++;
|
||||
}
|
||||
|
@ -1334,6 +1329,10 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Custom_Instance(const ch
|
|||
|
||||
GlyphXClientSidebarWidthInLeptons = 0;
|
||||
|
||||
Play_Movie(IntroMovie);
|
||||
Play_Movie(BriefMovie);
|
||||
Play_Movie(ActionMovie, TransitTheme);
|
||||
|
||||
/*
|
||||
if (!Start_Scenario(ScenarioName)) {
|
||||
return(false);
|
||||
|
@ -1701,13 +1700,13 @@ extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const cha
|
|||
|
||||
result = Load_Game(file_path_and_name);
|
||||
|
||||
// MBL 07.21.2020
|
||||
if (result == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
|
||||
DLLExportClass::Cancel_Placement(DLLExportClass::GlyphxPlayerIDs[0], -1, -1);
|
||||
Set_Logic_Page(SeenBuff);
|
||||
VisiblePage.Clear();
|
||||
Map.Flag_To_Redraw(true);
|
||||
|
@ -1860,6 +1859,24 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time)
|
|||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* CNC_Get_Start_Game_Info
|
||||
*
|
||||
* History: 8/31/2020 11:37AM - 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* DLLExportClass::Init -- Init the class
|
||||
*
|
||||
|
@ -3682,6 +3699,31 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Input(InputRequestEnum
|
|||
break;
|
||||
}
|
||||
|
||||
// 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;
|
||||
_Kbd->MouseQX = x1;
|
||||
_Kbd->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;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3806,7 +3848,7 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(Sidebar
|
|||
|
||||
switch (request_type) {
|
||||
|
||||
// MBL 06.02.2020 - 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
|
||||
// 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
|
||||
// Handle and fall through to start construction (from hold state) below
|
||||
case SIDEBAR_REQUEST_START_CONSTRUCTION_MULTI:
|
||||
|
||||
|
@ -6851,6 +6893,39 @@ extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Debug_Request(DebugRequ
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
|
||||
*
|
||||
|
|
|
@ -28,7 +28,7 @@ struct CarryoverObjectStruct;
|
|||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x101
|
||||
#include "DLLInterfaceVersion.h"
|
||||
|
||||
|
||||
|
||||
|
@ -421,7 +421,11 @@ enum InputRequestEnum {
|
|||
INPUT_REQUEST_SELL_AT_POSITION,
|
||||
INPUT_REQUEST_SELECT_AT_POSITION,
|
||||
INPUT_REQUEST_COMMAND_AT_POSITION,
|
||||
INPUT_REQUEST_SPECIAL_KEYS
|
||||
INPUT_REQUEST_SPECIAL_KEYS,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION,
|
||||
INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION,
|
||||
};
|
||||
|
||||
|
||||
|
@ -472,6 +476,18 @@ enum GameRequestEnum {
|
|||
};
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
**
|
||||
** Beacon Requests
|
||||
**
|
||||
**
|
||||
*/
|
||||
enum BeaconRequestEnum {
|
||||
INPUT_BEACON_NONE,
|
||||
INPUT_BEACON_PLACE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
**
|
||||
|
|
33
TIBERIANDAWN/DLLInterfaceVersion.h
Normal file
33
TIBERIANDAWN/DLLInterfaceVersion.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// 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
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DLL_INTERFACE_VERSION_H
|
||||
#define DLL_INTERFACE_VERSION_H
|
||||
|
||||
|
||||
/*
|
||||
** DLL Interface version
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
#define CNC_DLL_API_VERSION 0x102
|
||||
|
||||
|
||||
|
||||
#endif //DLL_INTERFACE_VERSION_H
|
|
@ -250,7 +250,7 @@ EventClass::EventClass(EventType type, TARGET src, TARGET dest)
|
|||
* HISTORY: *
|
||||
* 05/19/1995 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord)
|
||||
EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord, int visible)
|
||||
{
|
||||
ID = Houses.ID(PlayerPtr);
|
||||
Type = ANIMATION;
|
||||
|
@ -258,6 +258,7 @@ EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord)
|
|||
Data.Anim.What = anim;
|
||||
Data.Anim.Owner = owner;
|
||||
Data.Anim.Where = coord;
|
||||
Data.Anim.Visible = visible;
|
||||
}
|
||||
|
||||
|
||||
|
@ -506,14 +507,26 @@ CCDebugString ("C&C95 - Sell packet received\n");
|
|||
case ANIMATION:
|
||||
anim = new AnimClass(Data.Anim.What, Data.Anim.Where);
|
||||
if (anim) {
|
||||
//2019/09/19 JAS - Visibility needs to be determined per player
|
||||
if (Data.Anim.What != ANIM_MOVE_FLASH || Data.Anim.Owner == HOUSE_NONE || Special.IsVisibleTarget)
|
||||
anim->Set_Owner(Data.Anim.Owner);
|
||||
|
||||
if (Special.IsVisibleTarget)
|
||||
{
|
||||
anim->Set_Visible_Flags(static_cast<unsigned int>(-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
anim->Set_Visible_Flags(1 << Data.Anim.Owner);
|
||||
anim->Set_Visible_Flags(static_cast<unsigned int>(Data.Anim.Visible));
|
||||
}
|
||||
|
||||
/*
|
||||
** Beacons have a 30-second kill time.
|
||||
*/
|
||||
if (Data.Anim.What == ANIM_BEACON) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
unsigned long long kill_time = ((unsigned long long)ft.dwLowDateTime + ((unsigned long long)ft.dwHighDateTime << 32ULL)) + 300000000ULL;
|
||||
anim->Kill_At(kill_time);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -127,6 +127,7 @@ class EventClass
|
|||
AnimType What; // The animation to create.
|
||||
HousesType Owner; // The owner of the animation (when it matters).
|
||||
COORDINATE Where; // The location to place the animation.
|
||||
int Visible; // Who this animation is visible to.
|
||||
} Anim;
|
||||
struct {
|
||||
int Value; // general-purpose data
|
||||
|
@ -208,7 +209,7 @@ class EventClass
|
|||
EventClass(EventType type, RTTIType object, int id);
|
||||
EventClass(EventType type, RTTIType object, CELL cell);
|
||||
EventClass(EventType type, int id, CELL cell);
|
||||
EventClass(AnimType anim, HousesType owner, COORDINATE coord);
|
||||
EventClass(AnimType anim, HousesType owner, COORDINATE coord, int visible = -1);
|
||||
|
||||
// Process the event.
|
||||
void Execute(void);
|
||||
|
|
|
@ -305,14 +305,20 @@ bool FootClass::Mark(MarkType mark)
|
|||
/*
|
||||
** Inform the map of the refresh, occupation, and overlap
|
||||
** request.
|
||||
** Special case is fixed-wing aircraft, which are never placed
|
||||
** or picked up since they can never land.
|
||||
*/
|
||||
switch (mark) {
|
||||
case MARK_UP:
|
||||
Map.Pick_Up(cell, this);
|
||||
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
|
||||
Map.Pick_Up(cell, this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MARK_DOWN:
|
||||
Map.Place_Down(cell, this);
|
||||
if (What_Am_I() != RTTI_AIRCRAFT || !((AircraftClass*)this)->Class->IsFixedWing) {
|
||||
Map.Place_Down(cell, this);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -947,8 +953,10 @@ void FootClass::Approach_Target(void)
|
|||
/*
|
||||
** If a suitable intermediate location was found, then head toward it.
|
||||
** Otherwise, head toward the enemy unit directly.
|
||||
** Infantry always head towards the target since they can enter a cell
|
||||
** in range, but still not be able to hit the target if the spot is out of range.
|
||||
*/
|
||||
if (found) {
|
||||
if (found && What_Am_I() != RTTI_INFANTRY) {
|
||||
Assign_Destination(::As_Target(trycell));
|
||||
} else {
|
||||
Assign_Destination(TarCom);
|
||||
|
@ -990,6 +998,20 @@ int FootClass::Mission_Guard_Area(void)
|
|||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
|
||||
/*
|
||||
** Ensure units aren't trying to guard cells off the map.
|
||||
*/
|
||||
if (Target_Legal(NavCom) && Is_Target_Cell(NavCom)) {
|
||||
CELL cell = As_Cell(NavCom);
|
||||
int x = Cell_X(cell);
|
||||
int y = Cell_Y(cell);
|
||||
if (x < Map.MapCellX || y < Map.MapCellY || x >= (Map.MapCellX + Map.MapCellWidth) || y >= (Map.MapCellY + Map.MapCellHeight)) {
|
||||
Assign_Target(TARGET_NONE);
|
||||
Assign_Destination(TARGET_NONE);
|
||||
ArchiveTarget = ::As_Target(Coord_Cell(Coord));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure that the unit has not strayed too far from the home position.
|
||||
** If it has, then race back to it.
|
||||
|
@ -1320,7 +1342,7 @@ void FootClass::Active_Click_With(ActionType action, CELL cell)
|
|||
case ACTION_MOVE:
|
||||
if (AllowVoice) {
|
||||
COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord));
|
||||
OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
|
||||
}
|
||||
// Fall into next case.
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ void const *Get_Radar_Icon(void const *shapefile, int shapenum, int frames, int
|
|||
void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0);
|
||||
|
||||
// Added for draw intercept. ST - 1/17/2019 12:31PM
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0, int scale=0x100);
|
||||
void CC_Draw_Shape(ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata=0, void const * ghostdata=0, int scale=0x100, int width=0, int height=0);
|
||||
void CC_Draw_Shape(ObjectClass *object, const char *shape_file_name, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata = 0, void const * ghostdata = 0, char override_owner = HOUSE_NONE);
|
||||
|
||||
// Added for pip draw intercept - SKY
|
||||
|
|
|
@ -560,7 +560,7 @@ DynamicVectorClass <int> MPlayerFilenum;
|
|||
/***************************************************************************
|
||||
** This value determines the max allowable # of players.
|
||||
*/
|
||||
int MPlayerMax = 4;
|
||||
int MPlayerMax = 6;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
|
|
@ -1673,14 +1673,13 @@ void HouseClass::Attacked(BuildingClass* source)
|
|||
{
|
||||
Validate();
|
||||
|
||||
bool expired = SpeakAttackDelay.Expired();
|
||||
bool spoke = false;
|
||||
if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
|
||||
|
||||
// if (SpeakAttackDelay.Expired() && PlayerPtr->Class->House == Class->House) {
|
||||
if (expired && PlayerPtr->Class->House == Class->House) {
|
||||
|
||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||
spoke = true;
|
||||
if (GameToPlay == GAME_NORMAL) {
|
||||
Speak(VOX_BASE_UNDER_ATTACK, NULL, source ? source->Center_Coord() : 0);
|
||||
} else {
|
||||
Speak(VOX_BASE_UNDER_ATTACK, this);
|
||||
}
|
||||
|
||||
// MBL 06.13.2020 - Timing change from 2 minute cooldown, per https://jaas.ea.com/browse/TDRA-6784
|
||||
// SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
|
||||
|
@ -1695,23 +1694,6 @@ void HouseClass::Attacked(BuildingClass* source)
|
|||
HouseTriggers[Class->House][index]->Spring(EVENT_ATTACKED, Class->House);
|
||||
}
|
||||
}
|
||||
|
||||
// MBL 07.07.2020 - CNC Patch 3, fix for not working for all players in MP, per https://jaas.ea.com/browse/TDRA-7249
|
||||
// Separated to here as did not want to change any logic around the HouseTriggers[] Spring events
|
||||
//
|
||||
if (expired == true && spoke == false)
|
||||
{
|
||||
if (GameToPlay != GAME_NORMAL) // Multiplayer
|
||||
{
|
||||
Speak(VOX_BASE_UNDER_ATTACK, this);
|
||||
spoke = true;
|
||||
|
||||
// SpeakAttackDelay.Set(Options.Normalize_Delay(SPEAK_DELAY)); // 2 minutes
|
||||
// SpeakAttackDelay.Set(Options.Normalize_Delay(TICKS_PER_MINUTE/2)); // 30 seconds as requested
|
||||
SpeakAttackDelay.Set(Options.Normalize_Delay( (TICKS_PER_MINUTE/2)+(TICKS_PER_SECOND*5) )); // Tweaked for accuracy
|
||||
}
|
||||
}
|
||||
// END MBL 07.07.2020
|
||||
}
|
||||
|
||||
|
||||
|
@ -2584,7 +2566,15 @@ ProdFailType HouseClass::Abandon_Production(RTTIType type)
|
|||
if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
|
||||
if (IsHuman) {
|
||||
Sidebar_Glyphx_Abandon_Production(type, *factory, this);
|
||||
// Need to clear pending object here?
|
||||
|
||||
// Need to clear pending object here if legacy renderer enabled
|
||||
|
||||
if (type == RTTI_BUILDINGTYPE || type == RTTI_BUILDING && Map.PendingObjectPtr) {
|
||||
Map.PendingObjectPtr = 0;
|
||||
Map.PendingObject = 0;
|
||||
Map.PendingHouse = HOUSE_NONE;
|
||||
Map.Set_Cursor_Shape(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
|
@ -2692,7 +2682,7 @@ bool HouseClass::Place_Special_Blast(SpecialWeaponType id, CELL cell)
|
|||
case SPC_ION_CANNON:
|
||||
if (IonCannon.Is_Ready()) {
|
||||
anim = new AnimClass(ANIM_ION_CANNON, Cell_Coord(cell));
|
||||
if (anim) anim->OwnerHouse = Class->House;
|
||||
if (anim) anim->Set_Owner(Class->House);
|
||||
if (this == PlayerPtr) {
|
||||
Map.IsTargettingMode = false;
|
||||
}
|
||||
|
|
|
@ -444,6 +444,7 @@ class HouseClass {
|
|||
bool Is_Ally(HousesType house) const;
|
||||
bool Is_Ally(HouseClass const * house) const;
|
||||
bool Is_Ally(ObjectClass const * object) const;
|
||||
unsigned int Get_Allies(void) const {return Allies;}
|
||||
#ifdef CHEAT_KEYS
|
||||
void Debug_Dump(MonoClass *mono) const;
|
||||
#endif
|
||||
|
@ -517,6 +518,9 @@ class HouseClass {
|
|||
void Init_Unit_Trackers(void);
|
||||
void Free_Unit_Trackers(void);
|
||||
|
||||
// MBL 09.08.2020 Mod support stub
|
||||
void Handle_Mod_Game_Command(CELL cell, int mod_command_index); // mod_command_index = 0-3
|
||||
|
||||
#ifdef USE_RA_AI
|
||||
/*
|
||||
** AI Functions imported from RA
|
||||
|
|
|
@ -677,6 +677,10 @@ void InfantryClass::Per_Cell_Process(bool center)
|
|||
*/
|
||||
if (center && Mission == MISSION_CAPTURE) {
|
||||
TechnoClass * tech = cellptr->Cell_Techno();
|
||||
if (tech && tech->As_Target() == NavCom && tech->What_Am_I() == RTTI_BUILDING && !tech->Can_Capture()) {
|
||||
tech = NULL;
|
||||
Assign_Destination(TARGET_NONE);
|
||||
}
|
||||
if (tech && tech->As_Target() == NavCom) {
|
||||
tech->Captured(House);
|
||||
Delete_This();
|
||||
|
|
|
@ -491,11 +491,15 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
|||
** Build the full text of the mission objective.
|
||||
*/
|
||||
for (;;) {
|
||||
char buff[16];
|
||||
int len = (sizeof(BriefingText)-strlen(BriefingText))-1;
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char buff[16];
|
||||
sprintf(buff, "%d", index++);
|
||||
*stage = '\0';
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, (sizeof(BriefingText)-strlen(BriefingText))-1, buffer);
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, len, buffer);
|
||||
if (strlen(stage) == 0) break;
|
||||
strcat(stage, " ");
|
||||
stage += strlen(stage);
|
||||
|
@ -541,6 +545,7 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
|||
** NOD09A - delete airstrike trigger when radar destroyed
|
||||
** NOD10B cell 2015 - LAND_ROCK
|
||||
** NOD13B - trigger AI production when the player reaches the transports
|
||||
- fix repeating airstrike trigger
|
||||
** NOD13C - delete airstrike trigger when radar destroyed
|
||||
*/
|
||||
if (_stricmp(ScenarioName, "scb07ea") == 0) {
|
||||
|
@ -572,6 +577,10 @@ bool Read_Scenario_Ini(char *root, bool fresh)
|
|||
CellTriggers[340] = prod; prod->AttachCount++;
|
||||
CellTriggers[404] = prod; prod->AttachCount++;
|
||||
CellTriggers[468] = prod; prod->AttachCount++;
|
||||
|
||||
TriggerClass* xxxx = TriggerClass::As_Pointer("xxxx");
|
||||
assert(xxxx != NULL);
|
||||
xxxx->IsPersistant = TriggerClass::PERSISTANT;
|
||||
}
|
||||
if (_stricmp(ScenarioName, "scb13ec") == 0) {
|
||||
for (int index = 0; index < Buildings.Count(); ++index) {
|
||||
|
@ -920,11 +929,15 @@ bool Read_Scenario_Ini_File(char *scenario_file_name, char* bin_file_name, const
|
|||
** Build the full text of the mission objective.
|
||||
*/
|
||||
for (;;) {
|
||||
char buff[16];
|
||||
int len = (sizeof(BriefingText) - strlen(BriefingText)) - 1;
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char buff[16];
|
||||
sprintf(buff, "%d", index++);
|
||||
*stage = '\0';
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, (sizeof(BriefingText) - strlen(BriefingText)) - 1, buffer);
|
||||
WWGetPrivateProfileString("Briefing", buff, "", stage, len, buffer);
|
||||
if (strlen(stage) == 0) break;
|
||||
strcat(stage, " ");
|
||||
stage += strlen(stage);
|
||||
|
|
|
@ -1560,6 +1560,10 @@ bool UnitClass::Save(FileClass & file)
|
|||
*=============================================================================================*/
|
||||
void UnitClass::Code_Pointers(void)
|
||||
{
|
||||
if (TiberiumUnloadRefinery) {
|
||||
TiberiumUnloadRefinery = (BuildingClass *)TiberiumUnloadRefinery->As_Target();
|
||||
}
|
||||
|
||||
TarComClass::Code_Pointers();
|
||||
}
|
||||
|
||||
|
@ -1584,6 +1588,11 @@ void UnitClass::Code_Pointers(void)
|
|||
*=============================================================================================*/
|
||||
void UnitClass::Decode_Pointers(void)
|
||||
{
|
||||
if (TiberiumUnloadRefinery) {
|
||||
TiberiumUnloadRefinery = As_Building((TARGET)TiberiumUnloadRefinery, false);
|
||||
Check_Ptr((void *)TiberiumUnloadRefinery, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
TarComClass::Decode_Pointers();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
Electronic Arts Inc. released only TiberianDawn.dll, RedAlert.dll and
|
||||
the Command & Conquer Map Editor and their corresponding source code
|
||||
under the GPL V3 below, with additional terms at the bottom.
|
||||
Electronic Arts Inc. released only TiberianDawn.dll and RedAlert.dll and their corresponding source code under the GPL V3 below, with additional terms at the bottom.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
@ -711,4 +709,4 @@ PROVIDED BY ELECTRONIC ARTS OR ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A
|
|||
WARRANTY. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON
|
||||
IMPLIED WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY NOT APPLY
|
||||
TO YOU.
|
||||
TO YOU.
|
|
@ -428,7 +428,7 @@ dxisbig:
|
|||
#if (0)
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#97 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/MiscAsm.cpp#131 $
|
||||
;***************************************************************************
|
||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||
;***************************************************************************
|
||||
|
|
|
@ -317,7 +317,7 @@ int DLL_Startup(const char * command_line_in)
|
|||
if (Parse_Command_Line(argc, argv)) {
|
||||
|
||||
WindowsTimer = new WinTimerClass(60,FALSE);
|
||||
|
||||
#if (0)
|
||||
int time_test = WindowsTimer->Get_System_Tick_Count();
|
||||
Sleep (1000);
|
||||
if (WindowsTimer->Get_System_Tick_Count() == time_test){
|
||||
|
@ -332,6 +332,7 @@ int DLL_Startup(const char * command_line_in)
|
|||
#endif //FRENCH
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
RawFileClass cfile("CONQUER.INI");
|
||||
|
||||
|
|
|
@ -1402,7 +1402,7 @@ bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, Techno
|
|||
** If the scan is limited to capturable buildings only, then bail if the examined
|
||||
** object isn't a capturable building.
|
||||
*/
|
||||
if ((method & THREAT_CAPTURE) && (otype != RTTI_BUILDING || !((BuildingTypeClass const *)tclass)->IsCaptureable)) {
|
||||
if ((method & THREAT_CAPTURE) && (otype != RTTI_BUILDING || !object->Can_Capture())) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@
|
|||
<ClInclude Include="DIAL8.H" />
|
||||
<ClInclude Include="DISPLAY.H" />
|
||||
<ClInclude Include="DLLInterface.h" />
|
||||
<ClInclude Include="DLLInterfaceVersion.h" />
|
||||
<ClInclude Include="DOOR.H" />
|
||||
<ClInclude Include="DPMI.H" />
|
||||
<ClInclude Include="DRIVE.H" />
|
||||
|
|
|
@ -627,6 +627,9 @@
|
|||
<ClInclude Include="RULES.H">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DLLInterfaceVersion.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AADATA.CPP">
|
||||
|
|
|
@ -396,6 +396,20 @@ void UnitClass::AI(void)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the unload refinery if not haresting or entering a refinery.
|
||||
*/
|
||||
if (Class->IsToHarvest) {
|
||||
if (Mission != MISSION_HARVEST) {
|
||||
if (Mission != MISSION_ENTER ||
|
||||
!In_Radio_Contact() ||
|
||||
Contact_With_Whom()->What_Am_I() != RTTI_BUILDING ||
|
||||
*((BuildingClass*)Contact_With_Whom()) != STRUCT_REFINERY) {
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Rocket launchers will reload every so often.
|
||||
*/
|
||||
|
@ -1198,6 +1212,7 @@ UnitClass::UnitClass(UnitType classid, HousesType house) :
|
|||
Reload = 0;
|
||||
Ammo = Class->MaxAmmo;
|
||||
IsCloakable = Class->IsCloakable;
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
if (Class->IsAnimating) Set_Rate(Options.Normalize_Delay(3));
|
||||
|
||||
/*
|
||||
|
@ -2345,29 +2360,47 @@ bool UnitClass::Goto_Tiberium(void)
|
|||
int tiberium = 0;
|
||||
int besttiberium = 0;
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
|
||||
/*
|
||||
** Randomize the corners.
|
||||
*/
|
||||
int corner[2];
|
||||
int corners[4][2] = {
|
||||
{x, -radius},
|
||||
{x, +radius},
|
||||
{-radius, x},
|
||||
{+radius, x}
|
||||
};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int j = i + rand() / (RAND_MAX / (4 - i) + 1);
|
||||
memcpy(&corner, &corners[j], sizeof(corner));
|
||||
memcpy(&corners[j], &corners[i], sizeof(corner));
|
||||
memcpy(&corners[i], corner, sizeof(corner));
|
||||
}
|
||||
|
||||
cell = center;
|
||||
tiberium = Tiberium_Check(cell, x, -radius);
|
||||
tiberium = Tiberium_Check(cell, corners[0][0], corners[0][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
tiberium = Tiberium_Check(cell, x, +radius);
|
||||
tiberium = Tiberium_Check(cell, corners[1][0], corners[1][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
tiberium = Tiberium_Check(cell, -radius, x);
|
||||
tiberium = Tiberium_Check(cell, corners[2][0], corners[2][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
}
|
||||
|
||||
cell = center;
|
||||
tiberium = Tiberium_Check(cell, +radius, x);
|
||||
tiberium = Tiberium_Check(cell, corners[3][0], corners[3][1]);
|
||||
if (tiberium > besttiberium) {
|
||||
bestcell = cell;
|
||||
besttiberium = tiberium;
|
||||
|
@ -2385,6 +2418,96 @@ bool UnitClass::Goto_Tiberium(void)
|
|||
}
|
||||
|
||||
|
||||
struct RefineryData
|
||||
{
|
||||
BuildingClass* Refinery;
|
||||
int Distance;
|
||||
int Harvesters;
|
||||
};
|
||||
|
||||
static bool operator==(const RefineryData& lhs, const RefineryData& rhs)
|
||||
{
|
||||
return lhs.Refinery == rhs.Refinery;
|
||||
}
|
||||
|
||||
static bool operator!=(const RefineryData& lhs, const RefineryData& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
static int _refinery_compare(const void * left, const void * right)
|
||||
{
|
||||
const RefineryData& lhs = *reinterpret_cast<const RefineryData*>(left);
|
||||
const RefineryData& rhs = *reinterpret_cast<const RefineryData*>(right);
|
||||
if (lhs.Distance < rhs.Distance) {
|
||||
return -1;
|
||||
} else if (rhs.Distance < lhs.Distance) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BuildingClass* UnitClass::Find_Best_Refinery(void) const
|
||||
{
|
||||
static DynamicVectorClass<RefineryData> _refineries;
|
||||
|
||||
_refineries.Clear();
|
||||
for (int i = 0; i < Buildings.Count(); ++i) {
|
||||
BuildingClass* refinery = Buildings.Ptr(i);
|
||||
if (refinery != NULL &&
|
||||
refinery->House == House &&
|
||||
!refinery->IsInLimbo &&
|
||||
*refinery == STRUCT_REFINERY) {
|
||||
_refineries.Add(RefineryData{ refinery, Distance(refinery), 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// Base case for zero or one refineries.
|
||||
if (_refineries.Count() == 0) {
|
||||
return NULL;
|
||||
} else if (_refineries.Count() == 1) {
|
||||
return _refineries[0].Refinery;
|
||||
}
|
||||
|
||||
// Count harvesters going to each refinery as well as the total.
|
||||
int num_harvesters = 0;
|
||||
for (int i = 0; i < Units.Count(); ++i) {
|
||||
UnitClass* unit = Units.Ptr(i);
|
||||
if (unit->IsActive && unit->Class->IsToHarvest && unit->House == House) {
|
||||
BuildingClass* refinery = unit->Tiberium_Unload_Refinery();
|
||||
if (refinery != NULL) {
|
||||
int index = _refineries.ID(RefineryData{ refinery });
|
||||
assert(index >= 0);
|
||||
_refineries[index].Harvesters++;
|
||||
num_harvesters++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by distance (special case for 2 refineries as that's a single swap).
|
||||
if (_refineries.Count() == 2) {
|
||||
if (_refineries[0].Distance > _refineries[1].Distance) {
|
||||
RefineryData temp = _refineries[0];
|
||||
_refineries[0] = _refineries[1];
|
||||
_refineries[1] = temp;
|
||||
}
|
||||
} else {
|
||||
qsort(&_refineries[0], _refineries.Count(), sizeof(RefineryData), _refinery_compare);
|
||||
}
|
||||
|
||||
// Evenly distribute harvesters among refineries.
|
||||
int harvesters_per_refinery = (num_harvesters + _refineries.Count() - 1) / _refineries.Count();
|
||||
for (int i = 0; i < _refineries.Count(); ++i) {
|
||||
if (_refineries[i].Harvesters < harvesters_per_refinery) {
|
||||
return _refineries[i].Refinery;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back on closest refinery
|
||||
return _refineries[0].Refinery;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* UnitClass::Harvesting -- Harvests tiberium at the current location. *
|
||||
* *
|
||||
|
@ -2677,7 +2800,10 @@ int UnitClass::Mission_Harvest(void)
|
|||
Assign_Target(TARGET_NONE);
|
||||
Status = FINDHOME;
|
||||
return(1);
|
||||
} else if (Goto_Tiberium()) {
|
||||
}
|
||||
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
if (Goto_Tiberium()) {
|
||||
IsHarvesting = true;
|
||||
Set_Rate(2);
|
||||
Set_Stage(0);
|
||||
|
@ -2739,21 +2865,14 @@ int UnitClass::Mission_Harvest(void)
|
|||
if (!Target_Legal(NavCom)) {
|
||||
|
||||
/*
|
||||
** Find nearby refinery and head to it?
|
||||
** Find nearby refinery and head to it.
|
||||
*/
|
||||
BuildingClass * nearest = Find_Docking_Bay(STRUCT_REFINERY, false);
|
||||
|
||||
/*
|
||||
** Since the refinery said it was ok to load, establish radio
|
||||
** contact with the refinery and then await docking orders.
|
||||
*/
|
||||
if (nearest && Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
|
||||
Status = HEADINGHOME;
|
||||
} else {
|
||||
ScenarioInit++;
|
||||
nearest = Find_Docking_Bay(STRUCT_REFINERY, false);
|
||||
ScenarioInit--;
|
||||
if (nearest) {
|
||||
BuildingClass * nearest = Find_Best_Refinery();
|
||||
if (nearest) {
|
||||
TiberiumUnloadRefinery = nearest;
|
||||
if (Transmit_Message(RADIO_HELLO, nearest) == RADIO_ROGER) {
|
||||
Status = HEADINGHOME;
|
||||
} else {
|
||||
Assign_Destination(::As_Target(nearest->Nearby_Location(this)));
|
||||
}
|
||||
}
|
||||
|
@ -2770,6 +2889,7 @@ int UnitClass::Mission_Harvest(void)
|
|||
return(1);
|
||||
|
||||
case GOINGTOIDLE:
|
||||
TiberiumUnloadRefinery = NULL;
|
||||
Assign_Mission(MISSION_GUARD);
|
||||
break;
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ class UnitClass : public TarComClass
|
|||
bool Harvesting(void);
|
||||
void APC_Close_Door(void);
|
||||
void APC_Open_Door(void);
|
||||
BuildingClass* Tiberium_Unload_Refinery(void) const {return TiberiumUnloadRefinery;}
|
||||
BuildingClass* Find_Best_Refinery(void) const;
|
||||
|
||||
/*
|
||||
** Query functions.
|
||||
|
@ -199,10 +201,15 @@ class UnitClass : public TarComClass
|
|||
*/
|
||||
TCountDownTimerClass HarvestTimer;
|
||||
|
||||
/*
|
||||
** This is the refinery a harvester is interested in unloading at.
|
||||
*/
|
||||
BuildingClass* TiberiumUnloadRefinery;
|
||||
|
||||
/*
|
||||
** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load
|
||||
*/
|
||||
unsigned char SaveLoadPadding[32];
|
||||
unsigned char SaveLoadPadding[28];
|
||||
|
||||
/*
|
||||
** This contains the value of the Virtual Function Table Pointer
|
||||
|
|
|
@ -4841,7 +4841,7 @@ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int wi
|
|||
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#97 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/DrawMisc.cpp#131 $
|
||||
;***************************************************************************
|
||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||
;***************************************************************************
|
||||
|
|
|
@ -321,7 +321,7 @@ int __cdecl Desired_Facing8(long x1, long y1, long x2, long y2);
|
|||
|
||||
|
||||
/*
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#97 $
|
||||
; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/TIBERIANDAWN/WIN32LIB/FACINGFF.h#131 $
|
||||
;***************************************************************************
|
||||
;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
|
||||
;***************************************************************************
|
||||
|
|
Reference in a new issue