--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- MODIFIER FUNCTIONS
-- Provides a simple interface to add and remove specific modifiers from groups and players.
--
-- (c) 2005 Relic Entertainment
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- create the blank modifier storage table at the start of a mission
function Modifier_Init()
	_ModifiersSquadTable = {}
	_ModifiersEntityTable = {}
	_ModifiersReverseTable = {}
end
Scar_AddInit(Modifier_Init)




-- ALL Modify_* functions should call these function so that all SCAR-applied modifiers get indexed  <---- IMPORTANT!

-- this function adds a modifier id to the global modifier storage table
function Modifier_AddToSquadTable(squad, modid)

	-- each squad has it's own list in the table, indexed by it's unique game id
	local sid = Squad_GetGameID(squad)
	if _ModifiersSquadTable[sid] == nil then
		_ModifiersSquadTable[sid] = {}
	end
	table.insert(_ModifiersSquadTable[sid], modid)
	
	-- each modifier has a reverse lookup table, showing which squad/entity it was applied to
	_ModifiersReverseTable[modid] = {squad = sid}
	
end

-- this function adds a modifier id to the global modifier storage table
function Modifier_AddToEntityTable(entity, modid)

	-- each entity has it's own list in the table, indexed by it's unique game id
	local eid = Entity_GetGameID(entity)
	if _ModifiersEntityTable[eid] == nil then
		_ModifiersEntityTable[eid] = {}
	end
	table.insert(_ModifiersEntityTable[eid], modid)
	
	-- each modifier has a reverse lookup table, showing which squad/entity it was applied to
	_ModifiersReverseTable[modid] = {entity = eid}
	
end


-- this function adds a modifier id to the global modifier storage table
function Modifier_AddToMiscTable(modid)

	-- each modifier has a reverse lookup table, showing which squad/entity it was applied to
	_ModifiersReverseTable[modid] = {misc = true}
	
end


















--? @group Modifiers
--? @shortdesc Remove an applied modifier. 
--? @result Void
--? @args ModID modifier
function Modifier_Remove(modifier)

	-- if it's just one modID, put it in a table
	if (type(modifier) ~= "table") then
		modifier = {modifier}
	end
	
	-- remove each modID in turn
	for n = table.getn(modifier), 1, -1 do
		
		-- find what it was applied to and remove reference to it
		local modid = modifier[n]
		local entry = _ModifiersReverseTable[modid]
		
		if entry ~= nil then
			
			-- if it was applied to a squad, find out which one and amend that squad's records
			if entry.squad ~= nil then
				
				local squadlist = _ModifiersSquadTable[entry.squad]
				if squadlist ~= nil then
					for i = table.getn(squadlist), 1, -1 do
						if squadlist[i] == modid then
							table.remove(squadlist, i)
						end
					end
					if table.getn(squadlist) == 0 then
						_ModifiersSquadTable[entry.squad] = nil
					end
				end
			end
			
			-- if it was applied to an entity, find out which one and amend that entitiy's records
			if entry.entity ~= nil then
				local entitylist = _ModifiersEntityTable[entry.entity]
				if entitylist ~= nil then
					for i = table.getn(entitylist), 1, -1 do
						if entitylist[i] == modid then
							table.remove(entitylist, i)
						end
						if table.getn(entitylist) == 0 then
							_ModifiersEntityTable[entry.entity] = nil
						end
					end
				end
			end
			
			table.remove(_ModifiersReverseTable, modid)
			
		end
		
		Modifier_RemoveInternal(modid)
		
	end
	
	for n = table.getn(modifier), 1, -1 do
		table.remove(modifier, n)
	end
	
end


--? @group Modifiers
--? @shortdesc Removes all SCAR-applied modifiers for a specific SGroup. 
--? @result Void
--? @args SGroupID sgroup
function Modifier_RemoveAllFromSGroup(sgroup)
	
	local _RemoveFromSquad = function(gid, idx, sid)
		local id = Squad_GetGameID(sid)
		if _ModifiersSquadTable[id] ~= nil then
			Modifier_Remove(_ModifiersSquadTable[id])
			_ModifiersSquadTable[id] = nil
		end
	end
	
	SGroup_ForEach(sgroup, _RemoveFromSquad)

