Advertisement
Guest User

Untitled

a guest
Dec 9th, 2019
310
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 101.54 KB | None | 0 0
  1. Player = GameObject:extend()
  2.  
  3. function Player:new(area, x, y, opts)
  4.     Player.super.new(self, area, x, y, opts)
  5.  
  6.     -- This is only set to false when the player presses a key
  7.     -- When it's true the ship won't move or shoot
  8.     self.paused = true
  9.  
  10.     -- Movement
  11.     self.r = -math.pi/2
  12.     self.rv = 1.66*math.pi
  13.     self.v = 0
  14.     self.vx, self.vy = 0, 0
  15.     self.base_max_v = 100
  16.     self.max_v = self.base_max_v
  17.     self.a = 100
  18.  
  19.     -- Cycle
  20.     self.cycle_timer = 0
  21.     self.cycle_cooldown = 5
  22.  
  23.     -- Boost
  24.     self.max_boost = 100
  25.     self.boost = self.max_boost
  26.     self.boosting = false
  27.     self.can_boost = true
  28.     self.boost_timer = 0
  29.     self.boost_cooldown = 2
  30.  
  31.     -- HP
  32.     self.max_hp = 100
  33.     self.hp = self.max_hp
  34.  
  35.     -- Ammo
  36.     self.max_ammo = 100
  37.     self.ammo = self.max_ammo
  38.     self.protective_barrier = 0
  39.  
  40.     -- Attacks
  41.     self.shoot_timer = 0
  42.     self.shoot_cooldown = 0.24
  43.     self:setAttack(opts.attack or 'Neutral')
  44.     self.rampage_counter = 0
  45.     self.rampage_timer = 0
  46.     self.rampage_cooldown = 2.5
  47.     self.damage_multiplier = 1
  48.  
  49.     -- ES
  50.     self.energy_shield_recharge_cooldown = 2
  51.     self.energy_shield_recharge_amount = 1
  52.  
  53.     -- Commented to the right of each stat are its maximum values from the tree alone.
  54.     -- For stats that have both increases and decreases, the maximum/minimum of each is listed.
  55.     -- i.e. The player can get +1.87 (=2.87) maximum ASPD multiplier or -0.72 (=0.28) minimum ASPD multiplier from the tree, meaning he can attack ~3 times as fast as normal or ~4 times as slow.
  56.  
  57.     -- Flats
  58.     self.flat_hp = 0 -- 115 +185 -70
  59.     self.flat_ammo = 0 -- 130 +200 -70
  60.     self.flat_boost = 0 -- 250
  61.     self.ammo_gain = 0 -- 2
  62.  
  63.     -- Limiters
  64.     self.barrage_cooldown = 1
  65.     self.barrage_timer = 0
  66.     self.launch_homing_projectile_cooldown = 0.5
  67.     self.launch_homing_projectile_timer = 0
  68.  
  69.     -- Multipliers
  70.     self.hp_multiplier = 1 -- 4.46
  71.     self.ammo_multiplier = 1 -- 2.38
  72.     self.boost_multiplier = 1 -- 2.65
  73.     self.aspd_multiplier = Stat(1) -- 2.15 +1.87 -0.72
  74.     self.mvspd_multiplier = Stat(1) -- 1.24 +1.28 -1.04
  75.     self.pspd_multiplier = Stat(1) -- 1.22 +1.79 -1.57
  76.     self.cycle_multiplier = Stat(1) -- 3.06
  77.     self.luck_multiplier = 1 -- 2.15
  78.     self.enemy_spawn_rate_multiplier = 1 -- ????
  79.     self.item_spawn_rate_multiplier = 1 -- 3.43
  80.     self.hp_spawn_chance_multiplier = 1 -- 1.98
  81.     self.sp_spawn_chance_multiplier = 1 --3.98
  82.     self.boost_spawn_chance_multiplier = 1 -- 2.04
  83.     self.resource_spawn_rate_multiplier = 1 -- 2.04
  84.     self.attack_spawn_rate_multiplier = 1 -- 2.28
  85.     self.turn_rate_multiplier = 1 -- 0.82 +0.66 -0.84
  86.     self.boost_effectiveness_multiplier = 1 -- 2.1
  87.     self.projectile_size_multiplier = 1 -- 2.28
  88.     self.boost_recharge_rate_multiplier = 1 -- 2.22
  89.     self.invulnerability_time_multiplier = 1 -- 1.64
  90.     self.ammo_consumption_multiplier = 1 -- 1.58 +1 -0.42
  91.     self.size_multiplier = 1 -- 1.5 +0.7 -0.2
  92.     self.stat_boost_duration_multiplier = 1 -- 1.6
  93.     self.projectile_angle_change_frequency_multiplier = 1 -- 2.2
  94.     self.projectile_waviness_multiplier = 1 -- 2
  95.     self.projectile_acceleration_multiplier = 1 -- 1.6
  96.     self.projectile_deceleration_multiplier = 1 -- 1.6
  97.     self.projectile_duration_multiplier = 1 -- 1.78 +1.34 -0.56
  98.     self.area_multiplier = 1 -- 2.65
  99.     self.laser_width_multiplier = 1 -- 2.1
  100.     self.energy_shield_recharge_amount_multiplier = 1 -- 2.3 +1.6 -0.3
  101.     self.energy_shield_recharge_cooldown_multiplier = 1 -- 3.02 +2.32 -0.3
  102.     self.shield_projectile_damage_multiplier = 1
  103.     self.homing_speed_multiplier = 1
  104.  
  105.     -- Chances
  106.     self.regain_hp_on_item_pickup_chance = 0 -- 20
  107.     self.regain_hp_on_sp_pickup_chance = 0 -- 10
  108.     self.spawn_haste_area_on_hp_pickup_chance = 0 -- 20
  109.     self.spawn_haste_area_on_sp_pickup_chance = 0 -- 44
  110.     self.spawn_haste_area_on_cycle_chance = 0 -- 10
  111.     self.spawn_haste_area_on_item_pickup_chance = 0 -- 20
  112.     self.barrage_on_cycle_chance = 0 -- 22
  113.     self.launch_homing_projectile_on_cycle_chance = 0 -- 22
  114.     self.spawn_hp_on_cycle_chance = 0 -- 12
  115.     self.regain_hp_on_cycle_chance = 0 -- 11
  116.     self.regain_full_ammo_on_cycle_chance = 0 -- 11
  117.     self.regain_ammo_on_kill_chance = 0 -- 32
  118.     self.launch_homing_projectile_on_kill_chance = 0 -- 11
  119.     self.regain_boost_on_kill_chance = 0 -- 10
  120.     self.spawn_boost_on_kill_chance = 0 -- 10
  121.     self.change_attack_on_cycle_chance = 0 -- 50
  122.     self.launch_homing_projectile_on_item_pickup_chance = 0 -- 40
  123.     self.spawn_sp_on_cycle_chance = 0 -- 20
  124.     self.barrage_on_kill_chance = 0 -- 21
  125.     self.gain_aspd_boost_on_kill_chance = 0 -- 15
  126.     self.gain_mvspd_boost_on_cycle_chance = 0 -- 23
  127.     self.gain_pspd_boost_on_cycle_chance = 0 -- 20
  128.     self.gain_pspd_inhibit_on_cycle_chance = 0 -- 20
  129.     self.launch_homing_projectile_while_boosting_chance = 0 -- 8
  130.     self.shield_projectile_chance = 0 -- 24
  131.     self.added_chance_to_all_on_kill_events = 0 -- 5
  132.     self.drop_double_ammo_chance = 0 -- 30
  133.     self.attack_twice_chance = 0 -- 20
  134.     self.spawn_double_hp_chance = 0 -- 22
  135.     self.spawn_double_sp_chance = 0 -- 24
  136.     self.gain_double_sp_chance = 0 -- 20
  137.     self.drop_mines_chance = 0 -- 5
  138.     self.self_explode_on_cycle_chance = 0 -- 31
  139.     self.attack_from_sides_chance = 0 -- 20
  140.     self.attack_from_back_chance = 0 -- 20
  141.     self.spin_projectile_on_expiration_chance = 0 -- 50
  142.  
  143.     -- Booleans
  144.     self.increased_cycle_speed_while_boosting = false -- true
  145.     self.invulnerability_while_boosting = false -- true
  146.     self.increased_luck_while_boosting = false -- true
  147.     self.projectile_ninety_degree_change = false -- true
  148.     self.projectile_random_degree_change = false -- true
  149.     self.wavy_projectiles = false -- true
  150.     self.fast_slow = false -- true
  151.     self.slow_fast = false -- true
  152.     self.energy_shield = false -- true
  153.     self.barrage_nova = false -- true
  154.     self.projectiles_explode_on_expiration = false -- true
  155.     self.lesser_increased_self_explosion_size = false -- true
  156.     self.greater_increased_self_explosion_size = false -- true
  157.     self.projectiles_explosions = false -- true
  158.     self.change_attack_periodically = false -- true
  159.     self.gain_sp_on_death = false -- true
  160.     self.convert_hp_to_sp_if_hp_full = false -- true
  161.     self.no_boost = false -- true
  162.     self.half_ammo = false -- true
  163.     self.half_hp = false -- true
  164.     self.deals_damage_while_invulnerable = false -- true
  165.     self.refill_ammo_if_hp_full = false -- true
  166.     self.refill_boost_if_hp_full = false -- true
  167.     self.only_spawn_boost = false -- true
  168.     self.only_spawn_attack = false -- true
  169.     self.no_ammo_drop = false -- true
  170.     self.infinite_ammo = false -- true
  171.     self.cant_launch_homing_projectiles = false
  172.     self.cant_barrage = false
  173.     self.item_restores_hp = false
  174.     self.protective_barrier_when_no_ammo = false
  175.     self.gain_stat_boost_on_attack_change = false
  176.     self.rampage = false
  177.     self.absorb_hits = false
  178.     self.cant_trigger_on_cycle_events = false
  179.     self.change_attack_when_no_ammo = false
  180.     self.blast_shield = false
  181.     self.double_homing = false
  182.     self.ammo_gives_boost = false
  183.  
  184.     -- Conversions
  185.     self.ammo_to_aspd = 0 -- 30
  186.     self.mvspd_to_aspd = 0 -- 30
  187.     self.mvspd_to_hp = 0 -- 30
  188.     self.mvspd_to_pspd = 0 -- 30
  189.  
  190.     -- Adds
  191.     self.additional_barrage_projectile = 0 -- 6
  192.     self.additional_homing_projectile = 0 -- 2
  193.     self.additional_blast_projectile = 0 -- 6
  194.     self.projectile_pierce = 0 -- 2
  195.  
  196.     -- Attack
  197.     self.additional_lightning_bolt = 0 -- 2
  198.     self.lightning_trigger_distance_multiplier = 1 -- 1.5
  199.     self.additional_bounce = 0 -- 4
  200.     self.fixed_spin_direction = false -- true
  201.     self.split_projectiles_split_chance = 0 -- 24
  202.     self.start_with_double = false -- true
  203.     self.start_with_triple = false -- true
  204.     self.start_with_rapid = false -- true
  205.     self.start_with_spread = false -- true
  206.     self.start_with_back = false -- true
  207.     self.start_with_side = false -- true
  208.     self.start_with_homing = false -- true
  209.     self.start_with_blast = false -- true
  210.     self.start_with_spin = false -- true
  211.     self.start_with_lightning = false -- true
  212.     self.start_with_flame = false -- true
  213.     self.start_with_2split = false -- true
  214.     self.start_with_4split = false -- true
  215.     self.start_with_explode = false -- true
  216.     self.start_with_laser = false -- true
  217.     self.start_with_bounce = false -- true
  218.     self.double_spawn_chance = 0 -- 40
  219.     self.triple_spawn_chance = 0 -- 50
  220.     self.rapid_spawn_chance = 0 -- 40
  221.     self.spread_spawn_chance = 0 -- 40
  222.     self.back_spawn_chance = 0 -- 70
  223.     self.side_spawn_chance = 0 -- 30
  224.     self.homing_spawn_chance = 0 -- 40
  225.     self.blast_spawn_chance = 0 -- 50
  226.     self.spin_spawn_chance = 0 -- 70
  227.     self.lightning_spawn_chance = 0 -- 40
  228.     self.flame_spawn_chance = 0 -- 50
  229.     self.twosplit_spawn_chance = 0 -- 50
  230.     self.foursplit_spawn_chance = 0 -- 40
  231.     self.explode_spawn_chance = 0 -- 60
  232.     self.laser_spawn_chance = 0 -- 70
  233.     self.bounce_spawn_chance = 0 -- 50
  234.  
  235.     -- Classes
  236.     self.cycler = false
  237.     self.tanker = false
  238.     self.gunner = false
  239.     self.runner = false
  240.     self.swapper = false
  241.     self.barrager = false
  242.     self.seeker = false
  243.     self.shielder = false
  244.     self.regeneeer = false
  245.     self.recycler = false
  246.     self.buster = false
  247.     self.buffer = false
  248.     self.berserker = false
  249.     self.absorber = false
  250.     self.turner = false
  251.     self.driver = false
  252.     self.processor = false
  253.     self.gambler = false
  254.     self.panzer = false
  255.     self.reserver = false
  256.     self.repeater = false
  257.     self.launcher = false
  258.     self.deployer = false
  259.     self.booster = false
  260.     self.discharger = false
  261.     self.hoamer = false
  262.     self.splitter = false
  263.     self.spinner = false
  264.     self.bouncer = false
  265.     self.blaster = false
  266.     self.raider = false
  267.     self.waver = false
  268.     self.bomber = false
  269.     self.zoomer = false
  270.     self.racer = false
  271.     self.miner = false
  272.     self.piercer = false
  273.     self.dasher = false
  274.     self.engineer = false
  275.     self.threader = false
  276.  
  277.     self.ship = (trailer_mode and opts.device) or device or 'Fighter'
  278.     self:setShip()
  279.  
  280.     if not opts.trailer_stats then treeToPlayer(self)
  281.     else
  282.         for k, v in pairs(opts.trailer_stats) do
  283.             if type(self[k]) == 'number' then self[k] = self[k] + v
  284.             elseif type(self[k]) == 'boolean' then self[k] = v
  285.             elseif self[k]:is(Stat) then self[k] = Stat(self[k].value + v) end
  286.         end
  287.     end
  288.     self:setStats()
  289.     self:setClasses()
  290.  
  291.     -- Collider
  292.     self.x, self.y = x, y
  293.     self.w, self.h = 12*self.size_multiplier, 12*self.size_multiplier
  294.     self.shape = HC.circle(self.x, self.y, self.w)
  295.     self.shape.object = self
  296.     self.shape.tag = 'Player'
  297.     self.shape.id = self.id
  298.  
  299.     -- Ship visuals
  300.     self.polygons = {}
  301.     self:shipVisuals()
  302.     self:boostTrails()
  303.     self:generateChances()
  304.  
  305.     if self.threader then
  306.         self.cycle_timer_2 = 0
  307.         self.cycle_cooldown_2 = 5
  308.         self.cycle_timer_3 = 0
  309.         self.cycle_cooldown_3 = 5
  310.         self.cycle_timer_4 = 0
  311.         self.cycle_cooldown_4 = 5
  312.     end
  313.  
  314.     -- Mine drop
  315.     self.timer:every('drop_mines', 0.5, function()
  316.         if self.drop_mines_chance > 0 then
  317.             if self.chances.drop_mines_chance:next() then
  318.                 local d = 1.2*self.w
  319.                 self.area:addGameObject('Projectile', self.x - d*math.cos(self.r), self.y - d*math.sin(self.r),
  320.                 {r = self.r, rv = table.random({random(-12*math.pi, -10*math.pi), random(10*math.pi, 12*math.pi)}), mine = true, attack = self.attack})
  321.             end
  322.         end
  323.     end)
  324.  
  325.     -- Change attack periodically
  326.     self.timer:every('change_attack', 10, function()
  327.         if self.change_attack_periodically then
  328.             self:setAttack(table.random(attack_names))
  329.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Attack Change!'})
  330.         end
  331.     end)
  332.  
  333.     -- RollerPool
  334.     self.timer:every('roller_pool', 0.5, function()
  335.         if self.inside_roller_pool then
  336.             self:hit(10)
  337.         end
  338.     end)
  339.  
  340.     -- Sapper
  341.     self.sappers = {}
  342.     self.timer:every(10, function() self.sappers = {} end)
  343.  
  344.     -- Item
  345.     self.permanent_buffs = {
  346.         ['stat_buffs'] = {
  347.             ['protective_barrier'] = {chanceList({2, 10}, {5, 4}, {10, 1}), 'Protective Barrier'},
  348.             ['flat_hp'] = {chanceList({10, 10}, {25, 4}, {50, 1}), 'HP'},
  349.             ['flat_ammo'] = {chanceList({10, 10}, {25, 4}, {50, 1}), 'Ammo'},
  350.             ['flat_boost'] = {chanceList({10, 10}, {25, 4}, {50, 1}), 'Boost'},
  351.             ['ammo_gain'] = {chanceList({0.5, 10}, {1, 4}, {1.5, 1}), 'Ammo Gain'},
  352.             ['hp_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'HP'},
  353.             ['ammo_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Ammo'},
  354.             ['mvspd_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'MVPSD'},
  355.             ['pspd_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'PSPD'},
  356.             ['cycle_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Cycle Speed'},
  357.             ['luck_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Luck'},
  358.             ['turn_rate_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Turn Rate'},
  359.             ['projectile_size_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Size'},
  360.             ['invulnerability_time_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Invulnerability Time'},
  361.             ['stat_boost_duration_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Stat Boost Duration'},
  362.             ['ammo_consumption_multiplier'] = {chanceList({-0.1, 10}, {-0.2, 4}, {-0.3, 1}), 'Ammo Consumption'},
  363.             ['projectile_waviness_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Waviness'},
  364.             ['projectile_duration_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Duration'},
  365.             ['projectile_angle_change_frequency_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Angle Change Frequency'},
  366.             ['projectile_acceleration_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Acceleration'},
  367.             ['projectile_deceleration_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Projectile Deceleration'},
  368.             ['area_multiplier'] = {chanceList({0.1, 10}, {0.25, 4}, {0.5, 1}), 'Area'},
  369.             ['energy_shield_recharge_amount_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Energy Shield Recharge Amount'},
  370.             ['energy_shield_recharge_cooldown_multiplier'] = {chanceList({0.1, 10}, {0.2, 4}, {0.3, 1}), 'Energy Shield Recharge Cooldown'},
  371.             ['barrage_on_cycle_chance'] = {chanceList({2, 10}, {4, 4}, {8, 1}), 'Barrage on Cycle Chance'},
  372.             ['launch_homing_projectile_on_cycle_chance'] = {chanceList({2, 10}, {4, 4}, {8, 1}), 'Launch Homing Projectile on Cycle Chance'},
  373.             ['launch_homing_projectile_on_kill_chance'] = {chanceList({1, 10}, {2, 4}, {4, 1}), 'Launch Homing Projectile on Kill Chance'},
  374.             ['change_attack_on_cycle_chance'] = {chanceList({10, 10}, {25, 4}, {50, 1}), 'Change Attack on Cycle Chance'},
  375.             ['barrage_on_kill_chance'] = {chanceList({2, 10}, {4, 4}, {8, 1}), 'Barrage on Kill Chance'},
  376.             ['shield_projectile_chance'] = {chanceList({10, 10}, {25, 4}, {50, 1}), 'Shield Projectile Chance'},
  377.             ['added_chance_to_all_on_kill_events'] = {chanceList({1, 10}, {2, 4}, {3, 1}), 'Added Chance to All "On Kill" Events'},
  378.             ['drop_mines_chance'] = {chanceList({2, 10}, {4, 4}, {8, 1}), 'Drop Mines Chance'},
  379.             ['self_explode_on_cycle_chance'] = {chanceList({8, 10}, {16, 4}, {24, 1}), 'Self Explode on Cycle Chance'},
  380.             ['attack_twice_chance'] = {chanceList({10, 10}, {20, 4}, {30, 1}), 'Attack Twice Chance'},
  381.             ['attack_from_sides_chance'] = {chanceList({10, 10}, {15, 4}, {20, 1}), 'Attack from Sides Chance'},
  382.             ['attack_from_back_chance'] = {chanceList({10, 10}, {15, 4}, {20, 1}), 'Attack from Back Chance'},
  383.             ['additional_barrage_projectile'] = {chanceList({1, 10}, {2, 4}, {3, 1}), 'Additional Barrage Projectile'},
  384.             ['additional_homing_projectile'] = {chanceList({1, 10}, {2, 1}), 'Additional Homing Projectile'},
  385.             ['projectile_pierce'] = {chanceList({1, 10}, {2, 4}, {3, 1}), 'Projectile Pierce'},
  386.             ['additional_lightning_bolt'] = {chanceList({1, 10}, {2, 1}), 'Additional Lightning Bolt'},
  387.             ['additional_bounce'] = {chanceList({1, 10}, {2, 4}, {4, 1}), 'Additional Bounce'},
  388.             ['split_projectiles_split_chance'] = {chanceList({6, 10}, {12, 4}, {24, 1}), 'Split Projectiles Split Chance'},
  389.         },
  390.  
  391.         ['modifier_buffs'] = {
  392.             ['projectile_ninety_degree_change'] = {true, 'Projectile 90 Degree Change'},
  393.             ['projectile_random_degree_change'] = {true, 'Projectile Random Degree Change'},
  394.             ['increased_cycle_speed_while_boosting'] = {true, 'Increased Cycle Speed While Boosting'},
  395.             ['fast_slow'] = {true, 'Fast -> Slow Projectiles'},
  396.             ['slow_fast'] = {true, 'Slow -> Fast Projectiles'},
  397.             ['barrage_nova'] = {true, 'Barrage Nova'},
  398.             ['projectiles_explode_on_expiration'] = {true, 'Projectiles Explode on Expiration'},
  399.             ['projectiles_explosions'] = {true, 'Explosions Create Projectiles Instead'},
  400.             ['change_attack_periodically'] = {true, 'Change Attack Every 10 Seconds'},
  401.             ['deals_damage_while_invulnerable'] = {true, 'Deals Damage While Invulnerable'},
  402.             ['protective_barrier_when_no_ammo'] = {true, 'Protective Barrier When No Ammo'},
  403.             ['rampage'] = {true, 'Rampage'},
  404.             ['absorb_hits'] = {true, 'Absorb Hits'},
  405.         },
  406.  
  407.         ['classes'] = {
  408.             ['cycler'] = {true, 'Cycler'},
  409.             ['tanker'] = {true, 'Tanker'},
  410.             ['gunner'] = {true, 'Gunner'},
  411.             ['runner'] = {true, 'Runner'},
  412.             ['swapper'] = {true, 'Swapper'},
  413.             ['barrager'] = {true, 'Barrager'},
  414.             ['launcher'] = {true, 'Launcher'},
  415.             ['shielder'] = {true, 'Shielder'},
  416.             ['regeneer'] = {true, 'Regeneer'},
  417.             ['recycler'] = {true, 'Recycler'},
  418.             ['buster'] = {true, 'Buster'},
  419.             ['berserker'] = {true, 'Berserker'},
  420.             ['absorber'] = {true, 'Absorber'},
  421.             ['panzer'] = {true, 'Panzer'},
  422.             ['reserver'] = {true, 'Reserver'},
  423.             ['repeater'] = {true, 'Repeater'},
  424.             ['launcher'] = {true, 'Launcher'},
  425.             ['deployer'] = {true, 'Deployer'},
  426.             ['piercer'] = {true, 'Piercer'},
  427.             ['dasher'] = {true, 'Dasher'},
  428.             ['engineer'] = {true, 'Engineer'},
  429.             ['threader'] = {true, 'Threader'},
  430.         },
  431.  
  432.         ['attack_change'] = {
  433.             ['attack_change'] = {true, 'Attack Change'}
  434.         },
  435.     }
  436.     self.item_type_chance_list = chanceList({'stat_buffs', 30}, {'modifier_buffs', 10}, {'classes', 3}, {'attack_change', 8})
  437. end
  438.  
  439. function Player:update(dt)
  440.     Player.super.update(self, dt)
  441.  
  442.     -- Stat boosts
  443.     if self.inside_haste_area then self.aspd_multiplier:increase(100) end
  444.     if self.aspd_boosting then self.aspd_multiplier:increase(100) end
  445.     if self.mvspd_boosting then self.mvspd_multiplier:increase(50) end
  446.     if self.pspd_boosting then self.pspd_multiplier:increase(50) end
  447.     if self.pspd_inhibiting then self.pspd_multiplier:decrease(50) end
  448.     if self.cycle_boosting then self.cycle_multiplier:increase(200) end
  449.     if self.inside_roller_pool then self.mvspd_multiplier:decrease(150) end
  450.     self.inside_roller_pool = false
  451.     if self.rampage then
  452.         if self.rampage_counter >= 10 then
  453.             self.aspd_multiplier:increase(math.floor(self.rampage_counter/10))
  454.             self.pspd_multiplier:increase(math.floor(self.rampage_counter/10))
  455.         end
  456.     end
  457.  
  458.     -- Sappers
  459.     for id, sap_type in pairs(self.sappers) do
  460.         if sap_type == 'ASPD' then self.aspd_multiplier:decrease(50)
  461.         elseif sap_type == 'PSPD' then self.pspd_multiplier:decrease(50)
  462.         elseif sap_type == 'MVSPD' then self.mvspd_multiplier:decrease(50)
  463.         elseif sap_type == 'Cycle' then self.cycle_multiplier:decrease(50) end
  464.     end
  465.  
  466.     -- Conversions
  467.     if self.ammo_to_aspd > 0 then self.aspd_multiplier:increase((self.ammo_to_aspd/100)*(self.max_ammo - 100)) end
  468.     if self.mvspd_to_aspd > 0 then self.aspd_multiplier:increase((self.mvspd_to_aspd/100)*(self.mvspd_multiplier.value*100 - 100)) end
  469.     if self.mvspd_to_pspd > 0 then self.pspd_multiplier:increase((self.mvspd_to_pspd/100)*(self.pspd_multiplier.value*100 - 100)) end
  470.  
  471.     self.aspd_multiplier:update(dt)
  472.     self.mvspd_multiplier:update(dt)
  473.     self.pspd_multiplier:update(dt)
  474.     self.cycle_multiplier:update(dt)
  475.  
  476.     -- Collision
  477.     if self.x < 0 then self.r = math.pi - self.r; self:hit(10) end
  478.     if self.y < 0 then self.r = 2*math.pi - self.r; self:hit(10) end
  479.     if self.x > gw then self.r = math.pi - self.r; self:hit(10) end
  480.     if self.y > gh then self.r = 2*math.pi - self.r; self:hit(10) end
  481.  
  482.     for _, shape in ipairs(self:enter('Collectable')) do
  483.         local object = shape.object
  484.         if object then
  485.             if object:is(Ammo) then
  486.                 object:die()
  487.                 self:addAmmo(5)
  488.                 self:onAmmoPickup()
  489.  
  490.             elseif object:is(Boost) then
  491.                 playGameItem()
  492.                 object:die()
  493.                 self:addBoost(math.floor(self.max_boost/4))
  494.  
  495.             elseif object:is(SkillPoint) then
  496.                 playGameItem()
  497.                 object:die()
  498.                 self:addSP(1)
  499.                 self:onSPPickup()
  500.  
  501.             elseif object:is(Attack) then
  502.                 playGameItem()
  503.                 object:die()
  504.                 self:setAttack(object.attack)
  505.                 current_room.score = current_room.score + 200
  506.  
  507.             elseif object:is(HP) then
  508.                 playGameItem()
  509.                 object:die()
  510.                 self:addHP(math.floor(self.max_hp/4))
  511.                 self:onHPPickup()
  512.  
  513.             elseif object:is(Key) then
  514.                 playGameItem()
  515.                 object:die()
  516.                 current_room.key_found = 'KEY ' .. keys[object.n].address.. ' FOUND'
  517.                 timer:after(3, function() current_room.key_found = false end)
  518.                 found_keys[object.n] = 1
  519.                 current_room:glitchError()
  520.  
  521.             elseif object:is(Item) then
  522.                 playGameItem()
  523.                 object:die()
  524.                 self:onItemPickup()
  525.  
  526.                 local buff_type = self.item_type_chance_list:next()
  527.                 local buff = table.randomh(self.permanent_buffs[buff_type])
  528.                 if buff_type == 'attack_change' then
  529.                     self:setAttack(table.random(attack_names))
  530.                     self.area:addGameObject('InfoText', self.x, self.y, {text = 'Attack Change!'})
  531.  
  532.                 elseif type(self.permanent_buffs[buff_type][buff][1]) == 'table' then
  533.                     local n = self.permanent_buffs[buff_type][buff][1]:next()
  534.                     if buff == 'aspd_multiplier' or buff == 'mvspd_multiplier' or buff == 'pspd_multiplier' or buff == 'cycle_multiplier' then self[buff] = Stat(self[buff].value + n)
  535.                     elseif buff == 'hp_multiplier' then self.max_hp = self.max_hp*(1+n)
  536.                     elseif buff == 'ammo_multiplier' then self.max_ammo = self.max_ammo*(1+n)
  537.                     elseif buff == 'boost_multiplier' then self.max_boost = self.max_boost*(1+n)
  538.                     elseif buff == 'flat_hp' then self.max_hp = self.max_hp + n
  539.                     elseif buff == 'flat_ammo' then self.max_ammo = self.max_ammo + n
  540.                     elseif buff == 'flat_boost' then self.max_boost = self.max_boost + n
  541.                     else self[buff] = self[buff] + n end
  542.                     if self.projectile_waviness_multiplier > 1 then self.wavy_projectiles = true end
  543.                     if self.pspd_multiplier.value < 0 then self.pspd_multiplier.base = 0 end
  544.                     self:setClass(buff)
  545.                     self:generateChances()
  546.                     local text = ''
  547.                     if n < 1 then text = text .. '+' .. n*100 .. '% ' .. self.permanent_buffs[buff_type][buff][2] .. '!'
  548.                     else
  549.                         if self.permanent_buffs[buff_type][buff][2]:find('Chance') then text = text .. '+' .. n .. '% ' .. self.permanent_buffs[buff_type][buff][2] .. '!'
  550.                         else text = text .. '+' .. n .. ' ' .. self.permanent_buffs[buff_type][buff][2] .. '!' end
  551.                     end
  552.                     self.area:addGameObject('InfoText', object.x, object.y, {text = text})
  553.  
  554.                 elseif type(self.permanent_buffs[buff_type][buff][1]) == 'boolean' then
  555.                     self[buff] = true
  556.                     local text = self.permanent_buffs[buff_type][buff][2] .. '!'
  557.                     self:setClass(buff)
  558.                     self:generateChances()
  559.                     self.area:addGameObject('InfoText', object.x, object.y, {text = text})
  560.                 end
  561.             end
  562.         end
  563.     end
  564.  
  565.     for _, shape in ipairs(self:enter('Enemy')) do
  566.         local object = shape.object
  567.         if object then
  568.             if object:is(Sapper) then self:hit(10)
  569.             else self:hit(30) end
  570.             if self.deals_damage_while_invulnerable then object:hit(1000) end
  571.         end
  572.     end
  573.  
  574.     -- Rampage
  575.     self.rampage_timer = self.rampage_timer + dt
  576.     if self.rampage_timer > self.rampage_cooldown then
  577.         self.rampage_counter = 0
  578.         self.rampage_timer = 0
  579.     end
  580.  
  581.     -- Cycle
  582.     self.cycle_timer = self.cycle_timer + dt*self.cycle_multiplier.value
  583.     if self.cycle_timer > self.cycle_cooldown then
  584.         self.cycle_timer = 0
  585.         self:cycle()
  586.     end
  587.  
  588.     if self.threader then
  589.         self.cycle_timer_2 = self.cycle_timer_2 + dt*self.cycle_multiplier.value*0.47
  590.         if self.cycle_timer_2 > self.cycle_cooldown_2 then
  591.             self.cycle_timer_2 = 0
  592.             self:cycle()
  593.         end
  594.  
  595.         self.cycle_timer_3 = self.cycle_timer_3 + dt*self.cycle_multiplier.value*0.22
  596.         if self.cycle_timer_3 > self.cycle_cooldown_3 then
  597.             self.cycle_timer_3 = 0
  598.             self:cycle()
  599.         end
  600.  
  601.         self.cycle_timer_4 = self.cycle_timer_4 + dt*self.cycle_multiplier.value*0.06
  602.         if self.cycle_timer_4 > self.cycle_cooldown_4 then
  603.             self.cycle_timer_4 = 0
  604.             self:cycle()
  605.         end
  606.     end
  607.  
  608.     -- Boost
  609.     self.boost = math.min(self.boost + 10*dt*self.boost_recharge_rate_multiplier, self.max_boost)
  610.     self.boost_timer = self.boost_timer + dt
  611.     if self.boost_timer > self.boost_cooldown then self.can_boost = true end
  612.     self.max_v = self.base_max_v
  613.     self.boosting = false
  614.     if self.turner then
  615.         self.boosting_up = false
  616.         self.boosting_down = false
  617.     end
  618.     if input:pressed('up') and self.boost > 1 and self.can_boost then self:onBoostStart() end
  619.     if input:released('up') then self:onBoostEnd() end
  620.     if input:down('up') and self.boost > 1 and self.can_boost then
  621.         self.boosting = true
  622.         if self.turner then self.boosting_up = true end
  623.         self.max_v = 1.5*self.base_max_v*self.boost_effectiveness_multiplier
  624.         self.boost = self.boost - 50*dt
  625.         if self.boost <= 1 then
  626.             self.boosting = false
  627.             if self.turner then self.boosting_up = false end
  628.             self.can_boost = false
  629.             self.boost_timer = 0
  630.             self:onBoostEnd()
  631.         end
  632.     end
  633.     if input:pressed('down') and self.boost > 1 and self.can_boost then self:onBoostStart() end
  634.     if input:released('down') then self:onBoostEnd() end
  635.     if input:down('down') and self.boost > 1 and self.can_boost then
  636.         self.boosting = true
  637.         if self.turner then self.boosting_down = true end
  638.         self.max_v = 0.5*self.base_max_v*(2-self.boost_effectiveness_multiplier)
  639.         self.boost = self.boost - 50*dt
  640.         if self.boost <= 1 then
  641.             self.boosting = false
  642.             if self.turner then self.boosting_down = false end
  643.             self.can_boost = false
  644.             self.boost_timer = 0
  645.             self:onBoostEnd()
  646.         end
  647.     end
  648.     self.trail_color = skill_point_color
  649.     if self.boosting then self.trail_color = boost_color end
  650.  
  651.     -- Shoot
  652.     self.shoot_timer = self.shoot_timer + dt
  653.     if self.shoot_timer > self.shoot_cooldown/self.aspd_multiplier.value then
  654.         self.shoot_timer = 0
  655.         self:shoot()
  656.     end
  657.  
  658.     -- Barrage
  659.     self.barrage_timer = self.barrage_timer + dt
  660.  
  661.     -- Protective Barrier
  662.     if self.protective_barrier > 10 then self.protective_barrier = 10 end
  663.  
  664.     -- Dash
  665.     if self.dasher and input:sequence('up', 0.5, 'up') then
  666.         if self.boost >= 50 then
  667.             local angle = Vector.angle(self.vx, self.vy)
  668.             local tx, ty = self.x + 64*math.cos(angle), self.y + 64*math.sin(angle)
  669.             self.shape:moveTo(tx, ty)
  670.             self:removeBoost(50)
  671.             self.invincible = true
  672.             self.timer:after('invincibility', 2*self.invulnerability_time_multiplier, function() self.invincible = false end)
  673.             for i = 1, math.floor(50*self.invulnerability_time_multiplier) do self.timer:after((i-1)*0.04, function() self.invisible = not self.invisible end) end
  674.             self.timer:after((math.floor(50*self.invulnerability_time_multiplier)+1)*0.04, function() self.invisible = false end)
  675.             for i = 1, 10 do
  676.                 self.timer:after(0.1*i, function() self.area:addGameObject('Explosion', self.x + random(-32, 32), self.y + random(-32, 32), {color = boost_color, damage_multiplier = 2}) end)
  677.             end
  678.         end
  679.     end
  680.  
  681.     -- Movement
  682.     if input:down('left') then self.r = self.r - (self.boosting_up and 1.5 or 1)*(self.boosting_down and 0.5 or 1)*self.turn_rate_multiplier*self.rv*dt end
  683.     if input:down('right') then self.r = self.r + (self.boosting_up and 1.5 or 1)*(self.boosting_down and 0.5 or 1)*self.turn_rate_multiplier*self.rv*dt end
  684.     self.v = math.min(self.v + self.a*dt, self.max_v*self.mvspd_multiplier.value)
  685.     self.vx, self.vy = self.v*math.cos(self.r), self.v*math.sin(self.r)
  686.  
  687.     -- Paused
  688.     if self.paused then self.vx, self.vy = 0, 0 end
  689.     if input:pressed('left') or input:pressed('right') or input:pressed('up') or input:pressed('down') then self.paused = false end
  690.  
  691.     -- Move
  692.     self.shape:move(self.vx*dt, self.vy*dt)
  693.     self.x, self.y = self.shape:center()
  694. end
  695.  
  696. function Player:draw()
  697.     if self.invisible then return end
  698.  
  699.     pushRotate(self.x, self.y, self.r)
  700.     love.graphics.setColor(default_color)
  701.     for _, vertice_group in ipairs(self.polygons) do
  702.         local points = fn.map(vertice_group, function(k, v) if k % 2 == 1 then return self.x + v + random(-1, 1) else return self.y + v + random(-1, 1) end end)
  703.         love.graphics.polygon('line', points)
  704.     end
  705.  
  706.     if self.protective_barrier > 0 then
  707.         for i = 1, self.protective_barrier do
  708.             love.graphics.circle('line', self.x - self.w/2, self.y, 2*self.w + i*4 + random(-1, 1))
  709.         end
  710.     end
  711.     love.graphics.pop()
  712. end
  713.  
  714. function Player:destroy()
  715.     Player.super.destroy(self)
  716. end
  717.  
  718. function Player:cycle()
  719.     self.area:addGameObject('CycleEffect', self.x, self.y, {parent = self})
  720.     self:onCycle()
  721. end
  722.  
  723. function Player:shoot()
  724.     if self.paused then return end
  725.  
  726.     local d = 1.2*self.w
  727.     self.area:addGameObject('ShootEffect', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {parent = self, d = d})
  728.  
  729.     if self.attack == 'Neutral' then
  730.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  731.  
  732.     elseif self.attack == 'Double' then
  733.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  734.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + math.pi/12), self.y + 1.5*d*math.sin(self.r + math.pi/12), {r = self.r + math.pi/12, attack = self.attack})
  735.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi/12), self.y + 1.5*d*math.sin(self.r - math.pi/12), {r = self.r - math.pi/12, attack = self.attack})
  736.  
  737.     elseif self.attack == 'Triple' then
  738.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  739.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  740.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + math.pi/12), self.y + 1.5*d*math.sin(self.r + math.pi/12), {r = self.r + math.pi/12, attack = self.attack})
  741.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi/12), self.y + 1.5*d*math.sin(self.r - math.pi/12), {r = self.r - math.pi/12, attack = self.attack})
  742.  
  743.     elseif self.attack == 'Rapid' then
  744.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  745.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  746.  
  747.     elseif self.attack == 'Spread' then
  748.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  749.         local random_angle = random(-math.pi/8, math.pi/8)
  750.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + random_angle), self.y + 1.5*d*math.sin(self.r + random_angle), {r = self.r + random_angle, attack = self.attack})
  751.  
  752.     elseif self.attack == 'Back' then
  753.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  754.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  755.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi), self.y + 1.5*d*math.sin(self.r - math.pi), {r = self.r - math.pi, attack = self.attack})
  756.  
  757.     elseif self.attack == 'Side' then
  758.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  759.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  760.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi/2), self.y + 1.5*d*math.sin(self.r - math.pi/2), {r = self.r - math.pi/2, attack = self.attack})
  761.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + math.pi/2), self.y + 1.5*d*math.sin(self.r + math.pi/2), {r = self.r + math.pi/2, attack = self.attack})
  762.  
  763.     elseif self.attack == 'Homing' then
  764.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  765.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  766.         if self.double_homing then self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack}) end
  767.  
  768.     elseif self.attack == 'Blast' then
  769.         playGameShoot2()
  770.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  771.         for i = 1, 12+self.additional_blast_projectile do
  772.             local random_angle = random(-math.pi/6, math.pi/6)
  773.             self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + random_angle), self.y + 1.5*d*math.sin(self.r + random_angle),
  774.             {r = self.r + random_angle, attack = self.attack, v = random(500, 600)})
  775.         end
  776.         camera:shake(2, 60, 0.2)
  777.  
  778.     elseif self.attack == 'Spin' then
  779.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  780.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack})
  781.  
  782.     elseif self.attack == 'Bounce' then
  783.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  784.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r, attack = self.attack, bounce = 4 + self.additional_bounce})
  785.  
  786.     elseif self.attack == 'Lightning' then
  787.         local x1, y1 = self.x + d*math.cos(self.r), self.y + d*math.sin(self.r)
  788.         local cx, cy = x1 + 24*math.cos(self.r), y1 + 24*math.sin(self.r)
  789.         local enemy_amount_to_attack = 1 + self.additional_lightning_bolt
  790.  
  791.         -- Find closest enemy
  792.         local nearby_enemies = self.area:getAllGameObjectsThat(function(e)
  793.             for _, enemy in ipairs(enemies) do
  794.                 if self.lightning_targets_projectiles then
  795.                     if (e:is(_G[enemy]) or e:is(EnemyProjectile)) and (distance(e.x, e.y, cx, cy) < 64*self.lightning_trigger_distance_multiplier) then
  796.                         return true
  797.                     end
  798.                 else
  799.                     if e:is(_G[enemy]) and (distance(e.x, e.y, cx, cy) < 64*self.lightning_trigger_distance_multiplier) then
  800.                         return true
  801.                     end
  802.                 end
  803.             end
  804.         end)
  805.         table.sort(nearby_enemies, function(a, b) return distance(a.x, a.y, cx, cy) < distance(b.x, b.y, cx, cy) end)
  806.         local closest_enemies = fn.first(nearby_enemies, enemy_amount_to_attack)
  807.  
  808.         -- Attack closest enemies
  809.         for i, closest_enemy in ipairs(closest_enemies) do
  810.             self.timer:after((i-1)*0.05, function()
  811.                 if closest_enemy then
  812.                     playGameLightning()
  813.                     if not closest_enemy:is(EnemyProjectile) then self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier end
  814.                     closest_enemy:hit()
  815.                     if closest_enemy.dead then self:onKill(closest_enemy) end
  816.                     local x2, y2 = closest_enemy.x, closest_enemy.y
  817.                     self.area:addGameObject('LightningLine', 0, 0, {x1 = x1, y1 = y1, x2 = x2, y2 = y2})
  818.                     for i = 1, love.math.random(4, 8) do self.area.room.explode_particles:add(x1, y1, nil, nil, table.random({default_color, boost_color})) end
  819.                     for i = 1, love.math.random(4, 8) do self.area.room.explode_particles:add(x2, y2, nil, nil, table.random({default_color, boost_color})) end
  820.                 end
  821.             end)
  822.         end
  823.  
  824.     elseif self.attack == 'Flame' then
  825.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  826.         local random_angle = random(-math.pi/16, math.pi/16)
  827.         self.area:addGameObject('Projectile', self.x + 2*d*math.cos(self.r + random_angle), self.y + 2*d*math.sin(self.r + random_angle), {r = self.r + random_angle, attack = self.attack, s = 2})
  828.  
  829.     elseif self.attack == '2Split' then
  830.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  831.         self.area:addGameObject('Projectile', self.x + 2*d*math.cos(self.r), self.y + 2*d*math.sin(self.r), {r = self.r, attack = self.attack})
  832.  
  833.     elseif self.attack == '4Split' then
  834.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  835.         self.area:addGameObject('Projectile', self.x + 2*d*math.cos(self.r), self.y + 2*d*math.sin(self.r), {r = self.r, attack = self.attack, s = 3})
  836.  
  837.     elseif self.attack == 'Explode' then
  838.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  839.         self.area:addGameObject('Projectile', self.x + 2*d*math.cos(self.r), self.y + 2*d*math.sin(self.r), {r = self.r, attack = self.attack, s = 3})
  840.  
  841.     elseif self.attack == 'Laser' then
  842.         playGameLaser()
  843.  
  844.         self.ammo = self.ammo - attacks[self.attack].ammo*self.ammo_consumption_multiplier
  845.         local x1 = self.x + d*math.cos(self.r)
  846.         local y1 = self.y + d*math.sin(self.r)
  847.         local x2 = self.x + 1024*math.cos(self.r)
  848.         local y2 = self.y + 1024*math.sin(self.r)
  849.  
  850.         self.area:addGameObject('ProjectileDeathEffect', x1, y1, {w = 6*self.laser_width_multiplier, attack = self.attack, color = hp_color, r = self.r + math.pi/4})
  851.         local wm = 1*self.laser_width_multiplier
  852.         local x1n, y1n, x2n, y2n = x1 + wm*16*math.cos(self.r - math.pi/2), y1 + wm*16*math.sin(self.r - math.pi/2), x1 + wm*16*math.cos(self.r + math.pi/2), y1 + wm*16*math.sin(self.r + math.pi/2)
  853.         local x3n, y3n, x4n, y4n = x2 + wm*16*math.cos(self.r - math.pi/2), y2 + wm*16*math.sin(self.r - math.pi/2), x2 + wm*16*math.cos(self.r + math.pi/2), y2 + wm*16*math.sin(self.r + math.pi/2)
  854.         self.area:addGameObject('LaserLine', 0, 0, {x1 = x1, y1 = y1, x2 = x2, y2 = y2, angle = self.r, wm = wm})
  855.         local objects = self.area:queryPolygonArea({x1n, y1n, x2n, y2n, x3n, y3n, x4n, y4n}, {'EnemyProjectile', unpack(enemies)})
  856.         for _, object in ipairs(objects) do
  857.             object:hit(1000)
  858.             if object.dead then self:onKill(object) end
  859.         end
  860.  
  861.         camera:shake(4, 60, 0.25)
  862.     end
  863.  
  864.     if self.chances.attack_twice_chance:next() then
  865.         self.timer:after(self.shoot_cooldown/2, function()
  866.             -- self.area:addGameObject('InfoText', self.x, self.y, {text = 'Double Attack!'})
  867.             self:shoot()
  868.         end)
  869.     end
  870.  
  871.     if self.chances.attack_from_sides_chance:next() then
  872.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi/2), self.y + 1.5*d*math.sin(self.r - math.pi/2), {r = self.r - math.pi/2, attack = self.attack})
  873.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + math.pi/2), self.y + 1.5*d*math.sin(self.r + math.pi/2), {r = self.r + math.pi/2, attack = self.attack})
  874.     end
  875.  
  876.     if self.chances.attack_from_back_chance:next() then
  877.         self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi), self.y + 1.5*d*math.sin(self.r - math.pi), {r = self.r - math.pi, attack = self.attack})
  878.     end
  879.  
  880.     if self.ammo <= 0 then
  881.         self:setAttack('Neutral')
  882.         self.ammo = self.max_ammo
  883.  
  884.         if self.change_attack_when_no_ammo then
  885.             self:setRandomAttack()
  886.         end
  887.  
  888.         if self.protective_barrier_when_no_ammo then
  889.             self.protective_barrier = self.protective_barrier + math.floor(self.max_ammo/50)
  890.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Protective Barrier!', color = default_color})
  891.         end
  892.     end
  893.  
  894.     if self.infinite_ammo then
  895.         self.ammo = self.max_ammo
  896.     end
  897. end
  898.  
  899. function Player:explode()
  900.     local w = 64*self.area_multiplier
  901.     self.area:addGameObject('ShockwaveDisplacement', self.x, self.y)
  902.  
  903.     local c = {-1, 1}
  904.     local d = {}
  905.     for _, i in ipairs(c) do
  906.         for _, j in ipairs(c) do
  907.             table.insert(d, {i, j})
  908.         end
  909.     end
  910.     for _, c in ipairs(d) do self.timer:after(random(0.1, 0.2), function() self.area:addGameObject('Explosion', self.x + c[1]*w/2, self.y + c[2]*w/2, {color = hp_color, w = w}) end) end
  911.  
  912.     local c = {-2, -1, 1, 2}
  913.     local d = {}
  914.     for _, i in ipairs(c) do
  915.         for _, j in ipairs(c) do
  916.             if math.abs(i) == 2 or math.abs(j) == 2 then
  917.                 table.insert(d, {i, j})
  918.             end
  919.         end
  920.     end
  921.     for _, c in ipairs(d) do self.timer:after(random(0.2, 0.3), function() self.area:addGameObject('Explosion', self.x + c[1]*w/2, self.y + c[2]*w/2, {color = hp_color, w = w}) end) end
  922.  
  923.     if self.lesser_increased_self_explosion_size and self.greater_increased_self_explosion_size then
  924.         local c = {-3, -2, -1, 1, 2, 3}
  925.         local d = {}
  926.         for _, i in ipairs(c) do
  927.             for _, j in ipairs(c) do
  928.                 if math.abs(i) == 3 or math.abs(j) == 3 then
  929.                     table.insert(d, {i, j})
  930.                 end
  931.             end
  932.         end
  933.         for _, c in ipairs(d) do self.timer:after(random(0.3, 0.4), function() self.area:addGameObject('Explosion', self.x + c[1]*w/2, self.y + c[2]*w/2, {color = hp_color, w = w}) end) end
  934.  
  935.         local c = {-4, -3, -2, -1, 1, 2, 3, 4}
  936.         local d = {}
  937.         for _, i in ipairs(c) do
  938.             for _, j in ipairs(c) do
  939.                 if math.abs(i) == 4 or math.abs(j) == 4 then
  940.                     table.insert(d, {i, j})
  941.                 end
  942.             end
  943.         end
  944.         for _, c in ipairs(d) do self.timer:after(random(0.4, 0.5), function() self.area:addGameObject('Explosion', self.x + c[1]*w/2, self.y + c[2]*w/2, {color = hp_color, w = w}) end) end
  945.  
  946.     elseif self.lesser_increased_self_explosion_size and not self.greater_increased_self_explosion_size then
  947.         local c = {-3, -2, -1, 1, 2, 3}
  948.         local d = {}
  949.         for _, i in ipairs(c) do
  950.             for _, j in ipairs(c) do
  951.                 if math.abs(i) == 3 or math.abs(j) == 3 then
  952.                     table.insert(d, {i, j})
  953.                 end
  954.             end
  955.         end
  956.         for _, c in ipairs(d) do self.timer:after(random(0.3, 0.4), function() self.area:addGameObject('Explosion', self.x + c[1]*w/2, self.y + c[2]*w/2, {color = hp_color, w = w}) end) end
  957.     end
  958. end
  959.  
  960. function Player:setAttack(attack)
  961.     self.attack = attack
  962.     self.shoot_cooldown = attacks[attack].cooldown
  963.     self.ammo = self.max_ammo
  964.  
  965.     if self.gain_stat_boost_on_attack_change then self:grantRandomBuff() end
  966. end
  967.  
  968. function Player:setRandomAttack()
  969.     local all_attacks = fn.keys(attacks)
  970.     repeat self.attack = all_attacks[love.math.random(1, #all_attacks)] until self.attack ~= 'Neutral'
  971.     self.shoot_cooldown = attacks[self.attack].cooldown
  972.     self.ammo = self.max_ammo
  973.  
  974.     if self.gain_stat_boost_on_attack_change then self:grantRandomBuff() end
  975. end
  976.  
  977. function Player:grantRandomBuff()
  978.     local buff = table.random({'ASPD', 'MVSPD', 'Cycle', 'PSPD'})
  979.  
  980.     if buff == 'ASPD' then
  981.         self.aspd_boosting = true
  982.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.aspd_boosting = false end)
  983.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'ASPD Boost!', color = ammo_color})
  984.  
  985.     elseif buff == 'MVPSD' then
  986.         self.mvspd_boosting = true
  987.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.mvspd_boosting = false end)
  988.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'MVSPD Boost!'})
  989.  
  990.     elseif buff == 'Cycle' then
  991.         self.cycle_boosting = true
  992.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.cycle_boosting = false end)
  993.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Cycle Boost!'})
  994.  
  995.     elseif buff == 'PSPD' then
  996.         self.pspd_boosting = true
  997.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.pspd_boosting = false end)
  998.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'PSPD Boost!'})
  999.     end
  1000. end
  1001.  
  1002. function Player:hit(damage, hit_type)
  1003.     if self.invincible then return end
  1004.     hit_type = hit_type or 'Enemy'
  1005.     damage = damage or 10
  1006.  
  1007.     if self.absorb_hits then
  1008.         if hit_type == 'Projectile' then
  1009.             if self.boost > 25 then
  1010.                 self:removeBoost(25)
  1011.                 camera:shake(1, 60, 0.2)
  1012.                 flash(1)
  1013.                 self.area:addGameObject('InfoText', self.x, self.y, {text = 'Projectile Absorbed!', color = boost_color})
  1014.                 return
  1015.             end
  1016.         elseif hit_type == 'Enemy' then
  1017.             if self.boost > 50 then
  1018.                 self:removeBoost(50)
  1019.                 camera:shake(2, 60, 0.2)
  1020.                 flash(2)
  1021.                 self.invincible = true
  1022.                 self.timer:after('invincibility', 1*self.invulnerability_time_multiplier, function() self.invincible = false end)
  1023.                 for i = 1, math.floor(25*self.invulnerability_time_multiplier) do self.timer:after((i-1)*0.04, function() self.invisible = not self.invisible end) end
  1024.                 self.timer:after((math.floor(25*self.invulnerability_time_multiplier)+1)*0.04, function() self.invisible = false end)
  1025.                 self.area:addGameObject('InfoText', self.x, self.y, {text = 'Hit Absorbed!', color = boost_color})
  1026.                 return
  1027.             end
  1028.         end
  1029.     end
  1030.  
  1031.     if self.protective_barrier > 0 then
  1032.         self.protective_barrier = self.protective_barrier - 1
  1033.         camera:shake(1, 60, 0.2)
  1034.         flash(1)
  1035.         return
  1036.     end
  1037.  
  1038.     if self.energy_shield then
  1039.         damage = damage*2
  1040.         self.timer:after('energy_shield_recharge_cooldown', self.energy_shield_recharge_cooldown/self.energy_shield_recharge_cooldown_multiplier, function()
  1041.             self.timer:every('energy_shield_recharge_amount', 0.25, function()
  1042.                 self:addHP(self.energy_shield_recharge_amount*self.energy_shield_recharge_amount_multiplier)
  1043.             end)
  1044.         end)
  1045.     end
  1046.  
  1047.     for i = 1, love.math.random(4, 8) do self.area.room.explode_particles:add(self.x, self.y) end
  1048.     self:removeHP(damage)
  1049.     playGameHurt()
  1050.  
  1051.     if damage >= 30 then
  1052.         self.invincible = true
  1053.         self.timer:after('invincibility', 2*self.invulnerability_time_multiplier, function() self.invincible = false end)
  1054.         for i = 1, math.floor(50*self.invulnerability_time_multiplier) do self.timer:after((i-1)*0.04, function() self.invisible = not self.invisible end) end
  1055.         self.timer:after((math.floor(50*self.invulnerability_time_multiplier)+1)*0.04, function() self.invisible = false end)
  1056.  
  1057.         camera:shake(6, 60, 0.2)
  1058.         flash(3)
  1059.         slow(0.25/self.invulnerability_time_multiplier, 1.0)
  1060.         current_room:rgbShift()
  1061.     else
  1062.         camera:shake(3, 60, 0.1)
  1063.         flash(2)
  1064.         slow(0.75/self.invulnerability_time_multiplier, 0.5)
  1065.         current_room:rgbShift()
  1066.     end
  1067. end
  1068.  
  1069. function Player:bounce(bx, by)
  1070.    
  1071. end
  1072.  
  1073. function Player:die()
  1074.     self.dead = true
  1075.     flash(4)
  1076.     camera:shake(6, 60, 0.4)
  1077.     slow(0.15/self.invulnerability_time_multiplier, 1.5)
  1078.     for i = 1, love.math.random(8, 12) do self.area.room.explode_particles:add(self.x, self.y) end
  1079.  
  1080.     if self.gain_sp_on_death then
  1081.         self:addSP(3)
  1082.         self.area:addGameObject('InfoText', self.x, self.y, {text = '+3 SP', color = skill_point_color})
  1083.     end
  1084.  
  1085.     current_room:finish()
  1086. end
  1087.  
  1088. function Player:addAmmo(amount)
  1089.     if self.ammo_gives_boost then self.boost = math.min(self.boost + 2, self.max_boost)
  1090.     else self.ammo = math.min(self.ammo + amount + self.ammo_gain, self.max_ammo) end
  1091.  
  1092.     current_room.score = current_room.score + 50
  1093. end
  1094.  
  1095. function Player:addBoost(amount)
  1096.     self.boost = math.min(self.boost + amount, self.max_boost)
  1097.     current_room.score = current_room.score + 150  
  1098. end
  1099.  
  1100. function Player:removeBoost(amount)
  1101.     self.boost = self.boost - (amount or 1)
  1102.     if self.boost < 0 then self.boost = 0 end
  1103. end
  1104.  
  1105. function Player:addSP(amount)
  1106.     local multiplier = 1
  1107.     if loop <= 1 then multiplier = 2 end
  1108.  
  1109.     if self.chances.gain_double_sp_chance:next() then
  1110.         skill_points = skill_points + multiplier*2*amount
  1111.         current_room.score = current_room.score + 500
  1112.         self.area:addGameObject('InfoText', self.x, self.y, {text = '+1 SP', color = skill_point_color})
  1113.     else
  1114.         skill_points = skill_points + multiplier*amount
  1115.         current_room.score = current_room.score + 250
  1116.     end
  1117. end
  1118.  
  1119. function Player:addHP(amount)
  1120.     self.hp = math.min(self.hp + amount, self.max_hp)
  1121. end
  1122.  
  1123. function Player:removeHP(amount)
  1124.     self.hp = self.hp - (amount or 5)
  1125.     if self.hp <= 0 then
  1126.         self.hp = 0
  1127.         self:die()
  1128.     end
  1129. end
  1130.  
  1131. function Player:onItemPickup()
  1132.     if self.item_restores_hp then
  1133.         self:addHP(math.floor(self.max_hp/4))
  1134.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'RESTORED 25 HP!', color = hp_color})
  1135.     end
  1136.  
  1137.     if self.chances.launch_homing_projectile_on_item_pickup_chance:next() and not self.cant_launch_homing_projectiles then
  1138.         local d = 1.2*self.w
  1139.         for i = 1, 1+self.additional_homing_projectile do
  1140.             self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1141.         end
  1142.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1143.     end
  1144.  
  1145.     if self.chances.regain_hp_on_item_pickup_chance:next() then
  1146.         self:addHP(math.floor(self.max_hp/4))
  1147.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'HP Regain!', color = hp_color})
  1148.     end
  1149.  
  1150.     if self.chances.spawn_haste_area_on_item_pickup_chance:next() then
  1151.         self.area:addGameObject('HasteArea', self.x, self.y)
  1152.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Haste Area!'})
  1153.     end
  1154. end
  1155.  
  1156. function Player:onSPPickup()
  1157.     if self.chances.regain_hp_on_sp_pickup_chance:next() then
  1158.         self:addHP(math.floor(self.max_hp/4))
  1159.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'HP Regain!', color = hp_color})
  1160.     end
  1161.  
  1162.     if self.chances.spawn_haste_area_on_sp_pickup_chance:next() then
  1163.         self.area:addGameObject('HasteArea', self.x, self.y)
  1164.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Haste Area!'})
  1165.     end
  1166. end
  1167.  
  1168. function Player:onHPPickup()
  1169.     if self.chances.spawn_haste_area_on_hp_pickup_chance:next() then
  1170.         self.area:addGameObject('HasteArea', self.x, self.y)
  1171.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Haste Area!'})
  1172.     end
  1173.  
  1174.     if self.convert_hp_to_sp_if_hp_full then
  1175.         if self.hp >= self.max_hp then
  1176.             self:addSP(3)
  1177.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'HP -> SP!'})
  1178.         end
  1179.     end
  1180.  
  1181.     if self.refill_ammo_if_hp_full then
  1182.         if self.hp >= self.max_hp then
  1183.             self.ammo = self.max_ammo
  1184.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Ammo Refill!'})
  1185.         end
  1186.     end
  1187.  
  1188.     if self.refill_boost_if_hp_full then
  1189.         if self.hp >= self.max_hp then
  1190.             self.boost = self.max_boost
  1191.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Boost Refill!'})
  1192.         end
  1193.     end
  1194. end
  1195.  
  1196. function Player:onAmmoPickup()
  1197. end
  1198.  
  1199. function Player:onCycle()
  1200.     if self.cant_trigger_on_cycle_events then return end
  1201.  
  1202.     if self.chances.spawn_sp_on_cycle_chance:next() then
  1203.         self.area:addGameObject('SkillPoint')
  1204.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'SP Spawn!', color = skill_point_color})
  1205.     end
  1206.  
  1207.     if self.chances.spawn_hp_on_cycle_chance:next() then
  1208.         self.area:addGameObject('HP')
  1209.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'HP Spawn!', color = hp_color})
  1210.     end
  1211.  
  1212.     if self.chances.regain_hp_on_cycle_chance:next() then
  1213.         self:addHP(math.floor(self.max_hp/4))
  1214.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'HP Regain!', color = hp_color})
  1215.     end
  1216.  
  1217.     if self.chances.regain_full_ammo_on_cycle_chance:next() then
  1218.         self:addAmmo(self.max_ammo)
  1219.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Full Ammo Regain!', color = ammo_color})
  1220.     end
  1221.  
  1222.     if self.chances.change_attack_on_cycle_chance:next() then
  1223.         self:setRandomAttack()
  1224.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Random Attack!'})
  1225.     end
  1226.  
  1227.     if self.chances.spawn_haste_area_on_cycle_chance:next() then
  1228.         self.area:addGameObject('HasteArea', self.x, self.y)
  1229.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Haste Area!'})
  1230.     end
  1231.  
  1232.     if self.chances.barrage_on_cycle_chance:next() and not self.cant_barrage then
  1233.         self:barrage()
  1234.     end
  1235.  
  1236.     if self.chances.launch_homing_projectile_on_cycle_chance:next() and not self.cant_launch_homing_projectiles then
  1237.         local d = 1.2*self.w
  1238.         for i = 1, 1+self.additional_homing_projectile do
  1239.             self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1240.         end
  1241.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1242.     end
  1243.  
  1244.     if self.chances.gain_mvspd_boost_on_cycle_chance:next() then
  1245.         self.mvspd_boosting = true
  1246.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.mvspd_boosting = false end)
  1247.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'MVSPD Boost!'})
  1248.     end
  1249.  
  1250.     if self.chances.gain_pspd_boost_on_cycle_chance:next() then
  1251.         self.pspd_boosting = true
  1252.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.pspd_boosting = false end)
  1253.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'PSPD Boost!'})
  1254.     end
  1255.  
  1256.     if self.chances.gain_pspd_inhibit_on_cycle_chance:next() then
  1257.         self.pspd_inhibiting = true
  1258.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.pspd_inhibiting = false end)
  1259.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'PSPD Inhibit!'})
  1260.     end
  1261.  
  1262.     if self.chances.self_explode_on_cycle_chance:next() then
  1263.         self:explode()
  1264.     end
  1265. end
  1266.  
  1267. function Player:onKill(enemy)
  1268.     if self.rampage then
  1269.         self.rampage_counter = self.rampage_counter + 1
  1270.         self.rampage_timer = 0
  1271.  
  1272.         if self.rampage_counter == 15 then
  1273.             -- Barrage
  1274.             self:barrage()
  1275.  
  1276.         elseif self.rampage_counter == 30 then
  1277.             -- Launch 8 Homing Projectiles
  1278.             local d = 1.2*self.w
  1279.             for i = 1, 8 do
  1280.                 self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1281.             end
  1282.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1283.  
  1284.         elseif self.rampage_counter == 45 then
  1285.             -- 2 Barrage Novas
  1286.             for j = 1, 2 do
  1287.                 self.timer:after((j-1)*1, function()
  1288.                     self:barrage(true)
  1289.                 end)
  1290.             end
  1291.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Barrage Nova!!!'})
  1292.  
  1293.         elseif self.rampage_counter == 70 then
  1294.             -- +5 Protective Barrier
  1295.             self.protective_barrier = self.protective_barrier + 5
  1296.  
  1297.         elseif self.rampage_counter == 100 then
  1298.             -- +2 SP
  1299.             self:addSP(1)
  1300.             self.area:addGameObject('InfoText', self.x, self.y, {text = '+1 SP', color = skill_point_color})
  1301.  
  1302.         elseif self.rampage_counter == 130 then
  1303.             -- 5 Barrage Novas
  1304.             for j = 1, 5 do
  1305.                 self.timer:after((j-1)*1, function()
  1306.                     self:barrage(true)
  1307.                 end)
  1308.             end
  1309.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Barrage Nova!!!'})
  1310.  
  1311.         elseif self.rampage_counter == 170 then
  1312.             local ammos = self.area:getAllGameObjectsThat(function(e) return e:is(Ammo) end)
  1313.             local n = math.floor(#ammos/5)
  1314.             for i = 1, n do
  1315.                 local ammo = table.remove(ammos, love.math.random(1, #ammos))
  1316.                 if ammo then
  1317.                     ammo:die()
  1318.                     local d = 1.2*self.w
  1319.                     self.area:addGameObject('Projectile', ammo.x - d*math.cos(self.r), ammo.y - d*math.sin(self.r),
  1320.                     {r = self.r, rv = table.random({random(-12*math.pi, -10*math.pi), random(10*math.pi, 12*math.pi)}), mine = true, attack = self.attack})
  1321.                 end
  1322.             end
  1323.  
  1324.         elseif self.rampage_counter == 200 then
  1325.             -- +2 SP
  1326.             self:addSP(2)
  1327.             self.area:addGameObject('InfoText', self.x, self.y, {text = '+2 SP', color = skill_point_color})
  1328.  
  1329.         elseif self.rampage_counter == 240 then
  1330.             -- Launch 24 homing projectiles
  1331.             local d = 1.2*self.w
  1332.             for i = 1, 24 do
  1333.                 self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1334.             end
  1335.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1336.  
  1337.         elseif self.rampage_counter == 280 then
  1338.             -- Cast lightning attack on all enemies
  1339.             local d = 1.2*self.w
  1340.             local x1, y1 = self.x + d*math.cos(self.r), self.y + d*math.sin(self.r)
  1341.             local cx, cy = x1 + 24*math.cos(self.r), y1 + 24*math.sin(self.r)
  1342.             local enemies = self.area:getAllGameObjectsThat(function(e)
  1343.                 for _, enemy in ipairs(enemies) do
  1344.                     if e:is(_G[enemy]) then
  1345.                         return true
  1346.                     end
  1347.                 end
  1348.             end)
  1349.             for i, enemy in ipairs(enemies) do
  1350.                 self.timer:after((i-1)*0.05, function()
  1351.                     if enemy then
  1352.                         enemy:hit()
  1353.                         local x2, y2 = enemy.x, enemy.y
  1354.                         self.area:addGameObject('LightningLine', 0, 0, {x1 = x1, y1 = y1, x2 = x2, y2 = y2})
  1355.                         for i = 1, love.math.random(4, 8) do self.area.room.explode_particles:add(x1, y1, nil, nil, table.random({default_color, boost_color})) end
  1356.                         for i = 1, love.math.random(4, 8) do self.area.room.explode_particles:add(x2, y2, nil, nil, table.random({default_color, boost_color})) end
  1357.                     end
  1358.                 end)
  1359.             end
  1360.  
  1361.         elseif self.rampage_counter == 330 then
  1362.             -- +2 SP
  1363.             self:addSP(2)
  1364.             self.area:addGameObject('InfoText', self.x, self.y, {text = '+2 SP', color = skill_point_color})
  1365.  
  1366.         elseif self.rampage_counter == 380 then
  1367.             -- 20 Barrage Novas
  1368.             for j = 1, 20 do
  1369.                 self.timer:after((j-1)*1, function()
  1370.                     self:barrage(true)
  1371.                 end)
  1372.             end
  1373.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Barrage Nova!!!'})
  1374.  
  1375.         elseif self.rampage_counter == 440 then
  1376.             -- +10 Protective Barrier
  1377.             self.protective_barrier = self.protective_barrier + 10
  1378.  
  1379.         elseif self.rampage_counter == 500 then
  1380.             -- +4 SP
  1381.             self:addSP(4)
  1382.             self.area:addGameObject('InfoText', self.x, self.y, {text = '+4 SP', color = skill_point_color})
  1383.         end
  1384.     end
  1385.  
  1386.     if self.chances.barrage_on_kill_chance:next() and not self.cant_barrage then
  1387.         self:barrage()
  1388.     end
  1389.  
  1390.     if self.chances.gain_aspd_boost_on_kill_chance:next() then
  1391.         self.aspd_boosting = true
  1392.         self.timer:after(4*self.stat_boost_duration_multiplier, function() self.aspd_boosting = false end)
  1393.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'ASPD Boost!', color = ammo_color})
  1394.     end
  1395.  
  1396.     if self.chances.regain_ammo_on_kill_chance:next() then
  1397.         self:addAmmo(20)
  1398.     end
  1399.  
  1400.     if self.chances.launch_homing_projectile_on_kill_chance:next() and not self.cant_launch_homing_projectiles then
  1401.         local d = 1.2*self.w
  1402.         for i = 1, 1+self.additional_homing_projectile do
  1403.             self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1404.         end
  1405.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1406.     end
  1407.  
  1408.     if self.chances.regain_boost_on_kill_chance:next() then
  1409.         self:addBoost(math.floor(self.max_boost/4))
  1410.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Boost Regain!', color = boost_color})
  1411.     end
  1412.  
  1413.     if self.chances.spawn_boost_on_kill_chance:next() then
  1414.         self.area:addGameObject('Boost')
  1415.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Boost Spawn!', color = boost_color})
  1416.     end
  1417.  
  1418.     if self.chances.drop_double_ammo_chance:next() then
  1419.         self.area:addGameObject('Ammo', enemy.x, enemy.y)
  1420.         self.area:addGameObject('InfoText', self.x, self.y, {text = 'Double Ammo!', color = ammo_color})
  1421.     end
  1422. end
  1423.  
  1424. function Player:onBoostStart()
  1425.     self.timer:every('launch_homing_projectile_while_boosting_chance', 0.2, function()
  1426.         if self.chances.launch_homing_projectile_while_boosting_chance:next() and not self.cant_launch_homing_projectiles then
  1427.             local d = 1.2*self.w
  1428.             for i = 1, 1+self.additional_homing_projectile do
  1429.                 self.area:addGameObject('Projectile', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {r = self.r, attack = 'Homing', damage_multiplier = 2})
  1430.             end
  1431.             self.area:addGameObject('InfoText', self.x, self.y, {text = 'Homing Projectile!'})
  1432.         end
  1433.     end)
  1434.  
  1435.     if self.increased_luck_while_boosting then
  1436.         self.luck_boosting = true
  1437.         self.luck_multiplier = self.luck_multiplier*2
  1438.         self:generateChances()
  1439.     end
  1440.  
  1441.     if self.increased_cycle_speed_while_boosting then
  1442.         self.cycle_boosting = true
  1443.     end
  1444.  
  1445.     if self.invulnerability_while_boosting then
  1446.         self.invincible = true
  1447.         self.timer:every('invulnerability_while_boosting', 0.04, function() self.invisible = not self.invisible end)
  1448.     end
  1449. end
  1450.  
  1451. function Player:onBoostEnd()
  1452.     self.timer:cancel('launch_homing_projectile_while_boosting_chance')
  1453.  
  1454.     if self.increased_luck_while_boosting then
  1455.         self.luck_boosting = false
  1456.         self.luck_multiplier = self.luck_multiplier/2
  1457.         self:generateChances()
  1458.     end
  1459.  
  1460.     if self.increased_cycle_speed_while_boosting then
  1461.         self.cycle_boosting = false
  1462.     end
  1463.  
  1464.     if self.invulnerability_while_boosting then
  1465.         self.invincible = false
  1466.         self.invisible = false
  1467.         self.timer:cancel('invulnerability_while_boosting')
  1468.     end
  1469. end
  1470.  
  1471. function Player:insertSapper(id)
  1472.     if not self.sappers[id] then
  1473.         local sap_type = table.random({'ASPD', 'PSPD', 'MVSPD', 'Cycle'})
  1474.         self.sappers[id] = sap_type
  1475.         if sap_type == 'ASPD' then self.area:addGameObject('InfoText', self.x, self.y, {text = 'ASPD Decrease!'})
  1476.         elseif sap_type == 'PSPD' then self.area:addGameObject('InfoText', self.x, self.y, {text = 'PSPD Decrease!'})
  1477.         elseif sap_type == 'MVSPD' then self.area:addGameObject('InfoText', self.x, self.y, {text = 'MVSPD Decrease!'})
  1478.         elseif sap_type == 'Cycle' then self.area:addGameObject('InfoText', self.x, self.y, {text = 'Cycle Decrease!'}) end
  1479.     end
  1480. end
  1481.  
  1482. function Player:removeSapper(id)
  1483.     self.sappers[id] = nil
  1484. end
  1485.  
  1486. function Player:barrage(barrage_nova)
  1487.     if self.barrage_timer < self.barrage_cooldown then return end
  1488.     self.barrage_timer = 0
  1489.  
  1490.     for i = 1, 8+self.additional_barrage_projectile do
  1491.         self.timer:after((i-1)*0.05, function()
  1492.             local random_angle = random(-math.pi/8, math.pi/8)
  1493.             if self.barrage_nova or barrage_nova then random_angle = random(0, 2*math.pi) end
  1494.             local d = 2.2*self.w
  1495.             self.area:addGameObject('Projectile', self.x + d*math.cos(self.r + random_angle), self.y + d*math.sin(self.r + random_angle),
  1496.             {r = self.r + random_angle, attack = self.attack, damage_multiplier = 0.5})
  1497.         end)
  1498.     end
  1499.     self.area:addGameObject('InfoText', self.x, self.y, {text = 'Barrage!!!'})
  1500. end
  1501.  
  1502. function Player:setStats()
  1503.     -- Conversions
  1504.     if self.mvspd_to_hp > 0 then
  1505.         if self.mvspd_multiplier.value < 1 then
  1506.             self.flat_hp = self.flat_hp + self.mvspd_multiplier.value*self.mvspd_to_hp
  1507.         end
  1508.     end
  1509.  
  1510.     -- Basic stats
  1511.     self.max_hp = (self.max_hp + self.flat_hp)*self.hp_multiplier
  1512.     self.hp = self.max_hp
  1513.     self.max_ammo = (self.max_ammo + self.flat_ammo)*self.ammo_multiplier
  1514.     self.ammo = self.max_ammo
  1515.     self.max_boost = (self.max_boost + self.flat_boost)*self.boost_multiplier
  1516.     self.boost = self.max_boost
  1517.  
  1518.     -- Start with attack
  1519.     local starting_attacks = {
  1520.         self.start_with_double and 'Double', self.start_with_triple and 'Triple', self.start_with_rapid and 'Rapid', self.start_with_spread and 'Spread', self.start_with_back and 'Back',
  1521.         self.start_with_side and 'Side', self.start_with_homing and 'Homing', self.start_with_blast and 'Blast', self.start_with_spin and 'Spin', self.start_with_lightning and 'Lightning',
  1522.         self.start_with_flame and 'Flame', self.start_with_2split and '2Split', self.start_with_4split and '4Split', self.start_with_explode and 'Explode', self.start_with_laser and 'Laser',
  1523.     }
  1524.     starting_attacks = fn.select(starting_attacks, function(k, v) return v end)
  1525.     if #starting_attacks > 0 then self:setAttack(table.random(starting_attacks)) end
  1526.  
  1527.     -- Passives
  1528.     if self.energy_shield then
  1529.         self.invulnerability_time_multiplier = self.invulnerability_time_multiplier/2
  1530.     end
  1531.  
  1532.     if self.no_boost then
  1533.         self.max_boost = 0
  1534.         self.boost = self.max_boost
  1535.     end
  1536.  
  1537.     if self.half_ammo then
  1538.         self.max_ammo = math.ceil(self.max_ammo/2)
  1539.         self.ammo = self.max_ammo
  1540.     end
  1541.  
  1542.     if self.half_hp then
  1543.         self.max_hp = math.ceil(self.max_hp/2)
  1544.         self.hp = self.max_hp
  1545.     end
  1546.  
  1547.     if self.projectile_waviness_multiplier > 1 then self.wavy_projectiles = true end
  1548.     if self.pspd_multiplier.value < 0 then self.pspd_multiplier.base = 0 end
  1549. end
  1550.  
  1551. function Player:setClass(class)
  1552.     local classes = {}
  1553.     classes[class] = true
  1554.  
  1555.     if classes.cycler then
  1556.         self.luck_multiplier = self.luck_multiplier + 0.25
  1557.         self.cycle_multiplier = Stat(self.cycle_multiplier.value + 0.25)
  1558.     end
  1559.  
  1560.     if classes.tanker then
  1561.         self.max_hp = math.floor(self.max_hp*1.25)
  1562.         self.hp = self.max_hp
  1563.         self.max_ammo = math.floor(self.max_ammo*1.25)
  1564.         self.ammo = self.max_ammo
  1565.     end
  1566.  
  1567.     if classes.gunner then
  1568.         self.aspd_multiplier = Stat(self.aspd_multiplier.value + 0.15)
  1569.         self.pspd_multiplier = Stat(self.pspd_multiplier.value + 0.25)
  1570.     end
  1571.  
  1572.     if classes.runner then
  1573.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value + 0.25)
  1574.         self.max_boost = math.floor(self.max_boost*1.25)
  1575.         self.boost = self.max_boost
  1576.     end
  1577.  
  1578.     if classes.swapper then
  1579.         self.gain_stat_boost_on_attack_change = true
  1580.         self.max_hp = math.floor(self.max_hp*0.90)
  1581.         self.hp = self.max_hp
  1582.         self.max_ammo = math.floor(self.max_ammo*0.90)
  1583.         self.ammo = self.max_ammo
  1584.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.1)
  1585.         self.pspd_multiplier = Stat(self.pspd_multiplier.value - 0.1)
  1586.     end
  1587.  
  1588.     if classes.barrager then
  1589.         self.barrage_on_kill_chance = self.barrage_on_kill_chance + 5
  1590.         self.barrage_on_cycle_chance = self.barrage_on_cycle_chance + 10
  1591.         self.additional_barrage_projectile = self.additional_barrage_projectile + 2
  1592.         self.cant_launch_homing_projectiles = true
  1593.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1594.     end
  1595.  
  1596.     if classes.seeker then
  1597.         self.launch_homing_projectile_on_kill_chance = self.launch_homing_projectile_on_kill_chance + 10
  1598.         self.launch_homing_projectile_on_cycle_chance = self.launch_homing_projectile_on_cycle_chance + 5
  1599.         self.additional_homing_projectile = self.additional_homing_projectile + 1
  1600.         self.cant_barrage = true
  1601.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1602.     end
  1603.  
  1604.     if classes.shielder then
  1605.         self.shield_projectile_chance = self.shield_projectile_chance + 25
  1606.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1607.         self.shield_projectile_damage_multiplier = 0.75
  1608.     end
  1609.  
  1610.     if classes.regeneer then
  1611.         self.item_restores_hp = true
  1612.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.25)
  1613.     end
  1614.  
  1615.     if classes.recycler then
  1616.         self.protective_barrier_when_no_ammo = true
  1617.         self.ammo_consumption_multiplier = self.ammo_consumption_multiplier + 0.5
  1618.     end
  1619.  
  1620.     if classes.buster then
  1621.         self.projectile_size_multiplier = self.projectile_size_multiplier + 0.5
  1622.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1623.         self.max_hp = math.floor(self.max_hp*0.85)
  1624.         self.hp = self.max_hp
  1625.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.15)
  1626.     end
  1627.  
  1628.     if classes.buffer then
  1629.         self.stat_boost_duration_multiplier = self.stat_boost_duration_multiplier + 0.5
  1630.         self.max_boost = math.floor(self.max_boost*0.80)
  1631.         self.boost = self.max_boost
  1632.     end
  1633.  
  1634.     if classes.berserker then
  1635.         self.rampage = true
  1636.         self.luck_multiplier = self.luck_multiplier - 0.25
  1637.     end
  1638.  
  1639.     if classes.absorber then
  1640.         self.absorb_hits = true
  1641.     end
  1642.  
  1643.     if classes.turner then
  1644.  
  1645.     end
  1646.  
  1647.     if classes.driver then
  1648.         self.invulnerability_time_multiplier = self.invulnerability_time_multiplier + 0.3
  1649.         self.boost_recharge_rate_multiplier = self.boost_recharge_rate_multiplier + 0.3
  1650.         self.size_multiplier = self.size_multiplier + 0.3
  1651.     end
  1652.  
  1653.     if classes.processor then
  1654.         self.cycle_multiplier = Stat(self.cycle_multiplier.value + 0.5)
  1655.         self.max_hp = math.floor(self.max_hp*0.75)
  1656.         self.hp = self.max_hp
  1657.         self.sp_spawn_chance_multiplier = self.sp_spawn_chance_multiplier - 0.5
  1658.     end
  1659.  
  1660.     if classes.gambler then
  1661.         self.luck_multiplier = self.luck_multiplier + 0.5
  1662.         self.cant_trigger_on_cycle_events = true
  1663.     end
  1664.  
  1665.     if classes.panzer then
  1666.         self.max_hp = math.floor(self.max_hp*1.5)
  1667.         self.hp = self.max_hp
  1668.         self.size_multiplier = self.size_multiplier + 0.5
  1669.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.25)
  1670.     end
  1671.  
  1672.     if classes.reserver then
  1673.         self.max_ammo = math.floor(self.max_ammo*1.5)
  1674.         self.ammo = self.max_ammo
  1675.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1676.         self.change_attack_when_no_ammo = true
  1677.     end
  1678.  
  1679.     if classes.repeater then
  1680.         self.aspd_multiplier = Stat(self.aspd_multiplier.value + 0.5)
  1681.         self.damage_multiplier = 0.75
  1682.     end
  1683.  
  1684.     if classes.launcher then
  1685.         self.pspd_multiplier = Stat(self.pspd_multiplier.value + 0.75)
  1686.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1687.         self.max_hp = math.floor(self.max_hp*0.8)
  1688.         self.hp = self.max_hp
  1689.         self.max_ammo = math.floor(self.max_ammo*0.8)
  1690.         self.ammo = self.max_ammo
  1691.     end
  1692.  
  1693.     if classes.deployer then
  1694.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value + 0.25)
  1695.         self.size_multiplier = self.size_multiplier - 0.25
  1696.         self.drop_mines_chance = self.drop_mines_chance + 15
  1697.     end
  1698.  
  1699.     if classes.booster then
  1700.         self.max_boost = math.floor(self.max_boost*1.5)
  1701.         self.boost = self.max_boost
  1702.         self.luck_multiplier = self.luck_multiplier - 0.25
  1703.         self.max_ammo = math.floor(self.max_ammo*0.75)
  1704.         self.ammo = self.max_ammo
  1705.     end
  1706.  
  1707.     if classes.piercer then
  1708.         self.projectile_pierce = self.projectile_pierce + 2
  1709.         self.max_hp = math.floor(self.max_hp*0.85)
  1710.         self.hp = self.max_hp
  1711.         self.max_ammo = math.floor(self.max_ammo*0.85)
  1712.         self.ammo = self.max_ammo
  1713.         self.max_boost = math.floor(self.max_boost*0.85)
  1714.         self.boost = self.max_boost
  1715.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.15)
  1716.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.15)
  1717.     end
  1718.  
  1719.     if classes.dasher then
  1720.  
  1721.     end
  1722.  
  1723.     if classes.engineer then
  1724.         self.max_ammo = math.floor(self.max_ammo*0.5)
  1725.         self.ammo = self.max_ammo
  1726.         self.area:addGameObject('Drone', self.x, self.y, {rd = -math.pi/2, player = self})
  1727.         self.area:addGameObject('Drone', self.x, self.y, {rd = math.pi/2, player = self})
  1728.     end
  1729.  
  1730.     if classes.threader then
  1731.         self.cycle_timer_2 = 0
  1732.         self.cycle_cooldown_2 = 5
  1733.         self.cycle_timer_3 = 0
  1734.         self.cycle_cooldown_3 = 5
  1735.         self.cycle_timer_4 = 0
  1736.         self.cycle_cooldown_4 = 5
  1737.     end
  1738. end
  1739.  
  1740. function Player:setClasses()
  1741.     if fn.any(classes, 'Gunner') then self.gunner = true end
  1742.     if fn.any(classes, 'Runner') then self.runner = true end
  1743.     if fn.any(classes, 'Cycler') then self.cycler = true end
  1744.     if fn.any(classes, 'Tanker') then self.tanker = true end
  1745.     if fn.any(classes, 'Swapper') then self.swapper = true end
  1746.     if fn.any(classes, 'Barrager') then self.barrager = true end
  1747.     if fn.any(classes, 'Seeker') then self.seeker = true end
  1748.     if fn.any(classes, 'Shielder') then self.shielder = true end
  1749.     if fn.any(classes, 'Regeneer') then self.regeneer = true end
  1750.     if fn.any(classes, 'Recycler') then self.recycler = true end
  1751.     if fn.any(classes, 'Buster') then self.buster = true end
  1752.     if fn.any(classes, 'Buffer') then self.buffer = true end
  1753.     if fn.any(classes, 'Berserker') then self.berserker = true end
  1754.     if fn.any(classes, 'Absorber') then self.absorber = true end
  1755.     if fn.any(classes, 'Turner') then self.turner = true end
  1756.     if fn.any(classes, 'Driver') then self.driver = true end
  1757.     if fn.any(classes, 'Processor') then self.processor = true end
  1758.     if fn.any(classes, 'Panzer') then self.panzer = true end
  1759.     if fn.any(classes, 'Reserver') then self.reserver = true end
  1760.     if fn.any(classes, 'Gambler') then self.gambler = true end
  1761.     if fn.any(classes, 'Repeater') then self.repeater = true end
  1762.     if fn.any(classes, 'Launcher') then self.launcher = true end
  1763.     if fn.any(classes, 'Deployer') then self.deployer = true end
  1764.     if fn.any(classes, 'Booster') then self.booster = true end
  1765.     if fn.any(classes, 'Discharger') then self.discharger = true end
  1766.     if fn.any(classes, 'Hoamer') then self.hoamer = true end
  1767.     if fn.any(classes, 'Splitter') then self.splitter = true end
  1768.     if fn.any(classes, 'Spinner') then self.spinner = true end
  1769.     if fn.any(classes, 'Bouncer') then self.bouncer = true end
  1770.     if fn.any(classes, 'Blaster') then self.blaster = true end
  1771.     if fn.any(classes, 'Raider') then self.raider = true end
  1772.     if fn.any(classes, 'Waver') then self.waver = true end
  1773.     if fn.any(classes, 'Bomber') then self.bomber = true end
  1774.     if fn.any(classes, 'Zoomer') then self.zoomer = true end
  1775.     if fn.any(classes, 'Racer') then self.racer = true end
  1776.     if fn.any(classes, 'Miner') then self.miner = true end
  1777.     if fn.any(classes, 'Piercer') then self.piercer = true end
  1778.     if fn.any(classes, 'Dasher') then self.dasher = true end
  1779.     if fn.any(classes, 'Engineer') then self.engineer = true end
  1780.     if fn.any(classes, 'Threader') then self.threader = true end
  1781.  
  1782.     if self.cycler then
  1783.         self.luck_multiplier = self.luck_multiplier + 0.25
  1784.         self.cycle_multiplier = Stat(self.cycle_multiplier.value + 0.25)
  1785.     end
  1786.  
  1787.     if self.tanker then
  1788.         self.max_hp = math.floor(self.max_hp*1.25)
  1789.         self.hp = self.max_hp
  1790.         self.max_ammo = math.floor(self.max_ammo*1.25)
  1791.         self.ammo = self.max_ammo
  1792.     end
  1793.  
  1794.     if self.gunner then
  1795.         self.aspd_multiplier = Stat(self.aspd_multiplier.value + 0.15)
  1796.         self.pspd_multiplier = Stat(self.pspd_multiplier.value + 0.25)
  1797.     end
  1798.  
  1799.     if self.runner then
  1800.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value + 0.25)
  1801.         self.max_boost = math.floor(self.max_boost*1.25)
  1802.         self.boost = self.max_boost
  1803.     end
  1804.  
  1805.     if self.swapper then
  1806.         self.gain_stat_boost_on_attack_change = true
  1807.         self.max_hp = math.floor(self.max_hp*0.90)
  1808.         self.hp = self.max_hp
  1809.         self.max_ammo = math.floor(self.max_ammo*0.90)
  1810.         self.ammo = self.max_ammo
  1811.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.1)
  1812.         self.pspd_multiplier = Stat(self.pspd_multiplier.value - 0.1)
  1813.     end
  1814.  
  1815.     if self.barrager then
  1816.         self.barrage_on_kill_chance = self.barrage_on_kill_chance + 5
  1817.         self.barrage_on_cycle_chance = self.barrage_on_cycle_chance + 10
  1818.         self.additional_barrage_projectile = self.additional_barrage_projectile + 2
  1819.         self.cant_launch_homing_projectiles = true
  1820.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1821.     end
  1822.  
  1823.     if self.seeker then
  1824.         self.launch_homing_projectile_on_kill_chance = self.launch_homing_projectile_on_kill_chance + 10
  1825.         self.launch_homing_projectile_on_cycle_chance = self.launch_homing_projectile_on_cycle_chance + 5
  1826.         self.additional_homing_projectile = self.additional_homing_projectile + 1
  1827.         self.cant_barrage = true
  1828.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1829.     end
  1830.  
  1831.     if self.shielder then
  1832.         self.shield_projectile_chance = self.shield_projectile_chance + 25
  1833.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1834.         self.shield_projectile_damage_multiplier = 0.75
  1835.     end
  1836.  
  1837.     if self.regeneer then
  1838.         self.item_restores_hp = true
  1839.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.15)
  1840.     end
  1841.  
  1842.     if self.recycler then
  1843.         self.protective_barrier_when_no_ammo = true
  1844.         self.ammo_consumption_multiplier = self.ammo_consumption_multiplier + 0.5
  1845.     end
  1846.  
  1847.     if self.buster then
  1848.         self.projectile_size_multiplier = self.projectile_size_multiplier + 0.5
  1849.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1850.         self.max_hp = math.floor(self.max_hp*0.85)
  1851.         self.hp = self.max_hp
  1852.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.15)
  1853.     end
  1854.  
  1855.     if self.buffer then
  1856.         self.stat_boost_duration_multiplier = self.stat_boost_duration_multiplier + 0.5
  1857.         self.max_boost = math.floor(self.max_boost*0.80)
  1858.         self.boost = self.max_boost
  1859.     end
  1860.  
  1861.     if self.berserker then
  1862.         self.rampage = true
  1863.         self.luck_multiplier = self.luck_multiplier - 0.25
  1864.     end
  1865.  
  1866.     if self.absorber then
  1867.         self.absorb_hits = true
  1868.     end
  1869.  
  1870.     if self.turner then
  1871.  
  1872.     end
  1873.  
  1874.     if self.driver then
  1875.         self.invulnerability_time_multiplier = self.invulnerability_time_multiplier + 0.3
  1876.         self.boost_recharge_rate_multiplier = self.boost_recharge_rate_multiplier + 0.3
  1877.         self.size_multiplier = self.size_multiplier + 0.3
  1878.     end
  1879.  
  1880.     if self.processor then
  1881.         self.cycle_multiplier = Stat(self.cycle_multiplier.value + 0.5)
  1882.         self.max_hp = math.floor(self.max_hp*0.75)
  1883.         self.hp = self.max_hp
  1884.         self.sp_spawn_chance_multiplier = self.sp_spawn_chance_multiplier - 0.5
  1885.     end
  1886.  
  1887.     if self.gambler then
  1888.         self.luck_multiplier = self.luck_multiplier + 0.5
  1889.         self.cant_trigger_on_cycle_events = true
  1890.     end
  1891.  
  1892.     if self.panzer then
  1893.         self.max_hp = math.floor(self.max_hp*1.5)
  1894.         self.hp = self.max_hp
  1895.         self.size_multiplier = self.size_multiplier + 0.5
  1896.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.25)
  1897.     end
  1898.  
  1899.     if self.reserver then
  1900.         self.max_ammo = math.floor(self.max_ammo*1.5)
  1901.         self.ammo = self.max_ammo
  1902.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.25)
  1903.         self.change_attack_when_no_ammo = true
  1904.     end
  1905.  
  1906.     if self.repeater then
  1907.         self.aspd_multiplier = Stat(self.aspd_multiplier.value + 0.5)
  1908.         self.damage_multiplier = 0.75
  1909.     end
  1910.  
  1911.     if self.launcher then
  1912.         self.pspd_multiplier = Stat(self.pspd_multiplier.value + 0.75)
  1913.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1914.         self.max_hp = math.floor(self.max_hp*0.8)
  1915.         self.hp = self.max_hp
  1916.         self.max_ammo = math.floor(self.max_ammo*0.8)
  1917.         self.ammo = self.max_ammo
  1918.     end
  1919.  
  1920.     if self.deployer then
  1921.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value + 0.25)
  1922.         self.size_multiplier = self.size_multiplier - 0.25
  1923.         self.drop_mines_chance = self.drop_mines_chance + 25
  1924.     end
  1925.  
  1926.     if self.booster then
  1927.         self.max_boost = math.floor(self.max_boost*1.5)
  1928.         self.boost = self.max_boost
  1929.         self.luck_multiplier = self.luck_multiplier - 0.25
  1930.         self.max_ammo = math.floor(self.max_ammo*0.75)
  1931.         self.ammo = self.max_ammo
  1932.     end
  1933.  
  1934.     if self.discharger then
  1935.         self.lightning_targets_projectiles = true
  1936.         self.additional_lightning_bolt = self.additional_lightning_bolt + 2
  1937.         self.lightning_trigger_distance_multiplier = self.lightning_trigger_distance_multiplier + 0.5
  1938.     end
  1939.  
  1940.     if self.hoamer then
  1941.         self.homing_speed_multiplier = self.homing_speed_multiplier + 0.5
  1942.         self.double_homing = true
  1943.         self.attack_twice_chance = self.attack_twice_chance + 10
  1944.     end
  1945.  
  1946.     if self.splitter then
  1947.         self.split_projectiles_split_chance = self.split_projectiles_split_chance + 15
  1948.         self.pspd_multiplier = Stat(self.pspd_multiplier.value + 0.25)
  1949.     end
  1950.  
  1951.     if self.spinner then
  1952.         self.projectile_duration_multiplier = self.projectile_duration_multiplier + 0.25
  1953.         self.spin_projectile_on_expiration_chance = self.spin_projectile_on_expiration_chance + 50
  1954.     end
  1955.  
  1956.     if self.bouncer then
  1957.         self.additional_bounce = self.additional_bounce + 4
  1958.         self.pspd_multiplier = Stat(self.pspd_multiplier.value - 0.5)
  1959.     end
  1960.  
  1961.     if self.blaster then
  1962.         self.additional_blast_projectile = self.additional_blast_projectile + 8
  1963.         self.blast_shield = true
  1964.     end
  1965.  
  1966.     if self.raider then
  1967.         self.sp_spawn_chance_multiplier = self.sp_spawn_chance_multiplier + 1
  1968.     end
  1969.  
  1970.     if self.waver then
  1971.         self.projectile_waviness_multiplier = self.projectile_waviness_multiplier + 0.5
  1972.         self.projectile_angle_change_frequency_multiplier = self.projectile_angle_change_frequency_multiplier + 0.5
  1973.     end
  1974.  
  1975.     if self.bomber then
  1976.         self.area_multiplier = self.area_multiplier + 0.25
  1977.         self.attack_twice_chance = self.attack_twice_chance + 0.25
  1978.     end
  1979.  
  1980.     if self.zoomer then
  1981.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value + 0.30)
  1982.         self.size_multiplier = self.size_multiplier - 0.30
  1983.     end
  1984.  
  1985.     if self.racer then
  1986.         self.ammo_gives_boost = true
  1987.         self.max_ammo = math.floor(self.max_ammo*0.5)
  1988.         self.ammo = self.max_ammo
  1989.     end
  1990.  
  1991.     if self.miner then
  1992.         self.resource_spawn_rate_multiplier = self.resource_spawn_rate_multiplier + 0.5
  1993.         self.item_spawn_rate_multiplier = self.item_spawn_rate_multiplier + 0.25
  1994.     end
  1995.  
  1996.     if self.piercer then
  1997.         self.projectile_pierce = self.projectile_pierce + 2
  1998.         self.max_hp = math.floor(self.max_hp*0.85)
  1999.         self.hp = self.max_hp
  2000.         self.max_ammo = math.floor(self.max_ammo*0.85)
  2001.         self.ammo = self.max_ammo
  2002.         self.max_boost = math.floor(self.max_boost*0.85)
  2003.         self.boost = self.max_boost
  2004.         self.aspd_multiplier = Stat(self.aspd_multiplier.value - 0.15)
  2005.         self.mvspd_multiplier = Stat(self.mvspd_multiplier.value - 0.15)
  2006.     end
  2007.  
  2008.     if self.dasher then
  2009.  
  2010.     end
  2011.  
  2012.     if self.engineer then
  2013.         self.max_ammo = math.floor(self.max_ammo*0.5)
  2014.         self.ammo = self.max_ammo
  2015.         self.area:addGameObject('Drone', self.x, self.y, {rd = -math.pi/2, player = self})
  2016.         self.area:addGameObject('Drone', self.x, self.y, {rd = math.pi/2, player = self})
  2017.     end
  2018.  
  2019.     if self.threader then
  2020.         self.cycle_timer_2 = 0
  2021.         self.cycle_cooldown_2 = 5
  2022.         self.cycle_timer_3 = 0
  2023.         self.cycle_cooldown_3 = 5
  2024.         self.cycle_timer_4 = 0
  2025.         self.cycle_cooldown_4 = 5
  2026.     end
  2027. end
  2028.  
  2029. function Player:setShip()
  2030.     if self.ship == 'Fighter' then
  2031.  
  2032.     elseif self.ship == 'Crusader' then
  2033.         self.max_boost = 80
  2034.         self.boost = self.max_boost
  2035.         self.boost_effectiveness_multiplier = 2
  2036.         self.mvspd_multiplier = Stat(0.6)
  2037.         self.turn_rate_multiplier = 0.5
  2038.         self.aspd_multiplier = Stat(0.65)
  2039.         self.pspd_multiplier = Stat(1.5)
  2040.         self.max_hp = 150
  2041.         self.hp = self.max_hp
  2042.         self.size_multiplier = 1.5
  2043.  
  2044.     elseif self.ship == 'Rogue' then
  2045.         self.max_boost = 120
  2046.         self.boost = self.max_boost
  2047.         self.boost_recharge_rate_multiplier = 1
  2048.         self.mvspd_multiplier = Stat(1.3)
  2049.         self.max_ammo = 120
  2050.         self.ammo = self.max_ammo
  2051.         self.aspd_multiplier = Stat(1.25)
  2052.         self.max_hp = 80
  2053.         self.hp = self.max_hp
  2054.         self.invulnerability_time_multiplier = 0.5
  2055.         self.size_multiplier = 0.9
  2056.  
  2057.     elseif self.ship == 'Bit Hunter' then
  2058.         self.mvspd_multiplier = Stat(0.9)
  2059.         self.turn_rate_multiplier = 0.8
  2060.         self.max_ammo = 80
  2061.         self.ammo = self.max_ammo
  2062.         self.aspd_multiplier = Stat(0.8)
  2063.         self.pspd_multiplier = Stat(0.9)
  2064.         self.invulnerability_time_multiplier = 1.5
  2065.         self.size_multiplier = 1.1
  2066.         self.luck_multiplier = 1.5
  2067.         self.resource_spawn_rate_multiplier = 1.5
  2068.         self.item_spawn_rate_multiplier = 1.5
  2069.         self.cycle_multiplier = Stat(1.25)
  2070.  
  2071.     elseif self.ship == 'Sentinel' then
  2072.         self.energy_shield = true
  2073.  
  2074.     elseif self.ship == 'Striker' then
  2075.         self.max_ammo = 120
  2076.         self.ammo = self.max_ammo
  2077.         self.aspd_multiplier = Stat(2)
  2078.         self.pspd_multiplier = Stat(1.25)
  2079.         self.max_hp = 50
  2080.         self.hp = self.max_hp
  2081.         self.additional_barrage_projectile = 8
  2082.         self.barrage_nova = true
  2083.         self.barrage_on_kill_chance = 10
  2084.         self.barrage_on_cycle_chance = 10
  2085.  
  2086.     elseif self.ship == 'Nuclear' then
  2087.         self.max_boost = 80
  2088.         self.boost= self.max_boost
  2089.         self.turn_rate_multiplier = 0.8
  2090.         self.max_ammo = 80
  2091.         self.ammo = self.max_ammo
  2092.         self.aspd_multiplier = Stat(0.85)
  2093.         self.max_hp = 80
  2094.         self.hp = self.max_hp
  2095.         self.invulnerability_time_multiplier = 2
  2096.         self.luck_multiplier = 1.5
  2097.         self.resource_spawn_rate_multiplier = 1.5
  2098.         self.item_spawn_rate_multiplier = 1.5
  2099.         self.cycle_multiplier = Stat(1.5)
  2100.         self.self_explode_on_cycle_chance = 25
  2101.  
  2102.     elseif self.ship == 'Cycler' then
  2103.         self.cycle_multiplier = Stat(2)
  2104.  
  2105.     elseif self.ship == 'Wisp' then
  2106.         self.max_boost = 50
  2107.         self.boost = self.max_boost
  2108.         self.mvspd_multiplier = Stat(0.5)
  2109.         self.turn_rate_multiplier = 0.5
  2110.         self.aspd_multiplier = Stat(0.65)
  2111.         self.pspd_multiplier = Stat(0.5)
  2112.         self.max_hp = 50
  2113.         self.hp = self.max_hp
  2114.         self.size_multiplier = 0.75
  2115.         self.resource_spawn_rate_multiplier = 1.5
  2116.         self.item_spawn_rate_multiplier = 1.5
  2117.         self.shield_projectile_chance = 100
  2118.         self.projectile_duration_multiplier = 1.5
  2119.     end
  2120. end
  2121.  
  2122. function Player:generateChances()
  2123.     self.chances = {}
  2124.     for k, v in pairs(self) do
  2125.         if k:find('_chance') and type(v) == 'number' then
  2126.             if k:find('_on_kill') and v > 0 then
  2127.                 self.chances[k] = chanceList({true, math.ceil(self.luck_multiplier*(v+self.added_chance_to_all_on_kill_events))},
  2128.                 {false, 100-math.ceil(self.luck_multiplier*(v+self.added_chance_to_all_on_kill_events))})
  2129.             else
  2130.                 if k:find('sp') and v > 0 and self.raider then
  2131.                     self.chances[k] = chanceList({true, math.ceil(1.5*self.luck_multiplier*v)}, {false, 100-math.ceil(1.5*self.luck_multiplier*v)})
  2132.                 else
  2133.                     self.chances[k] = chanceList({true, math.ceil(self.luck_multiplier*v)}, {false, 100-math.ceil(self.luck_multiplier*v)})
  2134.                 end
  2135.             end
  2136.         end
  2137.     end
  2138. end
  2139.  
  2140.  
  2141. function Player:shipVisuals()
  2142.     if self.ship == 'Fighter' then
  2143.         self.polygons[1] = {
  2144.             self.w, 0,
  2145.             self.w/2, -self.w/2,
  2146.             -self.w/2, -self.w/2,
  2147.             -self.w, 0,
  2148.             -self.w/2, self.w/2,
  2149.             self.w/2, self.w/2,
  2150.         }
  2151.  
  2152.         self.polygons[2] = {
  2153.             self.w/2, -self.w/2,
  2154.             0, -self.w,
  2155.             -self.w - self.w/2, -self.w,
  2156.             -3*self.w/4, -self.w/4,
  2157.             -self.w/2, -self.w/2,
  2158.         }
  2159.  
  2160.         self.polygons[3] = {
  2161.             self.w/2, self.w/2,
  2162.             -self.w/2, self.w/2,
  2163.             -3*self.w/4, self.w/4,
  2164.             -self.w - self.w/2, self.w,
  2165.             0, self.w,
  2166.         }
  2167.  
  2168.     elseif self.ship == 'Crusader' then
  2169.         self.polygons[1] = {
  2170.             self.w, 0,
  2171.             self.w/2, self.w/2,
  2172.             -self.w/4, self.w/2,
  2173.             -self.w/2, self.w/4,
  2174.             -self.w/2, -self.w/4,
  2175.             -self.w/4, -self.w/2,
  2176.             self.w/2, -self.w/2,
  2177.         }
  2178.  
  2179.         self.polygons[2] = {
  2180.             self.w/2, self.w/2,
  2181.             self.w/2, self.w,
  2182.             -self.w/2, self.w,
  2183.             -self.w, self.w/2,
  2184.             -self.w, 0,
  2185.             -self.w/2, 0,
  2186.             -self.w/2, self.w/4,
  2187.             -self.w/4, self.w/2,
  2188.         }
  2189.  
  2190.         self.polygons[3] = {
  2191.             self.w/2, -self.w/2,
  2192.             self.w/2, -self.w,
  2193.             -self.w/2, -self.w,
  2194.             -self.w, -self.w/2,
  2195.             -self.w, 0,
  2196.             -self.w/2, 0,
  2197.             -self.w/2, -self.w/4,
  2198.             -self.w/4, -self.w/2,
  2199.         }
  2200.  
  2201.     elseif self.ship == 'Rogue' then
  2202.         self.polygons[1] = {
  2203.             self.w, 0,
  2204.             0, -self.w/2,
  2205.             -self.w, 0,
  2206.             0, self.w/2,
  2207.         }
  2208.  
  2209.         self.polygons[2] = {
  2210.             self.w/2, -self.w/4,
  2211.             self.w/4, -3*self.w/4,
  2212.             -self.w - self.w/2, -2*self.w,
  2213.             -self.w/2, -self.w/4,
  2214.             0, -self.w/2,
  2215.         }
  2216.  
  2217.         self.polygons[3] = {
  2218.             self.w/2, self.w/4,
  2219.             0, self.w/2,
  2220.             -self.w/2, self.w/4,
  2221.             -self.w - self.w/2, 2*self.w,
  2222.             self.w/4, 3*self.w/4,
  2223.         }
  2224.  
  2225.     elseif self.ship == 'Bit Hunter' then
  2226.         self.polygons[1] = {
  2227.             self.w, 0,
  2228.             self.w/2, -self.w/2,
  2229.             -self.w, -self.w/2,
  2230.             -self.w/2, 0,
  2231.             -self.w, self.w/2,
  2232.             self.w/2, self.w/2,
  2233.         }
  2234.  
  2235.     elseif self.ship == 'Sentinel' then
  2236.         self.polygons[1] = {
  2237.             self.w, 0,
  2238.             0, -self.w,
  2239.             -3*self.w/4, -3*self.w/4,
  2240.             -self.w, 0,
  2241.             -3*self.w/4, 3*self.w/4,
  2242.             0, self.w,
  2243.         }
  2244.  
  2245.     elseif self.ship == 'Striker' then
  2246.         self.polygons[1] = {
  2247.             self.w, 0,
  2248.             self.w/2, -self.w/2,
  2249.             -self.w/2, -self.w/2,
  2250.             -self.w, 0,
  2251.             -self.w/2, self.w/2,
  2252.             self.w/2, self.w/2,
  2253.         }
  2254.  
  2255.         self.polygons[2] = {
  2256.             0, self.w/2,
  2257.             -self.w/4, self.w,
  2258.             0, self.w + self.w/2,
  2259.             self.w, self.w,
  2260.             0, 2*self.w,
  2261.             -self.w/2, self.w + self.w/2,
  2262.             -self.w, 0,
  2263.             -self.w/2, self.w/2,
  2264.         }
  2265.  
  2266.         self.polygons[3] = {
  2267.             0, -self.w/2,
  2268.             -self.w/4, -self.w,
  2269.             0, -self.w - self.w/2,
  2270.             self.w, -self.w,
  2271.             0, -2*self.w,
  2272.             -self.w/2, -self.w - self.w/2,
  2273.             -self.w, 0,
  2274.             -self.w/2, -self.w/2,
  2275.         }
  2276.  
  2277.     elseif self.ship == 'Nuclear' then
  2278.         self.polygons[1] = {
  2279.             self.w, -self.w/4,
  2280.             self.w, self.w/4,
  2281.             self.w - self.w/4, self.w/2,
  2282.             -self.w + self.w/4, self.w/2,
  2283.             -self.w, self.w/4,
  2284.             -self.w, -self.w/4,
  2285.             -self.w + self.w/4, -self.w/2,
  2286.             self.w - self.w/4, -self.w/2,
  2287.         }
  2288.  
  2289.     elseif self.ship == 'Cycler' then
  2290.         self.polygons[1] = {
  2291.             self.w, 0,
  2292.             0, self.w,
  2293.             -self.w, 0,
  2294.             0, -self.w,
  2295.         }
  2296.  
  2297.     elseif self.ship == 'Wisp' then
  2298.         self.polygons[1] = {
  2299.             self.w, -self.w/4,
  2300.             self.w, self.w/4,
  2301.             self.w/4, self.w,
  2302.             -self.w/4, self.w,
  2303.             -self.w, self.w/4,
  2304.             -self.w, -self.w/4,
  2305.             -self.w/4, -self.w,
  2306.             self.w/4, -self.w,
  2307.         }
  2308.     end
  2309.  
  2310. end
  2311.  
  2312. function Player:boostTrails()
  2313.     self.trail_color = skill_point_color
  2314.     self.timer:every(0.01, function()
  2315.         if self.ship == 'Fighter' then
  2316.             self.area:addGameObject('TrailParticle',
  2317.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2),
  2318.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2),
  2319.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2320.             self.area:addGameObject('TrailParticle',
  2321.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2),
  2322.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2),
  2323.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2324.  
  2325.         elseif self.ship == 'Crusader' then
  2326.             self.area:addGameObject('TrailParticle',
  2327.             self.x - 1.2*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2),
  2328.             self.y - 1.2*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2),
  2329.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2330.             self.area:addGameObject('TrailParticle',
  2331.             self.x - 1.2*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2),
  2332.             self.y - 1.2*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2),
  2333.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2334.  
  2335.         elseif self.ship == 'Bit Hunter' then
  2336.             self.area:addGameObject('TrailParticle',
  2337.             self.x - 0.8*self.w*math.cos(self.r), self.y - 0.8*self.w*math.sin(self.r),
  2338.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.1, 0.2), color = self.trail_color})
  2339.  
  2340.         elseif self.ship == 'Rogue' then
  2341.             self.area:addGameObject('TrailParticle',
  2342.             self.x - 0.7*self.w*math.cos(self.r) + 0.4*self.w*math.cos(self.r - math.pi/2),
  2343.             self.y - 0.7*self.w*math.sin(self.r) + 0.4*self.w*math.sin(self.r - math.pi/2),
  2344.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2345.             self.area:addGameObject('TrailParticle',
  2346.             self.x - 0.7*self.w*math.cos(self.r) + 0.4*self.w*math.cos(self.r + math.pi/2),
  2347.             self.y - 0.7*self.w*math.sin(self.r) + 0.4*self.w*math.sin(self.r + math.pi/2),
  2348.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2349.  
  2350.         elseif self.ship == 'Sentinel' then
  2351.             self.area:addGameObject('TrailParticle',
  2352.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2),
  2353.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2),
  2354.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2355.             self.area:addGameObject('TrailParticle',
  2356.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2),
  2357.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2),
  2358.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2359.  
  2360.         elseif self.ship == 'Striker' then
  2361.             self.area:addGameObject('TrailParticle',
  2362.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2),
  2363.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2),
  2364.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2365.             self.area:addGameObject('TrailParticle',
  2366.             self.x - 1.0*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2),
  2367.             self.y - 1.0*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2),
  2368.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2369.  
  2370.         elseif self.ship == 'Nuclear' then
  2371.             self.area:addGameObject('TrailParticle',
  2372.             self.x - 1*self.w*math.cos(self.r), self.y - 1*self.w*math.sin(self.r),
  2373.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.1, 0.2), color = self.trail_color})
  2374.  
  2375.         elseif self.ship == 'Cycler' then
  2376.             self.area:addGameObject('TrailParticle',
  2377.             self.x - 1*self.w*math.cos(self.r), self.y - 1*self.w*math.sin(self.r),
  2378.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.1, 0.2), color = self.trail_color})
  2379.  
  2380.             self.area:addGameObject('TrailParticle',
  2381.             self.x - 0.8*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2),
  2382.             self.y - 0.8*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2),
  2383.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2384.  
  2385.             self.area:addGameObject('TrailParticle',
  2386.             self.x - 0.8*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2),
  2387.             self.y - 0.8*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2),
  2388.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.15, 0.25), color = self.trail_color})
  2389.  
  2390.         elseif self.ship == 'Wisp' then
  2391.             self.area:addGameObject('TrailParticle',
  2392.             self.x - 1*self.w*math.cos(self.r), self.y - 1*self.w*math.sin(self.r),
  2393.             {parent = self, r = random(2, 4)*self.size_multiplier, d = random(0.1, 0.15), color = self.trail_color})
  2394.         end
  2395.     end)
  2396. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement