You've already forked ComfyFactorio
							
							
				mirror of
				https://github.com/ComfyFactory/ComfyFactorio.git
				synced 2025-10-30 23:47:41 +02:00 
			
		
		
		
	new module and changes to rpg and mtn v3
This commit is contained in:
		| @@ -130,6 +130,9 @@ pointy_explosives=Detonate Chest | ||||
| repair_aoe=Repair AOE | ||||
| charge=Charge | ||||
| eternal_blades=Eternal Blades | ||||
| drone_enemy=Drone - Enemy | ||||
| drone_mine=Drone - Mine | ||||
|  | ||||
|  | ||||
|  | ||||
| [allocations] | ||||
|   | ||||
| @@ -13,7 +13,7 @@ local function on_entity_died(event) | ||||
|     end | ||||
|     local wagon_types = ICW.get('wagon_types') | ||||
|  | ||||
|     if not wagon_types[entity.type] then | ||||
|     if entity and entity.valid and not wagon_types[entity.type] then | ||||
|         return | ||||
|     end | ||||
|     local icw = ICW.get() | ||||
|   | ||||
| @@ -1,8 +1,11 @@ | ||||
| local WPT = require 'maps.mountain_fortress_v3.table' | ||||
| local RPG = require 'modules.rpg.main' | ||||
| local Event = require 'utils.event' | ||||
| local Ai = require 'modules.ai' | ||||
| require 'modules.check_fullness' | ||||
|  | ||||
| local Public = {} | ||||
| local Public = {events = {on_entity_mined = Event.generate_event_name('on_entity_mined')}} | ||||
|  | ||||
| local random = math.random | ||||
| local floor = math.floor | ||||
| local sqrt = math.sqrt | ||||
| @@ -337,7 +340,12 @@ local function randomness(data) | ||||
|         end | ||||
|     end | ||||
|     local particle = particles[harvest] | ||||
|     create_particles(player.surface, particle, position, 64, {x = player.position.x, y = player.position.y}) | ||||
|  | ||||
|     if data.script_character then | ||||
|         create_particles(player.surface, particle, position, 64, {x = data.script_character.position.x, y = data.script_character.position.y}) | ||||
|     else | ||||
|         create_particles(player.surface, particle, position, 64, {x = player.position.x, y = player.position.y}) | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function randomness_scrap(data) | ||||
| @@ -390,7 +398,11 @@ local function randomness_scrap(data) | ||||
|         end | ||||
|     end | ||||
|     local particle = particles[harvest] | ||||
|     create_particles(player.surface, particle, position, 64, {x = player.position.x, y = player.position.y}) | ||||
|     if data.script_character then | ||||
|         create_particles(player.surface, particle, position, 64, {x = data.script_character.position.x, y = data.script_character.position.y}) | ||||
|     else | ||||
|         create_particles(player.surface, particle, position, 64, {x = player.position.x, y = player.position.y}) | ||||
|     end | ||||
| end | ||||
|  | ||||
| function Public.on_player_mined_entity(event) | ||||
| @@ -413,13 +425,19 @@ function Public.on_player_mined_entity(event) | ||||
|     local buffer = event.buffer | ||||
|  | ||||
|     if valid_rocks[entity.name] or valid_trees[entity.name] or is_scrap then | ||||
|         buffer.clear() | ||||
|         if buffer then | ||||
|             buffer.clear() | ||||
|         end | ||||
|  | ||||
|         local data = { | ||||
|             entity = entity, | ||||
|             player = player | ||||
|         } | ||||
|  | ||||
|         if event.script_character then | ||||
|             data.script_character = event.script_character | ||||
|         end | ||||
|  | ||||
|         local index = player.index | ||||
|  | ||||
|         local scrap_zone = RPG.get_value_from_player(index, 'scrap_zone') | ||||
| @@ -433,4 +451,26 @@ function Public.on_player_mined_entity(event) | ||||
|     end | ||||
| end | ||||
|  | ||||
| Event.add( | ||||
|     Public.events.on_entity_mined, | ||||
|     function(event) | ||||
|         if not event then | ||||
|             return | ||||
|         end | ||||
|  | ||||
|         Public.on_player_mined_entity(event) | ||||
|     end | ||||
| ) | ||||
|  | ||||
| Event.add( | ||||
|     Ai.events.on_entity_mined, | ||||
|     function(event) | ||||
|         if not event then | ||||
|             return | ||||
|         end | ||||
|  | ||||
|         Public.on_player_mined_entity(event) | ||||
|     end | ||||
| ) | ||||
|  | ||||
| return Public | ||||
|   | ||||
| @@ -9,7 +9,7 @@ local Server = require 'utils.server' | ||||
| local MapFuntions = require 'tools.map_functions' | ||||
| local CommonFunctions = require 'utils.common' | ||||
| local LayersFunctions = require 'maps.planet_prison.mod.layers' | ||||
| local AIFunctions = require 'utils.ai' | ||||
| local AIFunctions = require 'maps.planet_prison.ai' | ||||
| local Blueprints = require 'maps.planet_prison.mod.bp' | ||||
| local AfkFunctions = require 'maps.planet_prison.mod.afk' | ||||
| local Timers = require 'utils.timers' | ||||
|   | ||||
							
								
								
									
										531
									
								
								modules/ai.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								modules/ai.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,531 @@ | ||||
