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:
PG-SteveT 2020-09-16 10:03:04 -07:00
parent e37e174be1
commit fd05be35c1
68 changed files with 1313 additions and 267 deletions

View file

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

View file

@ -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)) {

View file

@ -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);
}
}

View file

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

View file

@ -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

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

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

View file

@ -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

View file

@ -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;

View file

@ -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
*

View file

@ -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,
};
/**************************************************************************************
**

View 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

View file

@ -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;

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -560,7 +560,7 @@ DynamicVectorClass <int> MPlayerFilenum;
/***************************************************************************
** This value determines the max allowable # of players.
*/
int MPlayerMax = 4;
int MPlayerMax = 6;
/***************************************************************************

View file

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

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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();
}

View file

@ -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.

View file

@ -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 **
;***************************************************************************

View file

@ -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");

View file

@ -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);
}

View file

@ -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" />

View file

@ -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">

View file

@ -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;

View file

@ -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

View file

@ -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 **
;***************************************************************************

View file

@ -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 **
;***************************************************************************