Counter Strike Online Wiki
Advertisement

Script Structure example to create a Scenario T map (Based on Zombie Scenario)

NOTE: For the correct use of this Script, it is recommended that a Copy of Trail & Sewer Maps be created, these Scripts use a lot of calls from the Device control script block and the Function call script block

Codes used in each file to be imported by the destination map

common.lua[]

--[[Edit Game Options]] 
Common.UseWeaponInven(true) -- Use weapon inventory function
Common.SetSaveCurrentWeapons(true) -- Set to save currently equipped weapons
Common.SetSaveWeaponInven(true) -- Set to save weapon inventory content (UseWeaponInven must be set first)
Common.SetAutoLoad(true) -- Automatically load the saved information
Common.DisableWeaponParts(true) -- Weapon parts function disabled
Common.DisableWeaponEnhance(true) -- Disable weapon strengthening function
Common.DontGiveDefaultItems(true) -- Do not provide basic weapons at the start of the game
Common.DontCheckTeamKill(true) -- Even if you do a team kill, it will be treated as a normal kill.
Common.UseScenarioBuymenu(true) -- Make the store to use the scenario store window
Common.SetNeedMoney(true) -- So that you need money when buying a gun
Common.UseAdvancedMuzzle(true) -- When launching, draw muzzle in a new form (ignore scale)
Common.SetMuzzleScale(1.0) -- Fixed muzzle size on launch
Common.SetBloodScale(2) -- Fixed the effect size when hit
Common.SetGunsparkScale(10) -- Corrected the effect size when the bullet hit the wall
Common.SetHitboxScale(2.5) -- Modify hitbox size
Common.SetMouseoverOutline(true, {r = 255, g = 0, b = 0}) -- When you hover over an entity such as a monster, the outline is visible.
Common.SetUnitedPrimaryAmmoPrice(50) -- The price per Ammo for all Primary weapons is unified with this value.
Common.SetUnitedSecondaryAmmoPrice(0) -- The price per Ammo for all Secondary weapons is unified with this value.


--[[Common constant declaration]]


-- Used when comparing real values
EPSILON = 0.00001

-- Signal from UI to Game
SignalToGame = {
	openWeaponInven = 1,
}

-- Signal from Game to UI
SignalToUI = {
	reloadStarted = 1,
	reloadFinished = 2
}

-- Weapon rating to be used in the game
WeaponGrade = {
	normal = 1,
	rare = 2,
	unique = 3,
	legend = 4,
	END = 4
}

-- Shop weapon list
BuymenuWeaponList =	{
	Common.WEAPON.P228,
	Common.WEAPON.DualBeretta,
	Common.WEAPON.FiveSeven,
	Common.WEAPON.Glock18C,
	Common.WEAPON.USP45,
	Common.WEAPON.DesertEagle50C,
	Common.WEAPON.DualInfinity,
	Common.WEAPON.Galil,
	Common.WEAPON.FAMAS,
	Common.WEAPON.M4A1,
	Common.WEAPON.AK47,
	Common.WEAPON.OICW,
	Common.WEAPON.MAC10,
	Common.WEAPON.UMP45,
	Common.WEAPON.MP5,
	Common.WEAPON.TMP,
	Common.WEAPON.P90,
	Common.WEAPON.MP7A1ExtendedMag,
	Common.WEAPON.Needler,
	Common.WEAPON.M3,
	Common.WEAPON.XM1014,
	Common.WEAPON.DoubleBarrelShotgun,
	Common.WEAPON.WinchesterM1887,
	Common.WEAPON.USAS12,
	Common.WEAPON.FireVulcan,
	Common.WEAPON.M249,
	Common.WEAPON.MG3,
	Common.WEAPON.M134Minigun,
	Common.WEAPON.K3,
	Common.WEAPON.QBB95,
	Common.WEAPON.M32MGL,
	Common.WEAPON.Leviathan,
	Common.WEAPON.Salamander,
	Common.WEAPON.RPG7
}

-- Store weapon list settings (UseScenarioBuymenu must be set)
Common.SetBuymenuWeaponList(BuymenuWeaponList)

-- List of all weapons to be used in the game
WeaponList = {
	-- Secondary Weapon List
	Common.WEAPON.P228,
	Common.WEAPON.DualBeretta,
	Common.WEAPON.FiveSeven,
	Common.WEAPON.Glock18C,
	Common.WEAPON.USP45,
	Common.WEAPON.DesertEagle50C,
	Common.WEAPON.DualInfinity,
	Common.WEAPON.DualInfinityCustom,
	Common.WEAPON.DualInfinityFinal,
	Common.WEAPON.SawedOffM79,
	Common.WEAPON.Cyclone,
	Common.WEAPON.AttackM950,
	Common.WEAPON.DesertEagle50CGold,
	Common.WEAPON.ThunderGhostWalker,
	Common.WEAPON.PythonDesperado,
	Common.WEAPON.DesertEagleCrimsonHunter,
	Common.WEAPON.DualBerettaGunslinger,
	-- Rifle list
	Common.WEAPON.Galil,
	Common.WEAPON.FAMAS,
	Common.WEAPON.M4A1,
	Common.WEAPON.SG552,
	Common.WEAPON.AK47,
	Common.WEAPON.AUG,
	Common.WEAPON.AN94,
	Common.WEAPON.M16A4,
	Common.WEAPON.AK47Custom,
	Common.WEAPON.HK416,
	Common.WEAPON.AK74U,
	Common.WEAPON.AKM,
	Common.WEAPON.L85A2,
	Common.WEAPON.FNFNC,
	Common.WEAPON.TAR21,
	Common.WEAPON.SCAR,
	Common.WEAPON.SKULL4,
	Common.WEAPON.OICW,
	Common.WEAPON.PlasmaGun,
	Common.WEAPON.StunRifle,
	Common.WEAPON.StarChaserAR,
	Common.WEAPON.CompoundBow,
	Common.WEAPON.LightningAR2,
	Common.WEAPON.Ethereal,
	Common.WEAPON.LightningAR1,
	Common.WEAPON.F2000,
	Common.WEAPON.Crossbow,
	Common.WEAPON.CrossbowAdvance,
	Common.WEAPON.M4A1DarkKnight,
	Common.WEAPON.AK47Paladin,
	-- Submachine Gun List
	Common.WEAPON.MAC10,
	Common.WEAPON.UMP45,
	Common.WEAPON.MP5,
	Common.WEAPON.TMP,
	Common.WEAPON.P90,
	Common.WEAPON.MP7A1ExtendedMag,
	Common.WEAPON.DualKriss,
	Common.WEAPON.KrissSuperV,
	Common.WEAPON.DualMP7A1,
	Common.WEAPON.Tempest,
	Common.WEAPON.TMPDragon,
	Common.WEAPON.P90Lapin,
	Common.WEAPON.DualUZI,
	Common.WEAPON.Needler,
	Common.WEAPON.InfinityLaserFist,
	-- Shotgun list
	Common.WEAPON.M3,
	Common.WEAPON.XM1014,
	Common.WEAPON.DoubleBarrelShotgun,
	Common.WEAPON.WinchesterM1887,
	Common.WEAPON.USAS12,
	Common.WEAPON.JackHammer,
	Common.WEAPON.TripleBarrelShotgun,
	Common.WEAPON.SPAS12Maverick,
	Common.WEAPON.FireVulcan,
	Common.WEAPON.BALROGXI,
	Common.WEAPON.BOUNCER,
	Common.WEAPON.FlameJackhammer,
	Common.WEAPON.RailCannon,
	Common.WEAPON.LightningSG1,
	Common.WEAPON.USAS12CAMO,
	Common.WEAPON.WinchesterM1887Gold,
	Common.WEAPON.UTS15PinkGold,
	Common.WEAPON.Volcano,
	-- Machine gun list
	Common.WEAPON.M249,
	Common.WEAPON.MG3,
	Common.WEAPON.M134Minigun,
	Common.WEAPON.MG36,
	Common.WEAPON.MK48,
	Common.WEAPON.K3,
	Common.WEAPON.QBB95,
	Common.WEAPON.QBB95AdditionalMag,
	Common.WEAPON.BALROGVII,
	Common.WEAPON.MG3CSOGSEdition,
	Common.WEAPON.CHARGER7,
	Common.WEAPON.ShiningHeartRod,
	Common.WEAPON.Coilgun,
	Common.WEAPON.Aeolis,
	Common.WEAPON.BroadDivine,
	Common.WEAPON.LaserMinigun,
	Common.WEAPON.M249Phoenix,
	-- Equipment Weapon List
	Common.WEAPON.M32MGL,
	Common.WEAPON.PetrolBoomer,
	Common.WEAPON.Slasher,
	Common.WEAPON.Eruptor,
	Common.WEAPON.Leviathan,
	Common.WEAPON.Salamander,
	Common.WEAPON.RPG7,
	Common.WEAPON.M32MGLVenom,
	Common.WEAPON.Stinger,
	Common.WEAPON.MagnumDrill,
	Common.WEAPON.GaeBolg,
	Common.WEAPON.Ripper,
	Common.WEAPON.BlackDragonCannon,
	Common.WEAPON.Guillotine
}


--[[ Modify properties by weapon type ]]


-- Secondary Weapon Properties
option = Common.GetWeaponOption(Common.WEAPON.P228)
option.price = 100 -- Weapon purchase price
option.damage = 1.0 -- When set with the Weapon class, both are multiplied
option.penetration = 1.0 -- Penetration
option.rangemod = 1.0 -- Damage attenuation rate according to distance
option.cycletime = 1.0 -- Rate of Fire
option.reloadtime = 1.0 -- Reload speed
option.accuracy = 1.0 -- Accuracy
option.spread = 1.0 -- Degree of inaccuracy in performing an action
option:SetBulletColor({r = 255, g = 255, b = 50}); -- When the gun is fired, the firing path of the specified color is displayed.
option.user.grade = WeaponGrade.normal  -- Pre-defined minimum grades for each weapon type
option.user.level = 1 -- Level limit when purchasing weapons

-- Weapon attribute detailed settings Weapon id, price, rank, available level, R, G, B
function SetOption(weaponid, price, grade, level, red, green, blue)
	option = Common.GetWeaponOption(weaponid)
	option.price = price
	option.user.grade = grade
	option.user.level = level

	if red ~= nil then
		option:SetBulletColor({r = red, g = green, b = blue});
	end
end

SetOption(Common.WEAPON.DualBeretta,		100, WeaponGrade.normal, 3, 255, 255, 50)
SetOption(Common.WEAPON.FiveSeven,			100, WeaponGrade.normal, 1, 255, 255, 50)
SetOption(Common.WEAPON.Glock18C,			100, WeaponGrade.normal, 1, 255, 255, 50)
SetOption(Common.WEAPON.USP45,				100, WeaponGrade.normal, 1, 255, 255, 50)
SetOption(Common.WEAPON.DesertEagle50C,		500, WeaponGrade.normal, 5, 255, 255, 50)
SetOption(Common.WEAPON.DualInfinity,		500, WeaponGrade.normal, 3, 255, 255, 50)
SetOption(Common.WEAPON.DualInfinityCustom,	800, WeaponGrade.normal, 4, 255, 255, 50)
SetOption(Common.WEAPON.DualInfinityFinal,	1500, WeaponGrade.normal, 7, 255, 255, 50)
SetOption(Common.WEAPON.SawedOffM79,		1000, WeaponGrade.normal, 5)
SetOption(Common.WEAPON.Cyclone,			2000, WeaponGrade.unique, 8)
SetOption(Common.WEAPON.AttackM950,			700, WeaponGrade.unique, 5, 255, 255, 50)
SetOption(Common.WEAPON.DesertEagle50CGold,	700, WeaponGrade.unique, 5, 255, 255, 50)
SetOption(Common.WEAPON.ThunderGhostWalker,			5000, WeaponGrade.legend, 7)
SetOption(Common.WEAPON.PythonDesperado,			8000, WeaponGrade.legend, 15, 255, 255, 50)
SetOption(Common.WEAPON.DesertEagleCrimsonHunter,	7000, WeaponGrade.legend, 12, 255, 255, 50)
SetOption(Common.WEAPON.DualBerettaGunslinger,		20000, WeaponGrade.legend, 30, 255, 255, 50)

-- Rifle properties
SetOption(Common.WEAPON.Galil,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.FAMAS,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.M4A1,		700, WeaponGrade.normal, 5, 255, 128, 0)
SetOption(Common.WEAPON.SG552,		700, WeaponGrade.normal, 5, 255, 128, 0)
SetOption(Common.WEAPON.AK47,		700, WeaponGrade.normal, 5, 255, 128, 0)
SetOption(Common.WEAPON.AUG,		700, WeaponGrade.normal, 5, 255, 128, 0)
SetOption(Common.WEAPON.AN94,		500, WeaponGrade.normal, 1, 255, 128, 0)
SetOption(Common.WEAPON.M16A4,		500, WeaponGrade.normal, 1, 255, 128, 0)
SetOption(Common.WEAPON.AK47Custom,	15000, WeaponGrade.normal, 20, 255, 128, 0)
SetOption(Common.WEAPON.HK416,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.AK74U,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.AKM,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.L85A2,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.FNFNC,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.TAR21,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.SCAR,		500, WeaponGrade.normal, 2, 255, 128, 0)
SetOption(Common.WEAPON.SKULL4,				5000, WeaponGrade.rare, 10, 255, 128, 0)
SetOption(Common.WEAPON.OICW,				1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.PlasmaGun,			1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.StunRifle,			7000, WeaponGrade.unique, 15, 255, 128, 0)
SetOption(Common.WEAPON.StarChaserAR,		8000, WeaponGrade.unique, 20, 255, 128, 0)
SetOption(Common.WEAPON.CompoundBow,		1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.LightningAR2,		1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.Ethereal,			1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.LightningAR1,		1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.F2000,				1000, WeaponGrade.unique, 5, 255, 128, 0)
SetOption(Common.WEAPON.Crossbow,			1000, WeaponGrade.legend, 8, 255, 128, 0)
SetOption(Common.WEAPON.CrossbowAdvance,	2600, WeaponGrade.legend, 8, 255, 128, 0)
SetOption(Common.WEAPON.M4A1DarkKnight,		20000, WeaponGrade.legend, 25, 255, 128, 0)
SetOption(Common.WEAPON.AK47Paladin,		20000, WeaponGrade.legend, 25, 255, 128, 0)

