· 8 years ago · Jul 08, 2018, 04:06 PM
1import("ScarUtil.scar")
2import("Fatalities/Fatalities.scar")
3
4-- Creates a temporary SGroup from a squadID
5function SGroup_FromSquad(squad)
6 local sg_temp = SGroup_CreateIfNotFound("sg_temp_from_squad");
7 SGroup_Clear(sg_temp);
8 SGroup_Add(sg_temp, squad);
9 return sg_temp;
10end
11
12-- Fetches the first vehicle entity from a squad
13function Entity_VehicleFromSquad(squad)
14
15 for i = 0, Squad_Count(squad) - 1 do
16 local e = Squad_EntityAt(squad, i);
17 if Entity_IsVehicle(e) then
18 return e;
19 end
20 end
21
22 return nil;
23
24end
25
26function WinCondition_GameOver(winningTeam, losingTeam)
27 -- Set the winning team (this will fire win/loss events for each player).
28 World_SetTeamWin(winningTeam)
29
30 local winningPlayers = Team_GetPlayers(winningTeam)
31 local losingPlayers = Team_GetPlayers(losingTeam)
32
33 Fatality_Execute(winningPlayers, losingPlayers)
34end
35
36function WinCondition_Check()
37 local results = {}
38
39 -- Check every player on each team for ownership of the "annihilation_condition" entity.
40 for i = 1, World_GetPlayerCount() do
41 local player = World_GetPlayerAt(i)
42 local team = Player_GetTeam(player)
43
44 results[team] = results[team] or { surrender_count = 0, annihilation_condition_count = 0 }
45
46 -- If any player on a team has surrendered, that team loses.
47 if (Player_IsSurrendered(player)) then
48 results[team].surrender_count = results[team].surrender_count + 1
49 end
50
51 -- If at least one player on a given team owns an "annihilation_condition" entity, then that team has not yet lost.
52 if (Player_IsAlive(player)) then
53 local entities = Player_GetEntities(player)
54 for entityCount = 1, EGroup_CountSpawned(entities) do
55 local entity = EGroup_GetSpawnedEntityAt(entities, entityCount)
56 if (Entity_IsOfType(entity, "annihilation_condition")) then
57 results[team].annihilation_condition_count = results[team].annihilation_condition_count + 1
58 break
59 end
60 end
61 end
62 end
63
64 -- Check if any team has lost.
65 for team,result in pairs(results) do
66 if (result.surrender_count > 0 or result.annihilation_condition_count == 0) then
67 Rule_RemoveAll()
68
69 local winningTeam = Team_GetEnemyTeam(team)
70 local losingTeam = team
71
72 WinCondition_GameOver(winningTeam, losingTeam)
73 end
74 end
75end
76
77local function WinCondition_Init()
78
79 GAME_ISINITIALIZED = true;
80
81 Rule_AddGlobalEvent(Ammo_UpdateSquad, GE_SquadSizeChanged);
82
83 Ammo_RegisterPreSpawned();
84
85 Rule_AddInterval(WinCondition_Check, 3);
86
87end
88
89Scar_AddInit(WinCondition_Init)
90
91-- Fuel System:
92
93fuel_profiles = {};
94fuel_profiles["529d827de28f4899a6021f113a61bde5:dodge_wc51_ambulance_squad_mp"] = {fuel_max = 550, fuel_burn = 2.7};
95
96fuel_targets = {};
97
98-- Register a vehicle
99function Fuel_RegisterMe(...)
100
101 local entityVehicle = Entity_VehicleFromSquad(arg[1]); -- Get the vehicle entity in the squad
102
103 if entityVehicle == nil then -- Make sure the entity Vehicle is not Null/Nil
104 return; -- The target is not a vehicle, or atleast there's no entity in the squad that's marked as a vehicle
105 end
106
107 local entityID = Entity_GetGameID(entityVehicle); -- Get the entity ID of the vehicle entity
108 local squadbp = BP_GetName(Squad_GetBlueprint(arg[1])); -- Get the blueprint name of the squad
109 local player = Util_GetPlayerOwner(arg[1]); -- Get the player owner of the squad
110
111 if (fuel_targets[entityID] ~= nil) then -- Is the entity already registered in the system?
112 return; -- The target already exists in the system, no need to re-add it. Likewise we'll also avoid a bug where American vehicles can re-crew to regain lost fuel
113 end
114
115 Cmd_InstantUpgrade(SGroup_FromSquad(arg[1]), BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:fuel_capable"), 1); -- Give the squad an upgrade, marking it as fuel capable
116 -- Replace the <ModID> with your mod ID, so for example, this mod would use ID 529d827de28f4899a6021f113a61bde5
117 -- and will therefore look like this: Cmd_InstantUpgrade(SGroup_FromSquad(arg[1]), BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:fuel_capable"), 1);
118 -- The SGroup_FromSquad function is currently undefined, as it's a custom function that we'll introduce later.
119
120 -- Here we actually register the entity in the system
121 fuel_targets[entityID] = { -- Create a new entry in the table with indexing key set to the unique game ID given to the entity
122 is_aiOwned = AI_IsAIPlayer(player), -- Is the AI an owner of this vehicle?
123
124 -- The following three variables are set using the fuel_profiles table. You'll be filling in these profiles later, dont worry.
125 -- But as you can probably already see, the blueprint name is being used as a key. (if you want to challenge yourself, set up the fuel_profiles yourself without reading the tutorial)
126 maxf = fuel_profiles[squadbp].fuel_max;
127 current = fuel_profiles[squadbp].fuel_max;
128 burn = fuel_profiles[squadbp].fuel_burn;
129
130 warning50 = false; -- Variable used later, set it to false for now
131 out = false; -- Variable used to mark whether the vehicle is currently out of fuel
132 modifier = nil; -- A variable containing a speed modifier reference
133 position = Entity_GetPosition(entityVehicle); -- The current position of the vehicle
134 };
135
136 -- Should the AI ignore fuel for this vehicle? (this is handy for vehicles like the SWS where the AI could be dumb and have it use up its fuel before it gets to set up)
137 fuel_targets[entityID].ignoreifai = fuel_profiles[squadbp].ai_ignore or false; -- Make the default value false. If the ai_ignore flag is set to true, it will make the AI ignore the vehicle
138
139 if (Rule_Exists(Fuel_Update) == false) then -- Check if there's already a rule calling the Fuel_Update function (defined soon)
140 Rule_AddInterval(Fuel_Update, 1); -- Add an interval to update the fuel system every second
141 end
142
143end
144
145-- Updates the state of the fuel targets
146function Fuel_Update()
147
148 for k,v in pairs(fuel_targets) do -- Go through each element in the fuel_targets table where k = entity ID and v = entity entry
149
150 if Entity_IsValid(k) then -- Make sure the entity exists/is valid
151
152 if not (v.ignoreifai == true and v.is_aiOwned) then -- Make sure, that if the owner is an AI player, we're allowed to update it
153
154 local e = Entity_FromWorldID(k); -- Get the actual entity from the entity ID
155
156 if Entity_IsMoving(e) then -- Check if the entity is moving
157
158 local s = Entity_GetSquad(e); -- Get the squad the entity is part of
159 local sg = SGroup_FromSquad(s); -- Make a temporary SquadGroup
160
161 v.current = v.current - v.burn; -- Subtract the burn rate from the current amount of fuel
162
163 if v.current <= 0 and v.out == false then -- Check if the fuel amount is less than or equal to 0 AND the vehicle is not marked as out yet
164
165 Cmd_CriticalHit(Util_GetPlayerOwner(s), sg, BP_GetCriticalBlueprint("529d827de28f4899a6021f113a61bde5:vehicle_outfuel"), 0); -- Give a critical to the vehicle, disabling movement
166
167 if (Game_GetLocalPlayer() == Util_GetPlayerOwner(s)) then -- Is the vehicle owned by the local player?
168 EventCue_Create(CUE.VEHICLE, "$529d827de28f4899a6021f113a61bde5:1", "$529d827de28f4899a6021f113a61bde5:1", sg, "$529d827de28f4899a6021f113a61bde5:1", nil, 7, true); -- Alert the local player of the vehicle running out of fuel
169 end
170
171 v.out = true; -- Mark the vehicle as having run out of fuel
172
173 elseif v.current < (v.maxf / 3.0) and v.warning50 == false then -- Is the amount less than a third of the max fuel and the warning50 is set to false
174
175 if (v.modifier ~= nil) then -- Incase the modifier is already in place (to make sure it's not stacked)
176 Modifier_Remove(v.modifier); -- Remove the modifier
177 end
178
179 v.modifier = Modify_UnitSpeed(sg, 0.75); -- Add a speed modifier (makes the unit move 25% slower)
180 v.warning50 = true; -- Mark this as having reached it's low point
181
182 end
183 end
184 end
185
186 else -- Not valid
187
188 fuel_targets[k] = nil; -- Make it be nil, so we no longer check this vehicle
189
190 end
191
192 end
193
194end
195
196-- Allows the executer to refuel the target
197function Fuel_RefuelTarget(executer, target)
198
199 if scartype(executer) == ST_SQUAD and scartype(target) == ST_SQUAD then -- Firtsly make sure both are squads
200
201 local __InfantryGroup = SGroup_CreateIfNotFound("__InfantryGroup"); -- Crate a Sgroup for the infantry squad that is going to refuel the vehicle
202 SGroup_Add(__InfantryGroup, executer); -- Add the ability executer to the Sgroup
203
204 local entityVehicle = Entity_VehicleFromSquad(target); -- Get the vehicle from the target squad
205 local entityID = Entity_GetGameID(entityVehicle); -- Get the entityID
206
207 if fuel_targets[entityID] ~= nil then -- Make sure the entity is registered in the fuel system
208
209 fuel_targets[entityID].current = fuel_targets[entityID].maxf; -- Set the vehicles current fuel to its max fuel
210
211 UI_CreateColouredSquadKickerMessage(Game_GetLocalPlayer(), target, "$529d827de28f4899a6021f113a61bde5:2", 0, 255, 0, 0); -- Create a coloured kicker message that says 100% fuel (the last 4 numbers are RGBA numbers)
212 SGroup_RemoveUpgrade(SGroup_FromSquad(Entity_GetSquad(entityVehicle)), BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:fuel_out")); -- Remove the Fuel_Out upgrade from the entity
213
214 if Entity_HasCritical(entityVehicle, BP_GetCriticalBlueprint("529d827de28f4899a6021f113a61bde5:vehicle_outfuel")) == true then -- Make sure the target actually has this critical
215 Entity_RemoveCritical(entityVehicle, BP_GetCriticalBlueprint("529d827de28f4899a6021f113a61bde5:vehicle_outfuel")); -- Remove the critical
216 end
217
218 if (fuel_targets[entityID].modifier ~= nil) then -- Is the speed modifier valid?
219 Modifier_Remove(fuel_targets[entityID].modifier); -- Remove the speed modifier
220 end
221
222 fuel_targets[entityID].warning50 = false; -- Reset this variable
223 fuel_targets[entityID].out = false -- Reset the out variable
224
225 SGroup_RemoveUpgrade(__InfantryGroup, BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:fuel_equipped")); -- Remove the fuel_equippped upgrade from the infantry
226
227 end
228
229 SGroup_Clear(__InfantryGroup); -- Clear the infantry group
230
231 end -- You can add other combinations down here (like ST_SQUAD and ST_ENTITY)
232
233end
234
235-- Ammo system:
236
237ammo_profile = {};
238ammo_profile["529d827de28f4899a6021f113a61bde5:m1_carbine_rear_echelon_mp"] = { carried_clips = 1, rounds_in_clip = 4 };
239
240ammo_preSpawned = {}; -- A table that holds all squads prespawned. This is neccessarry because of the way the game spawns and initialises a match
241ammo_watch = {}; -- The table containing the entities and how much ammunition they have
242
243-- The function that will register a squad
244function Ammo_RegisterMe(...)
245 local squad = arg[1]; -- The squad that's passed as the first argument
246 local isTeamWeapon = Squad_HasTeamWeapon(squad); -- A variable to check if the
247 for i = 0, Squad_Count(squad)-1 do -- Go through eact entity in the squad
248 local e = Squad_EntityAt(squad, i); -- Get the entity found at i. Note that this operation is zero-indexed unlike how it's normally done in Lua to retrieve the first element
249 if (isTeamWeapon == false or (isTeamWeapon == true and Entity_IsSyncWeapon(e))) then -- Make sure it's an entity or the entity being the team weapon in the squad
250 Ammo_CreateEntity(e); -- Create the entity
251 end
252 end
253end
254
255-- Function to register the squads that have been prespawned
256function Ammo_RegisterPreSpawned()
257
258 for i=1, #ammo_preSpawned do -- Go through each entity in the table
259 Ammo_CreateEntity(ammo_preSpawned[i]); -- Register them
260 end
261
262 ammo_preSpawned = nil; -- "Delete" the table, no longer used
263
264end
265
266-- Team weapons override the team members stats meaning team members have unlimited bullets until the main weapon runs out
267function Ammo_CreateEntity(e)
268
269 if (GAME_ISINITIALIZED ~= nil) then -- Make sure this is not nil (we'll declare it later)
270
271 local bName = BP_GetName(Entity_GetWeaponBlueprint(e, 0)); -- Get the name of the weapon blueprint fround at hardpoint 1 (the main gun)
272 local squad = Entity_GetSquad(e); -- Get the squad from the entity
273 local isTeamWeapon = Squad_HasTeamWeapon(squad); -- Check to see if the squad has a team weapon
274
275 if (isTeamWeapon == false or (isTeamWeapon == true and Entity_IsSyncWeapon(e))) then -- if entity or a team weapon
276 local blueprint = ammo_profile[bName]; -- get the blueprint profile
277 if (blueprint ~= nil) then -- make sure the blueprint profile is valid
278 ammo_watch[Entity_GetGameID(e)] = { -- register the entity based on the profile
279 clips = blueprint.carried_clips,
280 rounds_current = blueprint.rounds_in_clip * blueprint.carried_clips,
281 rounds_total = blueprint.rounds_in_clip * blueprint.carried_clips,
282 rate = blueprint.fire_rate,
283 weapon_name = bName,
284 };
285 if (Squad_HasCritical(squad, BP_GetCriticalBlueprint("529d827de28f4899a6021f113a61bde5:infantry_ammo_out"))) then -- if the squad has the critical ammo out
286 ammo_watch[Entity_GetGameID(e)].rounds_current = 0; -- remove the current bullet count from this entity
287 end
288 end
289 end
290
291 else
292 table.insert(ammo_preSpawned, e); -- Insert this entity into the prespawned table, we'll then register the entity later
293 end
294
295end
296
297-- Registers the entity but with no ammunition
298function Ammo_CreateEntityWithoutRefill(e)
299
300 local bName = BP_GetName(Entity_GetWeaponBlueprint(e, 0));
301 local blueprint = ammo_profile[bName];
302 if (blueprint ~= nil) then
303 ammo_watch[Entity_GetGameID(e)] = {
304 clips = blueprint.carried_clips,
305 rounds_current = 0, -- Notice how this entity will start without any bullets
306 rounds_total = blueprint.rounds_in_clip * blueprint.carried_clips,
307 rate = blueprint.fire_rate,
308 weapon_name = bName,
309 };
310 end
311
312end
313
314-- The function to actually update the weapon stats for the entity
315function Ammo_UpdateMe(...)
316
317 local userentity = arg[2]; -- The entity using the fired weapon
318 local user = Entity_GetGameID(userentity); -- Get the game ID of the weapon
319
320 if (ammo_watch[user] ~= nil) then -- Make sure the entity exists in the system
321 Ammo_UpdateWeapon(userentity, user); -- Update the weapon (verify that we're using the same weapon as before. If we've been upgraded with a new weapon, our stats are reset)
322 ammo_watch[user].rounds_current = ammo_watch[user].rounds_current - (ammo_watch[user].rate or 1); -- Subtract the amount of fired bullets (if the fire rate is not defined, it will subtract 1)
323 if (ammo_watch[user].rounds_current <= 0) then -- Have we cun out of bullets?
324 if (Ammo_CheckSquad(Entity_GetSquad(userentity), user) == false) then -- Is the entire squad out of bullets?
325 Cmd_InstantUpgrade(SGroup_FromSquad(Entity_GetSquad(userentity)), BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:upg_ammo_out")); -- Give them the upg_ammo_out upgrade to mark them as being out of bullets
326 else -- The rest of the squad is doing just fine
327 ammo_watch[user].rounds_current = 1; -- We "loan" a bullet from our squad members
328 end
329 end
330 else -- Not registered (so register it, but without any ammunition)
331 local isTeamWeapon = Squad_HasTeamWeapon(Entity_GetSquad(userentity));
332 if (isTeamWeapon == false or (isTeamWeapon == true and Entity_IsSyncWeapon(userentity))) then
333 Ammo_CreateEntityWithoutRefill(userentity); -- Call the registering function, but with no ammunition
334 end
335 end
336
337end
338
339-- Updates the entity stats incase the entity has received a new weapon
340function Ammo_UpdateWeapon(e, eID)
341 local bName = BP_GetName(Entity_GetWeaponBlueprint(e, 0));
342 if (bName ~= ammo_watch[eID].weapon_name) then
343 local bp = ammo_profile[bName];
344 if (bp ~= nil) then
345 ammo_watch[eID].weapon_name = bName;
346 ammo_watch[eID].rounds_total = bp.rounds_in_clip * bp.carried_clips;
347 ammo_watch[eID].clips = bp.carried_clips;
348 return bp;
349 else
350 return ammo_profile[ammo_watch[eID].weapon_name];
351 end
352 else
353 return ammo_profile[bName];
354 end
355end
356
357-- Check if the squad has any ammunition left
358function Ammo_CheckSquad(squad, caller)
359
360 local total = 0;
361
362 for i = 0, Squad_Count(squad)-1 do
363
364 local eID = Entity_GetGameID(Squad_EntityAt(squad, i));
365
366 if (eID ~= caller) then
367 if (ammo_watch[eID] ~= nil) then
368 if (Entity_IsAlive(Squad_EntityAt(squad, i))) then
369 total = total + ammo_watch[eID].rounds_current;
370 end
371 end
372 end
373
374 end
375
376 if (total == 0) then
377 return false;
378 else
379 if (Ammo_RemoveFirst(squad, caller)) then -- Remove a bullet from the first location where it's possible
380 return true;
381 else
382 Ammo_Nullify(squad); -- Nullify this squad => remove all bullets from the squad
383 return false; -- We cant borrow from squad, as there a no more bullets
384 end
385 end
386
387end
388
389-- Removes 1 bullet from the first entity that has a spare bullet
390function Ammo_RemoveFirst(squad, caller)
391
392 for i = 0, Squad_Count(squad)-1 do
393
394 local eID = Entity_GetGameID(Squad_EntityAt(squad, i));
395
396 if (eID ~= caller) then
397 if (ammo_watch[eID] ~= nil) then
398 if (Entity_IsAlive(Squad_EntityAt(squad, i))) then
399 if (ammo_watch[eID].rounds_current > 1) then
400 ammo_watch[eID].rounds_current = ammo_watch[eID].rounds_current - 1;
401 return true;
402 end
403 end
404 end
405 end
406
407 end
408
409 return false;
410
411end
412
413-- Removes all bullets from a squad
414function Ammo_Nullify(squad)
415
416 for i = 0, Squad_Count(squad)-1 do
417
418 local eID = Entity_GetGameID(Squad_EntityAt(squad, i));
419
420 if (eID ~= caller) then
421 if (ammo_watch[eID] ~= nil) then
422 ammo_watch[eID].rounds_current = 0;
423 end
424 end
425
426 end
427
428end
429
430-- Updates the squad. Handles resizing of squads (eg. when a squad is reinforced)
431function Ammo_UpdateSquad(...)
432
433 local squad = arg[1];
434 local isTeamWeapon = Squad_HasTeamWeapon(squad);
435
436 for i = 0, Squad_Count(squad)-1 do
437 local e = Squad_EntityAt(squad, i);
438 local eID = Entity_GetGameID(e);
439 if (ammo_watch[eID] == nil) then
440 if (isTeamWeapon == false or (isTeamWeapon == true and Entity_IsSyncWeapon(e))) then
441 Ammo_CreateEntity(e);
442 end
443 end
444 end
445
446end
447
448-- Rearms a squad
449function Ammo_ReArm(...)
450
451 local squad = arg[1];
452 local isTeamWeapon = Squad_HasTeamWeapon(squad);
453
454 for i=0, Squad_Count(squad)-1 do -- We'll go through each entity in the squad
455 local e = Squad_EntityAt(squad, i);
456 local id = Entity_GetGameID(e);
457 if (ammo_watch[id] ~= nil) then
458 local blueprint = Ammo_UpdateWeapon(e, id);
459 ammo_watch[id].rounds_current = blueprint.rounds_in_clip * blueprint.carried_clips; -- Here we reset the supply
460 else
461 if (isTeamWeapon == false or (isTeamWeapon == true and Entity_IsSyncWeapon(e))) then
462 Ammo_CreateEntity(e); -- The entity is not registered, so we simply register them (and with ammunition this time)
463 end
464 end
465 end
466
467 Cmd_InstantUpgrade(SGroup_FromSquad(squad), BP_GetUpgradeBlueprint("529d827de28f4899a6021f113a61bde5:upg_ammo_refill")); -- Remember to update the ModID
468
469end