diff -urN sourceold/scripts/ConnectionRequest.h source/scripts/ConnectionRequest.h --- sourceold/scripts/ConnectionRequest.h 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/ConnectionRequest.h 2024-02-14 04:13:36.550373900 -0600 @@ -27,4 +27,5 @@ float clientVersion; uint clientRevisionNumber; WideStringClass password; + StringClass clientHardwareIdentifier; }; diff -urN sourceold/scripts/HUDSurfaceClass.h source/scripts/HUDSurfaceClass.h --- sourceold/scripts/HUDSurfaceClass.h 1969-12-31 18:00:00.000000000 -0600 +++ source/scripts/HUDSurfaceClass.h 2024-02-14 04:13:36.565998100 -0600 @@ -0,0 +1,200 @@ +/* Renegade Scripts.dll + Copyright 2023 Tiberian Technologies + + This file is part of the Renegade scripts.dll + The Renegade scripts.dll 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 2, or (at your option) any later + version. See the file COPYING for more details. + In addition, an exemption is given to allow Run Time Dynamic Linking of this code with any closed source module that does not contain code covered by this licence. + Only the source code to the module(s) containing the licenced code has to be released. +*/ + +#pragma once + +#include "engine_string.h" +#include "engine_vector.h" +#include "vector2.h" +#include "vector4.h" +#include "rect.h" + +typedef enum { + HUD_ELEMENT_LINE, + HUD_ELEMENT_RECTANGLE, + HUD_ELEMENT_OUTLINE, + HUD_ELEMENT_TEXT, + HUD_ELEMENT_MAX // Do NOT use! +} HUDElementType; + +typedef enum { + HUD_FONT_TITLE, + HUD_FONT_BIG_HEADER, + HUD_FONT_SMALL_HEADER, + HUD_FONT_BIG_BODY, + HUD_FONT_NORMAL_BODY, + HUD_FONT_SUBTITLE, + HUD_FONT_MAX // Do NOT use! +} HUDFontType; + +class HUDElementClass; +class HUDLineElementClass; +class HUDRectangleElementClass; +class HUDOutlineElementClass; +class HUDTextElementClass; + +class HUDSurfaceClass +{ +public: + HUDSurfaceClass(int client, int srf_id); + virtual ~HUDSurfaceClass(); + + int Get_Surface_ID() const { return id; } + int Get_Client_ID() const { return clientId; } + bool Is_Dirty() const { return isDirty; } + void Set_Dirty(bool dirty) { isDirty = dirty; } + const Vector2& Get_Boundary_Area() const { return boundary; } + float Get_Aspect_Ratio() const { return boundary.Y > WWMATH_EPSILON ? boundary.X / boundary.Y : 0; } + const StringClass& Get_Surface_Texture() const { return surfaceTexture; } + void Set_Surface_Texture(const char* texture) { surfaceTexture = texture; Set_Dirty(true); } + + virtual void Add_Element(HUDElementClass* element); + virtual HUDElementClass* Create_Element(HUDElementType type); + virtual HUDElementClass* Find_Element(int id); + virtual int Get_Element_Count(); + virtual HUDElementClass* Get_Element_Index(int index); + virtual void Remove_Element(int id); + virtual void Remove_Element(HUDElementClass* element); + virtual void Clear_Elements(); + +protected: + int id; + int clientId; + Vector2 boundary; + StringClass surfaceTexture; + DynamicVectorClass elements; + bool isDirty; +}; + +class HUDElementClass +{ +public: + HUDElementClass(int elem_id); + virtual ~HUDElementClass(); + + virtual HUDElementType Get_Element_Type() const = 0; + virtual HUDLineElementClass* As_HUDLineElementClass() { return NULL; } + virtual HUDRectangleElementClass* As_HUDRectangleElementClass() { return NULL; } + virtual HUDOutlineElementClass* As_HUDOutlineElementClass() { return NULL; } + virtual HUDTextElementClass* As_HUDTextElementClass() { return NULL; } + + int Get_Element_ID() const { return elementId; } + bool Is_Dirty() const { return isDirty; } + void Set_Dirty(bool dirty) { isDirty = dirty; } + bool Is_Rendered() const { return isRendered; } + void Set_Rendered(bool rendered) { isRendered = rendered; Set_Dirty(true); } + const RectClass& Get_UV_Range() const { return uvRange; } + void Set_UV_Range(const RectClass& newRange) { uvRange = newRange; Set_Dirty(true); } + +protected: + int elementId; + bool isDirty; + bool isRendered; + RectClass uvRange; +}; + +class HUDLineElementClass : public HUDElementClass { +public: + HUDLineElementClass(int elem_id); + + virtual HUDElementType Get_Element_Type() const { return HUD_ELEMENT_LINE; } + virtual HUDLineElementClass* As_HUDLineElementClass() { return this; } + + const Vector2& Get_P0() const { return p0; } + void Set_P0(const Vector2& newP0) { p0 = newP0; Set_Dirty(true); } + const Vector2& Get_P1() const { return p1; } + void Set_P1(const Vector2& newP1) { p1 = newP1; Set_Dirty(true); } + float Get_Length() const { return Vector2::Distance(p1, p0); } + float Get_Thickness() const { return thickness; } + void Set_Thickness(float newThickness) { thickness = newThickness; Set_Dirty(true); } + const Vector4& Get_Color() const { return color; } + void Set_Color(const Vector4& newColor) { color = newColor; Set_Dirty(true); } + void Set_Color(int a, int r, int g, int b) { color = Vector4(a / 255.f, r / 255.f, g / 255.f, b / 255.f); Set_Dirty(true); } + +protected: + Vector2 p0; + Vector2 p1; + float thickness; + Vector4 color; +}; + +class HUDRectangleElementClass : public HUDElementClass { +public: + HUDRectangleElementClass(int elem_id); + + virtual HUDElementType Get_Element_Type() const { return HUD_ELEMENT_RECTANGLE; } + virtual HUDRectangleElementClass* As_HUDRectangleElementClass() { return this; } + + const RectClass& Get_Rect() const { return rect; } + void Set_Rect(const RectClass& newRect) { rect = newRect; Set_Dirty(true); } + float Get_Area() const { const Vector2& a = rect.getSize(); return a.X * a.Y; } + float Get_Diagonal_Length() const { return rect.Extent().Length() * 2; } + const Vector4& Get_Color() const { return color; } + void Set_Color(const Vector4& newColor) { color = newColor; Set_Dirty(true); } + void Set_Color(int a, int r, int g, int b) { color = Vector4(a / 255.f, r / 255.f, g / 255.f, b / 255.f); Set_Dirty(true); } + +protected: + RectClass rect; + Vector4 color; +}; + +class HUDOutlineElementClass : public HUDElementClass { +public: + HUDOutlineElementClass(int elem_id); + + virtual HUDElementType Get_Element_Type() const { return HUD_ELEMENT_OUTLINE; } + virtual HUDOutlineElementClass* As_HUDOutlineElementClass() { return this; } + + const RectClass& Get_Rect() const { return rect; } + void Set_Rect(const RectClass& newRect) { rect = newRect; Set_Dirty(true); } + float Get_Area() const { const Vector2& a = rect.getSize(); return a.X * a.Y; } + float Get_Diagonal_Length() const { return rect.Extent().Length() * 2; } + float Get_Thickness() const { return thickness; } + void Set_Thickness(float newThickness) { thickness = newThickness; Set_Dirty(true); } + const Vector4& Get_Color() const { return color; } + void Set_Color(const Vector4& newColor) { color = newColor; Set_Dirty(true); } + void Set_Color(int a, int r, int g, int b) { color = Vector4(a / 255.f, r / 255.f, g / 255.f, b / 255.f); Set_Dirty(true); } + +protected: + RectClass rect; + float thickness; + Vector4 color; +}; + +class HUDTextElementClass : public HUDElementClass { +public: + HUDTextElementClass(int elem_id); + + virtual HUDElementType Get_Element_Type() const { return HUD_ELEMENT_TEXT; } + virtual HUDTextElementClass* As_HUDTextElementClass() { return this; } + + const WideStringClass& Get_Text() const { return text; } + void Set_Text(const wchar_t* newText) { text = newText; Set_Dirty(true); } + HUDFontType Get_Font() const { return font; } + void Set_Font(HUDFontType newFont) { font = newFont; Set_Dirty(true); } + const RectClass& Get_Clipping_Area() const { return clipArea; } + void Set_Clipping_Area(const RectClass& newArea) { clipArea = newArea; Set_Dirty(true); } + float Get_Clipping_Area_Size() const { const Vector2& a = clipArea.getSize(); return a.X * a.Y; } + float Get_Clipping_Area_Diagonal_Length() const { return clipArea.Extent().Length() * 2; } + bool Is_Clipping_Enabled() const { return clipEnabled; } + void Set_Clipping_Enabled(bool enabled) { clipEnabled = enabled; Set_Dirty(true); } + const Vector4& Get_Color() const { return color; } + void Set_Color(const Vector4& newColor) { color = newColor; Set_Dirty(true); } + void Set_Color(int a, int r, int g, int b) { color = Vector4(a / 255.f, r / 255.f, g / 255.f, b / 255.f); Set_Dirty(true); } + +protected: + WideStringClass text; + HUDFontType font; + RectClass clipArea; + bool clipEnabled; + Vector4 color; +}; \ No newline at end of file diff -urN sourceold/scripts/ScriptedControlClass.h source/scripts/ScriptedControlClass.h --- sourceold/scripts/ScriptedControlClass.h 2023-02-23 04:22:38.000000000 -0600 +++ source/scripts/ScriptedControlClass.h 2024-02-14 04:13:36.597247800 -0600 @@ -24,6 +24,7 @@ class ScriptedComboBoxControlClass; class ScriptedSliderControlClass; class ScriptedProgressBarControlClass; +class ScriptedHealthBarControlClass; typedef enum { @@ -34,7 +35,8 @@ CONTROLTYPE_CHECKBOX, CONTROLTYPE_COMBOBOX, CONTROLTYPE_SLIDER, - CONTROLTYPE_PROGRESSBAR + CONTROLTYPE_PROGRESSBAR, + CONTROLTYPE_HEALTHBAR } ControlType; class ScriptedControlClass @@ -52,6 +54,7 @@ virtual ScriptedComboBoxControlClass* As_ScriptedComboBoxControlClass() { return NULL; } virtual ScriptedSliderControlClass* As_ScriptedSliderControlClass() { return NULL; } virtual ScriptedProgressBarControlClass* As_ScriptedProgressBarControlClass() { return NULL; } + virtual ScriptedHealthBarControlClass* As_ScriptedHealthBarControlClass() { return NULL; } int Get_Control_ID() { return controlId; } const Vector2& Get_Location() { return location; } diff -urN sourceold/scripts/ScriptedControls.h source/scripts/ScriptedControls.h --- sourceold/scripts/ScriptedControls.h 2023-02-23 04:22:52.000000000 -0600 +++ source/scripts/ScriptedControls.h 2024-02-14 04:13:36.597247800 -0600 @@ -18,6 +18,14 @@ typedef enum { + TEXTSTYLE_BODY, + TEXTSTYLE_TITLE, + TEXTSTYLE_LARGE_CONTROL, + TEXTSTYLE_TOOLTIP +} TextStyle; + +typedef enum +{ TEXTORIENTATION_LEFT, TEXTORIENTATION_CENTER, TEXTORIENTATION_RIGHT @@ -45,14 +53,14 @@ const Vector3& Get_Text_Color() { return color; } void Set_Text_Color(Vector3& newColor) { color = newColor; Set_Dirty(true); } void Set_Text_Color(int r, int g, int b) { color.X = r / 255.f; color.Y = g / 255.f; color.Z = b / 255.f; Set_Dirty(true); } - bool Get_Is_Title() { return isTitle; } - void Set_Is_Title(bool title) { isTitle = title; Set_Dirty(true); } + TextStyle Get_Style() { return style; } + void Set_Style(TextStyle newStyle) { style = newStyle; Set_Dirty(true); } TextOrientation Get_Orientation() { return orientation; } void Set_Orientation(TextOrientation newOrientation) { orientation = newOrientation; Set_Dirty(true); } private: WideStringClass text; Vector3 color; - bool isTitle; + TextStyle style; TextOrientation orientation; }; @@ -221,3 +229,20 @@ }; /********************************************************************************/ + +class ScriptedHealthBarControlClass : public ScriptedControlClass +{ +public: + ScriptedHealthBarControlClass(int ctl_id); + + virtual ControlType Get_Control_Type() { return CONTROLTYPE_HEALTHBAR; } + virtual ScriptedHealthBarControlClass* As_ScriptedHealthBarControlClass() { return this; } + + float Get_Life() { return life; } + void Set_Life(float newLife) { life = WWMath::Clamp(newLife); Set_Dirty(true); } + +private: + float life; +}; + +/********************************************************************************/ \ No newline at end of file diff -urN sourceold/scripts/ScriptedDialogClass.h source/scripts/ScriptedDialogClass.h --- sourceold/scripts/ScriptedDialogClass.h 2023-02-23 04:22:42.000000000 -0600 +++ source/scripts/ScriptedDialogClass.h 2024-02-14 04:13:36.597247800 -0600 @@ -44,7 +44,7 @@ { public: ScriptedDialogClass(int client, int dlg_id); - ~ScriptedDialogClass(); + virtual ~ScriptedDialogClass(); virtual DialogType Get_Dialog_Type() = 0; virtual ScriptedMenuDialogClass* As_ScriptedMenuDialogClass() { return NULL; } @@ -63,6 +63,7 @@ virtual void Remove_Control(int id); virtual void Remove_Control(ScriptedControlClass* control); virtual void Clear_Controls(); + virtual void Focus_Control(ScriptedControlClass* control); protected: int id; @@ -75,7 +76,7 @@ { public: ScriptedMenuDialogClass(int client, int dlg_id); - ~ScriptedMenuDialogClass(); + virtual ~ScriptedMenuDialogClass(); virtual DialogType Get_Dialog_Type() { return DIALOGTYPE_MENU; } virtual ScriptedMenuDialogClass* As_ScriptedMenuDialogClass() { return this; } @@ -85,7 +86,7 @@ { public: ScriptedPopupDialogClass(int client, int dlg_id); - ~ScriptedPopupDialogClass(); + virtual ~ScriptedPopupDialogClass(); virtual DialogType Get_Dialog_Type() { return DIALOGTYPE_POPUP; } virtual ScriptedPopupDialogClass* As_ScriptedPopupDialogClass() { return this; } diff -urN sourceold/scripts/WeaponClass.h source/scripts/WeaponClass.h --- sourceold/scripts/WeaponClass.h 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/WeaponClass.h 2024-02-14 04:13:36.612871700 -0600 @@ -211,6 +211,7 @@ bool tiltGunWhileReloading; public: static void Set_Ammo_By_WeaponId_No_Networking(GameObject *obj,int weaponId,int clipBullets,int inventoryRounds); + float Get_State_Timer( void ) { return StateTimer; } }; // 00AC #endif \ No newline at end of file diff -urN sourceold/scripts/agtfix.cpp source/scripts/agtfix.cpp --- sourceold/scripts/agtfix.cpp 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/agtfix.cpp 2024-02-14 04:13:36.612871700 -0600 @@ -16,7 +16,9 @@ #include "engine_obj.h" #include "BuildingGameObj.h" #include "BuildingAggregateClass.h" - +#include "engine_def.h" +#include "engine_tt.h" + void GDI_AGT::Created(GameObject* AGTObj) { Commands->Enable_Hibernation(AGTObj,false); @@ -141,6 +143,14 @@ GameObject* MissileObj = Commands->Create_Object("GDI_AGT", MissilePos); if (MissileObj) { + if (DefinitionClass* Def = Find_Definition(Get_Int_Parameter("MissileDef"))) + { + if (Def->Get_Class_ID() == CID_Weapon) + { + Grant_Weapon(MissileObj, Def->Get_Name(), true, -1, true); + Commands->Select_Weapon(MissileObj, Def->Get_Name()); + } + } Set_Object_Type(MissileObj, Get_Object_Type(AGTObj)); Commands->Attach_Script(MissileObj, "GDI_AGT_Missile", "0"); MissileID = Commands->Get_ID(MissileObj); @@ -151,6 +161,14 @@ GameObject* GunObj = Commands->Create_Object("GDI_Ceiling_Gun_AGT", GunPos[i]); if (GunObj) { + if (DefinitionClass* Def = Find_Definition(Get_Int_Parameter("GunDef"))) + { + if (Def->Get_Class_ID() == CID_Weapon) + { + Grant_Weapon(MissileObj, Def->Get_Name(), true, -1, true); + Commands->Select_Weapon(MissileObj, Def->Get_Name()); + } + } Set_Object_Type(GunObj, Get_Object_Type(AGTObj)); Commands->Attach_Script(GunObj, "GDI_AGT_Gun", ""); Commands->Send_Custom_Event(AGTObj, GunObj, 0, MissileID, 0); @@ -352,7 +370,7 @@ -ScriptRegistrant M00_Advanced_Guard_Tower_Registrant("M00_Advanced_Guard_Tower", ""); -ScriptRegistrant GDI_AGT_Registrant("GDI_AGT", ""); +ScriptRegistrant M00_Advanced_Guard_Tower_Registrant("M00_Advanced_Guard_Tower", "MissileDef=0:int,GunDef=0:int"); +ScriptRegistrant GDI_AGT_Registrant("GDI_AGT", "MissileDef=0:int,GunDef=0:int"); ScriptRegistrant GDI_AGT_Gun_Registrant("GDI_AGT_Gun", ""); ScriptRegistrant GDI_AGT_Missile_Registrant("GDI_AGT_Missile", ""); \ No newline at end of file diff -urN sourceold/scripts/dllmain.cpp source/scripts/dllmain.cpp --- sourceold/scripts/dllmain.cpp 2023-02-01 09:01:36.000000000 -0600 +++ source/scripts/dllmain.cpp 2024-02-14 04:13:36.612871700 -0600 @@ -437,6 +437,42 @@ Print_Client_Console_Player = (pccp)Address(tt, "Print_Client_Console_Player"); Reload_Level = (rl)Address(tt, "Reload_Level"); Force_Client_Reload = (fcr)Address(tt, "Force_Client_Reload"); + Change_Enemy_HUD_Color = (chudc)Address(tt, "Change_Enemy_HUD_Color"); + Change_Enemy_HUD_Color_Player = (chudcp)Address(tt, "Change_Enemy_HUD_Color_Player"); + Change_Friendly_HUD_Color = (chudc)Address(tt, "Change_Friendly_HUD_Color"); + Change_Friendly_HUD_Color_Player = (chudcp)Address(tt, "Change_Friendly_HUD_Color_Player"); + Change_Neutral_HUD_Color = (chudc)Address(tt, "Change_Neutral_HUD_Color"); + Change_Neutral_HUD_Color_Player = (chudcp)Address(tt, "Change_Neutral_HUD_Color_Player"); + Enable_Global_Targeting = (egt)Address(tt, "Enable_Global_Targeting"); + Enable_Global_Targeting_Player = (egtp)Address(tt, "Enable_Global_Targeting_Player"); + Get_Screen_Resolution = (gsr)Address(tt, "Get_Screen_Resolution"); + Create_HUD_Surface = (chs)Address(tt, "Create_HUD_Surface"); + Find_HUD_Surface = (fhs)Address(tt, "Find_HUD_Surface"); + Show_HUD_Surface = (hudsfc)Address(tt, "Show_HUD_Surface"); + Hide_HUD_Surface = (hudsfc)Address(tt, "Hide_HUD_Surface"); + Delete_HUD_Surface = (hudsfc)Address(tt, "Delete_HUD_Surface"); + Get_Client_Hardware_Identifier = (gcsh)Address(tt, "Get_Client_Hardware_Identifier"); + Is_Overriding_Sky_Colors = (iosc)Address(tt, "Is_Overriding_Sky_Colors"); + Override_Sky_Colors = (osc)Address(tt, "Override_Sky_Colors"); + Get_Warm_Sky_Color = (spgui)Address(tt, "Get_Warm_Sky_Color"); + Get_Cold_Sky_Color = (spgui)Address(tt, "Get_Cold_Sky_Color"); + Get_Sun_Color = (spgui)Address(tt, "Get_Sun_Color"); + Get_Sun_Halo_Color = (spgui)Address(tt, "Get_Sun_Halo_Color"); + Get_Moon_Halo_Color = (spgui)Address(tt, "Get_Moon_Halo_Color"); + Get_Starfield_Alpha = (spguc)Address(tt, "Get_Starfield_Alpha"); + Get_Sky_Color = (spgui)Address(tt, "Get_Sky_Color"); + Get_Gloominess_Color = (spgui)Address(tt, "Get_Gloominess_Color"); + Set_Warm_Sky_Color = (spsui)Address(tt, "Set_Warm_Sky_Color"); + Set_Cold_Sky_Color = (spsui)Address(tt, "Set_Cold_Sky_Color"); + Set_Sun_Color = (spsui)Address(tt, "Set_Sun_Color"); + Set_Sun_Halo_Color = (spsui)Address(tt, "Set_Sun_Halo_Color"); + Set_Moon_Halo_Color = (spsui)Address(tt, "Set_Moon_Halo_Color"); + Set_Starfield_Alpha = (spsuc)Address(tt, "Set_Starfield_Alpha"); + Set_Sky_Color = (spsui)Address(tt, "Set_Sky_Color"); + Set_Gloominess_Color = (spsui)Address(tt, "Set_Gloominess_Color"); + Get_Time_Of_Day = (gtod)Address(tt, "Get_Time_Of_Day"); + Set_Time_Of_Day = (stod)Address(tt, "Set_Time_Of_Day"); + Is_Connection_Bad = (icbad)Address(tt, "Is_Connection_Bad"); #ifdef SSGM SSGMGameManager::Init(); diff -urN sourceold/scripts/dp88_ar_unitScripts.cpp source/scripts/dp88_ar_unitScripts.cpp --- sourceold/scripts/dp88_ar_unitScripts.cpp 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/dp88_ar_unitScripts.cpp 2024-02-14 04:13:36.628496700 -0600 @@ -875,8 +875,8 @@ "Modifier_Target_Value=0.05:float," "Requires_Power=1:int," "Debug=0:int," - "Detects_Stealth=1:int" -); + "Detects_Stealth=1:int," + "Reload_Before_Charge=0:int"); // IFV ScriptRegistrant dp88_AR_IFV_Registrant( "dp88_AR_IFV", "Turret_Frames_Animation=v_all_ifv.v_all_ifv:string,Switch_Time=10:int,Switching_Anim_Frame=2:int,Keyhook=VDeploy:string,String:int,Color:vector3,Sound:string" ); diff -urN sourceold/scripts/dp88_customAI.cpp source/scripts/dp88_customAI.cpp --- sourceold/scripts/dp88_customAI.cpp 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/dp88_customAI.cpp 2024-02-14 04:13:36.628496700 -0600 @@ -17,6 +17,7 @@ #include "dp88_customAI.h" #include "dp88_custom_timer_defines.h" #include "VehicleGameObj.h" +#include "WeaponClass.h" /*------------------------ Base class for custom AI's @@ -1198,292 +1199,309 @@ // Charged Turret AI // ------------------------------------------------------------------------------------------------- -void dp88_AI_ChargedTurret::Init(GameObject* pSelf) -{ - dp88_AI_Turret::Init(pSelf); - - m_myObjId = Commands->Get_ID(pSelf); - m_bIsCharging = false; - m_bIsDischarging = false; - m_bIsPreReloading = false; - m_chargeAnimObjId = NULL; - m_pAnimationObserver = NULL; - - // If a seperate charge animation model has been specified then go ahead and spawn it - if (strlen(Get_Parameter("Animation_Model")) > 0) - { - GameObject* pChargeAnimObj = Commands->Create_Object("Invisible_Object", Commands->Get_Position(pSelf)); - if (NULL != pChargeAnimObj) - { - m_chargeAnimObjId = Commands->Get_ID(pChargeAnimObj); - Commands->Set_Model(pChargeAnimObj, Get_Parameter("Animation_Model")); - Commands->Attach_To_Object_Bone(pChargeAnimObj, pSelf, Get_Parameter("Animation_Model_Bone")); - - // Create the looped animation controller on the charge animation object and attach an observer - // so we know when the charge animation is completed - m_pLoopedAnimCtrl = new LoopedAnimationController(pChargeAnimObj); - m_pAnimationObserver = new dp88_AI_ChargedTurret_AnimationObserver(this); - pChargeAnimObj->Add_Observer(m_pAnimationObserver); - } - } - - // If we don't have a charge animation object create the looped animation controller on ourselves - if (NULL == m_chargeAnimObjId) - m_pLoopedAnimCtrl = new LoopedAnimationController(pSelf); - - m_bPowerState = checkPowerState(pSelf); - ApplyIdleAnimation(pSelf); -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::loadSettings(GameObject* pSelf, bool loadSecondaryFireSettings, bool loadBuildingTargetSettings) -{ - dp88_AI_Turret::loadSettings(pSelf, loadSecondaryFireSettings, loadBuildingTargetSettings); - - // Not currently loading any settings... probably should add this sometime... -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::Timer_Expired(GameObject* pSelf, int number) -{ - // Use the existing custom AI think timer to check for a base power state changes and, if it has - // changed, update the idle animation (and abort any charge up in progress) - if (number == TIMER_AI_THINK && m_bPowerState != checkPowerState(pSelf)) - { - m_bPowerState = !m_bPowerState; - - // Charging state must always become false now - either we were unpowered to begin with or - // we were powered and have now gone offline. Either way, we can't possibly be charging now. - m_bIsCharging = false; - - // If we were discharging our weapon we need to stop now and trigger a reload so we don't - // fire a partial charge next time around - if (m_bIsDischarging) - { - m_bIsDischarging = false; - stopAttacking(pSelf); - Set_Current_Bullets(pSelf, 0); - } - - // Apply the appropriate idle animation - ApplyIdleAnimation(pSelf); - } - - - // We might as well piggy back the discharged checks on the same timer too whilst we are at it... - if (number == TIMER_AI_THINK && m_bIsDischarging) - { - // Have we unloaded our entire clip? If so then we can start charging for the next attack - if (0 == Get_Current_Bullets(pSelf)) - { - m_bIsDischarging = false; - stopAttacking(pSelf); // Don't want to fire again before we are ready! - - // todo: set bpreloading as appropriate - - if (m_target) - StartCharging(pSelf); - else - ApplyIdleAnimation(pSelf); - } - - // Has our target already died or ran like a coward before we could empty our clip? If so then - // reset and trigger a reload (so we don't have a partial charge next time round) - else if (!m_target) - { - m_bIsDischarging = false; - Set_Current_Bullets(pSelf, 0); - - // todo: set bpreloading as appropriate - - ApplyIdleAnimation(pSelf); - } - } - - - if (number == TIMER_AI_CHARGE_PRERELOAD_COMPLETE && m_bIsPreReloading) - { - m_bIsPreReloading = false; - if (m_target) - StartCharging(pSelf); - } - - dp88_AI_Turret::Timer_Expired(pSelf, number); -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::Animation_Complete(GameObject* obj, const char* animation_name) -{ - bool bSenderIsObserver = (NULL != m_chargeAnimObjId && Commands->Get_ID(obj) == m_chargeAnimObjId); - - // Only trigger on the name of the charge animation - if (0 == _stricmp(animation_name, Get_Parameter("Animation"))) - { - StartDischarging(bSenderIsObserver ? Commands->Find_Object(m_myObjId) : obj); - } - - if (!bSenderIsObserver) - dp88_AI_Turret::Animation_Complete(obj, animation_name); -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::Destroyed(GameObject* pSelf) -{ - if (NULL != m_pLoopedAnimCtrl) - { - delete m_pLoopedAnimCtrl; - m_pLoopedAnimCtrl = NULL; - } - - GameObject* pChargeAnimObj = (NULL != m_chargeAnimObjId) ? Commands->Find_Object(m_chargeAnimObjId) : NULL; - m_chargeAnimObjId = NULL; - - if (NULL != m_pAnimationObserver) - { - if (NULL != pChargeAnimObj) - pChargeAnimObj->Remove_Observer(m_pAnimationObserver); - - delete m_pAnimationObserver; - m_pAnimationObserver = NULL; - } - - if (NULL != pChargeAnimObj) - { - Commands->Destroy_Object(pChargeAnimObj); - } -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::attackTarget(GameObject* pSelf, GameObject* pTarget, bool primary) -{ - // Changing targets in the middle of discharging? Sure, why not... - if (m_bIsDischarging) - dp88_AI_Turret::attackTarget(pSelf, pTarget, primary); - - // Otherwise call StartCharging and let it determine what to do... - StartCharging(pSelf); -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::attackLocation(GameObject* pSelf, Vector3 location, bool primary) -{ - // Changing targets in the middle of discharging? Sure, why not... - if (m_bIsDischarging) - dp88_AI_Turret::attackLocation(pSelf, location, primary); - - // Otherwise call StartCharging and let it determine what to do... - StartCharging(pSelf); -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::StartCharging(GameObject* pSelf) -{ - // If we are not charging, not discharging, powered and have a target then we can start a new - // charging cycle - if (!m_bIsPreReloading && !m_bIsCharging && !m_bIsDischarging && checkPowerState(pSelf) && m_target) - { - m_bIsCharging = true; - - // Only play a single iteration of the charge up animation - if we need to keep attacking after - // the shot is fired this will get called again - m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Charge_Start_Frame"), Get_Int_Parameter("Animation_Charge_End_Frame"), 1); - - if (_stricmp(Get_Parameter("Charge_Sound"), "0")) - Commands->Create_Sound(Get_Parameter("Charge_Sound"), Commands->Get_Position(pSelf), pSelf); - - // Nothing to do but wait for the charging to complete... hum de dum... - } -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::StartDischarging(GameObject* pSelf) -{ - // Were we charging up? If so we are now fully charged and can start shooting stuff, if we still - // have a valid target... - if (m_bIsCharging) - { - m_bIsCharging = false; - - // Got an enemy? Also double check power state whilst we are here, just to be sure - if (m_target && checkPowerState(pSelf)) +void dp88_AI_ChargedTurret::Init(GameObject* pSelf) +{ + dp88_AI_Turret::Init(pSelf); + + m_myObjId = Commands->Get_ID(pSelf); + m_bIsCharging = false; + m_bIsDischarging = false; + m_bIsPreReloading = false; + m_chargeAnimObjId = NULL; + m_pAnimationObserver = NULL; + + // If a seperate charge animation model has been specified then go ahead and spawn it + if (strlen(Get_Parameter("Animation_Model")) > 0) + { + GameObject* pChargeAnimObj = Commands->Create_Object("Invisible_Object", Commands->Get_Position(pSelf)); + if (NULL != pChargeAnimObj) + { + m_chargeAnimObjId = Commands->Get_ID(pChargeAnimObj); + Commands->Set_Model(pChargeAnimObj, Get_Parameter("Animation_Model")); + Commands->Attach_To_Object_Bone(pChargeAnimObj, pSelf, Get_Parameter("Animation_Model_Bone")); + + // Create the looped animation controller on the charge animation object and attach an observer + // so we know when the charge animation is completed + m_pLoopedAnimCtrl = new LoopedAnimationController(pChargeAnimObj); + m_pAnimationObserver = new dp88_AI_ChargedTurret_AnimationObserver(this); + pChargeAnimObj->Add_Observer(m_pAnimationObserver); + } + } + + // If we don't have a charge animation object create the looped animation controller on ourselves + if (NULL == m_chargeAnimObjId) + m_pLoopedAnimCtrl = new LoopedAnimationController(pSelf); + + m_bPowerState = checkPowerState(pSelf); + ApplyIdleAnimation(pSelf); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::loadSettings(GameObject* pSelf, bool loadSecondaryFireSettings, bool loadBuildingTargetSettings) +{ + dp88_AI_Turret::loadSettings(pSelf, loadSecondaryFireSettings, loadBuildingTargetSettings); + + // Not currently loading any settings... probably should add this sometime... +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::Timer_Expired(GameObject* pSelf, int number) +{ + // Use the existing custom AI think timer to check for a base power state changes and, if it has + // changed, update the idle animation (and abort any charge up in progress) + if (number == TIMER_AI_THINK && m_bPowerState != checkPowerState(pSelf)) + { + m_bPowerState = !m_bPowerState; + m_target = 0; + + // Charging state must always become false now - either we were unpowered to begin with or + // we were powered and have now gone offline. Either way, we can't possibly be charging now. + m_bIsCharging = false; + + // If we were discharging our weapon we need to stop now and trigger a reload so we don't + // fire a partial charge next time around + if (m_bIsDischarging) + { + m_bIsDischarging = false; + stopAttacking(pSelf); + Set_Current_Bullets(pSelf, 0); + } + + // Apply the appropriate idle animation + ApplyIdleAnimation(pSelf); + } + + + // We might as well piggy back the discharged checks on the same timer too whilst we are at it... + if (number == TIMER_AI_THINK && m_bIsDischarging) + { + // Have we unloaded our entire clip? If so then we can start charging for the next attack + if (0 == Get_Current_Bullets(pSelf)) + { + m_bIsDischarging = false; + stopAttacking(pSelf); // Don't want to fire again before we are ready! + + // todo: set bpreloading as appropriate + + if (m_target) + StartCharging(pSelf); + else + ApplyIdleAnimation(pSelf); + } + + // Has our target already died or ran like a coward before we could empty our clip? If so then + // reset and trigger a reload (so we don't have a partial charge next time round) + else if (!m_target || Commands->Get_Health(m_target) <= 0) + { + m_target = 0; + m_bIsDischarging = false; + Set_Current_Bullets(pSelf, 0); + + // todo: set bpreloading as appropriate + + ApplyIdleAnimation(pSelf); + } + } + + + if (number == TIMER_AI_CHARGE_PRERELOAD_COMPLETE && m_bIsPreReloading) + { + m_bIsPreReloading = false; + if (m_target) + StartCharging(pSelf); + else + ApplyIdleAnimation(pSelf); + } + + dp88_AI_Turret::Timer_Expired(pSelf, number); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::Animation_Complete(GameObject* obj, const char* animation_name) +{ + bool bSenderIsObserver = (NULL != m_chargeAnimObjId && Commands->Get_ID(obj) == m_chargeAnimObjId); + + // Only trigger on the name of the charge animation + if (0 == _stricmp(animation_name, Get_Parameter("Animation"))) + { + StartDischarging(bSenderIsObserver ? Commands->Find_Object(m_myObjId) : obj); + } + + if (!bSenderIsObserver) + dp88_AI_Turret::Animation_Complete(obj, animation_name); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::Destroyed(GameObject* pSelf) +{ + if (NULL != m_pLoopedAnimCtrl) + { + delete m_pLoopedAnimCtrl; + m_pLoopedAnimCtrl = NULL; + } + + GameObject* pChargeAnimObj = (NULL != m_chargeAnimObjId) ? Commands->Find_Object(m_chargeAnimObjId) : NULL; + m_chargeAnimObjId = NULL; + + if (NULL != m_pAnimationObserver) + { + if (NULL != pChargeAnimObj) + pChargeAnimObj->Remove_Observer(m_pAnimationObserver); + + delete m_pAnimationObserver; + m_pAnimationObserver = NULL; + } + + if (NULL != pChargeAnimObj) + { + Commands->Destroy_Object(pChargeAnimObj); + } +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::attackTarget(GameObject* pSelf, GameObject* pTarget, bool primary) +{ + // Changing targets in the middle of discharging? Sure, why not... + if (m_bIsDischarging) + dp88_AI_Turret::attackTarget(pSelf, pTarget, primary); + + // Otherwise call StartCharging and let it determine what to do... + StartCharging(pSelf); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::attackLocation(GameObject* pSelf, Vector3 location, bool primary) +{ + // Changing targets in the middle of discharging? Sure, why not... + if (m_bIsDischarging) + dp88_AI_Turret::attackLocation(pSelf, location, primary); + + // Otherwise call StartCharging and let it determine what to do... + StartCharging(pSelf); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::StartCharging(GameObject* pSelf) +{ + // If we are not charging, not discharging, powered and have a target then we can start a new + // charging cycle + if (!m_bIsPreReloading && !m_bIsCharging && !m_bIsDischarging && checkPowerState(pSelf) && m_target) + { + if ( Get_Int_Parameter("Reload_Before_Charge") && pSelf->As_SmartGameObj() && pSelf->As_SmartGameObj()->Get_Weapon() && pSelf->As_SmartGameObj()->Get_Weapon()->Get_State() != WeaponClass::STATE_IDLE && pSelf->As_SmartGameObj()->Get_Weapon()->Get_State() != WeaponClass::STATE_READY) + { + Commands->Start_Timer(pSelf, this, pSelf->As_SmartGameObj()->Get_Weapon()->Get_State_Timer(), TIMER_AI_CHARGE_PRERELOAD_COMPLETE); + m_bIsPreReloading = true; + return; + } + + m_bIsCharging = true; + + // Only play a single iteration of the charge up animation - if we need to keep attacking after + // the shot is fired this will get called again + m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Charge_Start_Frame"), Get_Int_Parameter("Animation_Charge_End_Frame"), 1); + + if (_stricmp(Get_Parameter("Charge_Sound"), "0")) + Commands->Create_Sound(Get_Parameter("Charge_Sound"), Commands->Get_Position(pSelf), pSelf); + + // Nothing to do but wait for the charging to complete... hum de dum... + } +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::StartDischarging(GameObject* pSelf) +{ + // Were we charging up? If so we are now fully charged and can start shooting stuff, if we still + // have a valid target... + if (m_bIsCharging) + { + m_bIsCharging = false; + + // Got an enemy? Also double check power state whilst we are here, just to be sure + if (m_target && checkPowerState(pSelf) && Commands->Get_Health(m_target) > 0) + { + m_bIsDischarging = true; + + // Call into the base class and let it do it's thing + if (splashInfantry && m_target->As_SoldierGameObj()) + dp88_AI_Turret::attackLocation(pSelf, Commands->Get_Position(m_target), m_bTargetPrimaryFire); + else + dp88_AI_Turret::attackTarget(pSelf, m_target, m_bTargetPrimaryFire); + } + + else { - m_bIsDischarging = true; - - // Call into the base class and let it do it's thing - if (splashInfantry && m_target->As_SoldierGameObj()) - dp88_AI_Turret::attackLocation(pSelf, Commands->Get_Position(m_target), m_bTargetPrimaryFire); - else - dp88_AI_Turret::attackTarget(pSelf, m_target, m_bTargetPrimaryFire); - } - - // If we didn't find anything to shoot at then apply the idle animation again - if (!m_bIsDischarging) - ApplyIdleAnimation(pSelf); - } -} - -// ------------------------------------------------------------------------------------------------- - -GameObject* dp88_AI_ChargedTurret::GetAnimationObject(GameObject* pSelf) -{ - if (NULL != m_chargeAnimObjId) - return Commands->Find_Object(m_chargeAnimObjId); - return pSelf; -} - -// ------------------------------------------------------------------------------------------------- - -void dp88_AI_ChargedTurret::ApplyIdleAnimation(GameObject* pSelf) -{ - // Apply the correct animation frames for the uncharged state dependant upon base power conditions, - // which should already have been updated before calling this function - if (m_bPowerState) - m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Idle_Start_Frame"), Get_Int_Parameter("Animation_Idle_End_Frame")); - else - m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Unpowered_Start_Frame"), Get_Int_Parameter("Animation_Unpowered_End_Frame")); -} - -// ------------------------------------------------------------------------------------------------- - -ScriptRegistrant dp88_AI_ChargedTurret_Registrant( - "dp88_AI_ChargedTurret", - "Priority_Infantry=1.0:float," - "Weapon_Infantry=1:int," - "Splash_Infantry=0:int," - "Priority_Light_Vehicle=5.0:float," - "Weapon_Light_Vehicle=1:int," - "Priority_Heavy_Vehicle=7.0:float," - "Weapon_Heavy_Vehicle=1:int," - "Priority_VTOL=5.0:float," - "Weapon_VTOL=1:int," - "Min_Attack_Range=0:int," - "Max_Attack_Range=150:int," - "Min_Attack_Range_Secondary=0:int," - "Max_Attack_Range_Secondary=150:int," - "Animation_Model:string," - "Animation_Model_Bone:string," - "Animation:string," - "Animation_Idle_Start_Frame:int," - "Animation_Idle_End_Frame:int," - "Animation_Unpowered_Start_Frame:int," - "Animation_Unpowered_End_Frame:int," - "Animation_Charge_Start_Frame:int," - "Animation_Charge_End_Frame:int," - "Charge_Sound:string," - "Modifier_Distance=0.25:float," - "Modifier_Target_Damage=0.1:float," - "Modifier_Target_Value=0.05:float," - "Requires_Power=0:int," - "Debug=0:int," - "Detects_Stealth=1:int"); + m_target = 0; + } + + // If we didn't find anything to shoot at then apply the idle animation again + if (!m_bIsDischarging) + ApplyIdleAnimation(pSelf); + } +} + +// ------------------------------------------------------------------------------------------------- + +GameObject* dp88_AI_ChargedTurret::GetAnimationObject(GameObject* pSelf) +{ + if (NULL != m_chargeAnimObjId) + return Commands->Find_Object(m_chargeAnimObjId); + return pSelf; +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_ChargedTurret::ApplyIdleAnimation(GameObject* pSelf) +{ + // Apply the correct animation frames for the uncharged state dependant upon base power conditions, + // which should already have been updated before calling this function + if (m_bPowerState) + m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Idle_Start_Frame"), Get_Int_Parameter("Animation_Idle_End_Frame")); + else + m_pLoopedAnimCtrl->PlayAnimation(Get_Parameter("Animation"), Get_Int_Parameter("Animation_Unpowered_Start_Frame"), Get_Int_Parameter("Animation_Unpowered_End_Frame")); +} + +// ------------------------------------------------------------------------------------------------- + +ScriptRegistrant dp88_AI_ChargedTurret_Registrant( + "dp88_AI_ChargedTurret", + "Priority_Infantry=1.0:float," + "Weapon_Infantry=1:int," + "Splash_Infantry=0:int," + "Priority_Light_Vehicle=5.0:float," + "Weapon_Light_Vehicle=1:int," + "Priority_Heavy_Vehicle=7.0:float," + "Weapon_Heavy_Vehicle=1:int," + "Priority_VTOL=5.0:float," + "Weapon_VTOL=1:int," + "Min_Attack_Range=0:int," + "Max_Attack_Range=150:int," + "Min_Attack_Range_Secondary=0:int," + "Max_Attack_Range_Secondary=150:int," + "Animation_Model:string," + "Animation_Model_Bone:string," + "Animation:string," + "Animation_Idle_Start_Frame:int," + "Animation_Idle_End_Frame:int," + "Animation_Unpowered_Start_Frame:int," + "Animation_Unpowered_End_Frame:int," + "Animation_Charge_Start_Frame:int," + "Animation_Charge_End_Frame:int," + "Charge_Sound:string," + "Modifier_Distance=0.25:float," + "Modifier_Target_Damage=0.1:float," + "Modifier_Target_Value=0.05:float," + "Requires_Power=0:int," + "Debug=0:int," + "Detects_Stealth=1:int," + "Reload_Before_Charge=0:int"); diff -urN sourceold/scripts/engine_dialog.cpp source/scripts/engine_dialog.cpp --- sourceold/scripts/engine_dialog.cpp 2023-02-23 04:24:00.000000000 -0600 +++ source/scripts/engine_dialog.cpp 2024-02-14 04:13:36.628496700 -0600 @@ -13,13 +13,13 @@ #include "engine.h" #include "engine_dialog.h" -SCRIPTS_API ScriptedLabelControlClass* Create_Label_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const wchar_t* text, bool title, Vector3 label_color) +SCRIPTS_API ScriptedLabelControlClass* Create_Label_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const wchar_t* text, TextStyle style, Vector3 label_color) { ScriptedLabelControlClass* control = dialog->Create_Control(CONTROLTYPE_LABEL)->As_ScriptedLabelControlClass(); Set_Control_Bounds(control, x, y, width, height); control->Set_Text_Color(label_color); control->Set_Label_Text(text); - control->Set_Is_Title(title); + control->Set_Style(style); return control; } @@ -115,6 +115,14 @@ return control; } +SCRIPTS_API ScriptedHealthBarControlClass* Create_HealthBar_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, float value) +{ + ScriptedHealthBarControlClass* control = dialog->Create_Control(CONTROLTYPE_HEALTHBAR)->As_ScriptedHealthBarControlClass(); + Set_Control_Bounds(control, x, y, width, height); + control->Set_Life(value); + return control; +} + SCRIPTS_API void Set_Control_Bounds(ScriptedControlClass* control, int x, int y, int width, int height) { control->Set_Location(x > 400 ? 400 : (x < 0 ? 0 : x), y > 300 ? 300 : (y < 0 ? 0 : y)); @@ -145,7 +153,7 @@ ScriptedPopupDialogClass* dialog = Create_Centered_Popup(playerId, 230, 80, popup_title); - Create_Label_Control(dialog, 10, 10, 210, 30, label_text, false, label_color); + Create_Label_Control(dialog, 10, 10, 210, 30, label_text, TEXTSTYLE_BODY, label_color); ScriptedButtonControlClass* yes_button = Create_Bordered_Button_Control(dialog, 30, 50, 60, 20, L"Yes"); ScriptedButtonControlClass* no_button = Create_Bordered_Button_Control(dialog, 140, 50, 60, 20, L"No"); @@ -171,7 +179,7 @@ ScriptedPopupDialogClass* dialog = Create_Centered_Popup(playerId, 230, 80, popup_title); - Create_Label_Control(dialog, 10, 10, 210, 30, label_text, false, label_color); + Create_Label_Control(dialog, 10, 10, 210, 30, label_text, TEXTSTYLE_BODY, label_color); ScriptedButtonControlClass* yes_button = Create_Bordered_Button_Control(dialog, 10, 50, 60, 20, L"Yes"); ScriptedButtonControlClass* no_button = Create_Bordered_Button_Control(dialog, 85, 50, 60, 20, L"No"); @@ -199,7 +207,7 @@ ScriptedPopupDialogClass* dialog = Create_Centered_Popup(playerId, 230, 85, popup_title); - Create_Label_Control(dialog, 10, 10, 210, 20, label_text, false, label_color); + Create_Label_Control(dialog, 10, 10, 210, 20, label_text, TEXTSTYLE_BODY, label_color); ScriptedTextAreaControlClass* textarea = Create_TextArea_Control(dialog, 10, 30, 210, 15, initial_text, text_limit); ScriptedButtonControlClass* ok_button = Create_Bordered_Button_Control(dialog, 35, 55, 60, 20, L"Okay"); diff -urN sourceold/scripts/engine_dialog.h source/scripts/engine_dialog.h --- sourceold/scripts/engine_dialog.h 2023-02-23 04:23:42.000000000 -0600 +++ source/scripts/engine_dialog.h 2024-02-14 04:13:36.628496700 -0600 @@ -15,7 +15,7 @@ #include "ScriptedControlClass.h" #include "ScriptedControls.h" -SCRIPTS_API ScriptedLabelControlClass* Create_Label_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const wchar_t* text, bool title = false, Vector3 label_color = Vector3(1.0f, 0.9f, 0.0f)); +SCRIPTS_API ScriptedLabelControlClass* Create_Label_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const wchar_t* text, TextStyle style = TEXTSTYLE_BODY, Vector3 label_color = Vector3(1.0f, 0.9f, 0.0f)); SCRIPTS_API ScriptedImageControlClass* Create_Image_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const char* texture_name); SCRIPTS_API ScriptedButtonControlClass* Create_Bordered_Button_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const wchar_t* text); SCRIPTS_API ScriptedButtonControlClass* Create_Image_Button_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, const char* button_up_texture, const char* button_down_texture); @@ -25,6 +25,7 @@ SCRIPTS_API ScriptedComboBoxControlClass* Create_ComboBox_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, DynamicVectorClass* items = NULL, int selected_index = -1); // "height" is the height of dropdown, combobox height is calculated separately. SCRIPTS_API ScriptedSliderControlClass* Create_Slider_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, int value = 50, int min = 0, int max = 100); SCRIPTS_API ScriptedProgressBarControlClass* Create_ProgressBar_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, int value = 50, int min = 0, int max = 100); +SCRIPTS_API ScriptedHealthBarControlClass* Create_HealthBar_Control(ScriptedDialogClass* dialog, int x, int y, int width, int height, float value = 1); void SCRIPTS_API Set_Control_Bounds(ScriptedControlClass* control, int x, int y, int width, int height); SCRIPTS_API ScriptedPopupDialogClass* Create_Centered_Popup(int client, int width, int height, const wchar_t* title = NULL); SCRIPTS_API ScriptedDialogClass* Create_Yes_No_Dialog(GameObject* obj, const wchar_t* popup_title, const wchar_t* label_text, int& yes_button_id, int& no_button_id, Vector3 label_color = Vector3(1.0f, 0.9f, 0.0f)); diff -urN sourceold/scripts/engine_tt.cpp source/scripts/engine_tt.cpp --- sourceold/scripts/engine_tt.cpp 2023-02-01 09:01:36.000000000 -0600 +++ source/scripts/engine_tt.cpp 2024-02-14 04:13:36.644121600 -0600 @@ -288,6 +288,42 @@ SCRIPTS_API pccp Print_Client_Console_Player; SCRIPTS_API rl Reload_Level; SCRIPTS_API fcr Force_Client_Reload; +SCRIPTS_API chudc Change_Enemy_HUD_Color; +SCRIPTS_API chudcp Change_Enemy_HUD_Color_Player; +SCRIPTS_API chudc Change_Friendly_HUD_Color; +SCRIPTS_API chudcp Change_Friendly_HUD_Color_Player; +SCRIPTS_API chudc Change_Neutral_HUD_Color; +SCRIPTS_API chudcp Change_Neutral_HUD_Color_Player; +SCRIPTS_API egt Enable_Global_Targeting; +SCRIPTS_API egtp Enable_Global_Targeting_Player; +SCRIPTS_API gsr Get_Screen_Resolution; +SCRIPTS_API chs Create_HUD_Surface; +SCRIPTS_API fhs Find_HUD_Surface; +SCRIPTS_API hudsfc Show_HUD_Surface; +SCRIPTS_API hudsfc Hide_HUD_Surface; +SCRIPTS_API hudsfc Delete_HUD_Surface; +SCRIPTS_API gcsh Get_Client_Hardware_Identifier; +SCRIPTS_API iosc Is_Overriding_Sky_Colors; +SCRIPTS_API osc Override_Sky_Colors; +SCRIPTS_API spgui Get_Warm_Sky_Color; +SCRIPTS_API spgui Get_Cold_Sky_Color; +SCRIPTS_API spgui Get_Sun_Color; +SCRIPTS_API spgui Get_Sun_Halo_Color; +SCRIPTS_API spgui Get_Moon_Halo_Color; +SCRIPTS_API spguc Get_Starfield_Alpha; +SCRIPTS_API spgui Get_Sky_Color; +SCRIPTS_API spgui Get_Gloominess_Color; +SCRIPTS_API spsui Set_Warm_Sky_Color; +SCRIPTS_API spsui Set_Cold_Sky_Color; +SCRIPTS_API spsui Set_Sun_Color; +SCRIPTS_API spsui Set_Sun_Halo_Color; +SCRIPTS_API spsui Set_Moon_Halo_Color; +SCRIPTS_API spsuc Set_Starfield_Alpha; +SCRIPTS_API spsui Set_Sky_Color; +SCRIPTS_API spsui Set_Gloominess_Color; +SCRIPTS_API gtod Get_Time_Of_Day; +SCRIPTS_API stod Set_Time_Of_Day; +SCRIPTS_API icbad Is_Connection_Bad; SCRIPTS_API bool Can_Team_Build_Vehicle(int Team) { diff -urN sourceold/scripts/engine_tt.h source/scripts/engine_tt.h --- sourceold/scripts/engine_tt.h 2023-02-01 09:01:36.000000000 -0600 +++ source/scripts/engine_tt.h 2024-02-14 04:13:36.644121600 -0600 @@ -19,6 +19,7 @@ #include "HashTemplateClass.h" #include "SList.h" #include "cPlayer.h" +#include "HUDSurfaceClass.h" #include "ScriptedDialogClass.h" class ConnectionAcceptanceFilter; class WideStringClass; @@ -240,6 +241,23 @@ typedef void (*pccp) (GameObject* player, const char* text, Vector4 argb_color); typedef void (*rl) (); typedef void (*fcr) (int playerID); +typedef void (*chudc) (Vector3 color); +typedef void (*chudcp) (GameObject* obj, Vector3 color); +typedef void (*egt) (bool onoff); +typedef void (*egtp) (GameObject* obj, bool onoff); +typedef bool (*gsr) (int playerID, Vector2* out); +typedef HUDSurfaceClass* (*chs) (int target); +typedef HUDSurfaceClass* (*fhs) (int id); +typedef void (*hudsfc) (HUDSurfaceClass* surface); +typedef bool (*iosc) (); +typedef void (*osc) (bool onoff); +typedef unsigned int (*spgui) (); +typedef unsigned char (*spguc) (); +typedef void (*spsui) (unsigned int newval); +typedef void (*spsuc) (unsigned char newval); +typedef void (*gtod) (unsigned int* hours, unsigned int* minutes); +typedef void (*stod) (unsigned int hours, unsigned int minutes); +typedef bool (*icbad) (int playerID); SCRIPTS_API extern gpl Get_Player_List; SCRIPTS_API extern gcmi Get_Current_Map_Index; SCRIPTS_API extern gm Get_Map; @@ -485,6 +503,42 @@ SCRIPTS_API extern pccp Print_Client_Console_Player; SCRIPTS_API extern rl Reload_Level; SCRIPTS_API extern fcr Force_Client_Reload; +SCRIPTS_API extern chudc Change_Enemy_HUD_Color; +SCRIPTS_API extern chudcp Change_Enemy_HUD_Color_Player; +SCRIPTS_API extern chudc Change_Friendly_HUD_Color; +SCRIPTS_API extern chudcp Change_Friendly_HUD_Color_Player; +SCRIPTS_API extern chudc Change_Neutral_HUD_Color; +SCRIPTS_API extern chudcp Change_Neutral_HUD_Color_Player; +SCRIPTS_API extern egt Enable_Global_Targeting; +SCRIPTS_API extern egtp Enable_Global_Targeting_Player; +SCRIPTS_API extern gsr Get_Screen_Resolution; +SCRIPTS_API extern chs Create_HUD_Surface; +SCRIPTS_API extern fhs Find_HUD_Surface; +SCRIPTS_API extern hudsfc Show_HUD_Surface; +SCRIPTS_API extern hudsfc Hide_HUD_Surface; +SCRIPTS_API extern hudsfc Delete_HUD_Surface; +SCRIPTS_API extern gcsh Get_Client_Hardware_Identifier; +SCRIPTS_API extern iosc Is_Overriding_Sky_Colors; +SCRIPTS_API extern osc Override_Sky_Colors; +SCRIPTS_API extern spgui Get_Warm_Sky_Color; +SCRIPTS_API extern spgui Get_Cold_Sky_Color; +SCRIPTS_API extern spgui Get_Sun_Color; +SCRIPTS_API extern spgui Get_Sun_Halo_Color; +SCRIPTS_API extern spgui Get_Moon_Halo_Color; +SCRIPTS_API extern spguc Get_Starfield_Alpha; +SCRIPTS_API extern spgui Get_Sky_Color; +SCRIPTS_API extern spgui Get_Gloominess_Color; +SCRIPTS_API extern spsui Set_Warm_Sky_Color; +SCRIPTS_API extern spsui Set_Cold_Sky_Color; +SCRIPTS_API extern spsui Set_Sun_Color; +SCRIPTS_API extern spsui Set_Sun_Halo_Color; +SCRIPTS_API extern spsui Set_Moon_Halo_Color; +SCRIPTS_API extern spsuc Set_Starfield_Alpha; +SCRIPTS_API extern spsui Set_Sky_Color; +SCRIPTS_API extern spsui Set_Gloominess_Color; +SCRIPTS_API extern gtod Get_Time_Of_Day; +SCRIPTS_API extern stod Set_Time_Of_Day; +SCRIPTS_API extern icbad Is_Connection_Bad; class SCRIPTS_API JFW_Key_Hook_Base : public ScriptImpClass { public: diff -urN sourceold/scripts/engine_ttdef.h source/scripts/engine_ttdef.h --- sourceold/scripts/engine_ttdef.h 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/engine_ttdef.h 2024-02-14 04:13:36.644121600 -0600 @@ -32,10 +32,13 @@ }; enum DialogMessageType { - MESSAGE_TYPE_DIALOG_SHOW, - MESSAGE_TYPE_DIALOG_CLOSE, - MESSAGE_TYPE_CONTROL_MOUSE_CLICK, - MESSAGE_TYPE_CONTROL_VALUE_CHANGE + MESSAGE_TYPE_DIALOG_SHOW, // gets called when the dialog is shown + MESSAGE_TYPE_DIALOG_CLOSE, // gets called when the dialog is hidden/being deleted + MESSAGE_TYPE_DIALOG_ESCAPE, // gets called when the client hits Esc key + MESSAGE_TYPE_CONTROL_MOUSE_CLICK, // gets called when the client left-clicks on a supported control + MESSAGE_TYPE_CONTROL_VALUE_CHANGE, // gets called when the client changes the value of a supported control + MESSAGE_TYPE_CONTROL_VALUE_CONFIRM, // gets called when the client hits Enter key on a supported control + MESSAGE_TYPE_CONTROL_FOCUSED // gets called when the client changes the focused control }; typedef bool (*ChatHook) (int PlayerID,TextMessageEnum Type,const wchar_t *Message,int recieverID); typedef bool (*HostHook) (int PlayerID,TextMessageEnum Type,const char *Message); diff -urN sourceold/scripts/gmgame.cpp source/scripts/gmgame.cpp --- sourceold/scripts/gmgame.cpp 2023-02-01 08:59:56.000000000 -0600 +++ source/scripts/gmgame.cpp 2024-02-14 04:13:36.644121600 -0600 @@ -524,10 +524,12 @@ if (GDISpawnChar) { delete[] GDISpawnChar; + GDISpawnChar = nullptr; } if (NodSpawnChar) { delete[] NodSpawnChar; + NodSpawnChar = nullptr; } for (int i = 0;i < RegisteredEvents[EVENT_GLOBAL_INI].Count();i++) { @@ -657,10 +659,12 @@ if (GDISpawnChar) { delete[] GDISpawnChar; + GDISpawnChar = nullptr; } if (NodSpawnChar) { delete[] NodSpawnChar; + NodSpawnChar = nullptr; } INIClass *SSGMIni = 0; RawFileClass file("SSGM.ini"); diff -urN sourceold/scripts/jmgUtility.cpp source/scripts/jmgUtility.cpp --- sourceold/scripts/jmgUtility.cpp 2023-02-23 04:26:08.000000000 -0600 +++ source/scripts/jmgUtility.cpp 2024-02-14 04:13:36.659745600 -0600 @@ -5014,6 +5014,7 @@ if (Get_Int_Parameter("TriggerOnce")) Destroy_Script(); } +int JMG_Utility_Custom_Display_Briefing_Message::voiceId = 0; void JMG_Utility_Custom_Display_Briefing_Message::Created(GameObject *obj) { triggered = false; @@ -5074,6 +5075,7 @@ } Commands->Text_File_Close(File); CurrentNode = BriefingText; + voiceId = 0; Commands->Start_Timer(obj,this,0.1f,56345343); } void JMG_Utility_Custom_Display_Briefing_Message::Timer_Expired(GameObject *obj,int number) @@ -5105,7 +5107,9 @@ return; triggered = true; Commands->Start_Timer(obj,this,0.0f,56345344); - Commands->Create_2D_Sound(Get_Parameter("UISound")); + if (voiceId) + Commands->Stop_Sound(voiceId,true); + voiceId = Commands->Create_2D_Sound(Get_Parameter("UISound")); } } void JMG_Utility_Custom_Display_Briefing_Message::Destroyed(GameObject *obj) @@ -8535,6 +8539,7 @@ Count++; } } + JMG_Utility_Custom_Display_Briefing_Message::voiceId = 0; CurrentNode = BriefingText; } void JMG_Utility_Custom_Display_Briefing_Message_StringID::Timer_Expired(GameObject *obj,int number) @@ -8566,7 +8571,9 @@ return; triggered = true; Commands->Start_Timer(obj,this,0.0f,1); - Commands->Create_2D_Sound(Get_Parameter("UISound")); + if (JMG_Utility_Custom_Display_Briefing_Message::voiceId) + Commands->Stop_Sound(JMG_Utility_Custom_Display_Briefing_Message::voiceId,true); + JMG_Utility_Custom_Display_Briefing_Message::voiceId = Commands->Create_2D_Sound(Get_Parameter("UISound")); } } void JMG_Utility_Custom_Display_Briefing_Message_StringID::Destroyed(GameObject *obj) @@ -9813,7 +9820,7 @@ CastResultStruct res; res.ComputeContactPoint = true; LineSegClass ray(topRay,bottomRay); - PhysRayCollisionTestClass coltest(ray, &res, TERRAIN_ONLY_COLLISION_GROUP); + PhysRayCollisionTestClass coltest(ray, &res, TERRAIN_ONLY_COLLISION_GROUP,COLLISION_TYPE_PHYSICAL); PhysicsSceneClass::Get_Instance()->Cast_Ray(coltest,false); if (coltest.CollidedRenderObj && Vector3::Dot_Product(res.Normal,ray.Get_Dir()) <= 0) { @@ -18294,6 +18301,140 @@ Commands->Send_Custom_Event(obj,Commands->Find_Object(Get_Int_Parameter("ScriptZoneId")),ownerScriptId,ownerScriptId+1,0); Destroy_Script(); } +void JMG_Utility_Animate_While_Moving_Idle_Or_Dead::Created(GameObject *obj) +{ + if (!obj->As_SmartGameObj()) + { + Console_Input("msg JMG_Utility_Animate_While_Moving_Idle_Or_Dead ERROR: Only attach to smart game objects!"); + Commands->Destroy_Object(obj); + return; + } + sprintf(subObject,"%s",Get_Parameter("SubObject")); + sprintf(idle,"%s",Get_Parameter("IdleAnimation")); + sprintf(death,"%s",Get_Parameter("DeathAnimation")); + sprintf(move,"%s",Get_Parameter("MoveAnimation")); + deathFrame = Get_Float_Parameter("DeathFrame"); + PlayAnimation(obj,idle,-1); + moving = false; + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Animate_While_Moving_Idle_Or_Dead::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1 && Commands->Get_Health(obj)) + { + Vector3 speed; + obj->As_SmartGameObj()->Get_Velocity(speed); + if (speed.Length2() > 0.0f) + { + if (!moving) + { + moving = true; + PlayAnimation(obj,move,-1); + } + } + else if (moving) + { + moving = false; + PlayAnimation(obj,idle,-1); + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +void JMG_Utility_Animate_While_Moving_Idle_Or_Dead::Killed(GameObject *obj,GameObject *killer) +{ + PlayAnimation(obj,death,deathFrame); +} +void JMG_Utility_Animate_While_Moving_Idle_Or_Dead::PlayAnimation(GameObject *obj,const char *aniamtionName,float frame) +{ + if (_stricmp(subObject,"")) + { + for (int x = 1;x < 128;x++) + { + GameObject *player = Get_GameObj(x); + if (!player) + continue; + Set_Subobject_Animation_Player(player,obj,aniamtionName,frame < 0 ? true : false,subObject,0,frame,true); + } + } + else + Commands->Set_Animation(obj,aniamtionName,frame < 0 ? true : false,NULL,0,frame,true); +} +void JMG_Utility_Send_Custom_When_HP_Crosses_Threshold::Created(GameObject *obj) +{ + id = Get_Int_Parameter("ID"); + targetRatio = Get_Float_Parameter("TargetRatio"); + aboveCustom = Get_Int_Parameter("AboveCustom"); + aboveParam = Get_Int_Parameter("AboveParam"); + belowCustom = Get_Int_Parameter("BelowCustom"); + belowParam = Get_Int_Parameter("BelowParam"); + below = Get_Hitpoints(obj) < Get_Max_Hitpoints(obj)*targetRatio; +} +void JMG_Utility_Send_Custom_When_HP_Crosses_Threshold::Damaged(GameObject *obj,GameObject *damager,float damage) +{ + if (!damager) + damager = obj; + if (Get_Hitpoints(obj) < Get_Max_Hitpoints(obj)*targetRatio) + { + if (!below) + { + below = true; + GameObject *object = id ? (id == -1 ? damager : Commands->Find_Object(id)) : obj; + Commands->Send_Custom_Event(damager,object,belowCustom,belowParam,0); + } + } + else if (below) + { + below = false; + GameObject *object = id ? (id == -1 ? damager : Commands->Find_Object(id)) : obj; + Commands->Send_Custom_Event(damager,object,aboveCustom,aboveParam,0); + } +} +void JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged::Created(GameObject *obj) +{ + minHealthRatio = Get_Float_Parameter("MinHealthRatio"); + sprintf(skinType,"%s",Get_Skin(obj)); + Set_Skin(obj,"Blamo"); +} +void JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged::Damaged(GameObject *obj,GameObject *damager,float damage) +{ + if (damage < 0) + return; + if (Get_Hitpoints(obj)+damage < Get_Max_Hitpoints(obj)*minHealthRatio) + { + Set_Skin(obj,skinType); + Destroy_Script(); + } +} +void JMG_Utility_Send_Custom_When_Moved_Distance_From_Spawn::Created(GameObject *obj) +{ + distance = Get_Float_Parameter("Distance"); + distance *= distance; + requireInPathfind = Get_Int_Parameter("RequireInPathfind") ? true : false; + Commands->Start_Timer(obj,this,Get_Float_Parameter("StartDelay"),1); +} +void JMG_Utility_Send_Custom_When_Moved_Distance_From_Spawn::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + location = Commands->Get_Position(obj); + Vector3 out; + if (!requireInPathfind || Get_Random_Pathfind_Spot(Commands->Get_Position(obj),0.0f,&out)) + Commands->Start_Timer(obj,this,0.1f,2); + else + Commands->Start_Timer(obj,this,0.1f,1); + } + if (number == 2) + { + Vector3 out; + if ((!requireInPathfind || Get_Random_Pathfind_Spot(Commands->Get_Position(obj),0.0f,&out)) && JmgUtility::SimpleDistance(Commands->Get_Position(obj),location) >= distance) + { + GameObject *object = Get_Int_Parameter("ID") ? Commands->Find_Object(Get_Int_Parameter("ID")) : obj; + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("Custom"),Get_Int_Parameter("Param"),0); + } + Commands->Start_Timer(obj,this,0.1f,2); + } +} + ScriptRegistrant JMG_Utility_Check_If_Script_Is_In_Library_Registrant("JMG_Utility_Check_If_Script_Is_In_Library","ScriptName:string,CppName:string"); ScriptRegistrant JMG_Send_Custom_When_Custom_Sequence_Matched_Registrant("JMG_Send_Custom_When_Custom_Sequence_Matched","Success_Custom=0:int,Correct_Step_Custom=0:int,Partial_Failure_Custom=0:int,Failure_Custom=0:int,Send_To_ID=0:int,Custom_0=0:int,Custom_1=0:int,Custom_2=0:int,Custom_3=0:int,Custom_4=0:int,Custom_5=0:int,Custom_6=0:int,Custom_7=0:int,Custom_8=0:int,Custom_9=0:int,Disable_On_Success=1:int,Disable_On_Failure=0:int,Starts_Enabled=1:int,Enable_Custom=0:int,Correct_Step_Saftey=0:int,Failure_Saftey=1:int,Max_Failures=1:int"); ScriptRegistrant JMG_Utility_Change_Model_On_Timer_Registrant("JMG_Utility_Change_Model_On_Timer","Model=null:string,Time=0:float"); @@ -18738,3 +18879,7 @@ ScriptRegistrant JMG_Utility_Zone_Create_Object_While_Occupied_Registrant("JMG_Utility_Zone_Create_Object_While_Occupied","Preset:string,Location:Vector3,Facing:float,EnableCustom:int,ReCreateOnDeath:int"); ScriptRegistrant JMG_Utility_Zone_Create_Object_While_Occupied_Attached_Registrant("JMG_Utility_Zone_Create_Object_While_Occupied_Attached","ScriptZoneId:int,ScriptId:int"); ScriptRegistrant JMG_Utility_Zone_Create_Object_While_Occupied_Object_Attached_Registrant("JMG_Utility_Zone_Create_Object_While_Occupied_Object_Attached","ScriptZoneId:int,ScriptId:int"); +ScriptRegistrant JMG_Utility_Animate_While_Moving_Idle_Or_Dead_Registrant("JMG_Utility_Animate_While_Moving_Idle_Or_Dead","SubObject:string,IdleAnimation:string,MoveAnimation:string,DeathAnimation:string,DeathFrame:float"); +ScriptRegistrant JMG_Utility_Send_Custom_When_HP_Crosses_Threshold_Registrant("JMG_Utility_Send_Custom_When_HP_Crosses_Threshold","TargetRatio:float,ID:int,AboveCustom:int,AboveParam:int,BelowCustom:int,BelowParam:int"); +ScriptRegistrant JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged_Registrant("JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged","MinHealthRatio=1.0:float"); +ScriptRegistrant JMG_Utility_Send_Custom_When_Moved_Distance_From_Spawn_Registrant("JMG_Utility_Send_Custom_When_Moved_Distance_From_Spawn","Distance:float,ID:int,Custom:int,Param:int,StartDelay=0.0:float,RequireInPathfind=0:int"); diff -urN sourceold/scripts/jmgUtility.h source/scripts/jmgUtility.h --- sourceold/scripts/jmgUtility.h 2023-02-23 04:26:16.000000000 -0600 +++ source/scripts/jmgUtility.h 2024-02-14 04:13:36.659745600 -0600 @@ -4259,6 +4259,8 @@ void Destroyed(GameObject *obj); void AddNewTextNode(); void RemoveTextNodes(); +public: + static int voiceId; }; /*! @@ -12171,4 +12173,87 @@ void Created(GameObject *obj); void Custom(GameObject *obj,int message,int param,GameObject *sender); void Destroyed(GameObject *obj); +}; + +/*! +* \brief Makes the object or a sub-object of the object animate while moving, dead, or idle. +* \SubObject - Name of the sub-object if any +* \IdleAnimation - Name of the idle animation +* \MoveAnimation - Name of the move animation +* \DeathAnimation - Name of the death animation +* \DeathFrame - Last frame of the death animation +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Animate_While_Moving_Idle_Or_Dead : public ScriptImpClass { + char subObject[16]; + char idle[32]; + char death[32]; + char move[32]; + float deathFrame; + bool moving; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + void Killed(GameObject *obj,GameObject *killer); + void PlayAnimation(GameObject *obj,const char *aniamtionName,float frame); +}; + +/*! +* \brief Sends the matching custom when the units HP drops below the ratio +* \TargetRatio - (Health+Armor)*THIS VALUE returns the ratio +* \ID - ID to send to, 0 sends to self, -1 sends to damager, if no damager uses self +* \AboveCustom - Custom to send when you first go above the ratio +* \AboveParam - Param to send when you first go above the ratio +* \BelowCustom - Custom to send when you first go below the ratio +* \BelowParam - Param to send when you first go below the ratio +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Send_Custom_When_HP_Crosses_Threshold : public ScriptImpClass { + bool below; + int id; + float targetRatio; + int aboveCustom; + int aboveParam; + int belowCustom; + int belowParam; + void Created(GameObject *obj); + void Damaged(GameObject *obj,GameObject *damager,float damage); +}; + +/*! +* \brief Changes the SkinType to Blamo until Armor takes any damage, after that it reverts the SkinType back to the original and destroys the script +* \MinHealthRatio - Hitpoints have to drop below this value before reverting the SkinType from blamo +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged : public ScriptImpClass { + char skinType[128]; + float minHealthRatio; + void Created(GameObject *obj); + void Damaged(GameObject *obj,GameObject *damager,float damage); +public: + JMG_Utility_Change_SkinType_To_Blamo_Until_Damaged() + { + sprintf(skinType,"None"); + } +}; + +/*! +* \brief Sends a custom message when the attached object moves a distance from its initial spawn location +* \Distance - Distance object has to move +* \ID - ID to send to, 0 sends to self +* \Custom - Custom to send +* \Param - Param to send +* \StartDelay - amount of time to wait before doing first detection if the object has moved +* \RequireInPathfind - Only trigger if the object is in a pathfind zone +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Send_Custom_When_Moved_Distance_From_Spawn : public ScriptImpClass { + Vector3 location; + float distance; + bool requireInPathfind; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); }; \ No newline at end of file diff -urN sourceold/scripts/ms_ai.cpp source/scripts/ms_ai.cpp --- sourceold/scripts/ms_ai.cpp 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/ms_ai.cpp 2024-02-14 04:13:36.675370600 -0600 @@ -3787,19 +3787,19 @@ } if (i == Get_Parameter_Index("Max_Attack_Range") && Get_Int_Parameter("Max_Attack_Range") == -1) { - buffer.Format("%s,%d", buffer.Peek_Buffer(), maxAttackRange); + buffer.Format("%s%d", buffer.Peek_Buffer(), maxAttackRange); } else if (i == Get_Parameter_Index("Preferred_Attack_Range") && Get_Int_Parameter("Preferred_Attack_Range") == -1) { - buffer.Format("%s,%d", buffer.Peek_Buffer(), preferredAttackRange); + buffer.Format("%s%d", buffer.Peek_Buffer(), preferredAttackRange); } else if (i == Get_Parameter_Index("Max_Attack_Range_Secondary") && Get_Int_Parameter("Max_Attack_Range_Secondary") == -1) { - buffer.Format("%s,%d", buffer.Peek_Buffer(), maxAttackRangeSecondary); + buffer.Format("%s%d", buffer.Peek_Buffer(), maxAttackRangeSecondary); } else if (i == Get_Parameter_Index("Preferred_Attack_Range_Secondary") && Get_Int_Parameter("Preferred_Attack_Range_Secondary") == -1) { - buffer.Format("%s,%d", buffer.Peek_Buffer(), preferredAttackRangeSecondary); + buffer.Format("%s%d", buffer.Peek_Buffer(), preferredAttackRangeSecondary); } else { @@ -4263,6 +4263,7 @@ baseDefObjectiveIDTeam[1] = 0; radarRadius = 0; transportVehicleSeatCount = 0; + grantCreditsMultiplier = 1; chattingEnabled = true; radioCommandsEnabled = true; killedRespEnabled = false; diff -urN sourceold/scripts/obelfix.cpp source/scripts/obelfix.cpp --- sourceold/scripts/obelfix.cpp 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/obelfix.cpp 2024-02-14 04:13:36.675370600 -0600 @@ -53,8 +53,14 @@ // Create the Obelisk weapon GameObject* WeaponObj = Commands->Create_Object("Nod_Obelisk", WeaponPos); if (WeaponObj) { + if (DefinitionClass* Def = Find_Definition(Get_Int_Parameter("WeaponDef"))) { + if (Def->Get_Class_ID() == CID_Weapon) { + Grant_Weapon(WeaponObj, Def->Get_Name(), true, -1, true); + Commands->Select_Weapon(WeaponObj, Def->Get_Name()); + } + } Set_Object_Type(WeaponObj, Get_Object_Type(ObeliskObj)); - Commands->Attach_Script(WeaponObj, "Obelisk_Weapon_CnC", ""); + Commands->Attach_Script(WeaponObj, "Obelisk_Weapon_CnC", Get_Parameter("EffectModel")); WeaponID = Commands->Get_ID(WeaponObj); } } @@ -133,6 +139,9 @@ GameObject* EffectObj = Commands->Create_Object("Obelisk Effect", Commands->Get_Position(WeaponObj)); if (EffectObj) { + if (Get_Parameter("EffectModel") && Get_Parameter("EffectModel")[0]) { + Commands->Set_Model(EffectObj, Get_Parameter("EffectModel")); + } EffectID = Commands->Get_ID(EffectObj); } } @@ -192,8 +201,11 @@ { GameObject* EffectObj = Commands->Create_Object("Obelisk Effect", Commands->Get_Position(WeaponObj)); if (EffectObj) { - EffectID = Commands->Get_ID(EffectObj); + if (Get_Parameter("EffectModel") && Get_Parameter("EffectModel")[0]) { + Commands->Set_Model(EffectObj, Get_Parameter("EffectModel")); } + EffectID = Commands->Get_ID(EffectObj); + } } // Check effect in 4 seconds @@ -282,9 +294,9 @@ Auto_Save_Variable(&Charged, 1, 4); } -ScriptRegistrant M00_Nod_Obelisk_CnC_Registrant("M00_Nod_Obelisk_CnC", ""); -ScriptRegistrant Nod_Obelisk_CnC_Registrant("Nod_Obelisk_CnC", ""); -ScriptRegistrant Obelisk_Weapon_CnC_Registrant("Obelisk_Weapon_CnC", ""); +ScriptRegistrant M00_Nod_Obelisk_CnC_Registrant("M00_Nod_Obelisk_CnC", "WeaponDef=0:int,EffectModel:string"); +ScriptRegistrant Nod_Obelisk_CnC_Registrant("Nod_Obelisk_CnC", "WeaponDef=0:int,EffectModel:string"); +ScriptRegistrant Obelisk_Weapon_CnC_Registrant("Obelisk_Weapon_CnC", "EffectModel:string"); void Nod_Obelisk_CnC_Ground::Created(GameObject* ObeliskObj) { if (Commands->Get_Building_Power(ObeliskObj)) { @@ -295,6 +307,12 @@ // Create the Obelisk weapon GameObject* WeaponObj = Commands->Create_Object("Nod_Obelisk", WeaponPos); if (WeaponObj) { + if (DefinitionClass* Def = Find_Definition(Get_Int_Parameter("WeaponDef"))) { + if (Def->Get_Class_ID() == CID_Weapon) { + Grant_Weapon(WeaponObj, Def->Get_Name(), true, -1, true); + Commands->Select_Weapon(WeaponObj, Def->Get_Name()); + } + } WeaponID = Commands->Get_ID(WeaponObj); Commands->Attach_Script(WeaponObj, "Obelisk_Weapon_CnC_Ground", ""); } @@ -321,8 +339,14 @@ // Create the Obelisk weapon WeaponObj = Commands->Create_Object("Nod_Obelisk", WeaponPos); if (WeaponObj) { + if (DefinitionClass* Def = Find_Definition(Get_Int_Parameter("WeaponDef"))) { + if (Def->Get_Class_ID() == CID_Weapon) { + Grant_Weapon(WeaponObj, Def->Get_Name(), true, -1, true); + Commands->Select_Weapon(WeaponObj, Def->Get_Name()); + } + } WeaponID = Commands->Get_ID(WeaponObj); - Commands->Attach_Script(WeaponObj, "Obelisk_Weapon_CnC_Ground", ""); + Commands->Attach_Script(WeaponObj, "Obelisk_Weapon_CnC_Ground", Get_Parameter("EffectModel")); } } } else { @@ -406,6 +430,9 @@ GameObject* EffectObj = Commands->Create_Object("Obelisk Effect", Commands->Get_Position(WeaponObj)); if (EffectObj) { + if (Get_Parameter("EffectModel") && Get_Parameter("EffectModel")[0]) { + Commands->Set_Model(EffectObj, Get_Parameter("EffectModel")); + } EffectID = Commands->Get_ID(EffectObj); } } @@ -465,6 +492,9 @@ { GameObject* EffectObj = Commands->Create_Object("Obelisk Effect", Commands->Get_Position(WeaponObj)); if (EffectObj) { + if (Get_Parameter("EffectModel") && Get_Parameter("EffectModel")[0]) { + Commands->Set_Model(EffectObj, Get_Parameter("EffectModel")); + } EffectID = Commands->Get_ID(EffectObj); } } @@ -559,5 +589,5 @@ Auto_Save_Variable(&Charged, 1, 4); } -ScriptRegistrant Nod_Obelisk_CnC_Ground_Registrant("Nod_Obelisk_CnC_Ground", ""); -ScriptRegistrant Obelisk_Weapon_CnC_Ground_Registrant("Obelisk_Weapon_CnC_Ground", ""); +ScriptRegistrant Nod_Obelisk_CnC_Ground_Registrant("Nod_Obelisk_CnC_Ground", "WeaponDef=0:int,EffectModel:string"); +ScriptRegistrant Obelisk_Weapon_CnC_Ground_Registrant("Obelisk_Weapon_CnC_Ground", "EffectModel:string"); diff -urN sourceold/scripts/scripts.vcxproj source/scripts/scripts.vcxproj --- sourceold/scripts/scripts.vcxproj 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/scripts.vcxproj 2024-02-14 04:13:36.675370600 -0600 @@ -656,6 +656,7 @@ + diff -urN sourceold/scripts/scripts.vcxproj.filters source/scripts/scripts.vcxproj.filters --- sourceold/scripts/scripts.vcxproj.filters 2022-10-20 19:36:40.000000000 -0500 +++ source/scripts/scripts.vcxproj.filters 2024-02-14 04:13:36.675370600 -0600 @@ -1324,6 +1324,9 @@ 03. New Sources + + 02. Headers + diff -urN sourceold/scripts/unstoppable.cpp source/scripts/unstoppable.cpp --- sourceold/scripts/unstoppable.cpp 2023-02-23 04:24:52.000000000 -0600 +++ source/scripts/unstoppable.cpp 2024-02-14 04:13:36.690995200 -0600 @@ -682,6 +682,7 @@ Commands->Set_Facing(helicopter, facing); Commands->Attach_Script(helicopter, "UP_Unkillable_Until_Custom", "1496001"); + Commands->Set_Is_Visible(helicopter, false); Commands->Disable_All_Collisions(helicopter); Commands->Attach_To_Object_Bone(helicopter, trajectory, "BN_Chinook_1"); @@ -1387,4 +1388,90 @@ ScriptRegistrant UP_Remove_Bot_Tag_Registrant("UP_Remove_Bot_Tag", ""); +/******************************************************************************************************/ + +void UP_Stop_Sound::Created(GameObject* obj) +{ + Commands->Stop_Sound(Get_Int_Parameter("SoundID"), Get_Int_Parameter("Destroy") != 0); + Destroy_Script(); +} + +ScriptRegistrant UP_Stop_Sound_Registrant("UP_Stop_Sound", "SoundID:int,Destroy:int"); + +/******************************************************************************************************/ + +void UP_Sound_Controller_2D::Created(GameObject* obj) +{ + StartCustomType = Get_Int_Parameter("StartCustomType"); + StopCustomType = Get_Int_Parameter("StopCustomType"); + SoundDef = Get_Parameter("SoundDef"); + + SoundID = Commands->Create_2D_Sound(SoundDef); + if (!SoundID) + { + Destroy_Script(); + } +} + +void UP_Sound_Controller_2D::Destroyed(GameObject* obj) +{ + Commands->Stop_Sound(SoundID, true); +} + +void UP_Sound_Controller_2D::Custom(GameObject* obj, int type, int param, GameObject* sender) +{ + if (type == StartCustomType) + { + if (!SoundID) + { + SoundID = Commands->Create_2D_Sound(SoundDef); + } + } + else if (type == StopCustomType) + { + Commands->Stop_Sound(SoundID, true); + SoundID = 0; + } +} + +ScriptRegistrant UP_Sound_Controller_2D_Registrant("UP_Sound_Controller_2D", "SoundDef:string,StartCustomType=12300:int,StopCustomType=12301:int"); + +/******************************************************************************************************/ + +void UP_Sound_Controller_3D::Created(GameObject* obj) +{ + StartCustomType = Get_Int_Parameter("StartCustomType"); + StopCustomType = Get_Int_Parameter("StopCustomType"); + SoundDef = Get_Parameter("SoundDef"); + + SoundID = Commands->Create_Sound(SoundDef, Commands->Get_Position(obj), obj); + if (!SoundID) + { + Destroy_Script(); + } +} + +void UP_Sound_Controller_3D::Destroyed(GameObject* obj) +{ + Commands->Stop_Sound(SoundID, true); +} + +void UP_Sound_Controller_3D::Custom(GameObject* obj, int type, int param, GameObject* sender) +{ + if (type == StartCustomType) + { + if (!SoundID) + { + SoundID = Commands->Create_Sound(SoundDef, Commands->Get_Position(obj), obj); + } + } + else if (type == StopCustomType) + { + Commands->Stop_Sound(SoundID, true); + SoundID = 0; + } +} + +ScriptRegistrant UP_Sound_Controller_3D_Registrant("UP_Sound_Controller_3D", "SoundDef:string,StartCustomType=12300:int,StopCustomType=12301:int"); + /******************************************************************************************************/ \ No newline at end of file diff -urN sourceold/scripts/unstoppable.h source/scripts/unstoppable.h --- sourceold/scripts/unstoppable.h 2023-02-23 04:25:00.000000000 -0600 +++ source/scripts/unstoppable.h 2024-02-14 04:13:36.690995200 -0600 @@ -155,7 +155,7 @@ class UP_Master_Control_Terminal : public ScriptImpClass { private: - GameObject* MainBuilding; + ReferencerClass MainBuilding; float Multiplier; public: @@ -553,11 +553,11 @@ private: bool chinookKilled; int paratrooperIndex; - GameObject* presetObj1; - GameObject* presetObj2; - GameObject* presetObj3; - GameObject* helicopter; - GameObject* trajectory; + ReferencerClass presetObj1; + ReferencerClass presetObj2; + ReferencerClass presetObj3; + ReferencerClass helicopter; + ReferencerClass trajectory; bool Check_Object(GameObject* obj) { @@ -660,7 +660,7 @@ private: StringClass Script; StringClass Parameters; - GameObject* Target; + ReferencerClass Target; float Interval; int LoopCount; int Looped; @@ -856,6 +856,9 @@ * \ingroup UnstoppableScripts * * Sets the bot tag of attached soldier object, then detaches. + * + * \param Tag + * Tag to set. */ class UP_Set_Bot_Tag : public ScriptImpClass { @@ -869,6 +872,17 @@ * \ingroup UnstoppableScripts * * Sets the bot tag of attached soldier object with multiple lines, then detaches. + * + * \param Tag1 + * First line for the tag. + * \param Tag2 + * Second line for the tag. + * \param Tag3 + * Third line for the tag. + * \param Tag4 + * Fourth line for the tag. + * \param Tag5 + * Fifth line for the tag. */ class UP_Set_Bot_Tag_MultiLine : public ScriptImpClass { @@ -887,4 +901,80 @@ { public: void Created(GameObject* obj); +}; + +/*! + * \brief Stop Sound + * \author Unstoppable + * \ingroup UnstoppableScripts + * + * Stops the sound specified by its ID, then detaches. + * + * \param SoundID + * ID of the sound to stop. + * \param Destroy + * Whether or not to destroy the sound after stopping. + */ +class UP_Stop_Sound : public ScriptImpClass +{ +public: + void Created(GameObject* obj); +}; + +/*! + * \brief 2D Sound Controller + * \author Unstoppable + * \ingroup UnstoppableScripts + * + * Creates a 2D sound with specified definition name, and starts/stops it with customs. + * The created sound is destroyed when the script detaches or the attached object gets destroyed. + * + * \param SoundDef + * Definition name of the sound to create. + * \param StartCustomType + * Expected custom type to start the sound. + * \param StopCustomType + * Expected custom type to stop the sound. + */ +class UP_Sound_Controller_2D : public ScriptImpClass +{ +public: + void Created(GameObject* obj); + void Destroyed(GameObject* obj); + void Custom(GameObject* obj, int type, int param, GameObject* sender); + +private: + StringClass SoundDef; + int SoundID; + int StartCustomType; + int StopCustomType; +}; + +/*! + * \brief 3D Sound Controller + * \author Unstoppable + * \ingroup UnstoppableScripts + * + * Creates a 3D sound with specified definition name and at the position of the attached object, and starts/stops it with customs. + * The created sound is destroyed when the script detaches or the attached object gets destroyed. + * + * \param SoundDef + * Definition name of the sound to create. + * \param StartCustomType + * Expected custom type to start the sound. + * \param StopCustomType + * Expected custom type to stop the sound. + */ +class UP_Sound_Controller_3D : public ScriptImpClass +{ +public: + void Created(GameObject* obj); + void Destroyed(GameObject* obj); + void Custom(GameObject* obj, int type, int param, GameObject* sender); + +private: + StringClass SoundDef; + int SoundID; + int StartCustomType; + int StopCustomType; }; \ No newline at end of file