end




--? @group Modifiers
--? @shortdesc Removes all SCAR-applied modifiers for a specific EGroup. 
--? @result Void
--? @args EGroupID egroup
function Modifier_RemoveAllFromEGroup(egroup)
	
	local _RemoveFromEntity = function(gid, idx, eid)
		local id = Entity_GetGameID(eid)
		if _ModifiersEntityTable[id] ~= nil then
			Modifier_Remove(_ModifiersEntityTable[id])
			_ModifiersEntityTable[id] = nil
		end
	end
	
	EGroup_ForEach(egroup, _RemoveFromEntity)

end



--? @group Modifiers
--? @shortdesc Modifies the time taken to build a particular EBP. This only affects the given player. 
--? @result ModID
--? @args PlayerID playerId, String ebp, Real scalefactor
function Modify_EntityBuildTime(playerid, ebp, scalefactor)

	local modifier = Modifier_Create(MAT_EntityType, "modifiers\\cost_ticks_modifier.lua", MUT_Multiplication, false, scalefactor, ebp)

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end


--? @group Modifiers
--? @shortdesc Modifies the build time for a particular upgrade. This only affects the given player. 
--? @result ModID
--? @args PlayerID playerId, UpgradeID upgrade, Real scalefactor
function Modify_UpgradeBuildTime(playerid, upgrade, scalefactor)
	
	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Upgrade, "modifiers\\upgrade_production_speed_modifier.lua", MUT_Multiplication, false, scalefactor, upgrade)

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end


--? @group Modifiers
--? @shortdesc Modifies the upkeep for a player 
--? @result ModID
--? @args PlayerID playerId, Real scalefactor
function Modify_Upkeep(playerid, scalefactor)
	
	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Player, "modifiers\\income_upkeep_manpower_player_modifier.lua", MUT_Multiplication, false, scalefactor, "")

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end


--? @group Modifiers
--? @shortdesc Sets the cost of an upgrade. This only affects the given player
--? @result ModID
--? @args PlayerID playerId, UpgradeID upgrade, Integer resourceType, Real newCost
function Modify_SetUpgradeCost(playerid, upgrade, resource, newCost)

	local modifiertype
	if (resource == RT_Manpower) then
		modifiertype = "modifiers\\upgrade_cost_manpower_modifier.lua"
	elseif (resource == RT_Munition) then
		modifiertype =  "modifiers\\upgrade_cost_munition_modifier.lua"
	elseif (resource == RT_Fuel) then
		modifiertype =  "modifiers\\upgrade_cost_fuel_modifier.lua"
	elseif (resource == RT_Action) then
		modifiertype =  "modifiers\\upgrade_cost_action_modifier.lua"
	elseif (resource == RT_Command) then
		modifiertype =  "modifiers\\upgrade_cost_command_modifier.lua"
	end
	
	local currentCost = Player_GetUpgradeCost(playerid, upgrade, resource)
	local modifier = Modifier_Create(MAT_Upgrade, modifiertype, MUT_Addition, true, newCost - currentCost, upgrade)
	
	return {Modifier_ApplyToPlayer(modifier, playerid)}
end

--? @group Modifiers
--? @shortdesc Modifies a player's incoming resource rate. Possible resource types are RT_Manpower, RT_Munition, RT_Fuel, RT_Action 
--? @result ModID
--? @args PlayerID playerId, Integer resourceType, Real scalefactor
function Modify_PlayerResourceRate(playerid, resource, scalefactor)

	local modifiertype = ""
	
	if (resource == RT_Manpower) then
		modifiertype = "modifiers\\income_manpower_player_modifier.lua"
	elseif (resource == RT_Munition) then
		modifiertype =  "modifiers\\income_munition_player_modifier.lua"
	elseif (resource == RT_Fuel) then
		modifiertype =  "modifiers\\income_fuel_player_modifier.lua"
	elseif (resource == RT_Action) then
		modifiertype =  "modifiers\\income_combat_player_modifier.lua"
	end
	
	local modifier = Modifier_Create(MAT_Player, modifiertype, MUT_Multiplication, false, scalefactor, "")

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end



--? @group Modifiers
--? @shortdesc Modifies a player's resource bonus received (ie. one-time resource gifts) Possible resource types are RT_Manpower, RT_Munition, RT_Fuel, RT_Action 
--? @result ModID
--? @args PlayerID playerId, Integer resourceType, Real scalefactor
function Modify_PlayerResourceGift(playerid, resource, scalefactor)

	local modifiertype = ""
	
	if (resource == RT_Manpower) then
		modifiertype = "modifiers\\gift_manpower_player_modifier.lua"
	elseif (resource == RT_Munition) then
		modifiertype =  "modifiers\\gift_munition_player_modifier.lua"
	elseif (resource == RT_Fuel) then
		modifiertype =  "modifiers\\gift_fuel_player_modifier.lua"
	elseif (resource == RT_Action) then
		modifiertype =  "modifiers\\gift_combat_player_modifier.lua"
	end
	
	local modifier = Modifier_Create(MAT_Player, modifiertype, MUT_Multiplication, false, scalefactor, "")

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end

--? @group Modifiers
--? @shortdesc Allows paratroopers to reinforce from the sky.  Set to true to enable, false to disable.
--? @args PlayerID playerId, Boolean enable
function Modify_Enable_ParadropReinforcements(playerid, value)
	
	if value == true then
		value = 1
	elseif value == false then
		value = 0
	end
	
	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Player, "modifiers\\paradrop_reinforcements_modifier.lua", MUT_Enable, false, value, upgrade)
	Modifier_ApplyToPlayer( modifier, playerid )
	
end




--? @group Modifiers
--? @shortdesc Modifies a squad's weapon range.
--? @extdesc The hardpoint should be specified as a string - i.e. "hardpoint_01"
--? @result ModID
--? @args SGroupID/EGroupID group, String hardpoint, Real scalefactor
function Modify_WeaponRange(groupid, hardpoint, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Weapon, "modifiers\\range_weapon_modifier.lua", MUT_Multiplication, false, factor, hardpoint)
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end

	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies a squad's weapon accuracy.
--? @extdesc The hardpoint should be specified as a string - i.e. "hardpoint_01"
--? @result ModID
--? @args SGroupID/EGroupID group, String hardpoint, Real scalefactor
function Modify_WeaponAccuracy(groupid, hardpoint, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Weapon, "modifiers\\accuracy_weapon_modifier.lua", MUT_Multiplication, false, factor, hardpoint)
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end

	return result
	
end


--? @group Modifiers
--? @shortdesc Modifies a squad's weapon cooldown time.
--? @extdesc The hardpoint should be specified as a string - i.e. "hardpoint_01"
--? @result ModID
--? @args SGroupID/EGroupID group, String hardpoint, Real scalefactor
function Modify_WeaponCooldown(groupid, hardpoint, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Weapon, "modifiers\\cooldown_weapon_modifier.lua", MUT_Multiplication, false, factor, hardpoint)
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end