-- Submachine gun properties
SetOption(Common.WEAPON.MAC10,					300, WeaponGrade.normal, 2, 128, 255, 255)
SetOption(Common.WEAPON.UMP45,					300, WeaponGrade.normal, 2, 128, 255, 255)
SetOption(Common.WEAPON.MP5,					300, WeaponGrade.normal, 3, 128, 255, 255)
SetOption(Common.WEAPON.TMP,					300, WeaponGrade.normal, 1, 128, 255, 255)
SetOption(Common.WEAPON.P90,					300, WeaponGrade.normal, 1, 128, 255, 255)
SetOption(Common.WEAPON.MP7A1ExtendedMag,		2000, WeaponGrade.normal, 10, 128, 255, 255)
SetOption(Common.WEAPON.DualKriss,				500, WeaponGrade.normal, 5, 128, 255, 255)
SetOption(Common.WEAPON.KrissSuperV,			300, WeaponGrade.normal, 3, 128, 255, 255)
SetOption(Common.WEAPON.DualMP7A1,				500, WeaponGrade.normal, 5, 128, 255, 255)
SetOption(Common.WEAPON.Tempest,				1000, WeaponGrade.unique, 6, 128, 255, 255)
SetOption(Common.WEAPON.TMPDragon,				800, WeaponGrade.unique, 3, 128, 255, 255)
SetOption(Common.WEAPON.P90Lapin,				800, WeaponGrade.unique, 3, 128, 255, 255)
SetOption(Common.WEAPON.DualUZI,				1200, WeaponGrade.unique, 4, 128, 255, 255)
SetOption(Common.WEAPON.Needler,				1000, WeaponGrade.unique, 3, 128, 255, 255)
SetOption(Common.WEAPON.InfinityLaserFist,		20000, WeaponGrade.legend, 25)

-- Shotgun properties
SetOption(Common.WEAPON.M3,						300, WeaponGrade.normal, 3, 50, 255, 50)
SetOption(Common.WEAPON.XM1014,					500, WeaponGrade.normal, 4, 50, 255, 50)
SetOption(Common.WEAPON.DoubleBarrelShotgun,	200, WeaponGrade.normal, 1, 50, 255, 50)
SetOption(Common.WEAPON.WinchesterM1887,		500, WeaponGrade.normal, 4, 50, 255, 50)
SetOption(Common.WEAPON.USAS12,					700, WeaponGrade.normal, 5, 50, 255, 50)
SetOption(Common.WEAPON.JackHammer,				500, WeaponGrade.normal, 3, 50, 255, 50)
SetOption(Common.WEAPON.TripleBarrelShotgun,	600, WeaponGrade.normal, 4, 50, 255, 50)
SetOption(Common.WEAPON.SPAS12Maverick,			1200, WeaponGrade.rare, 7, 50, 255, 50)
SetOption(Common.WEAPON.FireVulcan,				3000, WeaponGrade.rare, 5, 50, 255, 50)
SetOption(Common.WEAPON.BALROGXI,				10000, WeaponGrade.rare, 12, 50, 255, 50)
SetOption(Common.WEAPON.BOUNCER,				20000, WeaponGrade.unique, 14)
SetOption(Common.WEAPON.FlameJackhammer,		3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.RailCannon,				3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.LightningSG1,			3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.USAS12CAMO,				3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.WinchesterM1887Gold,	3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.UTS15PinkGold,			3000, WeaponGrade.unique, 5, 50, 255, 50)
SetOption(Common.WEAPON.Volcano,				15000, WeaponGrade.legend, 14, 50, 255, 50)


-- Machine gun properties
SetOption(Common.WEAPON.M249,			600, WeaponGrade.normal, 3, 255, 50, 255)
SetOption(Common.WEAPON.MG3,			1500, WeaponGrade.normal, 7, 255, 50, 255)
SetOption(Common.WEAPON.M134Minigun,	1000, WeaponGrade.normal, 3, 255, 50, 255)
SetOption(Common.WEAPON.MG36,			1000, WeaponGrade.normal, 5, 255, 50, 255)
SetOption(Common.WEAPON.MK48,			1000, WeaponGrade.normal, 5, 255, 50, 255)
SetOption(Common.WEAPON.K3,				600, WeaponGrade.normal, 5, 255, 50, 255)
SetOption(Common.WEAPON.QBB95,			800, WeaponGrade.normal, 7, 255, 50, 255)
SetOption(Common.WEAPON.QBB95AdditionalMag,		1000, WeaponGrade.normal, 7, 255, 50, 255)
SetOption(Common.WEAPON.BALROGVII,				2500, WeaponGrade.rare, 7, 255, 50, 255)
SetOption(Common.WEAPON.MG3CSOGSEdition,		2500, WeaponGrade.rare, 7, 255, 50, 255)
SetOption(Common.WEAPON.CHARGER7,				5000, WeaponGrade.rare, 7, 255, 50, 255)
SetOption(Common.WEAPON.ShiningHeartRod,		8000, WeaponGrade.unique, 12, 255, 50, 255)
SetOption(Common.WEAPON.Coilgun,				5000, WeaponGrade.unique, 7, 255, 50, 255)
SetOption(Common.WEAPON.Aeolis,					5000, WeaponGrade.unique, 7, 255, 50, 255)
SetOption(Common.WEAPON.BroadDivine,			7000, WeaponGrade.unique, 10, 255, 50, 255)
SetOption(Common.WEAPON.LaserMinigun,			7000, WeaponGrade.unique, 10)
SetOption(Common.WEAPON.M249Phoenix,			30000, WeaponGrade.legend, 25, 255, 50, 255)


-- Equipment Weapon Properties
SetOption(Common.WEAPON.M32MGL,			3000, WeaponGrade.normal, 5)
SetOption(Common.WEAPON.PetrolBoomer,	3000, WeaponGrade.normal, 5)
SetOption(Common.WEAPON.Slasher,		3000, WeaponGrade.normal, 5)
SetOption(Common.WEAPON.Eruptor,		300, WeaponGrade.normal, 1)
SetOption(Common.WEAPON.Leviathan,		2000, WeaponGrade.normal, 7)
SetOption(Common.WEAPON.Salamander,		2000, WeaponGrade.normal, 7)
SetOption(Common.WEAPON.RPG7,			1200, WeaponGrade.normal, 3)
SetOption(Common.WEAPON.M32MGLVenom,	5000, WeaponGrade.unique, 15)
SetOption(Common.WEAPON.Stinger,		3000, WeaponGrade.unique, 3)
SetOption(Common.WEAPON.MagnumDrill,	20000, WeaponGrade.legend, 25, 50, 50, 255)
SetOption(Common.WEAPON.GaeBolg,		10000, WeaponGrade.legend, 15)
SetOption(Common.WEAPON.Ripper,			15000, WeaponGrade.legend, 20)
SetOption(Common.WEAPON.BlackDragonCannon,		10000, WeaponGrade.legend, 7)
SetOption(Common.WEAPON.Guillotine,		10000, WeaponGrade.legend, 10)

game.lua[]

--[[ Define constants and variables required in game ]]
players = {}
difficultySelectPlayer = 0 -- Selected difficulty level or selected player index

-- Reference level to use for setting weapon and monster stats
monsterLevel = 1 -- Monster level
LEVEL_MIN = 1 -- Player minimum level
LEVEL_MAX = 99 -- Player maximum level
WEAPONLEVEL_MAX = 60 -- Weapon Max Level
mapDifficulty = SignalToGame.difficulty0 -- Current map difficulty

-- We multiply and use the various abilities of weapons and monsters according to the level below.
LevelRatio = {
	1.000,
	1.050,
	1.103,
	1.158,
	1.216,
	1.276,
	1.340,
	1.407,
	1.477,
	1.551,
	1.629,
	1.710,
	1.796,
	1.886,
	1.980,
	2.079,
	2.183,
	2.292,
	2.407,
	2.527,
	2.653,
	2.786,
	2.925,
	3.072,
	3.225,
	3.386,
	3.556,
	3.733,
	3.920,
	4.116,
	4.322,
	4.538,
	4.765,
	5.003,
	5.253,
	5.516,
	5.792,
	6.081,
	6.385,
	6.705,
	7.040,
	7.392,
	7.762,
	8.150,
	8.557,
	8.985,
	9.434,
	9.906,
	10.401,
	10.921,
	11.467,
	12.041,
	12.643,
	13.275,
	13.939,
	14.636,
	15.367,
	16.136,
	16.943,
	17.790,
	18.679,
	19.613,
	20.594,
	21.623,
	22.705,
	23.840,
	25.032,
	26.283,
	27.598,
	28.978,
	30.426,
	31.948,
	33.545,
	35.222,
	36.984,
	38.833,
	40.774,
	42.813,
	44.954,
	47.201,
	49.561,
	52.040,
	54.641,
	57.374,
	60.242,
	63.254,
	66.417,
	69.738,
	73.225,
	76.886,
	80.730,
	84.767,
	89.005,
	93.455,
	98.128,
	103.035,
	108.186,
	113.596,
	119.276,
}

-- Weapon Rating Chance
WeaponGradeProb = {
	1.0,
	0.2,
	0.05,
	0.005
}

-- Basic damage by weapon class
WeaponGradeDamage = {
	1.0,
	1.25,
	1.5,
	2.0
}

-- Weapon random damage (at 0.15, randomly generated between 0.85 and 1.15)
WeaponRandomDamage = 0.15

-- Damage by weapon level
WeaponLevelDamage = 1.0

-- Save monster types to be used in the game
MonsterTypes = {
	Game.MONSTERTYPE.NORMAL0,
	Game.MONSTERTYPE.NORMAL1,
	Game.MONSTERTYPE.NORMAL2,
	Game.MONSTERTYPE.NORMAL3,
	Game.MONSTERTYPE.NORMAL4,
	Game.MONSTERTYPE.NORMAL5,
	Game.MONSTERTYPE.NORMAL6,
	Game.MONSTERTYPE.RUNNER0,
	Game.MONSTERTYPE.RUNNER1,
	Game.MONSTERTYPE.RUNNER2,
	Game.MONSTERTYPE.RUNNER3,
	Game.MONSTERTYPE.RUNNER4,
	Game.MONSTERTYPE.RUNNER5,
	Game.MONSTERTYPE.RUNNER6,
	Game.MONSTERTYPE.HEAVY1,
	Game.MONSTERTYPE.HEAVY2,
	Game.MONSTERTYPE.A101AR,
	Game.MONSTERTYPE.A104RL,
}

-- Define the monster rating to be used in the game
MonsterGrade = {
	normal = 1,
	rare = 2,
	unique = 3,
	legend = 4,
	END = 4
}

-- Table to count whether all monsters (groups) are dead
monsterGroupCnt = {}

-- Monster wave management table (similar to monster spawner)
monsterWaveCnt = {}
monsterWavePosition = {}

-- Whether to handle wave monsters or not
WaveFuncState = {
	enable = 1, -- All wave activated
	disable = 3, -- wave impossible
}
monsterWaveFuncState = WaveFuncState.enable

-- Monster rating probability
MonsterGradeProb = {
	1.0,
	0.3,
	0.1,
	0.01
}

-- Chance to drop weapons by monster level (max 1.0)
WeaponDropProb = {
	0.035,
	0.08,
	0.08,
	1
}

-- Setting values for each monster level
MonsterLevelVar = {
	normal =	{hpMin = 30, hpMax = 60, armorMin = 5, armorMax = 30, damageMin = 10, damageMax = 20, coinMin = 1, coinMax = 5},
	runner =	{hpMin = 20, hpMax = 50, armorMin = 0, armorMax = 20, damageMin = 10, damageMax = 30, coinMin = 3, coinMax = 8},
	heavy =		{hpMin = 150, hpMax = 250, armorMin = 20, armorMax = 55, damageMin = 20, damageMax = 40, coinMin = 10, coinMax = 15},
	a101ar =	{hpMin = 150, hpMax = 250, armorMin = 30, armorMax = 50, damageMin = 4, damageMax = 4, coinMin = 20, coinMax = 25},
	a104rl =	{hpMin = 150, hpMax = 250, armorMin = 30, armorMax = 50, damageMin = 17, damageMax = 17, coinMin = 20, coinMax = 25},
	etc =		{hpMin = 20, hpMax = 50, armorMin = 0, armorMax = 20, damageMin = 10, damageMax = 35, coinMin = 3, coinMax = 8},
}

-- EXP based on monster health (exp == hp * MonsterExpMult)
MonsterExpMult = 0.6

-- Set the maximum level and required experience level for each level
PlayerRequireExp = {
	87,
	360,
	864,
	1584,
	2625,
	3996,
	5586,
	7680,
	10206,
	13200,
	17061,
	21168,
	25857,
	31752,
	38475,
	45312,
	53754,
	64152,
	74727,
	87600,
	100548,
	116160,
	133308,
	152064,
	174375,
	196716,
	223074,
	251664,
	285099,
	318600,
	357492,
	402432,
	447579,
	499392,
	554925,
	618192,
	685869,
	758100,
	839592,
	926400,
	1023729,
	1127196,
	1236981,
	1359072,
	1494450,
	1637784,
	1795917,
	1969920,
	2153697,
	2355000,
	2574990,
	2806752,
	3067428,
	3341736,
	3639075,
	3960768,
	4308174,
	4682688,
	5096184,
	5529600,
	5994531,
	6504048,
	7060851,
	7643136,
	8276775,
	8964648,
	9696240,
	10487232,
	11340702,
	12245100,
	13232625,
	14292288,
	15427455,
	16641564,
	17955000,
	19355376,
	20864151,
	22486464,
	24208839,
	26073600,
	28067958,
	30217656,
	32509191,
	34948368,
	37584450,
	40404348,
	43415784,
	46626624,
	50092404,
	53775900,
	57735132,
	61956480,
	66476214,
	71306520,
	76486875,
	82003968,
	87898878,
	94215240,
	100000000
}


--[[ Monster-related user-defined functions ]]

-- Set the monster's ability according to the level
function SetMonsterAttribute(monster, grade)

	if monster == nil then
		return
	end

	monster.user.level = monsterLevel
	monster.user.grade = grade

	monster.applyKnockback = true -- So that the monster receives a knockback
	monster.canJump = false -- So that the monster cannot jump
	monster.viewDistance = 12 -- Field of view to spot enemies

	local levelVar
	if Game.MONSTERTYPE.NORMAL0 <= monster.type and monster.type <= Game.MONSTERTYPE.NORMAL6 then
		levelVar = MonsterLevelVar.normal
	elseif Game.MONSTERTYPE.RUNNER0 <= monster.type and monster.type <= Game.MONSTERTYPE.RUNNER6 then
		levelVar = MonsterLevelVar.runner
	elseif Game.MONSTERTYPE.HEAVY1 <= monster.type and monster.type <= Game.MONSTERTYPE.HEAVY2 then
		levelVar = MonsterLevelVar.heavy
	elseif monster.type == Game.MONSTERTYPE.A101AR then
		levelVar = MonsterLevelVar.a101ar
	elseif monster.type == Game.MONSTERTYPE.A104RL then
		levelVar = MonsterLevelVar.a104rl
	else
		levelVar = MonsterLevelVar.etc
	end

	-- Damage is more gentle than other figures
	local damageMult = ((LevelRatio[monsterLevel] - 1.0) * 0.5) + 1.0
	monster.damage = math.floor(Game.RandomInt(levelVar.damageMin, levelVar.damageMax) * damageMult)

	monster.health = math.floor(Game.RandomInt(levelVar.hpMin, levelVar.hpMax) * LevelRatio[monsterLevel])
	monster.coin = math.floor(Game.RandomInt(levelVar.coinMin, levelVar.coinMax) * LevelRatio[monsterLevel])
	monster.user.exp = math.floor(monster.health * MonsterExpMult) -- Experience that players will gain when they catch this monster

	-- Set color and ability according to the determined grade
	if grade == MonsterGrade.rare then
		monster:SetRenderFX(Game.RENDERFX.GLOWSHELL)
		monster:SetRenderColor({r = 0, g = 30, b = 255})
		monster.health = math.floor(monster.health * 3.0)
		monster.damage = monster.damage * 1.5
		monster.speed = 1.5
		monster.user.exp = math.floor(monster.user.exp * 1.5)
	elseif grade == MonsterGrade.unique then
		monster:SetRenderFX(Game.RENDERFX.GLOWSHELL)
		monster:SetRenderColor({r = 255, g = 30, b = 30})
		monster.health = math.floor(monster.health * 5.0)
		monster.damage = monster.damage * 2.0
		monster.speed = 1.5
		monster.user.exp = math.floor(monster.user.exp * 3.0)
	elseif grade == MonsterGrade.legend then
		monster:SetRenderFX(Game.RENDERFX.GLOWSHELL)
		monster:SetRenderColor({r = 255, g = 255, b = 100})
		monster.health = math.floor(monster.health * 12.0)
		monster.damage = monster.damage * 2.0
		monster.speed = 2.5
		monster.user.exp = math.floor(monster.user.exp * 10.0)
	end
end

-- Create a monster flock at a specified location
function CreateMonsters(type, num, pos, groupid, grade)

	if grade == nil then
		grade = MonsterGrade.normal
	end

	result = {}

	-- Create monsters by num
	for i = 1, num do
		monster = Game.Monster.Create(type, pos)
		if monster then
			-- Set stats according to monster level
			SetMonsterAttribute(monster, grade)

			-- Store the group number to which the monster belongs and increase the number by one
			monster.user.groupid = groupid
			if monsterGroupCnt[groupid] then
				monsterGroupCnt[groupid] = monsterGroupCnt[groupid] + 1
			else
				monsterGroupCnt[groupid] = 1;
			end

			-- Save result
			table.insert(result, monster)
		end
	end

	return result
end

-- Function called when all monsters die
function OnMonsterKilled(monster)
    if monster.user.waveFunc then
		if monsterWaveFuncState == WaveFuncState.enable then
			monster.user.waveFunc(true, monster.user.waveFuncArg)
		else
			monster.user.waveFunc = nil
		end
    end

    -- The boss group is dead
    if monster.user.groupid == 8055 then
        monsterWaveFuncState = WaveFuncState.disable
        difficultySelectPlayer = 0
        Game.KillAllMonsters() -- Kill all monsters after the next OnUpdate
    end

    Game.SetTrigger('OnMonsterKilled' ..  monster.user.groupid, true)
end


--[[ Weapon-related user-defined functions ]]


-- Set minimum basic stats for all weapons
function SetWeaponAttributeDefault(weapon)
	if weapon == nil then
		return
	end

	-- Secondary Weapons
	if weapon:GetWeaponType() == Game.WEAPONTYPE.PISTOL then
		weapon.infiniteclip = true
	else
		weapon:AddClip1(3) -- 3 basic ammo
	end

	-- Basic level
	if weapon.user.level == nil then
		weapon.user.level = Common.GetWeaponOption(weapon.weaponid).user.level
	end

	-- Basic grade
	weapon.user.grade = WeaponGrade.normal
	weapon.color = Game.WEAPONCOLOR.WHITE
end

-- Weapon stats set according to level
function SetWeaponAttribute(weapon, level)

	if weapon == nil then
		return
	end

	-- Basic stat settings
	SetWeaponAttributeDefault(weapon)

	-- Level setting
	weapon.user.level = level

	-- Get WeaponOption and grade of current weapon
	local option = Common.GetWeaponOption(weapon.weaponid)
	local grade = option.user.grade

	-- Determine the probability of appearance by grade
	local weightMax = 0.0
	for i = grade, WeaponGrade.END do
		weightMax = weightMax + WeaponGradeProb[i]
	end

	local weight = Game.RandomFloat(0.0, weightMax)

	local weightSum = 0.0
	for i = grade, WeaponGrade.END do
		weightSum = weightSum + WeaponGradeProb[i]
		if weight <= weightSum  then
			grade = i
			break
		end
	end

	-- Level, level, random damage calculation
	weapon.damage = WeaponLevelDamage * LevelRatio[level]
	weapon.damage = weapon.damage * (WeaponGradeDamage[grade] + Game.RandomFloat(-WeaponRandomDamage, WeaponRandomDamage))

	-- Maximum number of random stats
	local maxAttrNum = 0

	-- Set the number of colors and abilities according to the determined grade
	if grade == WeaponGrade.normal then
		weapon.color = Game.WEAPONCOLOR.WHITE
		maxAttrNum = 0
	elseif grade == WeaponGrade.rare then
		weapon.color = Game.WEAPONCOLOR.BLUE
		maxAttrNum = 1
	elseif grade == WeaponGrade.unique then
		weapon.color = Game.WEAPONCOLOR.RED
		maxAttrNum = 2
	elseif grade == WeaponGrade.legend then
		weapon.color = Game.WEAPONCOLOR.ORANGE
		maxAttrNum = 3
	end

	-- To avoid duplicate stats
	local attrDuplicateCheck = {}
	if weapon:GetWeaponType() == Game.WEAPONTYPE.PISTOL then
		attrDuplicateCheck[5] = true
	end

	-- Determination of stats
	local attrNum = Game.RandomInt(0, maxAttrNum)
	for i = 1, attrNum do
		local attrType = Game.RandomInt(1, 5) -- 5 types from speed to infiniteclip
		if attrDuplicateCheck[attrType] then
			-- If the stats overlap,
			i = i - 1
		else
			attrDuplicateCheck[attrType] = true

			if attrType == 1 then
				weapon.speed = Game.RandomFloat(1.2, 1.3)
			elseif attrType == 2 then
				weapon.knockback = Game.RandomFloat(1.2, 2.0)
				weapon.flinch = Game.RandomFloat(1.2, 2.0)
			elseif attrType == 3 then
				weapon.criticalrate = Game.RandomFloat(0.03, 0.2)
				weapon.criticaldamage = Game.RandomFloat(1.5, 2.5)
			elseif attrType == 4 then
				weapon.bloodsucking = Game.RandomFloat(0.01, 0.03)
			elseif attrType == 5 then
				weapon.infiniteclip = true
			end
		end
	end