| --- created by Gerkiz | ||||
| local Event = require 'utils.event' | ||||
| local Color = require 'utils.color_presets' | ||||
| local Utils = require 'utils.common' | ||||
| local Global = require 'utils.global' | ||||
| local Token = require 'utils.token' | ||||
| local Task = require 'utils.task' | ||||
|  | ||||
| local this = { | ||||
|     timers = {}, | ||||
|     characters = {}, | ||||
|     characters_unit_numbers = {} | ||||
| } | ||||
|  | ||||
| Global.register( | ||||
|     this, | ||||
|     function(tbl) | ||||
|         this = tbl | ||||
|     end | ||||
| ) | ||||
|  | ||||
| local Public = {events = {on_entity_mined = Event.generate_event_name('on_entity_mined')}} | ||||
|  | ||||
| local max_keepalive = 54000 -- 15 minutes | ||||
| local remove = table.remove | ||||
| local round = math.round | ||||
| local default_radius = 5 | ||||
|  | ||||
| Public.command = { | ||||
|     noop = 0, | ||||
|     seek_and_destroy_cmd = 1, | ||||
|     seek_and_mine_cmd = 2 | ||||
| } | ||||
|  | ||||
| local clear_corpse_token = | ||||
|     Token.register( | ||||
|     function(event) | ||||
|         local position = event.position | ||||
|         local surface = game.get_surface(event.surface_index) | ||||
|         local search_info = { | ||||
|             type = 'character-corpse', | ||||
|             position = position, | ||||
|             radius = 1 | ||||
|         } | ||||
|  | ||||
|         local corpses = surface.find_entities_filtered(search_info) | ||||
|         if corpses and #corpses > 0 then | ||||
|             for _, corpse in pairs(corpses) do | ||||
|                 if corpse and corpse.valid then | ||||
|                     if corpse.character_corpse_player_index == 65536 then | ||||
|                         corpse.destroy() | ||||
|                     end | ||||
|                 end | ||||
|             end | ||||
|         end | ||||
|     end | ||||
| ) | ||||
|  | ||||
| local function char_callback(callback) | ||||
|     local entities = this.characters | ||||
|  | ||||
|     for i = 1, #entities do | ||||
|         local data = entities[i] | ||||
|         if data and data.entity and data.entity.valid then | ||||
|             callback(data) | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function get_near_position(entity) | ||||
|     return {x = round(entity.position.x, 0), y = round(entity.position.y, 0)} | ||||
| end | ||||
|  | ||||
| local function is_mining_target_taken(selected) | ||||
|     if not selected then | ||||
|         return false | ||||
|     end | ||||
|  | ||||
|     char_callback( | ||||
|         function(data) | ||||
|             local entity = data.entity | ||||
|             if entity.selected == selected then | ||||
|                 return true | ||||
|             end | ||||
|         end | ||||
|     ) | ||||
|  | ||||
|     return false | ||||
| end | ||||
|  | ||||
| local function add_character(player_index, entity, render_id, data) | ||||
|     local index = #this.characters + 1 | ||||
|     if not this.characters[index] then | ||||
|         this.characters[index] = { | ||||
|             player_index = player_index, | ||||
|             index = index, | ||||
|             unit_number = entity.unit_number, | ||||
|             entity = entity, | ||||
|             ttl = game.tick + (data.ttl or max_keepalive), | ||||
|             command = data.command, | ||||
|             radius = default_radius, | ||||
|             max_radius_mine = 20, | ||||
|             max_radius_destroy = 150, | ||||
|             render_id = render_id, | ||||
|             search_local = data.search_local or false, | ||||
|             walking_position = {count = 1, position = get_near_position(entity)} | ||||
|         } | ||||
|     end | ||||
|     if not this.characters_unit_numbers[entity.unit_number] then | ||||
|         this.characters_unit_numbers[entity.unit_number] = true | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function exists_character(unit_number) | ||||
|     if not next(this.characters_unit_numbers) then | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     if this.characters_unit_numbers[unit_number] then | ||||
|         return true | ||||
|     end | ||||
|  | ||||
|     return false | ||||
| end | ||||
|  | ||||
| local function remove_character(unit_number) | ||||
|     if not next(this.characters) then | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     for index, data in pairs(this.characters) do | ||||
|         if data and data.unit_number == unit_number then | ||||
|             if data.entity and data.entity.valid then | ||||
|                 data.entity.destroy() | ||||
|             end | ||||
|             if rendering.is_valid(data.render_id) then | ||||
|                 rendering.destroy(data.render_id) | ||||
|             end | ||||
|             remove(this.characters, index) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     if this.characters_unit_numbers[unit_number] then | ||||
|         this.characters_unit_numbers[unit_number] = nil | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function get_dir(src, dest) | ||||
|     local src_x = Utils.get_axis(src, 'x') | ||||
|     local src_y = Utils.get_axis(src, 'y') | ||||
|     local dest_x = Utils.get_axis(dest, 'x') | ||||
|     local dest_y = Utils.get_axis(dest, 'y') | ||||
|  | ||||
|     local step = { | ||||
|         x = nil, | ||||
|         y = nil | ||||
|     } | ||||
|  | ||||
|     local precision = Utils.rand_range(1, 10) | ||||
|     if dest_x - precision > src_x then | ||||
|         step.x = 1 | ||||
|     elseif dest_x < src_x - precision then | ||||
|         step.x = -1 | ||||
|     else | ||||
|         step.x = 0 | ||||
|     end | ||||
|  | ||||
|     if dest_y - precision > src_y then | ||||
|         step.y = 1 | ||||
|     elseif dest_y < src_y - precision then | ||||
|         step.y = -1 | ||||
|     else | ||||
|         step.y = 0 | ||||
|     end | ||||
|  | ||||
|     return Utils.direction_lookup[step.x][step.y] | ||||
| end | ||||
|  | ||||
| local function move_to(entity, target, min_distance) | ||||
|     local state = { | ||||
|         walking = false | ||||
|     } | ||||
|  | ||||
|     local distance = Utils.get_distance(target.position, entity.position) | ||||
|     if min_distance < distance then | ||||
|         local dir = get_dir(entity.position, target.position) | ||||
|         if dir then | ||||
|             state = { | ||||
|                 walking = true, | ||||
|                 direction = dir | ||||
|             } | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     entity.walking_state = state | ||||
|     return state.walking | ||||
| end | ||||
|  | ||||
| local function refill_ammo(entity) | ||||
|     if not entity or not entity.valid then | ||||
|         return | ||||
|     end | ||||
|     local weapon = entity.get_inventory(defines.inventory.character_guns)[entity.selected_gun_index] | ||||
|     if weapon and weapon.valid_for_read then | ||||
|         local selected_ammo = entity.get_inventory(defines.inventory.character_ammo)[entity.selected_gun_index] | ||||
|         if selected_ammo then | ||||
|             if not selected_ammo.valid_for_read then | ||||
|                 if weapon.name == 'shotgun' then | ||||
|                     entity.insert({name = 'shotgun-shell', count = 5}) | ||||
|                 end | ||||
|                 if weapon.name == 'pistol' then | ||||
|                     entity.insert({name = 'firearm-magazine', count = 5}) | ||||
|                 end | ||||
|             end | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function shoot_at(entity, target) | ||||
|     entity.selected = target | ||||
|     entity.shooting_state = { | ||||
|         state = defines.shooting.shooting_enemies, | ||||
|         position = target.position | ||||
|     } | ||||
| end | ||||
|  | ||||
| local function check_progress_and_raise_event(data) | ||||
|     if data.entity.selected and data.entity.character_mining_progress >= 0.95 then | ||||
|         if not data.raised_event then | ||||
|             data.raised_event = true | ||||
|             Event.raise( | ||||
|                 Public.events.on_entity_mined, | ||||
|                 { | ||||
|                     player_index = data.player_index, | ||||
|                     entity = data.entity.selected, | ||||
|                     surface = data.entity.surface, | ||||
|                     script_character = data.entity | ||||
|                 } | ||||
|             ) | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function mine_entity(data, target) | ||||
|     data.entity.selected = target | ||||
|     data.entity.mining_state = {mining = true, position = target.position} | ||||
| end | ||||
|  | ||||
| local function shoot_stop(entity) | ||||
|     entity.shooting_state = { | ||||
|         state = defines.shooting.not_shooting, | ||||
|         position = {0, 0} | ||||
|     } | ||||
| end | ||||
|  | ||||
| local function insert_weapons(entity) | ||||
|     if not entity or not entity.valid then | ||||
|         return | ||||
|     end | ||||
|     local weapon = entity.get_inventory(defines.inventory.character_guns)[entity.selected_gun_index] | ||||
|     if weapon and weapon.valid_for_read then | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     if Utils.rand_range(1, 15) == 1 then | ||||
|         entity.insert({name = 'shotgun', count = 1}) | ||||
|         entity.insert({name = 'shotgun-shell', count = 5}) | ||||
|     elseif Utils.rand_range(1, 10) == 1 then | ||||
|         entity.insert({name = 'submachine-gun', count = 1}) | ||||
|         entity.insert({name = 'firearm-magazine', count = 5}) | ||||
|     else | ||||
|         entity.insert({name = 'pistol', count = 1}) | ||||
|         entity.insert({name = 'firearm-magazine', count = 5}) | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function seek_and_mine(data) | ||||
|     if data.radius >= data.max_radius_mine then | ||||
|         if data.overriden_command then | ||||
|             data.command = data.overriden_command | ||||
|             data.overriden_command = nil | ||||
|             return | ||||
|         else | ||||
|             data.radius = 1 | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     local entity = data.entity | ||||
|     if not entity or not entity.valid then | ||||
|         remove_character(data.unit_number) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local surface = entity.surface | ||||
|     local player_index = data.player_index | ||||
|     local player = game.get_player(player_index) | ||||
|     if not player or not player.valid or not player.connected then | ||||
|         remove_character(data.unit_number) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local position | ||||
|  | ||||
|     if data.search_local then | ||||
|         position = entity.position | ||||
|     else | ||||
|         position = player.position | ||||
|     end | ||||
|  | ||||
|     local search_info = { | ||||
|         position = position, | ||||
|         radius = data.radius, | ||||
|         type = { | ||||
|             'simple-entity-with-owner', | ||||
|             'simple-entity', | ||||
|             'tree' | ||||
|         }, | ||||
|         force = { | ||||
|             'neutral' | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     local closest = surface.find_entities_filtered(search_info) | ||||
|  | ||||
|     if #closest ~= 0 then | ||||
|         local target = Utils.get_closest_neighbour_non_player(entity.position, closest) | ||||
|         if not target then | ||||
|             data.radius = data.radius + 1 | ||||
|             return | ||||
|         end | ||||
|  | ||||
|         data.radius = 1 | ||||
|  | ||||
|         if not move_to(entity, target, 1) then | ||||
|             if not is_mining_target_taken(target) then | ||||
|                 if data.raised_event then | ||||
|                     data.raised_event = nil | ||||
|                 end | ||||
|  | ||||
|                 if entity.can_reach_entity(target) then | ||||
|                     mine_entity(data, target) | ||||
|                 else | ||||
|                     move_to(entity, target, 1) | ||||
|                 end | ||||
|             end | ||||
|             if data.overriden_command then | ||||
|                 data.command = data.overriden_command | ||||
|                 data.overriden_command = nil | ||||
|             end | ||||
|         end | ||||
|     else | ||||
|         data.radius = data.radius + 1 | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function seek_enemy_and_destroy(data) | ||||
|     if data.radius >= data.max_radius_destroy then | ||||
|         remove_character(data.unit_number) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local entity = data.entity | ||||
|     if not entity or not entity.valid then | ||||
|         remove_character(data.unit_number) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local surface = entity.surface | ||||
|     local player_index = data.player_index | ||||
|     local player = game.get_player(player_index) | ||||
|     if not player or not player.valid or not player.connected then | ||||
|         remove_character(data.unit_number) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local search_info = { | ||||
|         type = {'unit', 'unit-spawner', 'turret'}, | ||||
|         position = entity.position, | ||||
|         radius = data.radius, | ||||
|         force = 'enemy' | ||||
|     } | ||||
|  | ||||
|     local closest = surface.find_entities_filtered(search_info) | ||||
|  | ||||
|     if #closest ~= 0 then | ||||
|         local target = Utils.get_closest_neighbour_non_player(entity.position, closest) | ||||
|         if not target then | ||||
|             data.radius = data.radius + 5 | ||||
|             return | ||||
|         end | ||||
|         data.radius = default_radius | ||||
|         insert_weapons(entity) | ||||
|         refill_ammo(entity) | ||||
|  | ||||
|         local inside = ((entity.position.x - data.walking_position.position.x) ^ 2 + (entity.position.y - data.walking_position.position.y) ^ 2) < 1 ^ 2 | ||||
|         data.walking_position.position = get_near_position(entity) | ||||
|  | ||||
|         if inside then | ||||
|             data.walking_position.count = data.walking_position.count + 1 | ||||
|         end | ||||
|  | ||||
|         if data.walking_position.count == 3 then | ||||
|             data.radius = 1 | ||||
|             data.walking_position.count = 1 | ||||
|             data.overriden_command = data.command | ||||
|             data.command = Public.command.seek_and_mine_cmd | ||||
|             seek_and_mine(data) | ||||
|         else | ||||
|             if not move_to(entity, target, Utils.rand_range(5, 10)) then | ||||
|                 shoot_at(entity, target) | ||||
|             else | ||||
|                 shoot_stop(entity) | ||||
|             end | ||||
|         end | ||||
|     else | ||||
|         data.radius = data.radius + 5 | ||||
|     end | ||||
| end | ||||
|  | ||||
| --- Creates a new character that seeks and does stuff. | ||||
| ---@param data table | ||||
| ----- @usage local Ai = require 'modules.ai' Ai.create_char({player_index = game.player.index, command = 1}) | ||||
| function Public.create_char(data) | ||||
|     if not data or not type(data) == 'table' then | ||||
|         return error('No data was provided or the provided data was not a table.', 2) | ||||
|     end | ||||
|  | ||||
|     if not data.player_index or not data.command then | ||||
|         return error('No correct data was not provided.', 2) | ||||
|     end | ||||
|  | ||||
|     if data.command ~= Public.command.seek_and_destroy_cmd and data.command ~= Public.command.attack_objects_cmd and data.command ~= Public.command.seek_and_mine_cmd then | ||||
|         return error('No correct command was not provided.', 2) | ||||
|     end | ||||
|  | ||||
|     local player = game.get_player(data.player_index) | ||||
|     if not player or not player.valid or not player.connected then | ||||
|         return error('Provided player was not valid or not connected.', 2) | ||||
|     end | ||||
|  | ||||
|     local surface = player.surface | ||||
|     local valid_position = surface.find_non_colliding_position('character', {x = player.position.x, y = player.position.y + 2}, 3, 0.5) | ||||
|     if not valid_position then | ||||
|         return | ||||
|     end | ||||
|     local entity = surface.create_entity {name = 'character', position = valid_position, force = player.force} | ||||
|     if not entity or not entity.valid then | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     entity.associated_player = player | ||||
|     if player.character_health_bonus >= 200 then | ||||
|         entity.character_health_bonus = player.character_health_bonus / 2 | ||||
|     end | ||||
|  | ||||
|     entity.color = player.color | ||||
|     local index = #this.characters + 1 | ||||
|  | ||||
|     local render_id = | ||||
|         rendering.draw_text { | ||||
|         text = player.name .. "'s drone #" .. index, | ||||
|         surface = player.surface, | ||||
|         target = entity, | ||||
|         target_offset = {0, -2.25}, | ||||
|         color = Color.orange, | ||||
|         scale = 1.00, | ||||
|         font = 'default-large-semibold', | ||||
|         alignment = 'center', | ||||
|         scale_with_zoom = false | ||||
|     } | ||||
|  | ||||
|     add_character(player.index, entity, render_id, data) | ||||
| end | ||||
|  | ||||
| Event.on_nth_tick( | ||||
|     2, | ||||
|     function() | ||||
|         char_callback( | ||||
|             function(data) | ||||
|                 check_progress_and_raise_event(data) | ||||
|             end | ||||
|         ) | ||||
|     end | ||||
| ) | ||||
|  | ||||
| Event.on_nth_tick( | ||||
|     10, | ||||
|     function() | ||||
|         local tick = game.tick | ||||
|         char_callback( | ||||
|             function(data) | ||||
|                 if data.ttl <= tick then | ||||
|                     remove_character(data.unit_number) | ||||
|                     return | ||||
|                 end | ||||
|  | ||||
|                 local command = data.command | ||||
|  | ||||
|                 if command == Public.command.seek_and_destroy_cmd then | ||||
|                     seek_enemy_and_destroy(data) | ||||
|                 elseif command == Public.command.seek_and_mine_cmd then | ||||
|                     seek_and_mine(data) | ||||
|                 end | ||||
|             end | ||||
|         ) | ||||
|     end | ||||
| ) | ||||
|  | ||||
| Event.add( | ||||
|     defines.events.on_entity_died, | ||||
|     function(event) | ||||
|         local entity = event.entity | ||||
|         if not entity or not entity.valid then | ||||
|             return | ||||
|         end | ||||
|         if entity.type ~= 'character' then | ||||
|             return | ||||
|         end | ||||
|  | ||||
|         local unit_number = entity.unit_number | ||||
|         if not exists_character(unit_number) then | ||||
|             return | ||||
|         end | ||||
|  | ||||
|         Task.set_timeout_in_ticks(1, clear_corpse_token, {position = entity.position, surface_index = entity.surface.index}) | ||||
|  | ||||
|         remove_character(unit_number) | ||||
|     end | ||||
| ) | ||||
|  | ||||
| return Public | ||||
| @@ -910,12 +910,12 @@ local function on_player_used_capsule(event) | ||||
|         right_bottom = {x = position.x + radius, y = position.y + radius} | ||||
|     } | ||||
|  | ||||
|     if rpg_t.level < spell.level then | ||||
|     if not spell.enabled then | ||||
|         return Public.cast_spell(player, true) | ||||
|     end | ||||
|  | ||||
|     if not spell.enabled then | ||||
|         return | ||||
|     if rpg_t.level < spell.level then | ||||
|         return Public.cast_spell(player, true) | ||||
|     end | ||||
|  | ||||
|     if not Math2D.bounding_box.contains_point(area, player.position) then | ||||
|   | ||||
| @@ -28,7 +28,7 @@ local function get_comparator(sort_by) | ||||
|     return comparators[sort_by] | ||||
| end | ||||
|  | ||||
| local function create_input_element(frame, type, value, items, index) | ||||
| local function create_input_element(frame, type, value, items, index, tooltip) | ||||
|     if type == 'slider' then | ||||
|         return frame.add({type = 'slider', value = value, minimum_value = 0, maximum_value = 1}) | ||||
|     end | ||||
| @@ -38,6 +38,7 @@ local function create_input_element(frame, type, value, items, index) | ||||
|     if type == 'label' then | ||||
|         local label = frame.add({type = 'label', caption = value}) | ||||
|         label.style.font = 'default-listbox' | ||||
|         label.tooltip = tooltip or '' | ||||
|         return label | ||||
|     end | ||||
|     if type == 'dropdown' then | ||||
| @@ -46,7 +47,7 @@ local function create_input_element(frame, type, value, items, index) | ||||
|     return frame.add({type = 'text-box', text = value}) | ||||
| end | ||||
|  | ||||
| local function create_custom_label_element(frame, sprite, localised_string, value) | ||||
| local function create_custom_label_element(frame, sprite, localised_string, value, tooltip) | ||||
|     local t = frame.add({type = 'flow'}) | ||||
|     t.add({type = 'label', caption = '[' .. sprite .. ']'}) | ||||
|     local heading = t.add({type = 'label', caption = localised_string}) | ||||
| @@ -54,6 +55,8 @@ local function create_custom_label_element(frame, sprite, localised_string, valu | ||||
|     local subheading = t.add({type = 'label', caption = value}) | ||||
|     subheading.style.font = 'default-listbox' | ||||
|  | ||||
|     t.tooltip = tooltip or '' | ||||
|  | ||||
|     return subheading | ||||
| end | ||||
|  | ||||
| @@ -710,13 +713,15 @@ function Public.settings_tooltip(player) | ||||
|         table.sort(spells, comparator) | ||||
|  | ||||
|         for _, entity in pairs(spells) do | ||||
|             local cooldown = (entity.cooldown / 60) .. 's' | ||||
|             if entity.type == 'item' then | ||||
|                 local text = '[item=' .. entity.entityName .. '] ▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font].  Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                 create_input_element(normal_spell_grid, 'label', text) | ||||
|             elseif entity.type == 'entity' then | ||||
|                 local text = '[entity=' .. entity.entityName .. '] ▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font].  Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                 create_input_element(normal_spell_grid, 'label', text) | ||||
|             if entity.enabled then | ||||
|                 local cooldown = (entity.cooldown / 60) .. 's' | ||||
|                 if entity.type == 'item' then | ||||
|                     local text = '[item=' .. entity.entityName .. '] ▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font].  Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                     create_input_element(normal_spell_grid, 'label', text, nil, nil, entity.tooltip) | ||||
|                 elseif entity.type == 'entity' then | ||||
|                     local text = '[entity=' .. entity.entityName .. '] ▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font].  Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                     create_input_element(normal_spell_grid, 'label', text, nil, nil, entity.tooltip) | ||||
|                 end | ||||
|             end | ||||
|         end | ||||
|  | ||||
| @@ -741,10 +746,12 @@ function Public.settings_tooltip(player) | ||||
|         local special_spell_grid = special_spell_pane.add({type = 'table', column_count = 1}) | ||||
|  | ||||
|         for _, entity in pairs(spells) do | ||||
|             local cooldown = (entity.cooldown / 60) .. 's' | ||||
|             if entity.type == 'special' then | ||||
|                 local text = '▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font]. Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                 create_custom_label_element(special_spell_grid, entity.special_sprite, entity.name, text) | ||||
|             if entity.enabled then | ||||
|                 local cooldown = (entity.cooldown / 60) .. 's' | ||||
|                 if entity.type == 'special' then | ||||
|                     local text = '▪️ Level: [font=default-bold]' .. entity.level .. '[/font] Mana: [font=default-bold]' .. entity.mana_cost .. '[/font]. Cooldown: [font=default-bold]' .. cooldown .. '[/font]' | ||||
|                     create_custom_label_element(special_spell_grid, entity.special_sprite, entity.name, text, entity.tooltip) | ||||
|                 end | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local Public = require 'modules.rpg.table' | ||||
| local Token = require 'utils.token' | ||||
| local Task = require 'utils.task' | ||||
| local Ai = require 'modules.ai' | ||||
|  | ||||
| local spells = {} | ||||
| local random = math.random | ||||
| @@ -1030,6 +1031,58 @@ spells[#spells + 1] = { | ||||
|     end | ||||
| } | ||||
|  | ||||
| spells[#spells + 1] = { | ||||
|     name = {'spells.drone_enemy'}, | ||||
|     entityName = 'drone_enemy', | ||||
|     target = false, | ||||
|     force = 'player', | ||||
|     level = 200, | ||||
|     type = 'special', | ||||
|     mana_cost = 1000, | ||||
|     cooldown = 18000, | ||||
|     enabled = false, | ||||
|     enforce_cooldown = true, | ||||
|     log_spell = true, | ||||
|     sprite = 'virtual-signal/signal-info', | ||||
|     special_sprite = 'virtual-signal=signal-info', | ||||
|     tooltip = 'Creates a drone that searches for enemies and destroys them.', | ||||
|     callback = function(data) | ||||
|         local self = data.self | ||||
|         local player = data.player | ||||
|         Ai.create_char({player_index = player.index, command = 1, search_local = true}) | ||||
|  | ||||
|         Public.cast_spell(player) | ||||
|         Public.remove_mana(player, self.mana_cost) | ||||
|         return true | ||||
|     end | ||||
| } | ||||
|  | ||||
| spells[#spells + 1] = { | ||||
|     name = {'spells.drone_mine'}, | ||||
|     entityName = 'drone_mine', | ||||
|     target = false, | ||||
|     force = 'player', | ||||
|     level = 200, | ||||
|     type = 'special', | ||||
|     mana_cost = 1000, | ||||
|     cooldown = 18000, | ||||
|     enabled = false, | ||||
|     enforce_cooldown = true, | ||||
|     log_spell = true, | ||||
|     sprite = 'virtual-signal/signal-info', | ||||
|     special_sprite = 'virtual-signal=signal-info', | ||||
|     tooltip = 'Creates a drone mines entities around you.', | ||||
|     callback = function(data) | ||||
|         local self = data.self | ||||
|         local player = data.player | ||||
|         Ai.create_char({player_index = player.index, command = 2, search_local = false}) | ||||
|  | ||||
|         Public.cast_spell(player) | ||||
|         Public.remove_mana(player, self.mana_cost) | ||||
|         return true | ||||
|     end | ||||
| } | ||||
|  | ||||
| Public.projectile_types = { | ||||
|     ['explosives'] = {name = 'grenade', count = 0.5, max_range = 32, tick_speed = 1}, | ||||
|     ['distractor-capsule'] = {name = 'distractor-capsule', count = 1, max_range = 32, tick_speed = 1}, | ||||
|   | ||||
| @@ -162,7 +162,7 @@ function Public.get(key) | ||||
| end | ||||
|  | ||||
| --- Gets value from player rpg_t table | ||||
| ---@param key string | ||||
| ---@param key string|integer | ||||
| ---@param value string|nil | ||||
| function Public.get_value_from_player(key, value) | ||||
|     if key and value then | ||||
|   | ||||
| @@ -554,4 +554,32 @@ Public.get_closest_neighbour = function(position, objects) | ||||
|     return closest | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| get_closest_neighbour - Return object whose is closest to given position. | ||||
| @param position - Position, origin point | ||||
| @param object - Table of objects that have any sort of position datafield. | ||||
| --]] | ||||
| Public.get_closest_neighbour_non_player = function(position, objects) | ||||
|     local closest = objects[1] | ||||
|     local min_dist = Public.get_distance(position, closest) | ||||
|  | ||||
|     local object, dist | ||||
|     for i = #objects, 1, -1 do | ||||
|         object = objects[i] | ||||
|         if object and object.valid and object.destructible then | ||||
|             dist = Public.get_distance(position, object) | ||||
|             if dist < min_dist then | ||||
|                 closest = object | ||||
|                 min_dist = dist | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     if closest and closest.valid and not closest.destructible then | ||||
|         return false | ||||
|     end | ||||
|  | ||||
|     return closest | ||||
| end | ||||
|  | ||||
| return Public | ||||
|   | ||||
| @@ -117,4 +117,11 @@ Module.format_time = function(ticks) | ||||
|     return table.concat(result, ' ') | ||||
| end | ||||
|  | ||||
| function Module.inside(pos, area) | ||||
|     local lt = area.left_top | ||||
|     local rb = area.right_bottom | ||||
|  | ||||
|     return pos.x >= lt.x and pos.y >= lt.y and pos.x <= rb.x and pos.y <= rb.y | ||||
| end | ||||
|  | ||||
| return Module | ||||
|   | ||||
		Reference in New Issue
	
	Block a user