--? @group Modifiers
--? @shortdesc Modifies a squad's weapon burst time.
--? @extdesc The hardpoint should be specified as a string - i.e. "hardpoint_01"
--? @result ModID
--? @args SGroupID/EGroupID group, String hardpoint, Real scalefactor
function Modify_WeaponBurst(groupid, hardpoint, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Weapon, "modifiers\\burst_weapon_modifier.lua", MUT_Multiplication, false, factor, hardpoint)
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies a squad's weapon damage.
--? @extdesc The hardpoint should be specified as a string - i.e. "hardpoint_01"
--? @result ModID
--? @args SGroupID/EGroupID group, String hardpoint, Real scalefactor
function Modify_WeaponDamage(groupid, hardpoint, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Weapon, "modifiers\\damage_weapon_modifier.lua", MUT_Multiplication, false, factor, hardpoint)
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the damage a squad/entity receives.
--? @result ModID
--? @args SGroupID/EGroupID group, Real scalefactor
function Modify_ReceivedDamage(groupid, factor)

	-- create the appropriate modifier
	local modifier = 0
	local result = {}
	
	if (scartype(groupid) == ST_SGROUP) then
		modifier = Modifier_Create(MAT_Squad, "modifiers\\received_damage_modifier.lua", MUT_Multiplication, false, factor, "")
	elseif (scartype(groupid) == ST_EGROUP) then
		modifier = Modifier_Create(MAT_Entity, "modifiers\\received_damage_modifier.lua", MUT_Multiplication, false, factor, "")
	end
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then								-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then							-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the chance of a squad/entity being hit
--? @result ModID
--? @args SGroupID/EGroupID group, Real scalefactor
function Modify_ReceivedAccuracy(groupid, factor)

	-- create the appropriate modifier
	local modifier = 0
	local result = {}
	
	if (scartype(groupid) == ST_SGROUP) then
		modifier = Modifier_Create(MAT_Squad, "modifiers\\received_accuracy_modifier.lua", MUT_Multiplication, false, factor, "")
	elseif (scartype(groupid) == ST_EGROUP) then
		modifier = Modifier_Create(MAT_Entity, "modifiers\\received_accuracy_modifier.lua", MUT_Multiplication, false, factor, "")
	end
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then								-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then							-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end