end

-- Random weapon level determination (use monster level)
function GetWeaponRandomLevel(level)

	local minLevel = level - 5
	local maxLevel = level + 3

	if minLevel < LEVEL_MIN then
		minLevel = LEVEL_MIN
	end
	if maxLevel > WEAPONLEVEL_MAX then
		maxLevel = WEAPONLEVEL_MAX
	end

	return Game.RandomInt(minLevel, maxLevel)
end

-- Random weapon creation (level, location use)
function CreateWeapon(level, pos)

	-- Random weapon type (use weapon level)
	local weightMax = 0.0
	local list = {}
	for i = 1, #WeaponList do
		local weaponOption = Common.GetWeaponOption(WeaponList[i])
		if weaponOption.user.level <= level then
			table.insert(list, weaponOption)
			weightMax = weightMax + (LevelRatio[weaponOption.user.level] * WeaponGradeProb[weaponOption.user.grade])
		end
	end

	local type = 0
	local weightSum = 0.0
	local weight = Game.RandomFloat(0.0, weightMax)
	for i = 1, #list do
		weightSum = weightSum + (LevelRatio[list[i].user.level] * WeaponGradeProb[list[i].user.grade])
		if weight <= weightSum  then
			type = list[i].weaponid
			break
		end
	end

	if type == 0 then
		return nil
	end

	local weapon = Game.Weapon.CreateAndDrop(type, pos)
	if weapon then
		SetWeaponAttribute(weapon, level)
	end

	return weapon
end


--[[ User-level user-defined functions ]]


-- When the player levels up
function OnLevelUp(player)

	-- Increased stamina
	player.maxhealth = math.floor(100 * LevelRatio[player.user.level])
	player.health = player.maxhealth

	-- In normal difficulty, the monster level changes depending on the player level.
	if mapDifficulty == SignalToGame.difficulty0 then
		if player.user.level > monsterLevel then
			monsterLevel = player.user.level
			if monsterLevel > 30 then
				monsterLevel = 30
			end
		end
	end

	-- Compare WeaponOption and level to show the UI lock display (store window)
	for i = 1, #BuymenuWeaponList do
		local option = Common.GetWeaponOption(BuymenuWeaponList[i])
		if option then
			player:SetBuymenuLockedUI(BuymenuWeaponList[i], option.user.level > player.user.level, option.user.level)
		end
	end

	-- Weapon and level are compared to show the UI lock indication (weapon inventory)
	local invenWeapons = player:GetWeaponInvenList()
	for i = 1, #invenWeapons do
		player:SetWeaponInvenLockedUI(invenWeapons[i], invenWeapons[i].user.level > player.user.level, invenWeapons[i].user.level)
	end
end

-- Calculate the percentage of experience based on the player's current level and experience
function CalcExpRate(level, exp)
	return exp / PlayerRequireExp[level]
end

-- Players receive experience
function AddExp(player, exp)

	local pu = player.user

	-- Skip if it is full
	if pu.level >= LEVEL_MAX then
		return
	end

	pu.exp = pu.exp + exp

	 -- Level up
	if pu.exp > PlayerRequireExp[pu.level] then
		pu.level = pu.level + 1

		if pu.level >= LEVEL_MAX then
			pu.exp = 0
		else
			pu.exp = pu.exp - PlayerRequireExp[pu.level - 1]
		end

		OnLevelUp(player)
	end

	-- Show/Epdate level/Experience UI
	pu.expRate = CalcExpRate(pu.level, pu.exp)
	player:SetLevelUI(pu.level, pu.expRate)
end


--[[ Studio call functions (weapon, monster related) ]]


-- String separation function
function splitstr_tonumber(inputstr)
	local t = {}
	for str in string.gmatch(inputstr, "([^,]*)") do
		table.insert(t, tonumber(str))
	end
	return t
end

-- Specify AttackTo place by monster group
MonsterAttackPos = {

	-- CreateDefaultMonsters
	[1] = {x = -12, y = 100, z = 1},
	[2] = {x = -9, y = 98, z = 1},
	[3] = {x = 14, y = 77, z = 1},
	[7] = {x = 80, y = 26, z = 1},
	[9] = {x = 81, y = 22, z = 1},
	[11] = {x = 81, y = 24, z = 1},
	[13] = {x = 36, y = -14, z = 1},
	[14] = {x = 35, y = -11, z = 1},
	[17] = {x = 34, y = -32, z = -3},
	[18] = {x = 35, y = -40, z = -3},
	[8055] = {x = 25, y = -31, z = -3},

	-- CreateWaveMonsters
	[1000] = {x = -4, y = 72, z = 1},

	-- CreateSpecialMonsters
	[10000] = {x = -12, y = 108, z = 1},
}

-- Monster Rating
function GetRandomGrade(min, max)
	if min == max then
		return min
	end

	local grade = min

	local weightMax = 0.0
	for i = min, max do
		weightMax = weightMax + MonsterGradeProb[i]
	end

	local weight = Game.RandomFloat(0.0, weightMax)

	local weightSum = 0.0
	for i = min, max do
		weightSum = weightSum + MonsterGradeProb[i]
		if weight <= weightSum  then
			return i
		end
	end

	return min
end

function CreateDefaultMonsters(callerOn, arg)

	if callerOn == nil or callerOn == false then
		return
	end

	local args = splitstr_tonumber(arg) -- Divides arg string and stores it in a numeric array
	local type = MonsterTypes[args[1]] -- Monster type
	local num = args[2] -- Number of monsters to summon
	local groupid = args[3] -- Monster group id
	local grade = GetRandomGrade(args[4], args[5]) -- Monster rating

	-- Game.GetScriptCaller() : Get the script function call VoxelEntity that called this function
	local monsters = CreateMonsters(type, num, Game.GetScriptCaller().position, groupid, grade)

	-- Monster groups requiring AttackTo positioning
	for i = 1, #monsters do
		if MonsterAttackPos[groupid] then
			monsters[i]:AttackTo(MonsterAttackPos[groupid]) -- Attack while moving to the specified coordinates
		end
	end
end

