diff --git a/INDEV/Battle Royale.lua b/INDEV/Battle Royale.lua index a152de0c..d34e6215 100644 --- a/INDEV/Battle Royale.lua +++ b/INDEV/Battle Royale.lua @@ -51,7 +51,8 @@ local BattleRoyale = { 'spoils' }, ['./Battle Royale/misc/'] = { - 'misc' + 'initialize', + 'misc', }, ['./Battle Royale/safe zone/'] = { 'hurt_player', @@ -131,17 +132,18 @@ function BattleRoyale:loadDependencies() :: next :: end end + + self:onStart() -- in case the plugin loads mid-game end api_version = '1.12.0.0' function OnScriptLoad() BattleRoyale:loadDependencies() - OnStart() end function OnStart() - BattleRoyale:onStart(true) + BattleRoyale:onStart() end function OnEnd() diff --git a/INDEV/Battle Royale/commands/restart.lua b/INDEV/Battle Royale/commands/restart.lua index 31bda6d1..3ad34efa 100644 --- a/INDEV/Battle Royale/commands/restart.lua +++ b/INDEV/Battle Royale/commands/restart.lua @@ -5,6 +5,7 @@ local Command = {} -- @param args (table of command strings) -- function Command:run(id, args) + local player = self.players[id] -- admin if not player:commandEnabled(self.enabled, self.name) then return @@ -12,9 +13,7 @@ function Command:run(id, args) return end - -- - -- code will go here - -- + self:reset() end return Command \ No newline at end of file diff --git a/INDEV/Battle Royale/countdown/pre_game.lua b/INDEV/Battle Royale/countdown/pre_game.lua index 5a8eca49..33775f32 100644 --- a/INDEV/Battle Royale/countdown/pre_game.lua +++ b/INDEV/Battle Royale/countdown/pre_game.lua @@ -34,7 +34,7 @@ function timer:preGameTimer() self.safe_zone.timer = self:new() self.safe_zone.timer:start() - self:spawnLoot(self.looting.objects, 'loot') + self:spawnLoot(self.looting.random, 'random') self:spawnLoot(self.looting.crates, 'crates') for _, v in pairs(self.players) do diff --git a/INDEV/Battle Royale/events/on_death.lua b/INDEV/Battle Royale/events/on_death.lua index e7ef3e3e..3c15d980 100644 --- a/INDEV/Battle Royale/events/on_death.lua +++ b/INDEV/Battle Royale/events/on_death.lua @@ -27,6 +27,10 @@ function event:onDeath(victim) victim = tonumber(victim) victim = self.players[victim] + if (not victim) then + return + end + victim.weapon_parts = nil -- weapons parts loot victim.stun = nil -- stun grenades victim.can_stun = nil -- stun grenades diff --git a/INDEV/Battle Royale/events/on_join.lua b/INDEV/Battle Royale/events/on_join.lua index 1bd3a31a..743e1dc1 100644 --- a/INDEV/Battle Royale/events/on_join.lua +++ b/INDEV/Battle Royale/events/on_join.lua @@ -1,20 +1,12 @@ local event = {} -function event:hide(player, dyn) - local x, y, z = self:getXYZ(dyn) - write_float(player + 0xF8, x - 1000) - write_float(player + 0xFC, y - 1000) - write_float(player + 0x100, z - 1000) -end - function event:newPlayer(o) setmetatable(o, self) self.__index = self - o.messages = { primary = '' } o.lives = self.max_lives - + o.messages = { primary = '' } o.speed = { current = self.default_running_speed } @@ -32,25 +24,6 @@ function event:onJoin(id) self:phaseCheck(false, id) end -function event:resetPlayer() - - local id = self.id - local player = self.players[id] - - player.lives = self.max_lives - player.speed.current = self.default_running_speed - player.speed.duration = 0 - player.speed.timer = self:new() - player.speed.timer:start() - - player.messages = { primary = '' } - - player.weapon_parts = nil - player.stun = nil - player.can_stun = nil - player.spectator = nil -end - register_callback(cb['EVENT_JOIN'], 'OnJoin') return event \ No newline at end of file diff --git a/INDEV/Battle Royale/events/on_object_spawn.lua b/INDEV/Battle Royale/events/on_object_spawn.lua index 2924b279..4bb7f72e 100644 --- a/INDEV/Battle Royale/events/on_object_spawn.lua +++ b/INDEV/Battle Royale/events/on_object_spawn.lua @@ -11,7 +11,9 @@ function event:onObjectSpawn(player, map_id, parent_id, object_id, sapp_spawning -- Prevent players from using special ammo in vehicles: player = self.players[player] - if player:inVehicle(dyn) then + if (not player) then + return + elseif player:inVehicle(dyn) then return end @@ -71,7 +73,7 @@ end function event:trackNuke() local nukes = self.nukes - if (nukes and #nukes == 0) then + if (not self.game or not self.game.started or (not nukes or nukes and #nukes == 0)) then return end diff --git a/INDEV/Battle Royale/events/on_start.lua b/INDEV/Battle Royale/events/on_start.lua index 84aa7126..77f7509d 100644 --- a/INDEV/Battle Royale/events/on_start.lua +++ b/INDEV/Battle Royale/events/on_start.lua @@ -1,135 +1,11 @@ local event = {} -local format = string.format - -local function loadMapSettings(self) - - local map = get_var(0, '$map') - local path = './Battle Royale/map settings/' - - -- Try stock maps first: - local success, data = xpcall(require, function() - end, path .. 'stock/' .. map) - - -- Try custom maps: - if (not success) then - success, data = xpcall(require, function() - end, path .. 'custom/' .. map) - end - - for k, v in pairs(data) do - self[k] = v - end -end - -function event:getClipSizesTable() - for _, v in pairs(self.looting.spoils) do - if (v.clip_sizes) then - return v.clip_sizes - end - end -end - -function event:getStunTags() - for _, v in pairs(self.looting.spoils) do - if (v.grenade_tags) then - return v.grenade_tags - end - end -end - -function event:getRandomWeaponTags() - local spoils = self.looting.spoils - for _, v in pairs(spoils) do - if (v.random_weapons) then - return v.random_weapons - end - end -end - -local function getTagData(self) - local jpt = self.tank_shell_jpt_tag - local tag_address = read_dword(0x40440000) - local tag_count = read_dword(0x4044000C) - for i = 0, tag_count - 1 do - local tag = tag_address + 0x20 * i - local tag_name = read_string(read_dword(tag + 0x10)) - local tag_class = read_dword(tag) - if (tag_class == 1785754657 and tag_name == jpt) then - return read_dword(tag + 0x14) - end - end - return nil -end function event:onStart() if (get_var(0, '$gt') ~= 'n/a') then - - loadMapSettings(self) - - self.loot = nil - self.loot_crates = nil - - -- pre game timer: - self.game = nil - - -- players table: - self.players = {} - - -- weapons table: - self.weapons = {} - - -- nuke: - self.nukes = {} - - -- Sets initial radius of the safe zone and the total game time: - self.total_time = self:setSafeZone() - - local h, m, s = self:secondsToTime(self.total_time) - timer(33, 'pluginLogo', h, m, s, self.end_after) - - self.stuns = self:tagsToID(self:getStunTags(), 'jpt!') - self.clip_sizes = self:tagsToID(self:getClipSizesTable(), 'weap') - self.random_weapons = self:tagsToID(self:getRandomWeaponTags(), 'weap') - - self.weapon_weights = self:tagsToID(self.weight.weapons, 'weap') - self.energy_weapons = self:tagsToID(self._energy_weapons_, 'weap') - self.decay_rates = self:tagsToID(self.weapon_degradation.decay_rate, 'weap') - - -- For explosive bullets: - self.rocket_projectile = self:getTag('proj', self.rocket_projectile_tag) - - -- For grenade launcher: - self.frag_projectile = self:getTag('proj', self.frag_grenade_projectile) - - -- For nuke (weapon): - self.rocket_launcher = self:getTag('weap', self.rocket_launcher_weapon) - - self.nuke_projectile = self:getTag('proj', self.tank_shell_projectile) - self.nuke_tag_data = getTagData(self) - - self.overshield_object = self:getTag('eqip', self.overshield_equipment) - - -- Disable object that represents loot crates: - for name, _ in pairs(self.looting.crates['eqip']) do - execute_command('disable_object "' .. name .. '"') - end + self:initialize() end end -function pluginLogo(h, m, s, b) - cprint('=======================================================================================================================', 10) - cprint(" ") - cprint("'||''|. | |''||''| |''||''| '||' '||''''| '||''|. ..|''|| '||' '|' | '||' '||''''|", 12) - cprint(" || || ||| || || || || . || || .|' || || | ||| || || .", 12) - cprint(" ||'''|. | || || || || ||''| ||''|' || || || | || || ||''|", 12) - cprint(" || || .''''|. || || || || || |. '|. || || .''''|. || ||", 12) - cprint(".||...|' .|. .||. .||. .||. .||.....| .||.....| .||. '|' ''|...|' .||. .|. .||. .||.....| .||.....|", 12) - cprint(" ") - cprint(format("This game will end in %s hours, %s minutes and %s seconds", h, m, s), 15) - cprint(format('Crunch time: %s', b .. ' seconds'), 15) - cprint('========================================================================================================================', 10) -end - register_callback(cb['EVENT_GAME_START'], 'OnStart') return event \ No newline at end of file diff --git a/INDEV/Battle Royale/events/on_tick.lua b/INDEV/Battle Royale/events/on_tick.lua index ffea9c99..58edb7cf 100644 --- a/INDEV/Battle Royale/events/on_tick.lua +++ b/INDEV/Battle Royale/events/on_tick.lua @@ -30,9 +30,8 @@ function event:onTick() self:landing() -- sky spawning / god mode timer self:outsideSafeZone() -- checks if player is outside the safe zone self:shrinkSafeZone() -- safe zone shrinking - - self:monitorLoot(self.loot_crates) -- loot crate monitor - self:monitorLoot(self.loot) -- loot crate monitor + self:monitorLoot(self.loot.crates) -- loot crate monitor + self:monitorLoot(self.loot.random) -- loot crate monitor self:trackNuke() -- nuke projectile tracker @@ -44,6 +43,11 @@ function event:onTick() v:crateIntersect() + --[[ + -- todo: Move speed modifiers to a separate recursive function that is delayed by 1 second. + -- todo: This is to prevent micro-stuttering when modifying a players speed. + ]] + if (v.stun) then v:stunPlayer() else diff --git a/INDEV/Battle Royale/loot/crates.lua b/INDEV/Battle Royale/loot/crates.lua index ba97452f..cf946467 100644 --- a/INDEV/Battle Royale/loot/crates.lua +++ b/INDEV/Battle Royale/loot/crates.lua @@ -2,7 +2,7 @@ local crates = {} function crates:crateIntersect() - if (not self.looting.enabled or not self.loot_crates) then + if (not self.looting.enabled or not self.loot.crates) then return end @@ -13,7 +13,7 @@ function crates:crateIntersect() local px, py, pz = self:getXYZ(dyn) - for meta_id, v in pairs(self.loot_crates) do + for meta_id, v in pairs(self.loot.crates) do local object = get_object_memory(meta_id) if (object == 0) then @@ -45,14 +45,14 @@ local function getSpoils(t) for k, v in pairs(t) do index = index + k if (random <= index) then - return k, v + return v end end end function crates:openCrate() - local _, spoils = getSpoils(self.looting.spoils) + local spoils = getSpoils(self.looting.spoils) if (not spoils) then self:newMessage('Something went wrong. Unable to unlock spoils.', 5) diff --git a/INDEV/Battle Royale/loot/monitor.lua b/INDEV/Battle Royale/loot/monitor.lua index 747ad98a..784862c1 100644 --- a/INDEV/Battle Royale/loot/monitor.lua +++ b/INDEV/Battle Royale/loot/monitor.lua @@ -2,7 +2,9 @@ local loot = {} function loot:monitorLoot(objects) - if (not self.looting or not self.looting.enabled or not objects) then + local game_started = (self.game and self.game.started) + local looting = (self.looting and self.looting.enabled) + if (not game_started or not looting or not objects) then return end diff --git a/INDEV/Battle Royale/loot/spawn.lua b/INDEV/Battle Royale/loot/spawn.lua index c3179feb..9d91a788 100644 --- a/INDEV/Battle Royale/loot/spawn.lua +++ b/INDEV/Battle Royale/loot/spawn.lua @@ -57,11 +57,7 @@ function loot:spawnLoot(objects, type) :: next :: end - if (type == 'crates') then - self.loot_crates = t - else - self.loot = t - end + self.loot[type] = t end return loot \ No newline at end of file diff --git a/INDEV/Battle Royale/loot/spoils.lua b/INDEV/Battle Royale/loot/spoils.lua index e62c9422..8cda7d33 100644 --- a/INDEV/Battle Royale/loot/spoils.lua +++ b/INDEV/Battle Royale/loot/spoils.lua @@ -189,8 +189,6 @@ function spoils:giveOvershield(args) local id = self.id local label = args.label - label = label:gsub('$shield', level) - self:newMessage('You unlocked ' .. label, 5) local shield = spawn_object('', '', 0, 0, 0, 0, self.overshield_object) diff --git a/INDEV/Battle Royale/map settings/stock/bloodgulch.lua b/INDEV/Battle Royale/map settings/stock/bloodgulch.lua index ef27b953..30b6888f 100644 --- a/INDEV/Battle Royale/map settings/stock/bloodgulch.lua +++ b/INDEV/Battle Royale/map settings/stock/bloodgulch.lua @@ -42,7 +42,7 @@ return { -- The minimum amount of players required to start the game: -- Default: (2) -- - required_players = 2, + required_players = 1, --- Game start delay: @@ -50,7 +50,7 @@ return { -- The start delay will not begin until the required players have joined. -- Default (30) -- - start_delay = 30, + start_delay = 2, --- Lives: @@ -406,7 +406,7 @@ return { --- Random weapon/power up spawns: -- Format: ['tag class'] = { ['tag name'] = { { x, y, z, respawn time (in seconds)}, ... } } - objects = { + random = { ['weap'] = { ['weapons\\assault rifle\\assault rifle'] = { diff --git a/INDEV/Battle Royale/misc/initialize.lua b/INDEV/Battle Royale/misc/initialize.lua new file mode 100644 index 00000000..b38458c0 --- /dev/null +++ b/INDEV/Battle Royale/misc/initialize.lua @@ -0,0 +1,131 @@ +local plugin = {} +local format = string.format +local req = require +local call = xpcall +local pairs = pairs + +local function loadMapSettings(self) + + local map = get_var(0, '$map') + local path = './Battle Royale/map settings/' + + -- Try stock maps first: + local success, data = call(req, function() + end, path .. 'stock/' .. map) + + -- Try custom maps: + if (not success) then + success, data = call(req, function() + end, path .. 'custom/' .. map) + end + + for k, v in pairs(data) do + self[k] = v + end +end + +local function getTagData(self) + local jpt = self.tank_shell_jpt_tag + local tag_address = read_dword(0x40440000) + local tag_count = read_dword(0x4044000C) + for i = 0, tag_count - 1 do + local tag = tag_address + 0x20 * i + local tag_name = read_string(read_dword(tag + 0x10)) + local tag_class = read_dword(tag) + if (tag_class == 1785754657 and tag_name == jpt) then + return read_dword(tag + 0x14) + end + end + return nil +end + +local function getClipSizesTable(self) + for _, v in pairs(self.looting.spoils) do + if (v.clip_sizes) then + return v.clip_sizes + end + end +end + +local function getStunTags(self) + for _, v in pairs(self.looting.spoils) do + if (v.grenade_tags) then + return v.grenade_tags + end + end +end + +local function getRandomWeaponTags(self) + local spoils = self.looting.spoils + for _, v in pairs(spoils) do + if (v.random_weapons) then + return v.random_weapons + end + end +end + +function plugin:initialize() + + loadMapSettings(self) + + self:reset() + + local stuns = getStunTags(self) + local clip_sizes = getClipSizesTable(self) + local random_weapons = getRandomWeaponTags(self) + + local weights = self.weight.weapons + local energy_weapons = self._energy_weapons_ + local decay_rates = self.weapon_degradation.decay_rate + + self.nuke_tag_data = getTagData(self) + self.stuns = self:tagsToID(stuns, 'jpt!') + self.clip_sizes = self:tagsToID(clip_sizes, 'weap') + self.random_weapons = self:tagsToID(random_weapons, 'weap') + + self.weapon_weights = self:tagsToID(weights, 'weap') + self.energy_weapons = self:tagsToID(energy_weapons, 'weap') + self.decay_rates = self:tagsToID(decay_rates, 'weap') + + self.rocket_projectile = self:getTag('proj', self.rocket_projectile_tag) + self.frag_projectile = self:getTag('proj', self.frag_grenade_projectile) + self.rocket_launcher = self:getTag('weap', self.rocket_launcher_weapon) + self.nuke_projectile = self:getTag('proj', self.tank_shell_projectile) + self.overshield_object = self:getTag('eqip', self.overshield_equipment) + + for name, _ in pairs(self.looting.crates['eqip']) do + execute_command('disable_object "' .. name .. '"') + end + + local h, m, s = self:secondsToTime(self.total_time) + cprint('=======================================================================================================================', 10) + cprint(" ") + cprint("'||''|. | |''||''| |''||''| '||' '||''''| '||''|. ..|''|| '||' '|' | '||' '||''''|", 12) + cprint(" || || ||| || || || || . || || .|' || || | ||| || || .", 12) + cprint(" ||'''|. | || || || || ||''| ||''|' || || || | || || ||''|", 12) + cprint(" || || .''''|. || || || || || |. '|. || || .''''|. || ||", 12) + cprint(".||...|' .|. .||. .||. .||. .||.....| .||.....| .||. '|' ''|...|' .||. .|. .||. .||.....| .||.....|", 12) + cprint(" ") + cprint(format("This game will end in %s hours, %s minutes and %s seconds", h, m, s), 15) + cprint(format('Crunch time: %s', self.end_after .. ' seconds'), 15) + cprint('========================================================================================================================', 10) +end + +function plugin:reset() + + self.game = nil + self.nukes = {} + self.players = {} + self.weapons = {} + self.loot = { crates = {}, random = {} } + + self.total_time = self:setSafeZone() + + for i = 1, 16 do + if player_present(i) then + self.players[i] = self:onJoin(i) + end + end +end + +return plugin \ No newline at end of file diff --git a/INDEV/Battle Royale/safe zone/safe_zone.lua b/INDEV/Battle Royale/safe zone/safe_zone.lua index e593e101..e5edefe4 100644 --- a/INDEV/Battle Royale/safe zone/safe_zone.lua +++ b/INDEV/Battle Royale/safe zone/safe_zone.lua @@ -49,6 +49,10 @@ end function SafeZone:shrinkSafeZone() + if (not self.game or not self.game.started) then + return + end + local safe_zone = self.safe_zone if (not safe_zone or not safe_zone.timer) then return diff --git a/INDEV/Battle Royale/sky spawning/getters_and_setters.lua b/INDEV/Battle Royale/sky spawning/getters_and_setters.lua index 8560331c..df6bd139 100644 --- a/INDEV/Battle Royale/sky spawning/getters_and_setters.lua +++ b/INDEV/Battle Royale/sky spawning/getters_and_setters.lua @@ -25,10 +25,16 @@ function spawns:setSpawns() return end + local loops = 0 for _, v in pairs(self.players) do local point = getRandomPoint(locations) while (point.used) do + loops = loops + 1 point = getRandomPoint(locations) + if (loops == 500) then -- just in case + error('Unable to find spawn point!') + return + end end point.used = true v.spawn = point diff --git a/INDEV/Battle Royale/spectator/spectate.lua b/INDEV/Battle Royale/spectator/spectate.lua index fdba9e61..962ae547 100644 --- a/INDEV/Battle Royale/spectator/spectate.lua +++ b/INDEV/Battle Royale/spectator/spectate.lua @@ -1,5 +1,12 @@ local spectator = {} +local function hidePlayer(self, player, dyn) + local x, y, z = self:getXYZ(dyn) + write_float(player + 0xF8, x - 1000) + write_float(player + 0xFC, y - 1000) + write_float(player + 0x100, z - 1000) +end + function spectator:spectate() local id = self.id @@ -14,7 +21,7 @@ function spectator:spectate() return end - self:hide(player, dyn) + hidePlayer(player, dyn) -- In case the player picks up a weapon, force them to drop it: execute_command('wdrop ' .. id)