--? @group Modifiers
--? @shortdesc Modifies the rate at which a squad gets suppressed
--? @result ModID
--? @args SGroupID sgroup, Real scalefactor
function Modify_ReceivedSuppression(group, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Squad, "modifiers\\received_suppression_squad_modifier.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	-- apply this to each squad in the group
	local _ApplyModifier = function (gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	SGroup_ForEachEx(group, _ApplyModifier, true, true)
	
	return result
	
end




--? @group Modifiers
--? @shortdesc Modifies the maximum speed for a vehicle. This has no effect on infantry.
--? @result ModID
--? @args SGroupID sgroup, Real scalefactor
function Modify_UnitSpeed(group, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Squad, "modifiers\\speed_maximum_modifier.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	-- apply this to each squad in the group
	local _ApplyModifier = function (gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	SGroup_ForEachEx(group, _ApplyModifier, true, true)
	
	return result
	
end





--? @group Modifiers
--? @shortdesc Modifies the sight radius for a player.
--? @result ModID
--? @args PlayerID player, Real scalefactor
function Modify_PlayerSightRadius(playerid, factor)

	local race = Player_GetRace(playerid)
	local result = {}
	
	-- apply modifier to each entity
	for n = 1, World_GetPossibleBuildingsCount(race) do
		
		local ebpID = World_GetPossibleBuildingsPBGID(race, n-1)
		local modifier = Modifier_Create(MAT_EntityType, "modifiers\\sight_radius_modifier.lua", MUT_Multiplication, false, factor, ebpID)
		table.insert(result, Modifier_ApplyToPlayer(modifier, playerid))
		
	end
	
	return result
	
end


--? @group Modifiers
--? @shortdesc Modifies the sight radius for an egroup or an sgroup.
--? @result ModID
--? @args SGroupID/EGroupID group, Real scalefactor
function Modify_SightRadius(groupid, factor)

	local modifier = 0
	local result = {}
	
	if (scartype(groupid) == ST_SGROUP) then
		modifier = Modifier_Create(MAT_Squad, "modifiers\\sight_radius_modifier.lua", MUT_Multiplication, false, factor, "")
	elseif (scartype(groupid) == ST_EGROUP) then
		modifier = Modifier_Create(MAT_Entity, "modifiers\\sight_radius_modifier.lua", MUT_Multiplication, false, factor, "")
	end
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		print("SGROUP")
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		print("EGROUP")
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end

	return result
	
end


--? @group Modifiers
--? @shortdesc Modifies the territory radius for an egroup or an sgroup.
--? @result ModID
--? @args EGroupID group, Real scalefactor
function Modify_TerritoryRadius(groupid, factor)

	local modifier = Modifier_Create(MAT_Entity, "modifiers\\territory_radius_max.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		print("EGROUP")
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end

	return result
	
end


--? @group Modifiers
--? @shortdesc Increases the received accuracy, penetration, and damage on a squad by the scalefactor.  For example, a scalefactor of 2 means that the squad gets 2x the received accuracy, 2x the received penetration, and 2x the received damage.
--? @result ModID
--? @args SGroupID sgroup, Real scalefactor
function Modify_Vulnerability(group, factor)

	-- create the appropriate modifier
	local modifier1 = Modifier_Create(MAT_Squad, "modifiers\\received_penetration_modifier.lua", MUT_Multiplication, false, factor, "")
	local modifier2 = Modifier_Create(MAT_Squad, "modifiers\\received_accuracy_modifier.lua", MUT_Multiplication, false, factor, "")
	local modifier3 = Modifier_Create(MAT_Squad, "modifiers\\received_damage_modifier.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	-- apply this to each squad in the group
	local _ApplyModifier = function (gid, idx, sid)
		local modid1 = Modifier_ApplyToSquad(modifier1, sid)
		local modid2 = Modifier_ApplyToSquad(modifier2, sid)
		local modid3 = Modifier_ApplyToSquad(modifier3, sid)
		table.insert(result, modid1)
		table.insert(result, modid2)
		table.insert(result, modid3)
		Modifier_AddToSquadTable(sid, modid1)
		Modifier_AddToSquadTable(sid, modid2)
		Modifier_AddToSquadTable(sid, modid3)
	end
	SGroup_ForEachEx(group, _ApplyModifier, true, true)
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the availability limit of a squad type for any given player
--? @result ModID
--? @args PlayerID player, String blueprint, Integer addition
function Modify_SquadAvailability(playerid, blueprint, addition)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_SquadType, "modifiers\\squad_availability_modifier.lua", MUT_Addition, false, addition, blueprint)

	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end



--? @group Modifiers
--? @shortdesc Modifies the target priority of a squad or entity group from the attacker. The value is an addition
--? @result ModID
--? @args SGroupID/EGroupID group, Integer addition
function Modify_TargetPriority(groupid, addition)

	-- create the appropriate modifiers
	local modifier = 0
	local result = {}
	
	if (scartype(groupid) == ST_SGROUP) then
		modifier = Modifier_Create(MAT_Squad, "modifiers\\target_priority_squad_modifier.lua", MUT_Addition, false, addition, "")
	elseif (scartype(groupid) == ST_EGROUP) then
		modifier = Modifier_Create(MAT_Entity, "modifiers\\target_priority_modifier.lua", MUT_Addition, false, addition, "")
	end
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the capture time of all strategic points in an EGroup
--? @result ModID
--? @args EGroupID sgroup, Real scalefactor
function Modify_CaptureTime(group, factor)

	-- create the appropriate modifier
	if factor ~= 0 then
		factor = 1.0 / factor
	else
		factor = 99999 -- capture instantly
	end
	local modifier = Modifier_Create(MAT_Entity, "modifiers\\strategic_point_capture_ticks_modifier.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	-- apply this to each squad in the group
	local _ApplyModifier = function (gid, idx, sid)
		if Entity_IsStrategicPoint(sid) then
			local modid = Modifier_ApplyToEntity(modifier, sid)
			table.insert(result, modid)
			Modifier_AddToEntityTable(sid, modid)
		end
	end
	EGroup_ForEachEx(group, _ApplyModifier, true, true)
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the production rate of all factories in an EGroup
--? @result ModID
--? @args EGroupID sgroup, Real scalefactor
function Modify_ProductionRate(group, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Entity, "modifiers\\production_speed_modifier.lua", MUT_Multiplication, false, factor, "")
	local result = {}
	
	-- apply this to each squad in the group
	local _ApplyModifier = function (gid, idx, sid)
		local modid = Modifier_ApplyToEntity(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(sid, modid)
	end
	EGroup_ForEachEx(group, _ApplyModifier, true, true)
	
	return result
	
end



--? @group Modifiers
--? @shortdesc Modifies the production rate of a player.
--? @result ModID
--? @args PlayerID sgroup, Real scalefactor
function Modify_PlayerProductionRate(player, factor)

	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Player, "modifiers\\production_speed_player_modifier.lua", MUT_Multiplication, false, factor, "")
	
	return Modifier_ApplyToPlayer(modifier, player)
	
end



--? @group Modifiers
--? @shortdesc Modifies the recharge time of an ability
--? @result ModID
--? @args PlayerID player, AbilityID ability, Real scalefactor
function Modify_AbilityRechargeTime(playerid, abilityid, factor)
	
	-- create the appropriate modifier
	local modifier = Modifier_Create(MAT_Ability, "modifiers\\ability_recharge_time_modifier.lua", MUT_Multiplication, false, factor, abilityid)

	return {Modifier_ApplyToPlayer(modifier, playerid)}

end



--? @group Modifiers
--? @shortdesc Modifies the cost of an entity for a particular player. Possible resource types are RT_Manpower, RT_Munition, RT_Fuel, RT_Action 
--? @result ModID
--? @args PlayerID player, String blueprint, Integer resourcetype, Integer addition
function Modify_EntityCost(playerid, blueprint, resource, addition)

	local modifiertype = ""
	
	if (resource == RT_Manpower) then
		modifiertype = "modifiers\\cost_manpower_modifier.lua"
	elseif (resource == RT_Munition) then
		modifiertype =  "modifiers\\cost_munition_modifier.lua"
	elseif (resource == RT_Fuel) then
		modifiertype =  "modifiers\\cost_fuel_modifier.lua"
	elseif (resource == RT_Action) then
		modifiertype =  "modifiers\\cost_action_modifier.lua"
	end

	local modifier = Modifier_Create(MAT_EntityType, modifiertype, MUT_Addition, false, addition, blueprint)

	return {Modifier_ApplyToPlayer(modifier, playerid)}

end	

--? @group Modifiers
--? @shortdesc Modifies the vehicle repair rate of all a player's engineers
--? @result ModID
--? @args PlayerID player, Real factor[, String engineer_blueprint]
function Modify_VehicleRepairRate(playerid, factor, engineer_blueprint)

	if engineer_blueprint == nil then
		engineer_blueprint = "ebps\\races\\allies\\soldiers\\engineer.lua"
	end
	
	local modifier = Modifier_Create(MAT_EntityType, "modifiers\\vehicle_repair_rate_modifier.lua", MUT_Multiplication, false, factor, engineer_blueprint)
	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end

--? @group Modifiers
--? @shortdesc Modifies the veterancy experience received by a player
--? @result ModID
--? @args PlayerID player, Real factor
function Modify_PlayerExperienceReceived(playerid, factor)

	local modifier = Modifier_Create(MAT_Player, "modifiers\\received_experience_player_modifier.lua", MUT_Multiplication, false, factor, "")
	return {Modifier_ApplyToPlayer(modifier, playerid)}
	
end

--? @group Modifiers
--? @shortdesc Enable or disable hold (garrisoning) for an egroup or sgroup
--? @result ModID
--? @args EGroupID group, Boolean disable
function Modify_DisableHold(groupid, disable)

	local factor = -1.0
	if ( disable == true ) then
		factor = 1.0
	end
	
	local modifier = Modifier_Create(MAT_Entity, "modifiers\\hold_disable.lua", MUT_Enable, false, factor, "")
	local result = {}
	
	local _ApplyModifierToSquad = function(gid, idx, sid)
		local modid = Modifier_ApplyToSquad(modifier, sid)
		table.insert(result, modid)
		Modifier_AddToSquadTable(sid, modid)
	end
	local _ApplyModifierToEntity = function(gid, idx, eid)
		local modid = Modifier_ApplyToEntity(modifier, eid)
		table.insert(result, modid)
		Modifier_AddToEntityTable(eid, modid)
	end
	
	if (scartype(groupid) == ST_SGROUP) then
		-- apply this to each squad in the group
		SGroup_ForEachEx(groupid, _ApplyModifierToSquad, true, true)
	elseif (scartype(groupid) == ST_EGROUP) then
		-- apply this to each entity in the group
		EGroup_ForEach(groupid, _ApplyModifierToEntity)
	end

	return result
	
end