-- Monster Wave Generation Functions
function CreateWaveMonsters(callerOn, arg)
	if callerOn == nil or callerOn == false then
		return
	end

	local args = splitstr_tonumber(arg)
	local type = MonsterTypes[args[1]]
	local num = args[2]
	local groupid = args[3]
	local grade = GetRandomGrade(args[4], args[5])
	local waveCnt = args[6] -- Wave generation count

	if monsterWaveCnt[groupid] then
		monsterWaveCnt[groupid] = monsterWaveCnt[groupid] + 1
		if monsterWaveCnt[groupid] > waveCnt then
			if monsterWaveCnt[groupid] == waveCnt + 1 then
				Game.SetTrigger('OnWaveEnded' ..  groupid, true)
			end

			return
		end
	else
		monsterWaveCnt[groupid] = 1
	end

	if Game.GetScriptCaller() then
		monsterWavePosition[groupid] = Game.GetScriptCaller().position
	end

	local monsters = CreateMonsters(type, num, monsterWavePosition[groupid], groupid, grade)
	for i = 1, #monsters do
		monsters[i].user.waveFunc = CreateWaveMonsters
		monsters[i].user.waveFuncArg = arg

		if MonsterAttackPos[groupid] then
			monsters[i]:AttackTo(MonsterAttackPos[groupid]) -- Attack while moving to the specified coordinates
		end
	end
end

-- Specific item drop monster creation function
function CreateSpecialMonsters(callerOn, arg)
	if callerOn then

		local args = splitstr_tonumber(arg)
		local type = MonsterTypes[args[1]]
		local num = args[2]
		local groupid = args[3]
		local grade = GetRandomGrade(args[4], args[5])

		local monsters = CreateMonsters(type, num, Game.GetScriptCaller().position, groupid, grade)
		for i = 1, #monsters do
			monsters[i].user.specialWeaponDrop = groupid -- Drop specific items

			if MonsterAttackPos[groupid] then
				monsters[i]:AttackTo(MonsterAttackPos[groupid]) -- Attack while moving to the specified coordinates
			end
		end
	end
end

-- Specific item drop designation function
function CreateSpecialWeapon(specialWeaponDrop, position)

	if specialWeaponDrop == 10000 then
		local weapon = Game.Weapon.CreateAndDrop(Common.WEAPON.P90, position)
		SetWeaponAttributeDefault(weapon)
	elseif specialWeaponDrop == 10001 then
		local weapon = Game.Weapon.CreateAndDrop(Common.WEAPON.M134Minigun, position)
		SetWeaponAttributeDefault(weapon)
	end
end

-- Create basic weapons to place on the map
function CreateDefaultWeapon()
    local weapon = Game.Weapon.CreateAndDrop(Common.WEAPON.USP45, {x = -6, y = 150, z = 1})
	SetWeaponAttributeDefault(weapon)
end

-- Random weapon creation
function CreateRandomWeapon(callerOn, arg)
	if callerOn then
		CreateWeapon(tonumber(arg), Game.GetScriptCaller().position)
	end
end


--[[ Event functions ]]


-- Function called when the player first spawns after selecting a class
function Game.Rule:OnPlayerJoiningSpawn(player)

	-- Store in player array
	players[player.index] = player

	-- Change the camera to 3rd person and change the input method based on the mouse pointer.
	player:SetThirdPersonFixedView(-45, 53, 100, 250) -- yaw, pitch, minDist, maxDist

	-- Modify the method of calculating the mouse pointer's raycast position based on ThirdPersonFixedView.
	player:SetThirdPersonFixedPlane(Game.THIRDPERSON_FIXED_PLANE.GROUND)

	-- Basic level, experience
	player.user.level = 1
	player.user.exp = 0
	player.user.expRate = 0

	-- UI initialization by level
	OnLevelUp(player) -- Weapon lock ui reset use
	player:SetLevelUI(player.user.level, player.user.expRate) -- Level / Experience UI Settings

	-- Team Settings
	player.team = Game.TEAM.CT
end

-- Function called when an entity (monster, player, etc.) is damaged
function Game.Rule:OnTakeDamage(victim, attacker, damage, weapontype, hitbox)
	if attacker == nil or victim == nil then return end

	if victim:IsMonster() then
		victim = victim:ToMonster()
		victim:ShowOverheadDamage(damage, 0) -- Mark damage over your head. If the second argument (player index) is 0, it is shown to everyone.
	end
end

-- Function called when an entity dies
function Game.Rule:OnKilled(victim, killer)
	if victim == nil or killer == nil then
		return
	end

	-- When the player dies, resurrect it
	if victim:IsPlayer() then

		victim = victim:ToPlayer()

		-- 10% less experience if not normal difficulty
		if mapDifficulty ~= SignalToGame.difficulty0 then
			AddExp(victim, -math.floor(PlayerRequireExp[victim.user.level] / 10.0))
		end

		if victim.user.spawnable == true then
			victim:Respawn()
		end

		-- Hide the loader ui
		victim:Signal(SignalToUI.reloadFinished)
	end

	-- When a monster dies
	if victim:IsMonster() then

		victim = victim:ToMonster()

		-- Gives experience when the killer is a player
		if killer:IsPlayer() then
			killer = killer:ToPlayer()
			AddExp(killer, victim.user.exp)
		end

		-- Make a weapon assigned to a monster or drop a weapon by checking the probability of dropping a weapon according to the monster's grade
		if victim.user.specialWeaponDrop then
			CreateSpecialWeapon(victim.user.specialWeaponDrop, victim.position)
		else
			weight = Game.RandomFloat(0.0, 1.0)
			if weight <= WeaponDropProb[victim.user.grade] then
				CreateWeapon(GetWeaponRandomLevel(victim.user.level), victim.position)
			end
		end

		-- The number of monsters is checked, and when it reaches 0, it is transferred from OnMonsterKilled function to the studio.
		monsterGroupCnt[victim.user.groupid] = monsterGroupCnt[victim.user.groupid] - 1
		if monsterGroupCnt[victim.user.groupid] <= 0 then
			monsterGroupCnt[victim.user.groupid] = nil
			OnMonsterKilled(victim)
		end
	end
end

-- Function to check if a weapon can be purchased
-- Weapons not included in the script weapon list are not called
function Game.Rule:CanBuyWeapon(player, weaponid)
	local weaponOption = Common.GetWeaponOption(weaponid)
	return weaponOption.user.level <= player.user.level
end

-- Function to check if the weapon can be held
-- Weapons not included in the script weapon list are not called
-- If no Weapon class has been used, the weapon argument is passed as nil.
function Game.Rule:CanHaveWeaponInHand(player, weaponid, weapon)
	local weaponOptionCheck = Common.GetWeaponOption(weaponid).user.level <= player.user.level
	local weaponCheck = weapon == nil or weapon.user.level == nil or weapon.user.level <= player.user.level

	return weaponOptionCheck and weaponCheck
end

-- Function called when a weapon is acquired
-- Weapons not included in the script weapon list are not called
-- If no Weapon class has been used, the weapon argument is passed as nil.
function Game.Rule:OnGetWeapon(player, weaponid, weapon)
	if weapon == nil then
		return
	end

	-- Basic stat settings
	if weapon.user.level == nil then
		SetWeaponAttributeDefault(weapon)
	end

	-- Locked ui update
	player:SetWeaponInvenLockedUI(weapon, weapon.user.level > player.user.level, weapon.user.level)
end

-- Variable for loading time
reloadTimeSync = Game.SyncValue.Create("reloadTime")

-- Function called when loading
-- If the Weapon class has never been used or is not a script weapon, the weapon argument is passed as nil.
function Game.Rule:OnReload(player, weapon, time)
	-- Reload ui
	player:Signal(SignalToUI.reloadStarted)
	-- Loading time
	reloadTimeSync.value = time
end

