Compare commits

...

14 Commits

23 changed files with 3404 additions and 600 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
-- ------------------------------------------------------------------
-- ------------------------------------------------------------------
-- _____ _ _ _ _
-- | ___| (_) | | | | | |
-- | |__ _ __ ___ _ __ _ _ __ ___ __ _| |_ | | | | __ _ _ __
-- | __| '_ ` _ \| '_ \| | '__/ _ \ / _` | __| | |/\| |/ _` | '__|
-- | |__| | | | | | |_) | | | | __/ | (_| | |_ \ /\ / (_| | |
-- \____/_| |_| |_| .__/|_|_| \___| \__,_|\__| \/ \/ \__,_|_|
-- | |
-- |_|
-- _____ _ ______
-- | ___| | | | _ \
-- | |__ _ __ ___ _ __ ___ _ _| | _ _ __ _| | | |___ ___
-- | __| '_ ` _ \| '_ ` _ \| | | | | | | | |/ _` | | | / _ \ / __|
-- | |__| | | | | | | | | | | |_| | |___| |_| | (_| | |/ / (_) | (__
-- \____/_| |_| |_|_| |_| |_|\__, \_____/\__,_|\__,_|___/ \___/ \___|
-- __/ |
-- |___/
-- ------------------------------------------------------------------
-- ------------------------------------------------------------------
---@diagnostic disable
---Opens a message box that contains the handled event and its parameters as multi-line formatted string.
---**WARNING:** Appears to be non-functional.
---@param event any TODO: This is most likely be the same Event type as used in gamescoring.lua
---@param params table
function DebugEventAlert(event, params) end
---@vararg string
---Opens a message box that contains the formatted input string provided as a vararg.
---The vararg should be a string with _n_ formatting placeholders, and _n_ elements that will be handled via `string.format(unpack(arg))`.
---**WARNING:** Appears to be non-functional!
function MessageBox(...) end
---@vararg string
---Prints a debug message to the `AILog.txt` that contains the formatted input string provided as a vararg if the command `aiff script` has been used in the ingame console.
---The vararg should be a string with _n_ formatting placeholders, and _n_ elements that will be handled via `string.format(unpack(arg))`.
function ScriptMessage(...) end
---@vararg string
---Prints a debug message to the `AILog.txt` that contains the formatted input string provided as a vararg if the command `aiff script` has been used in the ingame console.
---The vararg should be a string with _n_ formatting placeholders, and _n_ elements that will be handled via `string.format(unpack(arg))`.
function DebugMessage(...) end
---@vararg string
---Prints a debug message that contains the formatted input string provided as a vararg directly to the `LogFile.txt`. Usually used as Error Log.
---The vararg should be a string with _n_ formatting placeholders, and _n_ elements that will be handled via `string.format(unpack(arg))`.
---@see string#format
---@see unpack
function OutputDebug(...) end
---@vararg string
---Prints an error log to `LogFile.txt` and `AILog.txt` including the contains the formatted input string provided as a vararg and a stack trace.
---The vararg should be a string with _n_ formatting placeholders, and _n_ elements that will be handled via `string.format(unpack(arg))`.
---@see string#format
---@see unpack
function ScriptError(...) end
---@param unit_table GameObjectWrapper[]
---Unpacks a table and prints its content to the `AILog.txt` if the command `aiff script` has been used in the ingame console.
function DebugPrintTable(unit_table) end

View File

@@ -0,0 +1,999 @@
-- ==================================================================
-- ==================================================================
-- _____ _ _ _ _
-- | ___| (_) | | | | | |
-- | |__ _ __ ___ _ __ _ _ __ ___ __ _| |_ | | | | __ _ _ __
-- | __| '_ ` _ \| '_ \| | '__/ _ \ / _` | __| | |/\| |/ _` | '__|
-- | |__| | | | | | |_) | | | | __/ | (_| | |_ \ /\ / (_| | |
-- \____/_| |_| |_| .__/|_|_| \___| \__,_|\__| \/ \/ \__,_|_|
-- | |
-- |_|
-- _____ _ ______
-- | ___| | | | _ \
-- | |__ _ __ ___ _ __ ___ _ _| | _ _ __ _| | | |___ ___
-- | __| '_ ` _ \| '_ ` _ \| | | | | | | | |/ _` | | | / _ \ / __|
-- | |__| | | | | | | | | | | |_| | |___| |_| | (_| | |/ / (_) | (__
-- \____/_| |_| |_|_| |_| |_|\__, \_____/\__,_|\__,_|___/ \___/ \___|
-- __/ |
-- |___/
-- ==================================================================
-- ==================================================================
---@diagnostic disable
---@class TaskForce
local TaskForce = {}
---@public
---@param targetingPrioritySetName string The name of the Targeting Priority Set as defined in the XML.
---@param categoryMask string The Category Mask of the units contained within the TaskForce to attach the Targeting Priority Set to.
---Attaches a given Targeting Priority Set to all units in the TaskForce that match the given Category Mask.
function TaskForce.Set_Targeting_Priorities(targetingPrioritySetName,
categoryMask)
end
---@public
---@return GameObject[] The units contained within the Task Force.
---Returns all units that are part of the task force. WARNING: The units may not be valid.
function TaskForce.Get_Unit_Table() end
---@public
---@return number The amount of units in the TaskForce's unit table.
---Returns the number of units in a task force.
function TaskForce.Get_Force_Count() end
---@public
---@param target GameObject The object to get the distance to.
---@return number The distance to the given game object.
function TaskForce.Get_Distance(target) end
---@public
---@overload fun()
---@overload fun(stage:PlanetObject)
---@param stage PlanetObject The planet to produce the taskforce on.
---@param unknownArgument boolean TODO: Find out what this does.
---Produces a task force.
function TaskForce.Produce_Force(stage, unknownArgument) end
---@public
---@param target GameObject The target to attack.
---Orders the task force to attack a given target.
function TaskForce.Attack_Target(target) end
---@public
---@param target GameObject The target to attack.
---@param unknownArgument number TODO: Find out what this does.
---@param shouldPathThroughObstacle boolean Should the task force ignore space obstacles.
---Orders the task force to attack a given target.
function TaskForce.Attack_Target(target, unknownArgument,
shouldPathThroughObstacle)
end
---@public
---@param target GameObject The target to guard.
---Orders the task force to guard a given target.
function TaskForce.Guard_Target(target) end
---@public
---@param target GameObject The target to reinforce (usually a position).
-----Orders the task force to reinforce (at) a given target.
function TaskForce.Reinforce(target) end
---@public
---@param target GameObject The target to move to (usually a position).
-----Orders the task force to move to a given target.
function TaskForce.Move_To(target) end
---@public
---@param gameObject GameObject The object to release.
---Releases a given unit from the task force.
function TaskForce.Release_Unit(gameObject) end
---@public
---@param abilityName string The ability to (de-)activate.
---@param shouldActivate boolean Activates the ability if true, deactivates if false.
---Activates or deactivates a given ability.
function TaskForce.Activate_Ability(abilityName, shouldActivate) end
---@public
---@return (PlanetObject|Position) The task force's staging area.
---Returns the task force's staging area.
function TaskForce.Get_Stage() end
---@public
---Lands the task force's units
function TaskForce.Land_Units() end
---@public
---Launches the task force's units into orbit.
function TaskForce.Launch_Units() end
---@public
---@return boolean Returns true if the invasion succeeded, false if the invasion failed.
---Invades a planet.
function TaskForce.Invade() end
---@public
---@param isRemovable boolean
---Adjusts whether the Goal the task force is associated with can be removed before it's been achieved.
function TaskForce.Set_As_Goal_System_Removable(isRemovable) end
---@class GameObject
---A wrapper around a single instance of a generic GameObjectType
local GameObject = {}
---@public
---@return GameObjectType
---Gets the type of the current game object wrapper.
function GameObject.Get_Type() end
---@public
---@param propertyFlag string A string representation of 1..n properties.
---@return boolean
---Tests if a GameObject has 1..n flags of the bitfield defined in GameObjectPropertiesType.xml set. Valid inputs are single items `"Turret"` or many `"Turret | InBase"`.
function GameObject.Has_Property(propertyFlag) end
---@public
---@return PlayerObject The PlayerObject owning the GameObject
---Returns the owner of the game object.
function GameObject.Get_Owner() end
---@public
---@return Position
---Returns the current position of the object in the world.
function GameObject.Get_Position() end
---@public
---@param categoryMask string The category mask to test for. Can be a single mask, or a combination: "CAPITAL" or "CAPITAL | SPACE_HERO"
---@return boolean
---Tests whether a given game object has a given category mask assigned to it.
function GameObject.Is_Category(categoryMask) end
---@public
---@return (GameObject|nil)
---Returns a game object if the unit has an attack target, nil else.
function GameObject.Get_Attack_Target() end
---@public
---@param abilityName string The ability to (de-)activate.
---@param shouldActivate boolean Activates the ability if true, deactivates if false.
---Activates or deactivates a given ability.
function GameObject.Activate_Ability(abilityName, shouldActivate) end
---@public
---@return boolean
---Tests whether a unit has active orders.
function GameObject.Has_Active_Orders() end
---@public
---@return number
---Returns a number between 0 and 1 representing the current percentage of hull points left.
function GameObject.Get_Hull() end
---@public
---@return number
---Returns a number between 0 and 1 representing the current percentage of shield points left.
function GameObject.Get_Shield() end
---@public
---@param target GameObject|Position
---@return number
function GameObject.Get_Distance(target) end
---@public
---@overload fun(target:Position|GameObject|PlanetObject):CommandBlock
---@param unit_list GameObject[]
---@param target Position|GameObject|PlanetObject
---@return CommandBlock
---Orders the GameObject to move to the given target. Returns a CommandBlock is marked as finished when the GameObject has arrived at target
function GameObject.Move_To(unit_list, target) end
---@public
---Despawns the GameObject
function GameObject.Despawn() end
---@public
---@param new_owner PlayerObject The PlayerObject the ownership will be transferred to
---Transfers ownership of a GameObject over to another Player
function GameObject.Change_Owner(new_owner) end
---@public
---@param behavior_id int The ID of the behavior
---@param enable boolean Enables the behavior if set to true. Disables it if it's false.
---Enables or disables a behavior defined in the XML entry of the GameObject
function GameObject.Enable_Behavior(behavior_id, enable) end
---@public
---@return GameObject Returns the parent object of the given GameObject. In galactic conquest this will return either a planet, a company or a container. In tactical mode it returns the squadron for single fighters.
function GameObject.Get_Parent_Object() end
---@public
---@return PlanetObject
---Returns the Planet the GameObject is located on. Can be nil if the GameObject is in Hyperspace
function GameObject.Get_Planet_Location() end
---@public
---@param hidden boolean Determines whether the GameObject is visible or invisible
---Makes the GameObject visible or invisible
function GameObject.Hide(hidden) end
---@public
---@param animation_name string The name of the animation
---@param should_repeat boolean Determines whether the animation gets repeated
---@param animation_index number The index of the animation, e.g. `3` to play `deploy_03.ala`
---Plays an animation on a GameObject. The animation must be present in the 3D model
function GameObject.Play_Animation(animation_name, should_repeat,
animation_index)
end
---@public
---@param abilityName string
---@return boolean
function GameObject.Is_Ability_Autofire(abilityName) end
---@public
---@param sfxEventName string
function GameObject.Play_SFX_Event(sfxEventName) end
---@public
---@return boolean
function GameObject.Is_Transport() end
---@public
---@param planet PlanetObject
---@return boolean
function GameObject.Can_Land_On_Planet(planet) end
---@public
---@return GameObjectType
function GameObject.Get_Game_Scoring_Type() end
---@public
---@param abilityName string
---@return boolean
function GameObject.Is_Ability_Ready(abilityName) end
---@public
---@param position Position|GameObject
function GameObject.Divert(position) end
---@public
---@return boolean
function GameObject.Is_On_Diversion() end
---@public
---@return GameObject[]
function GameObject.Get_Garrisoned_Units() end
---@public
---@param target GameObject
---@return boolean
function GameObject.Should_Switch_Weapons(target) end
---@public
---@param allow_spawn boolean
function GameObject.Set_Garrison_Spawn(allow_spawn) end
---@public
---@param disable boolean
function GameObject.Disable_Capture(disable) end
---@public
---@overload fun(damageAmount:number)
---@param damageAmount number
---@param hardpoint string
function GameObject.Take_Damage(damageAmount, hardpoint) end
---@public
---@overload fun(callbackFunction:function, range:number)
---@param callbackFunction fun(obj:GameObject, trigger:GameObject)
---@param range number
---@param player PlayerObject
function GameObject.Event_Object_In_Range(callbackFunction, range, player) end
---@public
---@param callbackFunction function
function GameObject.Cancel_Event_Object_In_Range(callbackFunction) end
---@public
--- The returned command block will never finish, even if the move is done and there is no target to be attacked.
---@overload fun(target:GameObject):CommandBlock
---@param unit_list GameObject[]
---@param target GameObject|Position
---@return CommandBlock
function GameObject.Attack_Move(unit_list, target) end
---@public
---@overload fun(target:GameObject):CommandBlock
---@param unit_list GameObject[]
---@param target GameObject
---@return CommandBlock
function GameObject.Attack_Target(unit_list, target) end
---@public
---@overload fun(target:GameObject):CommandBlock
---@param unit_list GameObject[]
---@param target GameObject|Position
---@return CommandBlock
function GameObject.Guard_Target(unit_list, target) end
---@public
--- Returns true if the unit can currently move (is false e.g. during hyperspace in)
---@return boolean
function GameObject.Can_Move() end
---@public
--- Stops the unit.
function GameObject.Stop() end
---@public
--- Movability on or off
---@param suspend boolean
function GameObject.Suspend_Locomotor(suspend) end
---@public
--- Activates targeted ability
---@param ability_name string
---@param turn_on GameObject|Position|boolean A target to turn on targeted abilities or a boolean.
function GameObject.Activate_Ability(ability_name, turn_on) end
---@public
--- Finishes ability cooldowns
function GameObject.Reset_Ability_Counter() end
---@public
---@param ability_name string
---@param autofire boolean
function GameObject.Set_Single_Ability_Autofire(ability_name, autofire) end
---@public
---@param autofire boolean
function GameObject.Set_All_Abilities_Autofire(autofire) end
---@public
---@param ability_name string
---@return boolean
function GameObject.Is_Ability_Active(ability_name) end
---@public
---@param ability_name string
---@return boolean
function GameObject.Has_Ability(ability_name) end
---@public
---@param ability_name string
---@param optional number
function GameObject.Force_Ability_Recharge(ability_name, optional) end
---@public
---@param ability_name string
function GameObject.Cancel_Ability(ability_name) end
---@public
---@return boolean
function GameObject.Are_Engines_Online() end
---@public
---@param speed number
function GameObject.Override_Max_Speed(speed) end
---@public
--- Makes the unit hyperspace into battle with a delay by the given number of frames.
---@param delay number The number of frames before the hyperspace animation is started
function GameObject.Cinematic_Hyperspace_In(delay) end
---@public
--- Makes unit leave into hyperspace. Will be removed from galactic level as well if the optional parameter is not set to false.
---@param remove_from_campaign boolean Default is true
function GameObject.Hyperspace_Away(remove_from_campaign) end
---@public
function GameObject.Cancel_Hyperspace() end
---@public
--- Allow or prevent AI usage. In tactical battles this crashes the game if the unit has no active AI! When the faction's AI changes, the unit is AI usable again.
---@param prevent boolean
function GameObject.Prevent_AI_Usage(prevent) end
---@public
--- Shall object be displayed in Cinematic?
---@param keep_visible boolean
function GameObject.In_End_Cinematic(keep_visible) end
---@public
---@param target Position|GameObject
function GameObject.Teleport(target) end
---@public
--- Teleport object make it face the same way as the target
---@param target GameObject
function GameObject.Teleport_And_Face(target) end
---@public
---@param target Position|GameObject
function GameObject.Face_Immediate(target) end
---@public
---@param target Position|GameObject
function GameObject.Turn_To_Face(target) end
---@public
--- Prevent automatically firing at targets in range
---@param prevent boolean
function GameObject.Prevent_Opportunity_Fire(prevent) end
---@public
--- Completely prevent a unit from firing
---@param prevent boolean
function GameObject.Prevent_All_Fire(prevent) end
---@public
--- Stops the unit from taking any damage
---@param invulnerable boolean
function GameObject.Make_Invulnerable(invulnerable) end
---@public
---@param check boolean
function GameObject.Set_Check_Contested_Space(check) end
---@public
function GameObject.Lock_Current_Orders() end
---@public
function GameObject.Unlock_Current_Orders() end
---@public
---@return boolean
function GameObject.Is_In_Asteroid_Field() end
---@public
---@return boolean
function GameObject.Is_In_Ion_Storm() end
---@public
---@return boolean
function GameObject.Is_In_Nebula() end
---@public
---@param enable boolean
function GameObject.Enable_Dynamic_LOD(enable) end
---@public
--- Only for fleets with land units in orbit over an enemy planet (is used in FoC campaign but doesn't seem to work)
function GameObject.Invade() end
---@public
---@param unknown boolean
function GameObject.Set_In_Limbo(unknown) end
---@public
--- Returns a list of the projectile types the unit uses
---@return GameObjectType[]
function GameObject.Get_All_Projectile_Types() end
---@public
---@return boolean
function GameObject.Is_Selectable() end
---@public
--- Sets a unit to be selectable or not selectable by the player
---@param selectable boolean
function GameObject.Set_Selectable(selectable) end
---@public
--- Returns the projectile type the unit is currently using
---@return GameObjectType
function GameObject.Get_Current_Projectile_Type() end
---@public
---@param target GameObject
---@return boolean
function GameObject.Is_Good_Against(target) end
---@public
---@return boolean
function GameObject.Is_In_Garrison() end
---@public
--- Returns true if the object contains any garrisoned units
---@return boolean
function GameObject.Has_Garrison() end
---@public
--- Eject all garrisoned units
function GameObject.Eject_Garrison() end
---@public
--- Make a garrisoned unit leave its garrison
function GameObject.Leave_Garrison() end
---@public
---@return boolean
function GameObject.Can_Garrison_Fire() end
---@public
--- Can the unit be garrisoned in the given object?
---@param target GameObject
---@return boolean
function GameObject.Can_Garrison(target) end
---@public
--- Garrison the unit in the given object
---@param target GameObject
function GameObject.Garrison(target) end
---@public
function GameObject.Play_Cinematic_Engine_Flyby() end
---@public
---@overload fun(event_name:string)
---@param event_name string
---@param optional number
function GameObject.Stop_SFX_Event(event_name, optional) end
---@public
---@overload fun(type:string|GameObjectType)
---@param type string|GameObjectType
---@param optional string
---@return GameObject
function GameObject.Attach_Particle_Effect(type, optional) end
---@public
---@return boolean
function GameObject.Has_Attack_Target() end
---@public
---@param emitter string
---@param show boolean
function GameObject.Show_Emitter(emitter, show) end
---@public
--- Put a small arrow highlight on top of the object
---@overload fun(highlight:boolean)
---@param highlight boolean
---@param optional number Seems to change the distance of the arrow to the object
function GameObject.Highlight_Small(highlight, optional) end
---@public
--- Put an arrow highlight on top of the object
---@overload fun(highlight:boolean)
---@param highlight boolean
---@param optional number Seems to change the distance of the arrow to the object
function GameObject.Highlight(highlight, optional) end
---@public
---@param target AITarget
---@return CommandBlock
function GameObject.Explore_Area(target) end
---@public
--- Check if a space battle should be initiated, e.g. after spawning a fleet at an enemy planet (only works on fleets and planets)
function GameObject.Force_Test_Space_Conflict() end
---@public
--- Keep a unit from dying (it can still be damaged)
---@param cannot_be_killed boolean
function GameObject.Set_Cannot_Be_Killed(cannot_be_killed) end
---@public
--- Returns the hint set for this object in the map editor or nil.
---@return string|nil
function GameObject.Get_Hint() end
---@public
--- Fire death star in tactical mode
function GameObject.Fire_Tactical_Superweapon() end
---@public
--- Test if death star is ready to fire
---@return boolean
function GameObject.Is_Tactical_Superweapon_Ready() end
---@public
---@param bone_name string
---@return Position
function GameObject.Get_Bone_Position(bone_name) end
---@public
---@param lock boolean
function GameObject.Lock_Build_Pad_Contents(lock) end
---@public
--- Only used on fleets
---@param number number
function GameObject.Destroy_Contained_Objects(number) end
---@public
--- Only used on fleets
---@param object_type GameObjectType
---@return boolean
function GameObject.Contains_Object_Type(object_type) end
---@public
--- Only used on fleets
---@return number
function GameObject.Get_Contained_Object_Count() end
---@public
--- (tactical only)
---@param game_object GameObject
---@return number
function GameObject.Get_AI_Power_Vs_Unit(game_object) end
---@public
--- Use in tactical. This kills the corresponding GC object
function GameObject.Mark_Parent_Mode_Object_For_Death() end
---@public
---@param number number
function GameObject.Set_Importance(number) end
---@public
function GameObject.Service_Wrapper() end
---@public
--- Possibly only for build pad contents
function GameObject.Sell() end
---@public
--- Use on build pads or MDUs
---@return GameObject
function GameObject.Get_Build_Pad_Contents() end
---@public
--- Only for fleets
---@return GameObject[]
function GameObject.Get_Contained_Heroes() end
---@public
--- Only for fleets
---@return boolean
function GameObject.Contains_Hero() end
---@public
--- Use on spawned special weapon or on space station with special weapon
---@param target GameObject
---@param user PlayerObject
function GameObject.Fire_Special_Weapon(target, user) end
---@public
---@return number
function GameObject.Get_Rate_Of_Damage_Taken() end
---@public
--- Expected time til death based on damage taken.
---@return number
function GameObject.Get_Time_Till_Dead() end
---@public
---@param number number
function GameObject.Set_Targeting_Stickiness_Time_Threshold(number) end
---@public
---@param targeting_priority_set string
function GameObject.Set_Targeting_Priorities(targeting_priority_set) end
---@public
--- Obeject needs UNIT_AI behavior
---@param prefer boolean
function GameObject.Set_Prefer_Ground_Over_Space(prefer) end
---@public
--- Normalized with respect to unit's total energy
---@return number Float between 0 and 1
function GameObject.Get_Energy() end
---@public
--- Normalized with respect to unit's total health
---@return number Float between 0 and 1
function GameObject.Get_Health() end
---@public
function GameObject.Release() end
---@public
--- Use on buildpads and MDUs. Takes a UC type
---@param type string|GameObjectType
---@param optional boolean
function GameObject.Build(type, optional) end
---@class Position
---Represents a position in the world.
local Position = {}
---@class GameObjectType
---A generic GameObjectType that represents a C++ GameObjectTypeClass
local GameObjectType = {}
---@public
---@return string
---Retrieves the XML name of a GameObjectType
function GameObjectType.Get_Name() end
---@public
---@return boolean
function GameObjectType.Is_Hero() end
---@public
---@return number
function GameObjectType.Get_Build_Cost() end
---@public
--- Returns the AI_Combat_Power
---@return number
function GameObjectType.Get_Combat_Rating() end
---@public
--- Returns required tech level
---@return number
function GameObjectType.Get_Tech_Level() end
---@public
--- Returns level of a starbase type
---@return number
function GameObjectType.Get_Base_Level() end
---@public
---@param player PlayerObject
---@return boolean
function GameObjectType.Is_Affiliated_With(player) end
---@public
---@param player PlayerObject
---@return boolean
function GameObjectType.Is_Build_Locked(player) end
---@public
---@param player PlayerObject
---@return boolean
function GameObjectType.Is_Obsolete(player) end
---@public
---@return number
function GameObjectType.Get_Tactical_Build_Cost() end
---@public
---@return number
function GameObjectType.Get_Score_Cost_Credits() end
---@public
---@return number
function GameObjectType.Get_Max_Range() end
---@public
---@return number
function GameObjectType.Get_Min_Range() end
---@public
---@return number
function GameObjectType.Get_Bribe_Cost() end
---@public
--- This only makes sense for projectile types though it can be used for others as well.
---@return boolean
function GameObjectType.Is_Affected_By_Missile_Shield() end
---@public
--- This only makes sense for projectile types though it can be used for others as well.
---@return boolean
function GameObjectType.Is_Affected_By_Laser_Defense() end
---@class GameObjectWrapper
---A generic wrapper around a GameObject
local GameObjectWrapper = {}
---@public
---Returns `true` if the contained game object is valid.
---@return boolean
function GameObjectWrapper.Is_Valid() end
---@class PlayerObject
---A wrapper around a player (AI or human) taking control of a faction.
local PlayerObject = {}
---@public
---@return boolean
---Tests whether a PlayerObject is human.
function PlayerObject.Is_Human() end
---@public
---@param playerObject PlayerObject
---@return boolean
---Tests whether a player object is an enemy of another player object.
function PlayerObject.Is_Enemy(playerObject) end
---@public
---@param amount number
function PlayerObject.Give_Money(amount) end
---@public
---@return number
function PlayerObject.Get_ID() end
---@public
---@param playerObject PlayerObject
---@return boolean
function PlayerObject.Is_Ally(playerObject) end
---@public
--- Enables Advisor Hints
---@param mode string Is "space" or "ground"
---@param enable boolean
function PlayerObject.Enable_Advisor_Hints(mode, enable) end
---@public
--- Returns an enemy player (may only ever returns Rebel or Empire, in any case there is not much point using it outside the base EaW though it might be related to the Primary Enemy tag)
---@return PlayerObject
function PlayerObject.Get_Enemy() end
---@public
--- Forces player to select object
---@param object GameObject
function PlayerObject.Select_Object(object) end
---@public
--- Activates the AI for the player
function PlayerObject.Enable_As_Actor() end
---@public
--- Enables retreat event. Returns false if player is not able to retreat.
---@return boolean
function PlayerObject.Retreat() end
---@public
--- returns the displayed faction name
---@return string
function PlayerObject.Get_Name() end
---@public
--- Returns xml faction name
---@return string
function PlayerObject.Get_Faction_Name() end
---@public
---@return number
function PlayerObject.Get_Tech_Level() end
---@public
function PlayerObject.Give_Random_Sliceable_Tech() end
---@public
--- Gets reset with any game mode changes, in particular at the end of every tactical battle!
---@param player PlayerObject
function PlayerObject.Make_Ally(player) end
---@public
--- Gets reset with any game mode changes, in particular at the end of every tactical battle!
---@param player PlayerObject
function PlayerObject.Make_Enemy(player) end
---@public
--- Returns the player's space station in space tactical
---@return GameObject
function PlayerObject.Get_Space_Station() end
---@public
--- Team ID in skirmish
---@return number
function PlayerObject.Get_Team() end
---@public
--- Clan ID in skirmish
---@return number
function PlayerObject.Get_Clan_ID() end
---@public
--- Removes the orbital bombardment. Countdown for usage will continue and not be reset if the bombardment is re-enabled.
---@param remove boolean
function PlayerObject.Remove_Orbital_Bombardment(remove) end
---@public
--- Disable the bombardment. The countdown for usage will continue.
---@param disable boolean
function PlayerObject.Disable_Orbital_Bombardment(disable) end
---@public
---@param set boolean
function PlayerObject.Set_Sabotage_Tutorial(set) end
---@public
---@param set boolean
function PlayerObject.Set_Black_Market_Tutorial(set) end
---@public
---@return string Returns "Easy", "Normal" or "Hard"
function PlayerObject.Get_Difficulty() end
---@public
--- The parameter logic is reversed here. The bombing run is disabled if false is passed.
---@param enable boolean
function PlayerObject.Disable_Bombing_Run(enable) end
---@public
---@param object_type GameObjectType
function PlayerObject.Unlock_Tech(object_type) end
---@public
function PlayerObject.Get_GameSpy_Stats_Player_ID() end
---@public
---@return number
function PlayerObject.Get_Credits() end
---@public
--- For AI player (with galactic AI) only. Releases credits for spending in tactical mode.
---@param amount number
function PlayerObject.Release_Credits_For_Tactical(amount) end
---@public
---@param level number
function PlayerObject.Set_Tech_Level(level) end
---@class PlanetObject : GameObject
local PlanetObject = {}
---@public
---@return boolean
function PlanetObject.Get_Is_Planet_AI_Usable() end
---@public
---@return boolean
function PlanetObject.Is_Corrupted() end
---@public
--- Check if a space battle should be initiated, e.g. after spawning a fleet at an enemy planet (only works on fleets and planets)
function PlanetObject.Force_Test_Space_Conflict() end
---@public
---@return boolean
function PlanetObject.Is_Planet_Destroyed() end
---@public
--- Returns the indigenous unit type of that planet affiliated with the given player
---@return GameObjectType
function PlanetObject.Get_Affiliated_Indigenous_Type(player) end
---@public
---@return GameObjectType
function PlanetObject.Get_Next_Starbase_Type() end
---@public
---@return PlayerObject
function PlanetObject.Get_Final_Blow_Player() end
---@public
---@return number
function PlanetObject.Get_Starbase_Level() end
---@class GameScoringType
local GameScoringType = {}
---@public
---@return number
function GameScoringType.Get_Score_Cost_Credits() end
---@public
---@return number
function GameScoringType.Get_Combat_Rating() end
---@public
---@return number
function GameScoringType.Get_Build_Cost() end
---@class CommandBlock
local CommandBlock = {}
---@public
---@return table
---Returns the result of the CommandBlock
function CommandBlock.Result() end
---@public
---@return boolean
---Returns a boolean indicating whether the CommandBlock has finished its command
function CommandBlock.IsFinished() end
---@class AITarget
local AITarget = {}
---@public
--- Returns corresponding game object if there is one (e.g. a targeted unit or planet).
---@return GameObject
function AITarget.Get_Game_Object() end
---@public
---@param position Position
---@return number
function AITarget.Get_Distance(position) end
-- return TaskForce, GameObject, Position, GameObjectType, GameObjectWrapper, PlayerObject, PlanetObject, GameScoringType, CommandBlock

View File

@@ -1,152 +0,0 @@
---@meta
---@diagnostic disable: missing-fields
-- Empire at War / Forces of Corruption engine API stubs.
-- This file is never executed — the Lua Language Server reads it as definitions only.
-- ==================================================
-- Engine Object Types
-- ==================================================
---A player in the game (C++ PlayerWrapper userdata).
---@class PlayerWrapper
---@field Get_Name fun(): string
---@field Get_ID fun(): integer
---@field Get_Faction fun(): string
---@field Get_Credits fun(): number
---@field Is_Valid fun(): boolean
---@field Is_Human fun(): boolean
---@field Is_Ally fun(other: PlayerWrapper): boolean
---@field Is_Enemy fun(other: PlayerWrapper): boolean
---@field Select_Object fun(other: GameObjectWrapper)
---A game object instance (C++ GameObjectWrapper userdata).
---@class GameObjectWrapper
---@field Get_Type fun(): GameObjectTypeWrapper
---@field Get_Owner fun(): PlayerWrapper
---@field Get_Final_Blow_Player fun(): PlayerWrapper
---@field Get_Game_Scoring_Type fun(): GameObjectTypeWrapper
---@field Is_Valid fun(): boolean
---@field Is_Pool_Safe fun(): boolean
---@field Service_Wrapper fun()
---A game object type definition (C++ GameObjectTypeWrapper userdata).
---@class GameObjectTypeWrapper
---@field Get_Name fun(): string
---@field Is_Valid fun(): boolean
-- ==================================================
-- Script Object
-- ==================================================
---The engine-injected script context object.
---@class ScriptObject
---@field Debug_Should_Issue_Event_Alert fun(): boolean
---Engine-injected script context. Set by the engine before the script runs.
---@type ScriptObject
Script = {}
---Engine-injected object context. Set by the engine before the script runs.
---@type GameObjectWrapper
Object = {}
-- ==================================================
-- GlobalValue / ThreadValue
-- (callable table: GlobalValue("key") to get, GlobalValue.Set("key", val) to set)
-- ==================================================
---@class ValueStore
---@field Set fun(key: string, value: any)
---@operator call(string): any
---Persistent global value store shared across scripts.
---@type ValueStore
GlobalValue = {}
---Per-thread value store.
---@type ValueStore
ThreadValue = {}
-- ==================================================
-- Engine Global Functions
-- ==================================================
---Pumps services for the script.
function Pump_Service() end
---Compares two strings for equality (case-insensitive in FoC).
---@param a string
---@param b string
---@return boolean
function StringCompare(a, b) end
---Finds a player by name (e.g. "local", "empire", "rebel").
---@param name string
---@return PlayerWrapper
function Find_Player(name) end
---Returns the current game time in seconds.
---@return number
function GetCurrentTime() end
---Returns the ID of the current thread, or -1 if not in a thread.
---@return integer
function GetThreadID() end
---Returns the next pending event function, or nil if the queue is empty.
---@return (fun(...): any) | nil
function GetEvent() end
---Exits the current script.
function _ScriptExit() end
---Pops up a message box (internal engine call).
---@param message string
function _MessagePopup(message) end
---Sends a message to the script log (internal engine call).
---@param message string
function _ScriptMessage(message) end
---Sends a message to the debug output (internal engine call — note: typo in original source).
---@param message string
function _OuputDebug(message) end
---Dumps the current Lua call stack as a string.
---@return string
function DumpCallStack() end
---Sets the visibility of the named component.
---@param component string
---@param isVisible boolean
function GUI_Component_Visibility(component, isVisible) end
---Sets the text for the named component.
---@param component string
---@param text string
function GUI_Component_Text(component, text) end
---Sets the text color for the named component.
---@param component string
---@param r number
---@param g number
---@param b number
---@param a number
function GUI_Text_Color(component, r, g, b, a) end
---Sets the icon for the named component.
---@param component string
---@param icon string
---@param r number
---@param g number
---@param b number
---@param a number
function GUI_Button_Icon(component, icon, r, g, b, a) end
---Finds all objects matching the criteria.
---@param a any
---@param b any
---@param c any
---@param d any
---@return GameObjectWrapper[]
function Find_All_Objects_Of_Type(a, b, c, d) end

View File

@@ -0,0 +1,53 @@
---@diagnostic disable
-- ==================================================
-- I/O
-- ==================================================
---@public
---Appends the text to file.
---@param file string The file name.
---@param text string The text to append.
function WriteToFile(file, text) end
-- ==================================================
-- Finders
-- ==================================================
---Finds all Players in the game.
---@return PlayerObject[]
function Get_All_Players() end
-- ==================================================
-- UI
-- ==================================================
---@public
---Adds the specified text to the tutorial text box.
---A new text key will be appended as a new line.
---An existing text key will be overwritten.
---@param key string The key to use.
---@param text string The text to add.
---@param duration number The duration to keep text on screen, defaults to -1 (infinite).
---@param r number The red color component.
---@param g number The green color component.
---@param b number The blue color component.
---@param a number The alpha channel component.
function Add_Tutorial_Text(key, text, duration, r, g, b, a) end
---@public
---Removes the specified text key from the tutorial text box.
---@param key string The key to remove.
function Remove_Tutorial_Text(key) end
-- ==================================================
-- GameObjectType extensions
-- ==================================================
---@class GameObjectType
---A generic GameObjectType that represents a C++ GameObjectTypeClass
local GameObjectType = {}
---@public
---Returns the display name for the object type.
---@return string
function GameObjectType.Get_Display_Name() end

View File

@@ -39,6 +39,8 @@
-- --
--///////////////////////////////////////////////////////////////////////////////////////////////// --/////////////////////////////////////////////////////////////////////////////////////////////////
---@diagnostic disable
require("PGDebug") require("PGDebug")
YieldCount = 0; YieldCount = 0;
@@ -52,7 +54,6 @@ function ScriptExit()
end end
function Sleep(time) function Sleep(time)
--DebugMessage("Sleeping... SleepTime: %.3f, CurTime: %.3f\n", time, GetCurrentTime()) --DebugMessage("Sleeping... SleepTime: %.3f, CurTime: %.3f\n", time, GetCurrentTime())
ThreadValue.Set("StartTime", GetCurrentTime()) ThreadValue.Set("StartTime", GetCurrentTime())
while GetCurrentTime() - ThreadValue("StartTime") < time do while GetCurrentTime() - ThreadValue("StartTime") < time do
@@ -64,7 +65,6 @@ end
-- Service the block until optional max duration has expired or alternate break function returns true -- Service the block until optional max duration has expired or alternate break function returns true
-- Pass -1 max_duration to use optional alternate break function with no time limit -- Pass -1 max_duration to use optional alternate break function with no time limit
function BlockOnCommand(block, max_duration, alternate_break_func) function BlockOnCommand(block, max_duration, alternate_break_func)
PumpEvents() PumpEvents()
if not block then if not block then
@@ -84,7 +84,7 @@ function BlockOnCommand(block, max_duration, alternate_break_func)
PumpEvents() PumpEvents()
if ((max_duration ~= nil) and (max_duration ~= -1) if ((max_duration ~= nil) and (max_duration ~= -1)
and (GetCurrentTime() - ThreadValue("BlockStart") > max_duration)) then and (GetCurrentTime() - ThreadValue("BlockStart") > max_duration)) then
--MessageBox("%s -- Had a time limit and it expired", tostring(Script)) --MessageBox("%s -- Had a time limit and it expired", tostring(Script))
return nil return nil
end end
@@ -93,7 +93,6 @@ function BlockOnCommand(block, max_duration, alternate_break_func)
--MessageBox("%s-- had a break func and it returned true", tostring(Script)) --MessageBox("%s-- had a break func and it returned true", tostring(Script))
return nil return nil
end end
until (block.IsFinished() == true) until (block.IsFinished() == true)
PumpEvents() PumpEvents()
@@ -116,7 +115,6 @@ function TestCommand(block)
end end
function PumpEvents() function PumpEvents()
if Object and type(Object) == "userdata" then if Object and type(Object) == "userdata" then
Object.Service_Wrapper() Object.Service_Wrapper()
end end
@@ -183,24 +181,23 @@ function Dirty_Floor(val)
end end
-- Machine independent modulus function -- Machine independent modulus function
function Simple_Mod(a,b) function Simple_Mod(a, b)
--return a-b*math.floor(a/b) --return a-b*math.floor(a/b)
return a-b*Dirty_Floor(a/b) return a - b * Dirty_Floor(a / b)
end end
-- Returns if something happened, given a % chance -- Returns if something happened, given a % chance
function Chance(seed, percent) function Chance(seed, percent)
roll = Simple_Mod((seed + 1), 100) roll = Simple_Mod((seed + 1), 100)
is_allowed = roll < percent is_allowed = roll < percent
DebugMessage("%s -- seed:%d percent:%d roll:%d is_allowed:%s", tostring(Script), seed, percent, roll, tostring(is_allowed)) DebugMessage("%s -- seed:%d percent:%d roll:%d is_allowed:%s", tostring(Script), seed, percent, roll,
tostring(is_allowed))
return is_allowed return is_allowed
end end
function GetCurrentMinute() function GetCurrentMinute()
--return math.floor(GetCurrentTime()/60) --return math.floor(GetCurrentTime()/60)
return Dirty_Floor(GetCurrentTime()/60) return Dirty_Floor(GetCurrentTime() / 60)
end end
-- Every X seconds, the AI will have a new opportunity to see if it's allowed to use an ability -- Every X seconds, the AI will have a new opportunity to see if it's allowed to use an ability
@@ -219,41 +216,38 @@ function GetChanceAllowed(difficulty)
return chance return chance
end end
function PlayerSpecificName(player_object, var_name) function PlayerSpecificName(player_object, var_name)
-- ret_value = tostring(player_object.Get_ID()) .. "_" .. var_name -- ret_value = tostring(player_object.Get_ID()) .. "_" .. var_name
-- DebugMessage("%s -- creating player specific string %s.", tostring(Script), ret_value) -- DebugMessage("%s -- creating player specific string %s.", tostring(Script), ret_value)
-- return ret_value -- return ret_value
return (tostring("PLAYER" .. player_object.Get_ID()) .. "_" .. var_name) return (tostring("PLAYER" .. player_object.Get_ID()) .. "_" .. var_name)
end end
function Flush_G() function Flush_G()
entries_for_deletion = {} entries_for_deletion = {}
--Define the set of tables that we had better keep around --Define the set of tables that we had better keep around
very_important_tables = { very_important_tables = {
_LOADED, _LOADED,
coroutine, coroutine,
string, string,
LuaWrapperMetaTable, LuaWrapperMetaTable,
_G, _G,
security, security,
table, table,
entries_for_deletion entries_for_deletion
} }
--Silly thing is nil (we think) if we try to add it earlier --Silly thing is nil (we think) if we try to add it earlier
table.insert(very_important_tables, very_important_tables) table.insert(very_important_tables, very_important_tables)
--Iterate all globals --Iterate all globals
for i,g_entry in pairs(_G) do for i, g_entry in pairs(_G) do
if type(g_entry) == "table" then if type(g_entry) == "table" then
--Tables are inherently unsafe: who knows what might be in there? --Tables are inherently unsafe: who knows what might be in there?
--If they're not in the list of things we must keep then they go. --If they're not in the list of things we must keep then they go.
for j,important_entry in pairs(very_important_tables) do for j, important_entry in pairs(very_important_tables) do
if important_entry == g_entry then if important_entry == g_entry then
keep_table = true keep_table = true
end end
@@ -263,7 +257,6 @@ function Flush_G()
end end
keep_table = nil keep_table = nil
elseif type(g_entry) == "userdata" then elseif type(g_entry) == "userdata" then
--Some User Data (e.g. our code functions) should be kept, but some is very, very dangerous. --Some User Data (e.g. our code functions) should be kept, but some is very, very dangerous.
--Query the object to see whether it's safe to persist. --Query the object to see whether it's safe to persist.
@@ -271,17 +264,13 @@ function Flush_G()
if not g_entry.Is_Pool_Safe() then if not g_entry.Is_Pool_Safe() then
table.insert(entries_for_deletion, i) table.insert(entries_for_deletion, i)
end end
end end
end end
for i,bad_entry in pairs(entries_for_deletion) do for i, bad_entry in pairs(entries_for_deletion) do
_G[bad_entry] = nil _G[bad_entry] = nil
end end
entries_for_deletion = nil entries_for_deletion = nil
very_important_tables = nil very_important_tables = nil
end end

View File

@@ -39,6 +39,7 @@
-- --
--///////////////////////////////////////////////////////////////////////////////////////////////// --/////////////////////////////////////////////////////////////////////////////////////////////////
---@diagnostic disable
function DebugEventAlert(event, params) function DebugEventAlert(event, params)
message = tostring(Script) .. ": handled event " .. tostring(event) message = tostring(Script) .. ": handled event " .. tostring(event)

View File

@@ -4,6 +4,7 @@ require("PGBase")
---@field R number The red component. ---@field R number The red component.
---@field G number The green component. ---@field G number The green component.
---@field B number The blue component. ---@field B number The blue component.
---@field A number The alpha component.
ColorStruct = {} ColorStruct = {}
ColorStruct.__index = ColorStruct ColorStruct.__index = ColorStruct
@@ -11,17 +12,19 @@ ColorStruct.__index = ColorStruct
---@param r number The red component ---@param r number The red component
---@param g number The green component ---@param g number The green component
---@param b number The blue component ---@param b number The blue component
---@param a number The alpha component
---@return ColorStruct ---@return ColorStruct
function ColorStruct:New(r, g, b) function ColorStruct:New(r, g, b, a)
local self = setmetatable({}, ColorStruct) local self = setmetatable({}, ColorStruct)
self.R = Clamp(r, 0, 1) self.R = Clamp(r, 0, 1)
self.G = Clamp(g, 0, 1) self.G = Clamp(g, 0, 1)
self.B = Clamp(b, 0, 1) self.B = Clamp(b, 0, 1)
self.A = Clamp(a, 0, 1)
return self return self
end end
function ColorStruct:Debug() function ColorStruct:Debug()
return string.format("RGB (%d, %d, %d)", self.R, self.G, self.B) return string.format("RGB (%d, %d, %d, %d)", self.R, self.G, self.B, self.A)
end end

View File

@@ -1,4 +1,28 @@
require("FactionStruct") require("GameManager/FactionStruct")
require("GameManager/GUIManager")
require("GameManager/TutorialTextManager")
-- ==================================================
-- Define Manager constants
-- ==================================================
---The singleton GUI Manager.
---@type GUIManager
GUIManager = GUIManager:New()
---The singleton Tutorial Text Manager.
---@type TutorialTextManager
TextManager = TutorialTextManager:New()
---The local player.
---@type PlayerObject|nil
LocalPlayer = nil
---Frag Index of Kill Stat Tables
FragIndex = 1
---Death Index of Kill Stat Tables
DeathIndex = 2
-- ================================================== -- ==================================================
-- Define Faction constants -- Define Faction constants
@@ -15,9 +39,9 @@ function DefineFactions()
local RebelFaction = FactionStruct:New("REBEL") local RebelFaction = FactionStruct:New("REBEL")
RebelFaction.DisplayName = "Rebellion" RebelFaction.DisplayName = "Rebellion"
RebelFaction.Color = ColorStruct:New(1, 0, 0) RebelFaction.Color = ColorStruct:New(1, 0, 0, 1)
RebelFaction.Icon = "I_ICON_SPECTATOR_REBEL.TGA" RebelFaction.Icon = "I_ICON_SPECTATOR_REBEL.TGA"
RebelFaction.LandStartUnitName = "Rebel_Infantry_Squad" RebelFaction.LandStartUnitName = "Rebel_Trooper_Team"
RebelFaction.SpaceStartUnitName = "Rebel_X-Wing_Squadron" RebelFaction.SpaceStartUnitName = "Rebel_X-Wing_Squadron"
factions[RebelFaction.Name] = RebelFaction factions[RebelFaction.Name] = RebelFaction
@@ -26,9 +50,9 @@ function DefineFactions()
local EmpireFaction = FactionStruct:New("EMPIRE") local EmpireFaction = FactionStruct:New("EMPIRE")
EmpireFaction.DisplayName = "Empire" EmpireFaction.DisplayName = "Empire"
EmpireFaction.Color = ColorStruct:New(0, 1, 1) EmpireFaction.Color = ColorStruct:New(0, 1, 1, 1)
EmpireFaction.Icon = "I_ICON_SPECTATOR_EMPIRE.TGA" EmpireFaction.Icon = "I_ICON_SPECTATOR_EMPIRE.TGA"
EmpireFaction.LandStartUnitName = "Imperial_Stormtrooper_Squad" EmpireFaction.LandStartUnitName = "Stormtrooper_Team"
EmpireFaction.SpaceStartUnitName = "TIE_Interceptor_Squadron_Container" EmpireFaction.SpaceStartUnitName = "TIE_Interceptor_Squadron_Container"
factions[EmpireFaction.Name] = EmpireFaction factions[EmpireFaction.Name] = EmpireFaction
@@ -37,9 +61,9 @@ function DefineFactions()
local UnderworldFaction = FactionStruct:New("UNDERWORLD") local UnderworldFaction = FactionStruct:New("UNDERWORLD")
UnderworldFaction.DisplayName = "Zann Consortium" UnderworldFaction.DisplayName = "Zann Consortium"
UnderworldFaction.Color = ColorStruct:New(1, 1, 0) UnderworldFaction.Color = ColorStruct:New(1, 1, 0, 1)
UnderworldFaction.Icon = "I_ICON_SPECTATOR_UNDERWORLD.TGA" UnderworldFaction.Icon = "I_ICON_SPECTATOR_UNDERWORLD.TGA"
UnderworldFaction.LandStartUnitName = "Underworld_Merc_Squad" UnderworldFaction.LandStartUnitName = "Underworld_Merc_Team"
UnderworldFaction.SpaceStartUnitName = "StarViper_Team" UnderworldFaction.SpaceStartUnitName = "StarViper_Team"
factions[UnderworldFaction.Name] = UnderworldFaction factions[UnderworldFaction.Name] = UnderworldFaction
@@ -47,9 +71,9 @@ function DefineFactions()
local HuttFaction = FactionStruct:New("HUTTS") local HuttFaction = FactionStruct:New("HUTTS")
HuttFaction.DisplayName = "Hutt Cartel" HuttFaction.DisplayName = "Hutt Cartel"
HuttFaction.Color = ColorStruct:New(1, 0, 1) HuttFaction.Color = ColorStruct:New(1, 0, 1, 1)
HuttFaction.Icon = "I_ICON_SPECTATOR_HUTTS.TGA" HuttFaction.Icon = "I_ICON_SPECTATOR_HUTTS.TGA"
HuttFaction.LandStartUnitName = "Hutt_Soldier_Squad" HuttFaction.LandStartUnitName = "Hutt_Soldier_Team"
HuttFaction.SpaceStartUnitName = "V_Wing_Squadron_Container" HuttFaction.SpaceStartUnitName = "V_Wing_Squadron_Container"
factions[HuttFaction.Name] = HuttFaction factions[HuttFaction.Name] = HuttFaction
@@ -57,9 +81,9 @@ function DefineFactions()
local PirateFaction = FactionStruct:New("PIRATES") local PirateFaction = FactionStruct:New("PIRATES")
PirateFaction.DisplayName = "Pirates" PirateFaction.DisplayName = "Pirates"
PirateFaction.Color = ColorStruct:New(0, 1, 0) PirateFaction.Color = ColorStruct:New(0, 1, 0, 1)
PirateFaction.Icon = "I_ICON_SPECTATOR_PIRATES.TGA" PirateFaction.Icon = "I_ICON_SPECTATOR_PIRATES.TGA"
PirateFaction.LandStartUnitName = "Pirate_Soldier_Squad" PirateFaction.LandStartUnitName = "Pirate_Trooper_Team"
PirateFaction.SpaceStartUnitName = "Pirate_Fighter_Squadron" PirateFaction.SpaceStartUnitName = "Pirate_Fighter_Squadron"
factions[PirateFaction.Name] = PirateFaction factions[PirateFaction.Name] = PirateFaction
@@ -70,6 +94,16 @@ end
---@type FactionStruct[] ---@type FactionStruct[]
Factions = DefineFactions() Factions = DefineFactions()
-- ==================================================
-- Define Spectator Constants
-- ==================================================
---Space marker used to identify the spectator player.
Spectator_Marker_Space = "Spectator_Reveal_Marker"
---Land marker used to identify the spectator player.
Spectator_Marker_Land = "Spectator_Reveal_Marker_Land"
-- ================================================== -- ==================================================
-- Define UI Constants -- Define UI Constants
-- ================================================== -- ==================================================
@@ -77,12 +111,16 @@ Factions = DefineFactions()
---GUI Component to display game time. ---GUI Component to display game time.
UI_GameTime = "s_select_41" UI_GameTime = "s_select_41"
---GUI Components to display Team 1 credits. ---GUI Component to display Team 1 faction icon.
UI_IconT1 = "s_health_42" UI_IconT1 = "s_health_42"
--- GUI Component to display Team 1 credits text.
UI_CreditsT1 = "s_health_41" UI_CreditsT1 = "s_health_41"
---GUI Component to display Team 2 credits. ---GUI Component to display Team 2 faction icon.
UI_IconT2 = "s_shield_42" UI_IconT2 = "s_shield_42"
---GUI Component to display Team 2 credits text.
UI_CreditsT2 = "s_shield_41" UI_CreditsT2 = "s_shield_41"
---GUI Component to enable/disable population. ---GUI Component to enable/disable population.
@@ -91,15 +129,5 @@ UI_PlanetaryPop = "text_planetary_pop"
---GUI Component to enable/disable tactical credits. ---GUI Component to enable/disable tactical credits.
UI_CreditsTactical = "text_credits_tactical" UI_CreditsTactical = "text_credits_tactical"
---Gets the specator marker for the game mode. ---GUI Component to enable/disable tactical tech.
---@param gameMode string Game mode. UI_TechTactical = "text_tactical_tech"
---@return string|nil
function GetSpectatorMarkerName(gameMode)
if StringCompare(gameMode, "Space") then
return "Spectator_Reveal_Marker"
elseif StringCompare(gameMode, "Land") then
return "Spectator_Reveal_Marker_Land"
end
return nil
end

View File

@@ -1,4 +1,4 @@
require("ColorStruct") require("GameManager/ColorStruct")
---@class FactionStruct ---@class FactionStruct
---@field Name string Faction name. ---@field Name string Faction name.
@@ -18,7 +18,7 @@ function FactionStruct:New(name)
self.Name = name self.Name = name
self.DisplayName = name self.DisplayName = name
self.Color = ColorStruct:New(1, 1, 1) self.Color = ColorStruct:New(1, 1, 1, 1)
self.Icon = "" self.Icon = ""
self.LandStartUnitName = "" self.LandStartUnitName = ""
self.SpaceStartUnitName = "" self.SpaceStartUnitName = ""

View File

@@ -1,10 +1,7 @@
require("PGBase") require("PGBase")
require("GameManager.Constants") require("GameManager/Utilities")
---@class GUIManager ---@class GUIManager
---@field TacticalGame TacticalGameClass|nil The local Tactical Game state.
---@field SkirmishGame SkirmishGameClass|nil The local Skirmish Game state.
---@field ShowTeamId integer The Team ID units to display.
GUIManager = {} GUIManager = {}
GUIManager.__index = GUIManager GUIManager.__index = GUIManager
@@ -13,22 +10,15 @@ GUIManager.__index = GUIManager
function GUIManager:New() function GUIManager:New()
local self = setmetatable({}, GUIManager) local self = setmetatable({}, GUIManager)
self.TacticalGame = nil
self.SkirmishGame = nil
self.ShowTeamId = 0
return self return self
end end
---Initializes the GUI Manager for Skirmish mode. ---Initializes the GUI Manager for Skirmish mode.
---@param game SkirmishGameClass The Skirmish Game state. ---@param isSpectator boolean Whether to initialize in spectator mode.
function GUIManager:InitSkirmish(game) function GUIManager:InitSkirmish(isSpectator)
self.SkirmishGame = game self:InitTactical()
self.TacticalGame = game.TacticalGame
GUI_Component_Visibility(UI_GameTime, true) if isSpectator then
if self.SkirmishGame.IsLocalSpectator then
GUI_Component_Visibility(UI_CreditsT1, true) GUI_Component_Visibility(UI_CreditsT1, true)
GUI_Component_Visibility(UI_IconT1, true) GUI_Component_Visibility(UI_IconT1, true)
@@ -37,22 +27,17 @@ function GUIManager:InitSkirmish(game)
GUI_Component_Visibility(UI_PlanetaryPop, false) GUI_Component_Visibility(UI_PlanetaryPop, false)
GUI_Component_Visibility(UI_CreditsTactical, false) GUI_Component_Visibility(UI_CreditsTactical, false)
GUI_Component_Visibility(UI_TechTactical, false)
end end
end end
---Initializes the GUI Manager for Tactical mode. ---Initializes the GUI Manager for Tactical mode.
---@param game TacticalGameClass The Tactical Game state. function GUIManager:InitTactical()
function GUIManager:InitTactical(game)
self.TacticalGame = game
GUI_Component_Visibility(UI_GameTime, true) GUI_Component_Visibility(UI_GameTime, true)
end end
---Resets the GUI Manager. ---Resets the GUI Manager.
function GUIManager:Reset() function GUIManager:Reset()
self.SkirmishGame = nil
self.TacticalGame = nil
GUI_Component_Text(UI_GameTime, "") GUI_Component_Text(UI_GameTime, "")
GUI_Text_Color(UI_GameTime, 1, 1, 1, 1) GUI_Text_Color(UI_GameTime, 1, 1, 1, 1)
GUI_Component_Visibility(UI_GameTime, false) GUI_Component_Visibility(UI_GameTime, false)
@@ -73,122 +58,46 @@ function GUIManager:Reset()
GUI_Component_Visibility(UI_PlanetaryPop, true) GUI_Component_Visibility(UI_PlanetaryPop, true)
GUI_Component_Visibility(UI_CreditsTactical, true) GUI_Component_Visibility(UI_CreditsTactical, true)
end GUI_Component_Visibility(UI_TechTactical, true)
---Services the GUI Manager.
function GUIManager:Service()
if not self.TacticalGame then
-- Nothing to service
return
end
ScriptMessage("Servicing GUI Updates...")
ServiceGameTime(self.TacticalGame)
ServiceTeamCredits(self.SkirmishGame)
--ServiceUnitDisplay(self.SkirmishGame, self.ShowTeamId)
end end
---Services Game Time display. ---Services Game Time display.
---@param tacticalGame TacticalGameClass The current Tactical Game state ---@param gameTime number The current game time.
function ServiceGameTime(tacticalGame) function GUIManager:DisplayGameTime(gameTime)
if not tacticalGame then local timeText = FormatTime(gameTime)
return local text = string.format("Time: %s", timeText)
end
local gameTime = Dirty_Floor(GetCurrentTime()) - tacticalGame.StartTime
local minutes = Dirty_Floor(gameTime / 60)
local minutesText = tostring(minutes)
if tonumber(minutes) < 10 then
minutesText = "0" .. minutesText
end
local seconds = gameTime - (minutes * 60)
local secondsText = tostring(seconds)
if tonumber(seconds) < 10 then
secondsText = "0" .. secondsText
end
local text = string.format("Time: %s:%s", minutesText, secondsText)
GUI_Component_Text(UI_GameTime, text) GUI_Component_Text(UI_GameTime, text)
end end
---Services Team Credits display. ---Displays credits for the specified team
---@param skirmishGame SkirmishGameClass The current Skirmish Game state. ---@param team TeamStruct The team.
function ServiceTeamCredits(skirmishGame) ---@param credits number The team credits.
if not skirmishGame then ---@param income number The team income.
function GUIManager:DisplayTeamCredits(team, credits, income)
local uiText, uiIcon = "", ""
if team.Number == 1 then
uiText = UI_CreditsT1
uiIcon = UI_IconT1
elseif team.Number == 2 then
uiText = UI_CreditsT2
uiIcon = UI_IconT2
else
return return
end end
if not skirmishGame.IsLocalSpectator then local positiveText = "+"
return
if income < 0 then
positiveText = ""
end end
---Displays credits for the specified team local text = string.format("Team %d: $ %d (%s%d)", team.Number, credits, positiveText, income)
---@param team TeamStruct The team to service. local icon = team.Faction.Icon
---@param uiText string The name of the UI Component to display Team credits in. local color = team.Faction.Color
---@param uiIcon string The name of the UI Component to display the Faction icon in.
local function DisplayTeamCredits(team, uiText, uiIcon)
local teamCredits = skirmishGame:CalculateTeamTotalCredits(team.Id)
local teamIncome = skirmishGame:CalculateTeamTotalIncome(team.Id)
local positiveText = "+"
if teamIncome < 0 then GUI_Button_Icon(uiIcon, icon, color.R, color.G, color.B, 1)
positiveText = "" GUI_Component_Text(uiText, text)
end GUI_Text_Color(uiText, color.R, color.G, color.B, 1)
local text = string.format("Team %d: $%d (%s%d)", team.Number, teamCredits, positiveText, teamIncome)
local icon = team.Faction.Icon
local color = team.Faction.Color
GUI_Button_Icon(uiIcon, icon, color.R, color.G, color.B, 1)
GUI_Component_Text(uiText, text)
GUI_Text_Color(uiText, color.R, color.G, color.B, 1)
end
for _, team in pairs(skirmishGame.Teams) do
if team.Number == 1 then
DisplayTeamCredits(team, UI_CreditsT1, UI_IconT1)
elseif team.Number == 2 then
DisplayTeamCredits(team, UI_CreditsT2, UI_IconT2)
end
end
end
---Services Team Units display.
---@param skirmishGame SkirmishGameClass The current Skirmish Game state.
---@param teamId integer The Team ID's units to display.
function ServiceUnitDisplay(skirmishGame, teamId)
if not skirmishGame then
return
end
if not skirmishGame.IsLocalSpectator then
return
end
local function DisplayTeamUnit(unit, uiComponent)
end
local localPlayer = Find_Player("local")
local players = skirmishGame:GetPlayersOnTeam(teamId)
---@type table<string, integer> Units Table by name with alive count.
local units = {}
for _, player in pairs(players) do
local playerUnits = player:GetAliveUnits()
for _, playerUnit in pairs(playerUnits) do
localPlayer.Select_Object(playerUnit.GameObjectWrapper)
if not units[playerUnit.Name] then
units[playerUnit.Name] = 1
else
units[playerUnit.Name] = units[playerUnit.Name] + 1
end
end
end
end end

View File

@@ -1,6 +1,6 @@
require("PGBase") require("PGBase")
require("GameManager.PlayerClass") require("GameManager/PlayerClass")
require("GameManager.UnitClass") require("GameManager/UnitClass")
---@class GalacticGameClass ---@class GalacticGameClass
---@field StartTime integer The start time. ---@field StartTime integer The start time.
@@ -65,9 +65,9 @@ end
---@param player table The FoC PlayerWrapper object that owns the new Unit. ---@param player table The FoC PlayerWrapper object that owns the new Unit.
function GalacticGameClass:UnitBuilt(objectType, player) function GalacticGameClass:UnitBuilt(objectType, player)
local playerId = player.Get_ID() local playerId = player.Get_ID()
local player = self.Players[playerId] local playerEntry = self.Players[playerId]
if player then if playerEntry then
player:AddUnit(objectType) playerEntry:AddUnit(objectType)
end end
end end

View File

@@ -1,6 +1,6 @@
require("PGBase") require("PGBase")
require("GameManager.ResourceClass") require("GameManager/ResourceClass")
require("GameManager.UnitClass") require("GameManager/UnitClass")
---@class PlayerClass ---@class PlayerClass
---@field Id integer Player ID. ---@field Id integer Player ID.
@@ -45,10 +45,10 @@ function PlayerClass:Service()
-- Pass 1: Collect assigned game object wrappers from alive units -- Pass 1: Collect assigned game object wrappers from alive units
for _, unit in pairs(self:GetAliveUnits()) do for _, unit in pairs(self:GetAliveUnits()) do
if TestValid(unit.GameObjectWrapper) then if TestValid(unit.GameObject) then
assignedUnits[unit.GameObjectWrapper] = true assignedUnits[unit.GameObject] = true
else else
unit:SetDead() unit:SetDead(-1)
end end
end end
@@ -81,11 +81,14 @@ end
---Adds a Unit type to the Player's reinforcement list. ---Adds a Unit type to the Player's reinforcement list.
---@param objectType table FoC GameObjectTypeWrapper object that was built. ---@param objectType table FoC GameObjectTypeWrapper object that was built.
---@return UnitClass
function PlayerClass:AddUnit(objectType) function PlayerClass:AddUnit(objectType)
local unit = UnitClass:New(objectType, self.Id) local unit = UnitClass:New(objectType, self.Id)
table.insert(self.Units, unit) table.insert(self.Units, unit)
ScriptMessage("Unit Added: %s", unit:Debug()) ScriptMessage("Unit Added: %s", unit:Debug())
return unit
end end
---Gets all Reinforcement Units for this Player. ---Gets all Reinforcement Units for this Player.

View File

@@ -20,7 +20,6 @@ end
---@param credits number ---@param credits number
function ResourceClass:SetCredits(credits) function ResourceClass:SetCredits(credits)
self.LastCredits = self.Credits self.LastCredits = self.Credits
self.Credits = credits
if credits < 0 then if credits < 0 then
self.Credits = 0 self.Credits = 0

View File

@@ -1,99 +1,26 @@
require("PGBase") require("GameManager/TacticalGameClass")
require("GameManager.Constants") require("GameManager/SpectatorStruct")
require("GameManager.TacticalGameClass") require("GameManager/TeamStruct")
require("GameManager.SpectatorStruct")
require("GameManager.TeamStruct")
---@class SkirmishGameClass ---@class SkirmishGameClass : TacticalGameClass
---@field TacticalGame TacticalGameClass The underlying Tactical Game context.
---@field Spectators SpectatorStruct[] The spectator players in this game. ---@field Spectators SpectatorStruct[] The spectator players in this game.
---@field IsLocalSpectator boolean Whether the local player is a spectator. ---@field IsLocalSpectator boolean Whether the local player is a spectator.
---@field Teams TeamStruct[] The teams in this game. ---@field Teams TeamStruct[] The teams in this game.
SkirmishGameClass = {} SkirmishGameClass = {}
SkirmishGameClass.__index = SkirmishGameClass SkirmishGameClass.__index = SkirmishGameClass
setmetatable(SkirmishGameClass, { __index = TacticalGameClass })
---Creates a new Skirmish Game context. ---Creates a new Skirmish Game context.
---@param gameMode string The game mode. ---@param gameMode string The game mode.
---@return SkirmishGameClass ---@return SkirmishGameClass
function SkirmishGameClass:New(gameMode) function SkirmishGameClass:New(gameMode)
ScriptMessage("Initializing Skirmish game...") ScriptMessage("Initializing Skirmish game...")
local self = setmetatable({}, SkirmishGameClass) local self = setmetatable(TacticalGameClass:New(gameMode), SkirmishGameClass)
---Finds all spectators in the game. ---@cast self SkirmishGameClass
---@return SpectatorStruct[] self:_FindSpectators()
local function FindSpectators() self.IsLocalSpectator = self:_GetLocalSpectator()
---@type SpectatorStruct[] self:_BuildTeams()
local spectators = {}
local spectatorMarker = GetSpectatorMarkerName(gameMode)
if spectatorMarker ~= nil then
for k, marker in pairs(Find_All_Objects_Of_Type(spectatorMarker)) do
local playerWrapper = marker.Get_Owner()
local playerId = playerWrapper.Get_ID()
if not spectators[playerId] then
local spectator = SpectatorStruct:New(playerWrapper)
spectators[playerId] = spectator
ScriptMessage("Found Spectator: %s", spectator:Debug())
end
end
end
return spectators
end
self.TacticalGame = TacticalGameClass:New(gameMode)
self.Spectators = FindSpectators()
---Gets whether the local player is a spectator.
---@returns boolean
local function GetLocalSpectator()
local localPlayer = Find_Player("local")
return self:GetSpectator(localPlayer.Get_ID()) ~= nil
end
self.IsLocalSpectator = GetLocalSpectator()
---Builds all teams in the game.
---@return TeamStruct[]
local function BuildTeams()
---@type TeamStruct[]
local teams = {}
-- Build combatant player teams
for playerId, player in pairs(self.TacticalGame.Players) do
local teamId = player.TeamId
if teamId >= 0 then
if teams[teamId] == nil then
teams[teamId] = TeamStruct:New(teamId, player.Faction, false)
end
end
end
-- Build spectator player teams
for playerId, spectator in pairs(self.Spectators) do
local teamId = spectator.TeamId
if teamId >= 0 then
local team = teams[teamId]
if team == nil then
team = TeamStruct:New(teamId, spectator.Faction, true)
teams[teamId] = team
ScriptMessage("Found Team: %s", team:Debug())
else
team.IsSpectator = true
end
end
end
return teams
end
self.Teams = BuildTeams()
ScriptMessage("Skirmish Game initialized!") ScriptMessage("Skirmish Game initialized!")
return self return self
@@ -101,31 +28,144 @@ end
---Services the Skirmish Game. ---Services the Skirmish Game.
function SkirmishGameClass:Service() function SkirmishGameClass:Service()
ScriptMessage("Servicing Skirmish Game...")
-- Service TacticalGame -- Service TacticalGame
self.TacticalGame:Service() TacticalGameClass.Service(self)
ScriptMessage("Servicing Skirmish Game...")
for _, team in pairs(self.Teams) do
local credits = self:CalculateTeamTotalCredits(team.Id)
local income = self:CalculateTeamTotalIncome(team.Id)
GUIManager:DisplayTeamCredits(team, credits, income)
end
end end
-- ==================================================
-- Unit event handlers
-- ==================================================
---Displays unit built combat text.
---@param unit UnitClass The built unit.
function SkirmishGameClass:CombatTextUnitBuilt(unit)
if not self.IsLocalSpectator then
-- No Text feed for combatants
return
end
local owner = self.Players[unit.OwnerId]
if not owner then
return
end
local team = self.Teams[owner.TeamId]
if not team then
return
end
local timeText = FormatTime(unit.BuildTime)
local text = string.format("%s [T%d %s]: BUILT %s ($ %d)", timeText, team.Number, team.Faction.DisplayName,
unit.DisplayName, unit.BuildCost)
local faction = Factions[owner.Faction]
---@type ColorStruct
local color
if faction then
color = faction.Color
else
color = ColorStruct:New(1, 1, 1, 1)
end
self.CombatFeed:Append(text, -1, color)
TextManager:SetCurrentView("combat_feed")
end
---Displays killed unit combat text.
---@param unit UnitClass The killed unit.
function SkirmishGameClass:CombatTextUnitKilled(unit)
-- Right now, we don't really care about seeing killed units in the combat feed
-- If we want it in the future, uncomment the lines below.
return
-- if not self.IsLocalSpectator then
-- -- No Text feed for combatants
-- return
-- end
-- local owner = self.Players[unit.OwnerId]
-- if not owner then
-- return
-- end
-- local killer = self.Players[unit.KillerId]
-- local timeText = FormatTime(unit.DeathTime)
-- if not killer then
-- local team = self.Teams[owner.TeamId]
-- if not team then
-- return
-- end
-- local text = string.format("%s\t<T%d> [%s]: MISTAKES WERE MADE %s", timeText, team.Number, owner.Name,
-- unit.DisplayName)
-- local color = ColorStruct:New(0.8, 0.8, 0.8, 1)
-- self.CombatFeed:Append(text, -1, color)
-- else
-- local team = self.Teams[killer.TeamId]
-- if not team then
-- return
-- end
-- local text = string.format("%s\t<T%d> [%s]: KILLED %s (%s)", timeText, team.Number, killer.Name, unit
-- .DisplayName,
-- owner.Name)
-- local faction = Factions[killer.Faction]
-- ---@type ColorStruct
-- local color = nil
-- if faction then
-- color = faction.Color
-- else
-- color = ColorStruct:New(1, 1, 1, 1)
-- end
-- self.CombatFeed:Append(text, -1, color)
-- end
end
-- ==================================================
-- Player functions
-- ==================================================
---Gets the Spectator by Player ID. ---Gets the Spectator by Player ID.
---@param id integer Player ID ---@param id integer Player ID
---@return SpectatorStruct|nil ---@return SpectatorStruct|nil
function SkirmishGameClass:GetSpectator(id) function SkirmishGameClass:GetSpectator(id)
for playerId, spectator in pairs(self.Spectators) do return self.Spectators[id]
if playerId == id then
return spectator
end
end
end end
---Gets the Team by ID. ---Gets the Team by ID.
---@param id integer Team ID ---@param id integer Team ID
---@return TeamStruct|nil ---@return TeamStruct|nil
function SkirmishGameClass:GetTeam(id) function SkirmishGameClass:GetTeam(id)
for teamId, team in pairs(self.Teams) do return self.Teams[id]
if teamId == id then end
return team
end ---Gets the Team of the Player ID.
---@param id integer Player ID.
---@return TeamStruct|nil
function SkirmishGameClass:GetTeamForPlayer(id)
local player = self.Players[id]
if not player then
return nil
end end
return self.Teams[player.TeamId]
end end
---Gets the Players for the Team ID. ---Gets the Players for the Team ID.
@@ -135,7 +175,7 @@ function SkirmishGameClass:GetPlayersOnTeam(id)
---@type PlayerClass[] ---@type PlayerClass[]
local players = {} local players = {}
for playerId, player in pairs(self.TacticalGame.Players) do for playerId, player in pairs(self.Players) do
if player.TeamId == id then if player.TeamId == id then
players[playerId] = player players[playerId] = player
end end
@@ -144,6 +184,10 @@ function SkirmishGameClass:GetPlayersOnTeam(id)
return players return players
end end
-- ==================================================
-- Team functions
-- ==================================================
---Calculates the Team ID's current total credits. ---Calculates the Team ID's current total credits.
---@param id integer Team ID. ---@param id integer Team ID.
---@return integer ---@return integer
@@ -171,3 +215,193 @@ function SkirmishGameClass:CalculateTeamTotalIncome(id)
return totalIncome return totalIncome
end end
--- ==================================================
--- Stat tables
--- ==================================================
---Updates the Tactical Kill Stats Table with the killed object.
---@param unit UnitClass The object that was killed.
---@param killer PlayerObject The player that killed the object.
function SkirmishGameClass:UpdateTacticalKillStatsTable(unit, killer)
if not TestValid(killer) then
return
end
-- Update Frags
local fragEntry = self.KillStatsTable[FragIndex]
if not fragEntry then
fragEntry = {}
self.KillStatsTable[FragIndex] = fragEntry
end
local killerId = killer.Get_ID()
if self.IsLocalSpectator then
local killerTeam = self:GetTeamForPlayer(killerId)
if killerTeam and killerTeam.Number == 1 then
-- For the spectator, let's show Team 1's kills on the left side
killerId = LocalPlayer.Get_ID()
end
end
local killerEntry = fragEntry[killerId]
if not killerEntry then
killerEntry = {}
fragEntry[killerId] = killerEntry
end
local killerObjEntry = killerEntry[unit.GameObjectType]
if not killerObjEntry then
killerObjEntry = {
kills = 1,
combat_power = unit.CombatRating,
build_cost = unit.BuildCost,
score_value = unit.ScoreValue
}
killerEntry[unit.GameObjectType] = killerObjEntry
else
killerObjEntry.kills = killerObjEntry.kills + 1
killerObjEntry.combat_power = killerObjEntry.combat_power + unit.CombatRating
killerObjEntry.build_cost = killerObjEntry.build_cost + unit.BuildCost
killerObjEntry.score_value = killerObjEntry.score_value + unit.ScoreValue
end
-- Update Deaths
local deathEntry = self.KillStatsTable[DeathIndex]
if not deathEntry then
deathEntry = {}
self.KillStatsTable[DeathIndex] = deathEntry
end
local ownerId = unit.OwnerId
if self.IsLocalSpectator then
local ownerTeam = self:GetTeamForPlayer(ownerId)
if ownerTeam and ownerTeam.Number == 1 then
-- For the spectator, let's show Team 1's lost units on the left side
ownerId = LocalPlayer.Get_ID()
end
else
-- Non-spectator: show all teammate deaths as local player's losses
local ownerTeam = self:GetTeamForPlayer(ownerId)
local localTeam = self:GetTeamForPlayer(LocalPlayer.Get_ID())
if ownerTeam and localTeam and ownerTeam.Id == localTeam.Id then
ownerId = LocalPlayer.Get_ID()
end
end
local ownerEntry = deathEntry[ownerId]
if not ownerEntry then
ownerEntry = {}
deathEntry[ownerId] = ownerEntry
end
local ownerObjEntry = ownerEntry[unit.GameObjectType]
if not ownerObjEntry then
ownerObjEntry = {
kills = 1,
combat_power = unit.CombatRating,
build_cost = unit.BuildCost,
score_value = unit.ScoreValue
}
ownerEntry[unit.GameObjectType] = ownerObjEntry
else
ownerObjEntry.kills = ownerObjEntry.kills + 1
ownerObjEntry.combat_power = ownerObjEntry.combat_power + unit.CombatRating
ownerObjEntry.build_cost = ownerObjEntry.build_cost + unit.BuildCost
ownerObjEntry.score_value = ownerObjEntry.score_value + unit.ScoreValue
end
end
-- ==================================================
-- Private functions
-- ==================================================
---@private
---Finds all spectators in the game.
function SkirmishGameClass:_FindSpectators()
---@type SpectatorStruct[]
local spectators = {}
---@type string
local spectatorMarker = nil
if StringCompare(self.GameMode, "Space") then
spectatorMarker = Spectator_Marker_Space
elseif StringCompare(self.GameMode, "Land") then
spectatorMarker = Spectator_Marker_Land
end
if spectatorMarker then
for k, marker in pairs(Find_All_Objects_Of_Type(spectatorMarker)) do
local playerWrapper = marker.Get_Owner()
local playerId = playerWrapper.Get_ID()
if not spectators[playerId] then
local spectator = SpectatorStruct:New(playerWrapper)
spectators[playerId] = spectator
ScriptMessage("Found Spectator: %s", spectator:Debug())
end
end
end
self.Spectators = spectators
end
---@private
---Gets whether the local player is a spectator.
---@returns boolean
function SkirmishGameClass:_GetLocalSpectator()
if not LocalPlayer then
return false
end
return self:GetSpectator(LocalPlayer.Get_ID()) ~= nil
end
---@private
---Builds all teams in the game.
function SkirmishGameClass:_BuildTeams()
---@type TeamStruct[]
local teams = {}
-- Build combatant player teams
for playerId, player in pairs(self.Players) do
local teamId = player.TeamId
if teamId >= 0 then
if teams[teamId] == nil then
teams[teamId] = TeamStruct:New(teamId, player.Faction, false)
end
end
end
-- Build spectator player teams
for playerId, spectator in pairs(self.Spectators) do
local teamId = spectator.TeamId
if teamId >= 0 then
local team = teams[teamId]
if team == nil then
team = TeamStruct:New(teamId, spectator.Faction, true)
teams[teamId] = team
ScriptMessage("Found Team: %s", team:Debug())
else
team.IsSpectator = true
end
end
end
self.Teams = teams
end

View File

@@ -1,13 +1,14 @@
require("PGBase") require("PGBase")
require("GameManager.PlayerClass") require("GameManager/Constants")
require("GameManager/PlayerClass")
require("GameManager/TutorialTextFeed")
---@class TacticalGameClass ---@class TacticalGameClass
---@field GameMode string The tactical game mode. ---@field GameMode string The tactical game mode.
---@field StartTime integer The start time. ---@field StartTime integer The start time.
---@field Players PlayerClass[] The combatant players in this game. ---@field Players PlayerClass[] The combatant players in this game.
---@field ReinforcementUnitCount table<string, integer> Key: Unit Type, Value: Count ---@field CombatFeed TutorialTextFeed Text feed for unit builds and kills.
---@field AliveUnitCount table<string, integer> Key: Unit Type, Value: Count ---@field KillStatsTable table The engine-owned TacticalKillStatsTable reference, set from GameScoring.lua.
---@field DeadUnitCount table<string, integer> Key: Unit Type, Value: Count
TacticalGameClass = {} TacticalGameClass = {}
TacticalGameClass.__index = TacticalGameClass TacticalGameClass.__index = TacticalGameClass
@@ -18,42 +19,10 @@ function TacticalGameClass:New(gameMode)
ScriptMessage("Initializing Tactical game...") ScriptMessage("Initializing Tactical game...")
local self = setmetatable({}, TacticalGameClass) local self = setmetatable({}, TacticalGameClass)
---Finds all combatant players in the game.
---@return PlayerClass[]
local function FindPlayers()
---@type PlayerClass[]
local players = {}
for k, faction in pairs(Factions) do
local startingUnit = nil
if StringCompare(gameMode, "Land") then
startingUnit = faction.LandStartUnitName
elseif StringCompare(gameMode, "Space") then
startingUnit = faction.SpaceStartUnitName
end
if startingUnit then
for i, unit in pairs(Find_All_Objects_Of_Type(startingUnit)) do
local playerWrapper = unit.Get_Owner()
local playerId = playerWrapper.Get_ID()
if players[playerId] == nil then
local player = PlayerClass:New(playerWrapper)
players[playerId] = player
ScriptMessage("Found Player: %s", player:Debug())
end
end
end
end
return players
end
self.GameMode = gameMode self.GameMode = gameMode
self.StartTime = GetCurrentTime() self.StartTime = GetCurrentTime()
self.Players = FindPlayers() self.Players = self:_FindPlayers(gameMode)
self.CombatFeed = TutorialTextFeed:New("combat_feed", 6)
ScriptMessage("Tactical Game initialized!") ScriptMessage("Tactical Game initialized!")
return self return self
@@ -67,8 +36,16 @@ function TacticalGameClass:Service()
for _, player in pairs(self.Players) do for _, player in pairs(self.Players) do
player:Service() player:Service()
end end
local gameTime = GetCurrentTime() - self.StartTime
GUIManager:DisplayGameTime(gameTime)
end end
-- ==================================================
-- State functions
-- ==================================================
---Whether this Tactical game is in space mode. ---Whether this Tactical game is in space mode.
---@return boolean ---@return boolean
function TacticalGameClass:IsSpaceMode() function TacticalGameClass:IsSpaceMode()
@@ -80,41 +57,252 @@ function TacticalGameClass:IsLandMode()
return StringCompare(self.GameMode, "Land") return StringCompare(self.GameMode, "Land")
end end
-- ==================================================
-- Player functions
-- ==================================================
---Gets the Player by ID. ---Gets the Player by ID.
---@param id integer Player ID ---@param id integer Player ID
---@return PlayerClass|nil ---@return PlayerClass|nil
function TacticalGameClass:GetPlayer(id) function TacticalGameClass:GetPlayer(id)
for playerId, player in pairs(self.Players) do return self.Players[id]
if playerId == id then
return player
end
end
end end
---Records the Player ID as having quit at the current time. ---Records the Player ID as having quit at the current time.
---@param id integer Player ID. ---@param id integer Player ID.
function TacticalGameClass:PlayerQuit(id) function TacticalGameClass:PlayerQuit(id)
for playerId, player in pairs(self.Players) do local player = self.Players[id]
if playerId == id then
player:Quit() if player then
end player:Quit()
end end
end end
-- ==================================================
-- Unit event handlers
-- ==================================================
---Adds a built unit to the Unit table. ---Adds a built unit to the Unit table.
---@param objectType table The FoC GameObjectTypeWrapper object type that was built. ---@param objectType GameObjectType The FoC GameObjectTypeWrapper object type that was built.
---@param player table The FoC PlayerWrapper object that owns the new Unit. ---@param player PlayerObject The FoC PlayerWrapper object that owns the new Unit.
function TacticalGameClass:UnitBuilt(objectType, player) function TacticalGameClass:UnitBuilt(objectType, player)
local playerId = player.Get_ID() local playerId = player.Get_ID()
local player = self.Players[playerId] local playerEntry = self.Players[playerId]
if player then if playerEntry then
player:AddUnit(objectType) local unit = playerEntry:AddUnit(objectType)
self:CombatTextUnitBuilt(unit)
end end
end end
---Displays unit built combat text.
---@param unit UnitClass The built unit.
function TacticalGameClass:CombatTextUnitBuilt(unit)
local owner = self.Players[unit.OwnerId]
if not owner then
return
end
if not StringCompare(LocalPlayer.Get_Faction_Name(), owner.Faction) then
-- Do not display combat feed for players on opposite factions
return
end
local timeText = FormatTime(unit.BuildTime)
local text = string.format("%s\t[%s]: BUILT %s ($%d)", timeText, owner.Name, unit.Name, unit.BuildCost)
local faction = Factions[owner.Faction]
---@type ColorStruct
local color
if faction then
color = faction.Color
else
color = ColorStruct:New(1, 1, 1, 1)
end
self.CombatFeed:Append(text, -1, color)
end
---Sets a unit as killed. ---Sets a unit as killed.
---@param gameObject table The FoC GameObjectWrapper object that was killed. ---@param gameObject GameObject The FoC GameObjectWrapper object that was killed.
function TacticalGameClass:UnitKilled(gameObject) ---@param killer PlayerObject The FoC PlayerWrapper object that killed the Unit.
-- Find a way to set the unit as killed function TacticalGameClass:UnitKilled(gameObject, killer)
local ownerId = gameObject.Get_Owner().Get_ID()
local owner = self.Players[ownerId]
if not owner then
return
end
---@type UnitClass|nil
local killedUnit = nil
for _, unit in pairs(owner.Units) do
if unit.GameObject == gameObject then
killedUnit = unit
break
end
end
if killedUnit then
killedUnit:SetDead(killer.Get_ID())
self:UpdateTacticalKillStatsTable(killedUnit, killer)
self:CombatTextUnitKilled(killedUnit)
end
end
---Displays killed unit combat text.
---@param unit UnitClass The killed unit.
function TacticalGameClass:CombatTextUnitKilled(unit)
local owner = self.Players[unit.OwnerId]
if not owner then
return
end
if not StringCompare(LocalPlayer.Get_Faction_Name(), owner.Faction) then
-- Do not display combat feed for players on opposite factions
return
end
local killer = self.Players[unit.KillerId]
local timeText = FormatTime(unit.DeathTime)
if not killer then
local text = string.format("%s\t[%s]: MISTAKES WERE MADE %s", timeText, owner.Name, unit.Name)
local color = ColorStruct:New(0.8, 0.8, 0.8, 1)
self.CombatFeed:Append(text, -1, color)
else
local text = string.format("%s\t[%s]: KILLED %s (%s)", timeText, killer.Name, unit.Name, owner.Name)
local faction = Factions[killer.Faction]
---@type ColorStruct
local color = nil
if faction then
color = faction.Color
else
color = ColorStruct:New(1, 1, 1, 1)
end
self.CombatFeed:Append(text, -1, color)
end
end
--- ==================================================
--- Stat tables
--- ==================================================
---Updates the Tactical Kill Stats Table with the killed object.
---@param unit UnitClass The object that was killed.
---@param killer PlayerObject The player that killed the object.
function TacticalGameClass:UpdateTacticalKillStatsTable(unit, killer)
if not TestValid(killer) then
return
end
-- Update Frags
local fragEntry = self.KillStatsTable[FragIndex]
if not fragEntry then
fragEntry = {}
self.KillStatsTable[FragIndex] = fragEntry
end
local killerId = killer.Get_ID()
local killerEntry = fragEntry[killerId]
if not killerEntry then
killerEntry = {}
fragEntry[killerId] = killerEntry
end
local killerObjEntry = killerEntry[unit.GameObjectType]
if not killerObjEntry then
killerObjEntry = {
kills = 1,
combat_power = unit.CombatRating,
build_cost = unit.BuildCost,
score_value = unit.ScoreValue
}
killerEntry[unit.GameObjectType] = killerObjEntry
else
killerObjEntry.kills = killerObjEntry.kills + 1
killerObjEntry.combat_power = killerObjEntry.combat_power + unit.CombatRating
killerObjEntry.build_cost = killerObjEntry.build_cost + unit.BuildCost
killerObjEntry.score_value = killerObjEntry.score_value + unit.ScoreValue
end
-- Update Deaths
local deathEntry = self.KillStatsTable[DeathIndex]
if not deathEntry then
deathEntry = {}
self.KillStatsTable[DeathIndex] = deathEntry
end
local ownerEntry = deathEntry[unit.OwnerId]
if not ownerEntry then
ownerEntry = {}
deathEntry[unit.OwnerId] = ownerEntry
end
local ownerObjEntry = ownerEntry[unit.GameObjectType]
if not ownerObjEntry then
ownerObjEntry = {
kills = 1,
combat_power = unit.CombatRating,
build_cost = unit.BuildCost,
score_value = unit.ScoreValue
}
ownerEntry[unit.GameObjectType] = ownerObjEntry
else
ownerObjEntry.kills = ownerObjEntry.kills + 1
ownerObjEntry.combat_power = ownerObjEntry.combat_power + unit.CombatRating
ownerObjEntry.build_cost = ownerObjEntry.build_cost + unit.BuildCost
ownerObjEntry.score_value = ownerObjEntry.score_value + unit.ScoreValue
end
end
-- ==================================================
-- Private functions
-- ==================================================
---@private
---@param gameMode string The current game mode.
---@return PlayerClass[]
function TacticalGameClass:_FindPlayers(gameMode)
---@type PlayerClass[]
local players = {}
for k, faction in pairs(Factions) do
local startingUnit = nil
if StringCompare(gameMode, "Land") then
startingUnit = faction.LandStartUnitName
elseif StringCompare(gameMode, "Space") then
startingUnit = faction.SpaceStartUnitName
end
if startingUnit then
for i, unit in pairs(Find_All_Objects_Of_Type(startingUnit)) do
local playerWrapper = unit.Get_Owner()
local playerId = playerWrapper.Get_ID()
if players[playerId] == nil then
local player = PlayerClass:New(playerWrapper)
players[playerId] = player
ScriptMessage("Found Player: %s", player:Debug())
end
end
end
end
return players
end end

View File

@@ -1,4 +1,4 @@
require("GameManager.Constants") require("GameManager/Constants")
---@class TeamStruct ---@class TeamStruct
---@field Id integer Team ID. ---@field Id integer Team ID.

View File

@@ -0,0 +1,74 @@
require("GameManager/TutorialTextView")
---A fixed-capacity feed view. Appending a new line when at capacity evicts the
---oldest (top-most) entry first. Rendering is driven by the IsActive flag set
---by TutorialTextManager; no manager reference is needed.
---
---@class TutorialTextFeed : TutorialTextView
---@field MaxLines integer Maximum number of lines to display at once.
---@field _KeyOrder string[] Insertion-ordered list of active entry keys (oldest first).
---@field _NextId integer Counter used to generate unique entry keys.
TutorialTextFeed = setmetatable({}, { __index = TutorialTextView })
TutorialTextFeed.__index = TutorialTextFeed
---Creates a new Tutorial Text Feed.
---@param name string The view name.
---@param maxLines integer Maximum number of lines to display at once.
---@return TutorialTextFeed
function TutorialTextFeed:New(name, maxLines)
local self = setmetatable(TutorialTextView:New(name), TutorialTextFeed)
---@cast self TutorialTextFeed
self.MaxLines = maxLines
self._KeyOrder = {}
self._NextId = 0
return self
end
---Appends a new line to the bottom of the feed.
---If the feed is at capacity, the oldest line is removed first.
---Only renders to the screen when this view is active.
---@param text string The display text.
---@param duration number|nil Duration in seconds, defaults to -1 (infinite).
---@param color ColorStruct|nil The text color, defaults to white.
function TutorialTextFeed:Append(text, duration, color)
---@diagnostic disable-next-line
if table.getn(self._KeyOrder) >= self.MaxLines then
local oldestKey = table.remove(self._KeyOrder, 1)
self.Entries[oldestKey] = nil
if self.IsActive then
Remove_Tutorial_Text(oldestKey)
end
end
self._NextId = self._NextId + 1
local key = self.Name .. "_" .. self._NextId
self:SetEntry(key, text, duration, color)
table.insert(self._KeyOrder, key)
if self.IsActive then
local entry = self.Entries[key]
Add_Tutorial_Text(entry.Key, entry.Text, entry.Duration,
entry.Color.R, entry.Color.G, entry.Color.B, entry.Color.A)
end
end
---Removes all entries from the feed.
---Only clears the screen when this view is active.
function TutorialTextFeed:Clear()
if self.IsActive then
for _, key in ipairs(self._KeyOrder) do
Remove_Tutorial_Text(key)
end
end
self.Entries = {}
self._KeyOrder = {}
end
function TutorialTextFeed:Debug()
return string.format("TutorialTextFeed '%s' (%d/%d lines)",
---@diagnostic disable-next-line
self.Name, table.getn(self._KeyOrder), self.MaxLines)
end

View File

@@ -0,0 +1,169 @@
require("GameManager/TutorialTextView")
---Manages multiple named tutorial text views, rendering only the active view.
---
---Views hold their own state independently. Only the current view is rendered
---to the screen. Switching views clears the screen and renders the new view's
---current state.
---
---@class TutorialTextManager
---@field Views table<string, TutorialTextView> All registered views by name.
---@field CurrentViewName string|nil The name of the currently active view.
TutorialTextManager = {}
TutorialTextManager.__index = TutorialTextManager
---Creates a new Tutorial Text Manager.
---@return TutorialTextManager
function TutorialTextManager:New()
local self = setmetatable({}, TutorialTextManager)
self.Views = {}
self.CurrentViewName = nil
return self
end
---Registers a new view. If a view with the given name already exists it is returned as-is.
---@param name string The view name.
---@return TutorialTextView
function TutorialTextManager:AddView(name)
if not self.Views[name] then
self.Views[name] = TutorialTextView:New(name)
end
return self.Views[name]
end
---Registers an existing view instance (e.g. a TutorialTextFeed).
---If a view with the same name already exists it is returned as-is.
---@param view TutorialTextView The view to register.
---@return TutorialTextView
function TutorialTextManager:RegisterView(view)
if not self.Views[view.Name] then
self.Views[view.Name] = view
end
return self.Views[view.Name]
end
---Returns a registered view by name, or nil if it does not exist.
---@param name string The view name.
---@return TutorialTextView|nil
function TutorialTextManager:GetView(name)
return self.Views[name]
end
---Switches the active view. Clears the screen then renders the new view's current state.
---@param name string The view name to activate.
function TutorialTextManager:SetCurrentView(name)
if self.CurrentViewName == name then
return
end
local oldView = self.Views[self.CurrentViewName]
if oldView then
oldView.IsActive = false
end
self:_ClearScreen()
self.CurrentViewName = name
local newView = self.Views[name]
if newView then
newView.IsActive = true
self:_RenderView(newView)
end
end
---Sets or updates a text entry in a view.
---If the view is currently active the change is immediately rendered to the screen.
---@param viewName string The view to update.
---@param key string The unique key for this entry.
---@param text string The display text.
---@param duration number|nil Duration in seconds, defaults to -1 (infinite).
---@param color ColorStruct|nil The text color, defaults to white.
function TutorialTextManager:UpdateEntry(viewName, key, text, duration, color)
local view = self.Views[viewName]
if not view then
return
end
view:SetEntry(key, text, duration, color)
if self.CurrentViewName == viewName then
local entry = view.Entries[key]
Add_Tutorial_Text(entry.Key, entry.Text, entry.Duration,
entry.Color.R, entry.Color.G, entry.Color.B, entry.Color.A)
end
end
---Removes a text entry from a view.
---If the view is currently active the entry is immediately removed from the screen.
---@param viewName string The view to update.
---@param key string The key to remove.
function TutorialTextManager:RemoveEntry(viewName, key)
local view = self.Views[viewName]
if not view then
return
end
view:RemoveEntry(key)
if self.CurrentViewName == viewName then
Remove_Tutorial_Text(key)
end
end
---Clears all entries from a view.
---If the view is currently active all entries are immediately removed from the screen.
---@param viewName string The view to clear.
function TutorialTextManager:ClearView(viewName)
local view = self.Views[viewName]
if not view then
return
end
if self.CurrentViewName == viewName then
self:_ClearScreen()
end
view:Clear()
end
---Removes all views and clears the screen.
function TutorialTextManager:Reset()
self:_ClearScreen()
self.Views = {}
self.CurrentViewName = nil
end
---Renders all entries of a view to the screen.
---@param view TutorialTextView
function TutorialTextManager:_RenderView(view)
for _, entry in pairs(view.Entries) do
Add_Tutorial_Text(entry.Key, entry.Text, entry.Duration,
entry.Color.R, entry.Color.G, entry.Color.B, entry.Color.A)
end
end
---Removes all entries of the current view from the screen.
function TutorialTextManager:_ClearScreen()
if not self.CurrentViewName then
return
end
local view = self.Views[self.CurrentViewName]
if not view then
return
end
for key in pairs(view.Entries) do
Remove_Tutorial_Text(key)
end
end
function TutorialTextManager:Debug()
local count = 0
for _ in pairs(self.Views) do count = count + 1 end
return string.format("TutorialTextManager (views: %d, current: '%s')",
count, self.CurrentViewName or "none")
end

View File

@@ -0,0 +1,60 @@
require("GameManager/ColorStruct")
---Represents a single text entry in a tutorial text view.
---@class TutorialTextEntry
---@field Key string The unique key for this entry.
---@field Text string The display text.
---@field Duration number Duration in seconds, or -1 for infinite.
---@field Color ColorStruct The text color.
---Represents a named set of tutorial text entries.
---@class TutorialTextView
---@field Name string The view name.
---@field Entries table<string, TutorialTextEntry> Entries keyed by their text key.
---@field IsActive boolean Whether this view is currently being displayed.
TutorialTextView = {}
TutorialTextView.__index = TutorialTextView
---Creates a new Tutorial Text View.
---@param name string The view name.
---@return TutorialTextView
function TutorialTextView:New(name)
local self = setmetatable({}, TutorialTextView)
self.Name = name
self.Entries = {}
self.IsActive = false
return self
end
---Sets or updates a text entry in this view.
---@param key string The unique key for this entry.
---@param text string The display text.
---@param duration number|nil Duration in seconds, defaults to -1 (infinite).
---@param color ColorStruct|nil The text color, defaults to white.
function TutorialTextView:SetEntry(key, text, duration, color)
self.Entries[key] = {
Key = key,
Text = text,
Duration = duration or -1,
Color = color or ColorStruct:New(1, 1, 1, 1),
}
end
---Removes a text entry from this view.
---@param key string The key to remove.
function TutorialTextView:RemoveEntry(key)
self.Entries[key] = nil
end
---Removes all entries from this view.
function TutorialTextView:Clear()
self.Entries = {}
end
function TutorialTextView:Debug()
local count = 0
for _ in pairs(self.Entries) do count = count + 1 end
return string.format("TutorialTextView '%s' (%d entries)", self.Name, count)
end

View File

@@ -2,34 +2,38 @@ require("PGBase")
---@class UnitClass ---@class UnitClass
---@field Name string Unit name. ---@field Name string Unit name.
---@field DisplayName string The localized display name.
---@field OwnerId integer Owner Player ID. ---@field OwnerId integer Owner Player ID.
---@field BuildCost integer Tactical build cost. ---@field BuildCost integer Tactical build cost.
---@field CombatRating integer AI combat power rating. ---@field CombatRating integer AI combat power rating.
---@field ScoreValue integer Score cost credits.
---@field BuildTime number Game time that this unit was built. ---@field BuildTime number Game time that this unit was built.
---@field AliveTime number Game time that this unit became "alive". ---@field AliveTime number Game time that this unit became "alive".
---@field DeathTime number Game time that this unit was killed. ---@field DeathTime number Game time that this unit was killed.
---@field GameObjectWrapper table|nil The FoC GameObjectWrapper object. ---@field KillerId integer|nil The Player ID that killed this unit.
---@field GameObjectTypeWrapper table The FoC GameObjectTypeWrapper object. ---@field GameObject GameObject|nil The FoC GameObjectWrapper object.
---@field Icon string Name of the icon for this object. ---@field GameObjectType GameObjectType The FoC GameObjectTypeWrapper object.
UnitClass = {} UnitClass = {}
UnitClass.__index = UnitClass UnitClass.__index = UnitClass
---Constructs a new Unit object. ---Constructs a new Unit object.
---@param objectType table FoC GameObjectTypeWrapper object ---@param objectType GameObjectType FoC GameObjectTypeWrapper object
---@param playerId integer The Owner Player ID ---@param playerId integer The Owner Player ID
function UnitClass:New(objectType, playerId) function UnitClass:New(objectType, playerId)
local self = setmetatable({}, UnitClass) local self = setmetatable({}, UnitClass)
self.Name = objectType.Get_Name() self.Name = objectType.Get_Name()
self.DisplayName = objectType.Get_Display_Name()
self.OwnerId = playerId self.OwnerId = playerId
self.BuildCost = objectType.Get_Tactical_Build_Cost() self.BuildCost = objectType.Get_Tactical_Build_Cost()
self.CombatRating = objectType.Get_Combat_Rating() self.CombatRating = objectType.Get_Combat_Rating()
self.ScoreValue = objectType.Get_Score_Cost_Credits()
self.BuildTime = GetCurrentTime() self.BuildTime = GetCurrentTime()
self.AliveTime = -1 self.AliveTime = -1
self.DeathTime = -1 self.DeathTime = -1
self.GameObjectWrapper = nil self.KillerId = nil
self.GameObjectTypeWrapper = objectType self.GameObject = nil
self.Icon = "I_BUTTON_COMMAND_BAR_PIRATE_SYMBOL.TGA" self.GameObjectType = objectType
return self return self
end end
@@ -61,18 +65,20 @@ function UnitClass:SetAlive(object)
end end
self.AliveTime = GetCurrentTime() self.AliveTime = GetCurrentTime()
self.GameObjectWrapper = object self.GameObject = object
ScriptMessage("Unit Spawned: %s", self:Debug()) ScriptMessage("Unit Spawned: %s", self:Debug())
end end
---Sets the unit as dead. ---Sets the unit as dead.
function UnitClass:SetDead() ---@param killerId integer The Player ID that killed this unit.
function UnitClass:SetDead(killerId)
if self.DeathTime >= 0 then if self.DeathTime >= 0 then
-- Do not override once set -- Do not override once set
return return
end end
self.DeathTime = GetCurrentTime() self.DeathTime = GetCurrentTime()
self.KillerId = killerId
ScriptMessage("Unit Killed: %s", self:Debug()) ScriptMessage("Unit Killed: %s", self:Debug())
end end

View File

@@ -0,0 +1,20 @@
---Formats the game time in seconds to MM:SS.
---@param gameTime number The game time in seconds.
---@return string
function FormatTime(gameTime)
local minutes = Dirty_Floor(gameTime / 60)
local minutesText = tostring(minutes)
if tonumber(minutes) < 10 then
minutesText = "0" .. minutesText
end
local seconds = Dirty_Floor(gameTime - (minutes * 60))
local secondsText = tostring(seconds)
if tonumber(seconds) < 10 then
secondsText = "0" .. secondsText
end
return string.format("%s:%s", minutesText, secondsText)
end

View File

@@ -1,9 +1,8 @@
require("PGBase") require("PGBase")
require("GameManager.Constants") require("GameManager/Constants")
require("GameManager.GUIManager") require("GameManager/GalacticGameClass")
require("GameManager.GalacticGameClass") require("GameManager/TacticalGameClass")
require("GameManager.TacticalGameClass") require("GameManager/SkirmishGameClass")
require("GameManager.SkirmishGameClass")
-- ================================================== -- ==================================================
-- Script Locals -- Script Locals
@@ -15,25 +14,14 @@ local DebugCounter = 0
---Debugging service rate. ---Debugging service rate.
local ServiceDebugRate = 10 local ServiceDebugRate = 10
---The Local Player FoC PlayerWrapper object.
local LocalPlayer = nil
---The GUI Manager.
---@type GUIManager
local GUIManager = GUIManager:New()
---The Galactic Game manager. ---The Galactic Game manager.
---@type GalacticGameClass|nil ---@type GalacticGameClass|nil
local GalacticGame = nil local GalacticGame = nil
---The Tactical Game manager. ---The Tactical Game manager.
---@type TacticalGameClass|nil ---@type TacticalGameClass|SkirmishGameClass|nil
local TacticalGame = nil local TacticalGame = nil
---The Skirmish Game manager.
---@type SkirmishGameClass|nil
local SkirmishGame = nil
-- ================================================== -- ==================================================
-- Script Globals -- Script Globals
-- ================================================== -- ==================================================
@@ -50,6 +38,13 @@ GameSpy_Game_Stats = {}
---@deprecated ---@deprecated
GameSpy_Player_Stats = {} GameSpy_Player_Stats = {}
---Tactical Frag/Death Stat Table for post-game.
---[frag|death][playerid][object_type][build_count, credits_spent, combat_power]
TacticalKillStatsTable = {
[FragIndex] = {},
[DeathIndex] = {}
}
-- ================================================== -- ==================================================
-- Script State Functions -- Script State Functions
-- ================================================== -- ==================================================
@@ -59,10 +54,10 @@ function Base_Definitions()
DebugMessage("%s -- In Base_Definitions.", tostring(Script)) DebugMessage("%s -- In Base_Definitions.", tostring(Script))
DebugCounter = 0 DebugCounter = 0
LocalPlayer = Find_Player("local")
end end
---Main script function. Does event pumps and servicing. ---Main script function. Does event pumps and servicing.
---@diagnostic disable-next-line
function main() function main()
DebugMessage("%s -- In main.", tostring(Script)) DebugMessage("%s -- In main.", tostring(Script))
@@ -87,24 +82,40 @@ function GameService()
if GalacticGame then if GalacticGame then
GalacticGame:Service() GalacticGame:Service()
if TacticalGame then
TacticalGame:Service()
end
end end
if SkirmishGame then if TacticalGame then
SkirmishGame:Service() TacticalGame:Service()
end
if GUIManager then
GUIManager:Service()
end end
end end
---Script debug servicing. ---Script debug servicing.
function ServiceDebug() function ServiceDebug()
DebugMessage("%s -- TacticalKillStatsTable dump:", tostring(Script))
local fragEntry = TacticalKillStatsTable[FragIndex]
if fragEntry then
for playerId, unitTypes in pairs(fragEntry) do
for objType, data in pairs(unitTypes) do
DebugMessage(" FRAG player=%d type=%s kills=%d cp=%d cost=%d score=%d",
playerId, tostring(objType), data.kills, data.combat_power, data.build_cost, data.score_value)
end
end
else
DebugMessage(" FRAG (empty)")
end
local deathEntry = TacticalKillStatsTable[DeathIndex]
if deathEntry then
for playerId, unitTypes in pairs(deathEntry) do
for objType, data in pairs(unitTypes) do
DebugMessage(" DEATH player=%d type=%s kills=%d cp=%d cost=%d score=%d",
playerId, tostring(objType), data.kills, data.combat_power, data.build_cost, data.score_value)
end
end
else
DebugMessage(" DEATH (empty)")
end
end end
-- ================================================== -- ==================================================
@@ -115,6 +126,15 @@ end
function Reset_Tactical_Stats() function Reset_Tactical_Stats()
DebugMessage("%s -- In Reset_Tactical_Stats", tostring(Script)) DebugMessage("%s -- In Reset_Tactical_Stats", tostring(Script))
TacticalKillStatsTable = {
[FragIndex] = {},
[DeathIndex] = {}
}
TacticalTeamKillStatsTable = {
[FragIndex] = {},
[DeathIndex] = {}
}
ResetTacticalRegistry() ResetTacticalRegistry()
end end
@@ -141,6 +161,10 @@ end
function Game_Mode_Starting_Event(mode, map) function Game_Mode_Starting_Event(mode, map)
DebugMessage("%s -- Game Mode %s (%s) now starting.", tostring(Script), mode, map) DebugMessage("%s -- Game Mode %s (%s) now starting.", tostring(Script), mode, map)
LocalPlayer = Find_Player("local")
DebugMessage("Local Player: %s (%d)", LocalPlayer.Get_Name(), LocalPlayer.Get_ID())
if StringCompare(mode, "Galactic") then if StringCompare(mode, "Galactic") then
-- Galactic Campaign -- Galactic Campaign
Init_Galactic() Init_Galactic()
@@ -168,10 +192,12 @@ function Game_Mode_Ending_Event(oldMode)
-- Skirmish mode ending -- Skirmish mode ending
Reset_Skirmish() Reset_Skirmish()
end end
LocalPlayer = nil
end end
---This event is triggered when a player quits the game. ---This event is triggered when a player quits the game.
---@param player table FoC PlayerWrapper object that just quit. ---@param player PlayerObject FoC PlayerWrapper object that just quit.
function Player_Quit_Event(player) function Player_Quit_Event(player)
DebugMessage("%s -- Player %s (%d) has quit.", tostring(Script), player.Get_Name(), player.Get_ID()) DebugMessage("%s -- Player %s (%d) has quit.", tostring(Script), player.Get_Name(), player.Get_ID())
@@ -181,9 +207,9 @@ function Player_Quit_Event(player)
end end
---This event is triggered when production has finished in a tactical mode ---This event is triggered when production has finished in a tactical mode
---@param objectType table FoC GameObjectTypeWrapper object that was just built. ---@param objectType GameObjectType FoC GameObjectTypeWrapper object that was just built.
---@param player table FoC PlayerWrapper object that built the object. ---@param player PlayerObject FoC PlayerWrapper object that built the object.
---@param location table|nil FoC GameObjectWrapper of the planet. ---@param location PlanetObject|nil FoC GameObjectWrapper of the planet.
function Tactical_Production_End_Event(objectType, player, location) function Tactical_Production_End_Event(objectType, player, location)
if location then if location then
DebugMessage("%s -- Tactical production of unit %s by %s ended at %s.", tostring(Script), objectType.Get_Name(), DebugMessage("%s -- Tactical production of unit %s by %s ended at %s.", tostring(Script), objectType.Get_Name(),
@@ -200,20 +226,20 @@ function Tactical_Production_End_Event(objectType, player, location)
end end
---This event is triggered when a unit is destroyed in tactical mode. ---This event is triggered when a unit is destroyed in tactical mode.
---@param object table FoC GameObjectWrapper object that was just killed. ---@param object GameObject FoC GameObjectWrapper object that was just killed.
---@param killer table FoC PlayerWrapper object that killed the object. ---@param killer PlayerObject FoC PlayerWrapper object that killed the object.
function Tactical_Unit_Destroyed_Event(object, killer) function Tactical_Unit_Destroyed_Event(object, killer)
DebugMessage("%s -- Tactical unit %s destroyed by %s.", tostring(Script), object.Get_Type().Get_Name(), DebugMessage("%s -- Tactical unit %s destroyed by %s.", tostring(Script), object.Get_Type().Get_Name(),
killer.Get_Name()) killer.Get_Name())
if TacticalGame then if TacticalGame then
TacticalGame:UnitKilled(object) TacticalGame:UnitKilled(object, killer)
end end
end end
---This event is triggered when production has begun on an item at a given planet. ---This event is triggered when production has begun on an item at a given planet.
---@param planet table FoC GameObjectWrapper object of the planet. ---@param planet PlanetObject FoC GameObjectWrapper object of the planet.
---@param objectType table FoC GameObjectTypeWrapper object that was just queued. ---@param objectType GameObjectType FoC GameObjectTypeWrapper object that was just queued.
function Galactic_Production_Begin_Event(planet, objectType) function Galactic_Production_Begin_Event(planet, objectType)
DebugMessage("%s -- Galactic production of %s started at %s.", tostring(Script), objectType.Get_Name(), DebugMessage("%s -- Galactic production of %s started at %s.", tostring(Script), objectType.Get_Name(),
planet.Get_Type().Get_Name()) planet.Get_Type().Get_Name())
@@ -221,16 +247,16 @@ end
---This event is triggered when production has been prematurely canceled ---This event is triggered when production has been prematurely canceled
---on an item at a given planet. ---on an item at a given planet.
---@param planet table FoC GameObjectWrapper object of the planet. ---@param planet PlanetObject FoC GameObjectWrapper object of the planet.
---@param objectType table FoC GameObjectTypeWrapper object that was just canceled.. ---@param objectType GameObjectType FoC GameObjectTypeWrapper object that was just canceled..
function Galactic_Production_Canceled_Event(planet, objectType) function Galactic_Production_Canceled_Event(planet, objectType)
DebugMessage("%s -- Galactic production of %s canceled at %s.", tostring(Script), objectType.Get_Name(), DebugMessage("%s -- Galactic production of %s canceled at %s.", tostring(Script), objectType.Get_Name(),
planet.Get_Type().Get_Name()) planet.Get_Type().Get_Name())
end end
---This event is triggered when production has finished on an item at a given planet. ---This event is triggered when production has finished on an item at a given planet.
---@param planet table FoC GameObjectWrapper or of the planet. ---@param planet PlanetObject FoC GameObjectWrapper or of the planet.
---@param object table FoC GameObjectWrapper or GameObjectTypeWrapper of the object that was just created. ---@param object GameObject|GameObjectType FoC GameObjectWrapper or GameObjectTypeWrapper of the object that was just created.
function Galactic_Production_End_Event(planet, object) function Galactic_Production_End_Event(planet, object)
local typeName = "" local typeName = ""
@@ -248,16 +274,16 @@ function Galactic_Production_End_Event(planet, object)
end end
---This event is triggered when a unit is destroyed in galactic mode. ---This event is triggered when a unit is destroyed in galactic mode.
---@param object table FoC GameObjectWrapper object that was just killed. ---@param object GameObject FoC GameObjectWrapper object that was just killed.
---@param killer table FoC PlayerWrapper object that killed the object. ---@param killer PlayerObject FoC PlayerWrapper object that killed the object.
function Galactic_Unit_Destroyed_Event(object, killer) function Galactic_Unit_Destroyed_Event(object, killer)
DebugMessage("%s -- Object %s killed by %s.", tostring(Script), object.Get_Type().Get_Name(), killer.Get_Name()) DebugMessage("%s -- Object %s killed by %s.", tostring(Script), object.Get_Type().Get_Name(), killer.Get_Name())
end end
---This event is triggered when the level of a starbase changes. ---This event is triggered when the level of a starbase changes.
---@param planet table FoC GameObjectWrapper object of the planet. ---@param planet PlanetObject FoC GameObjectWrapper object of the planet.
---@param oldType table FoC GameObjectTypeWrapper object of the old starbase type. ---@param oldType GameObjectType FoC GameObjectTypeWrapper object of the old starbase type.
---@param newType table FoC GameObjectTypeWrapper object of the new starbase type. ---@param newType GameObjectType FoC GameObjectTypeWrapper object of the new starbase type.
function Galactic_Starbase_Level_Change(planet, oldType, newType) function Galactic_Starbase_Level_Change(planet, oldType, newType)
DebugMessage("%s -- %s Starbase changed from %s to %s.", tostring(Script), planet.Get_Type().Get_Name(), DebugMessage("%s -- %s Starbase changed from %s to %s.", tostring(Script), planet.Get_Type().Get_Name(),
tostring(oldType), tostring(newType)) tostring(oldType), tostring(newType))
@@ -294,9 +320,9 @@ function Galactic_Starbase_Level_Change(planet, oldType, newType)
end end
---This event is called when a planet changes faction in galactic mode. ---This event is called when a planet changes faction in galactic mode.
---@param planet table FoC GameObjectWrapper object of the planet. ---@param planet PlanetObject FoC GameObjectWrapper object of the planet.
---@param newOwner table FoC PlayerWrapper of the new owner. ---@param newOwner PlayerObject FoC PlayerWrapper of the new owner.
---@param oldOwner table FoC PlayerWrapper of the old owner. ---@param oldOwner PlayerObject FoC PlayerWrapper of the old owner.
function Galactic_Planet_Faction_Change(planet, newOwner, oldOwner) function Galactic_Planet_Faction_Change(planet, newOwner, oldOwner)
local planetName = planet.Get_Type().Get_Name() local planetName = planet.Get_Type().Get_Name()
@@ -305,8 +331,8 @@ function Galactic_Planet_Faction_Change(planet, newOwner, oldOwner)
end end
---This event is called when a hero is neutralized by another hero in galactic mode. ---This event is called when a hero is neutralized by another hero in galactic mode.
---@param heroType table FoC GameObjectTypeWrapper object for the neutralized hero type. ---@param heroType GameObjectType FoC GameObjectTypeWrapper object for the neutralized hero type.
---@param killer table FoC GameObjectWrapper object that killed the hero. ---@param killer GameObject FoC GameObjectWrapper object that killed the hero.
function Galactic_Neutralized_Event(heroType, killer) function Galactic_Neutralized_Event(heroType, killer)
DebugMessage("%s -- Hero %s killed by %s.", tostring(Script), heroType.Get_Name(), killer.Get_Owner().Get_Name()) DebugMessage("%s -- Hero %s killed by %s.", tostring(Script), heroType.Get_Name(), killer.Get_Owner().Get_Name())
end end
@@ -316,23 +342,23 @@ end
--- ================================================== --- ==================================================
---Returns the number of frags by player for the given object type. ---Returns the number of frags by player for the given object type.
---@param objectType table FoC GameObjectTypeWrapper object to query. ---@param objectType GameObjectType FoC GameObjectTypeWrapper object to query.
---@param player table FoC PlayerWrapper object to query. ---@param player PlayerObject FoC PlayerWrapper object to query.
---@return integer ---@return integer
function Get_Frag_Count_For_Type(objectType, player) function Get_Frag_Count_For_Type(objectType, player)
return 0 return 0
end end
---Returns the number of heroes neutralized by player for the given object type. ---Returns the number of heroes neutralized by player for the given object type.
---@param objectType table FoC GameObjectTypeWrapper object to query. ---@param objectType GameObjectType FoC GameObjectTypeWrapper object to query.
---@param player table FoC PlayerWrapper object to query. ---@param player PlayerObject FoC PlayerWrapper object to query.
---@return integer ---@return integer
function Get_Neutralized_Count_For_Type(objectType, player) function Get_Neutralized_Count_For_Type(objectType, player)
return 0 return 0
end end
---Returns a game stat for the provided control ID. ---Returns a game stat for the provided control ID.
---@param player table FoC PlayerWrapper object to query. ---@param player PlayerObject FoC PlayerWrapper object to query.
---@param controlId string The Control ID. ---@param controlId string The Control ID.
---@param isTactical boolean Whether the game mode was a tactical mode. ---@param isTactical boolean Whether the game mode was a tactical mode.
---@return number|string ---@return number|string
@@ -376,7 +402,8 @@ function Update_GameSpy_Game_Stats()
end end
---Updates the GameSpy player stats table ---Updates the GameSpy player stats table
---@param player table FoC PlayerWrapper object. ---@param player PlayerObject FoC PlayerWrapper object.
---@deprecated
function Update_GameSpy_Player_Stats(player) function Update_GameSpy_Player_Stats(player)
GameSpy_Player_Stats = {} GameSpy_Player_Stats = {}
end end
@@ -409,15 +436,19 @@ function Init_Tactical(gameMode)
DebugMessage("%s -- Initializing Tactical %s rules.", tostring(Script), gameMode) DebugMessage("%s -- Initializing Tactical %s rules.", tostring(Script), gameMode)
Reset_Tactical_Stats() Reset_Tactical_Stats()
TacticalGame = TacticalGameClass:New(gameMode) TacticalGame = TacticalGameClass:New(gameMode)
GUIManager:InitTactical(TacticalGame) TacticalGame.KillStatsTable = TacticalKillStatsTable
GUIManager:InitTactical()
TextManager:RegisterView(TacticalGame.CombatFeed)
TextManager:SetCurrentView("combat_feed")
end end
---Resets Tactica mode. ---Resets Tactical mode.
function Reset_Tactical() function Reset_Tactical()
DebugMessage("%s -- Resetting Tactical rules.", tostring(Script)) DebugMessage("%s -- Resetting Tactical rules.", tostring(Script))
Reset_Tactical_Stats() Reset_Tactical_Stats()
TacticalGame = nil TacticalGame = nil
GUIManager:Reset() GUIManager:Reset()
TextManager:Reset()
end end
--- ================================================== --- ==================================================
@@ -427,17 +458,20 @@ end
---Initializes Skirmish mode. ---Initializes Skirmish mode.
---@param gameMode string The tactical game mode. ---@param gameMode string The tactical game mode.
function Init_Skirmish(gameMode) function Init_Skirmish(gameMode)
DebugMessage("%s -- Initializing Skirmish Tacitcal %s rules.", tostring(Script), gameMode) DebugMessage("%s -- Initializing Skirmish Tactical %s rules.", tostring(Script), gameMode)
Reset_Stats() Reset_Stats()
SkirmishGame = SkirmishGameClass:New(gameMode) TacticalGame = SkirmishGameClass:New(gameMode)
TacticalGame = SkirmishGame.TacticalGame TacticalGame.KillStatsTable = TacticalKillStatsTable
GUIManager:InitSkirmish(SkirmishGame) GUIManager:InitSkirmish(TacticalGame.IsLocalSpectator)
TextManager:RegisterView(TacticalGame.CombatFeed)
TextManager:SetCurrentView("combat_feed")
end end
---Resets Skirmish mode.
function Reset_Skirmish() function Reset_Skirmish()
DebugMessage("%s -- Resetting Skirmish Tactical rules.", tostring(Script)) DebugMessage("%s -- Resetting Skirmish Tactical rules.", tostring(Script))
Reset_Stats() Reset_Stats()
SkirmishGame = nil
TacticalGame = nil TacticalGame = nil
GUIManager:Reset() GUIManager:Reset()
TextManager:Reset()
end end