-- Function called after loading
-- If the Weapon class has never been used or is not a script weapon, the weapon argument is passed as nil.
function Game.Rule:OnReloadFinished(player, weapon)
	player:Signal(SignalToUI.reloadFinished) -- 장전 ui를 숨긴다
end

-- Function called when the player replaces a weapon
function Game.Rule:OnSwitchWeapon(player)
	player:Signal(SignalToUI.reloadFinished) -- 장전 ui를 숨긴다
end

-- Function called after launch
-- If the Weapon class has never been used or is not a script weapon, the weapon argument is passed as nil.
function Game.Rule:PostFireWeapon(player, weapon, time)

	-- Shows ui only for weapons with a firing interval of 1 second or longer.
	if time > 1.0 then
		-- Reload ui
		player:Signal(SignalToUI.reloadStarted)
		-- Loading time
		reloadTimeSync.value = time
	end
end

-- Function called when the player takes out a weapon
function Game.Rule:OnDeployWeapon(player, weapon)
	player:Signal(SignalToUI.reloadFinished) -- 장전 ui를 숨긴다
end

-- Save information for each player
function Game.Rule:OnGameSave(player)
	if player == nil then
		return
	end

	-- Level, experience saved
	player:SetGameSave('level', player.user.level)
	player:SetGameSave('exp', player.user.exp)

	-- Save the current weapon level
	local primaryWeapon = player:GetPrimaryWeapon()
	local secondaryWeapon = player:GetSecondaryWeapon()

	if primaryWeapon then
		player:SetGameSave('wpn_lv_pri', primaryWeapon.user.level)
	else
		player:SetGameSave('wpn_lv_pri', 0)
	end

	if secondaryWeapon then
		player:SetGameSave('wpn_lv_sec', secondaryWeapon.user.level)
	else
		player:SetGameSave('wpn_lv_sec', 0)
	end

	-- Save inventory weapon levels
	local invenWeapons = player:GetWeaponInvenList()
	for i = 1, #invenWeapons do
		player:SetGameSave('wpn_lv_inven' .. i, invenWeapons[i].user.level)
	end
end

function DoubleToInt(number)
	return math.floor(math.abs(number + EPSILON))
end

-- Load save information for each player
function Game.Rule:OnLoadGameSave(player)
	if player == nil then
		return
	end

	-- Level, experience load
	player.user.level = DoubleToInt(player:GetGameSave('level'))
	player.user.exp = DoubleToInt(player:GetGameSave('exp'))

	if player.user.level == nil then
		player.user.level = 1
	end
	if player.user.exp == nil then
		player.user.exp = 0
	end

	player.user.expRate = CalcExpRate(player.user.level, player.user.exp)

	-- Loading the current weapon
	local primaryWeapon = player:GetPrimaryWeapon()
	local secondaryWeapon = player:GetSecondaryWeapon()

	if primaryWeapon then
		primaryWeapon.user.level = DoubleToInt(player:GetGameSave('wpn_lv_pri'))
	end

	if secondaryWeapon then
		secondaryWeapon.user.level = DoubleToInt(player:GetGameSave('wpn_lv_sec'))
	end

	-- Loading inventory weapon levels
	local invenWeapons = player:GetWeaponInvenList()
	for i = 1, #invenWeapons do
		invenWeapons[i].user.level = DoubleToInt(player:GetGameSave('wpn_lv_inven' .. i))
	end

	-- UI initialization by level
	OnLevelUp(player) -- Weapon lock ui reset use
	player:SetLevelUI(player.user.level, player.user.expRate) -- Level / Experience UI Settings
end

-- Initialize save information for each player
function Game.Rule:OnClearGameSave(player)
	player.user.level = 1
	player.user.exp = 0
	player.user.expRate = 0
	player:RemoveWeapon()
	player:ClearWeaponInven()

	-- UI initialization by level
	OnLevelUp(player) -- Weapon lock ui reset use
	player:SetLevelUI(player.user.level, player.user.expRate) -- Level / Experience UI Settings
end


--[[ Communication with UI ]]


function Game.Rule:OnPlayerSignal(player, signal)

	if signal == SignalToGame.openWeaponInven then
		player:ToggleWeaponInven()
	end
end

-- Open store (function for studio call)
function ShowBuymenu(callerOn)
	local triggerEnt = Game.GetTriggerEntity()
	if triggerEnt and triggerEnt:IsPlayer() then
		triggerEnt = triggerEnt:ToPlayer()
		triggerEnt:ShowBuymenu()
	end
end

ui.lua[]

screen = UI.ScreenSize()
center = {x = screen.width / 2, y = screen.height / 2}

--[[ Show inventory key ]]
weaponInvenKeyText = UI.Text.Create()
weaponInvenKeyText:Set({text = '인벤토리 : [B]', font='small', align='right', x = center.x + 80, y = screen.height - 25, width = 185, height = 30, r = 255, g = 200, b = 0, a = 100})

--[[ Loading ui ]]

reloadingInit = false
reloadingBG = UI.Box.Create()
reloadingGauge = UI.Box.Create()
reloadingText = UI.Text.Create()
reloadingBG:Hide()
reloadingGauge:Hide()
reloadingText:Hide()

reloadTime = 0 -- Time required for loading
reloadStartTime = 0 -- Reload start time

reloadTimeSync = UI.SyncValue.Create("reloadTime")
function reloadTimeSync:OnSync()
	reloadTime = self.value
end

function UI.Event:OnUpdate(time)
	if reloadingBG:IsVisible() and reloadTime > EPSILON then
		if reloadStartTime < EPSILON then
			reloadStartTime = time
		else
			-- Change the gauge width by calculating the time that has passed since the start of loading.
			local diff = time - reloadStartTime
			local ratio = diff / reloadTime
			if ratio > 1 then
				reloadingBG:Hide()
				reloadingGauge:Hide()
				reloadingText:Hide()
				reloadingGauge:Set({width = 0})
				reloadTime = 0
			else
				reloadingGauge:Set({width = 100 * ratio})
			end
		end
	end
end


--[[ Event functions ]]


-- Event function when key is pressed
function UI.Event:OnKeyDown(inputs)
	if inputs[UI.KEY.B] then
		UI.Signal(SignalToGame.openWeaponInven)
	end
end

-- Communication with game
function UI.Event:OnSignal(signal)
	if signal == SignalToUI.reloadStarted then

		-- Fill in the contents the first time you open
		if reloadingInit == false then
			reloadingInit = true
			reloadingBG:Set({x = center.x - 50, y = center.y - 20, width = 100, height = 27, r = 25, g = 25, b = 25, a = 220})
			reloadingGauge:Set({x = center.x - 50, y = center.y - 20, width = 100, height = 27, r = 100, g = 120, b = 150, a = 220})
			reloadingText:Set({text = '장전중', font='small', align='center', x = center.x - 50, y = center.y - 4, width = 100, height = 20, r = 255, g = 255, b = 255})
		end

		reloadingBG:Show()
		reloadingGauge:Show()
		reloadingText:Show()
		reloadingGauge:Set({width = 0})
		reloadStartTime = 0
		reloadTime = 0

	elseif signal == SignalToUI.reloadFinished then
		reloadingBG:Hide()
		reloadingGauge:Hide()
		reloadingText:Hide()
		reloadingGauge:Set({width = 0})
		reloadTime = 0
	end
end

Advertisement