Building units now uses orders 😃

This commit is contained in:
2021-01-01 14:25:44 -06:00
parent 74458dbfd0
commit 5f301337b4
35 changed files with 171 additions and 100 deletions

Binary file not shown.

View File

@@ -0,0 +1,2 @@
# Music Source
* EmptyCity - CC0 - yd - https://opengameart.org/content/emptycity-background-music

View File

@@ -1,5 +1,7 @@
class IMICRTS class IMICRTS
class Component class Component
include CyberarmEngine::Common
@@components = {} @@components = {}
def self.get(name) def self.get(name)

View File

@@ -2,13 +2,13 @@ class IMICRTS
class BuildQueue < Component class BuildQueue < Component
attr_reader :queue attr_reader :queue
Item = Struct.new(:entity, :progress) Item = Struct.new(:entity, :progress, :completed)
def setup def setup
@queue = [] @queue = []
end end
def add(type) def add(type)
@queue << Item.new(Entity.get(type), 0.0) @queue << Item.new(Entity.get(type), 0.0, false)
end end
end end
end end

View File

@@ -2,7 +2,7 @@ class IMICRTS
class Building < Component class Building < Component
def setup def setup
data.construction_progress ||= 0 data.construction_progress ||= 0
data.construction_goal ||= 100 data.construction_goal ||= Entity.get(@parent.name).build_steps
@text = CyberarmEngine::Text.new("", y: @parent.position.y, z: Float::INFINITY, size: 12) @text = CyberarmEngine::Text.new("", y: @parent.position.y, z: Float::INFINITY, size: 12)
data.state = :construct # deconstruct, building, idle data.state = :construct # deconstruct, building, idle
@@ -48,8 +48,8 @@ class IMICRTS
end end
def draw_construction def draw_construction
@fencing ||= Gosu::Image.new(IMICRTS::ASSETS_PATH + "/fencing/fencing.png") @fencing ||= get_image(IMICRTS::ASSETS_PATH + "/fencing/fencing.png")
@fencing_edge ||= Gosu::Image.new(IMICRTS::ASSETS_PATH + "/fencing/fencing_edge.png") @fencing_edge ||= get_image(IMICRTS::ASSETS_PATH + "/fencing/fencing_edge.png")
tiles = [] tiles = []
each_tile(@parent.position / @parent.director.map.tile_size) do |tile, data, x, y| each_tile(@parent.position / @parent.director.map.tile_size) do |tile, data, x, y|

View File

@@ -16,12 +16,12 @@ class IMICRTS
end end
def rotate_towards(vector) def rotate_towards(vector)
_angle = Gosu.angle(@parent.position.x, @parent.position.y, vector.x, vector.y) angle = Gosu.angle(@parent.position.x, @parent.position.y, vector.x, vector.y)
a = (360.0 + (_angle - @parent.angle)) % 360.0 a = (360.0 + (angle - @parent.angle)) % 360.0
# FIXME: Fails if vector is directly behind entity # FIXME: Fails if vector is directly behind entity
if a.round == 180 if a.round == 180
@parent.angle = (_angle + 180.0) % 360.0 @parent.angle = (angle + 180.0) % 360.0
elsif a < 180 elsif a < 180
@parent.angle -= 1.0 @parent.angle -= 1.0
else else

View File

@@ -17,7 +17,9 @@ class IMICRTS
action.label = ent.name.to_s.split("_").map{ |s| s.capitalize }.join(" ") action.label = ent.name.to_s.split("_").map{ |s| s.capitalize }.join(" ")
action.description = "Cost: #{ent.cost}\n#{ent.description}" action.description = "Cost: #{ent.cost}\n#{ent.description}"
action.block = proc { @parent.component(:build_queue).add(data[:entity]) } action.block = proc do
@parent.director.schedule_order(IMICRTS::Order::BUILD_UNIT, @parent.player.id, @parent.id, data[:entity])
end
when :set_tool when :set_tool
ent = IMICRTS::Entity.get(data[:entity]) ent = IMICRTS::Entity.get(data[:entity])

View File

@@ -1,21 +1,17 @@
class IMICRTS class IMICRTS
class Spawner < Component class Spawner < Component
def tick(tick_id) def tick(tick_id)
# TODO: Ensure that a build order is created before working on entity
item = @parent.component(:build_queue).queue.first item = @parent.component(:build_queue).queue.first
if item return unless item
item.progress += 1 item.progress += 1
if item.progress >= 100 # TODO: Define work units required for construction if item.progress >= item.entity.build_steps
@parent.component(:build_queue).queue.shift unless item.completed
item.completed = true
spawn_point = @parent.position.clone @parent.director.schedule_order(IMICRTS::Order::BUILD_UNIT_COMPLETE, @parent.player.id, @parent.id)
spawn_point.y += 96 # TODO: Use one of entity's reserved tiles for spawning
ent = @parent.director.spawn_entity(player_id: @parent.player.id, name: item.entity.name, position: spawn_point)
ent.target = @parent.component(:waypoint).waypoint if @parent.component(:waypoint)
end end
end end
end end

View File

@@ -7,15 +7,15 @@ class IMICRTS
end end
def body_image=(image) def body_image=(image)
@body_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @body_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def shell_image=(image) def shell_image=(image)
@shell_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @shell_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def overlay_image=(image) def overlay_image=(image)
@overlay_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @overlay_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def render def render
@@ -28,8 +28,11 @@ class IMICRTS
def draw def draw
render unless @render render unless @render
@angle += 0.1
@render.draw_rot(@parent.position.x, @parent.position.y, @parent.position.z, @angle, @center.x, @center.y) @render.draw_rot(@parent.position.x, @parent.position.y, @parent.position.z, @angle, @center.x, @center.y)
end end
def update
@angle = @parent.angle
end
end end
end end

View File

@@ -3,6 +3,7 @@ class IMICRTS
def setup def setup
@waypoint = @parent.position.clone @waypoint = @parent.position.clone
@waypoint.y += @parent.director.map.tile_size @waypoint.y += @parent.director.map.tile_size
@waypoint_color = 0xffffff00
end end
def set(vector) def set(vector)
@@ -17,11 +18,11 @@ class IMICRTS
return unless @parent.player.selected_entities.include?(@parent) return unless @parent.player.selected_entities.include?(@parent)
Gosu.draw_line( Gosu.draw_line(
@parent.position.x, @parent.position.y, @parent.player.color, @parent.position.x, @parent.position.y, @waypoint_color,
@waypoint.x, @waypoint.y, @parent.player.color, ZOrder::ENTITY_GIZMOS @waypoint.x, @waypoint.y, @waypoint_color, ZOrder::ENTITY_GIZMOS
) )
Gosu.draw_circle(@waypoint.x, @waypoint.y, 4, 9, @parent.player.color, ZOrder::ENTITY_GIZMOS) Gosu.draw_circle(@waypoint.x, @waypoint.y, 4, 9, @waypoint_color, ZOrder::ENTITY_GIZMOS)
end end
end end
end end

View File

@@ -6,7 +6,7 @@ tiles = [
[false, :path, :path, :path, false], [false, :path, :path, :path, false],
] ]
IMICRTS::Entity.define_entity(:barracks, :building, 400, "Builds and soldiers", tiles) do |entity| IMICRTS::Entity.define_entity(:barracks, :building, 400, 40, "Builds and soldiers", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.has(:waypoint) entity.has(:waypoint)
entity.has(:spawner) entity.has(:spawner)

View File

@@ -6,7 +6,7 @@ tiles = [
[false, :path, :path, :path, false], [false, :path, :path, :path, false],
] ]
IMICRTS::Entity.define_entity(:construction_yard, :building, 2_000, "Provides radar and builds construction workers", tiles) do |entity| IMICRTS::Entity.define_entity(:construction_yard, :building, 2_000, 310, "Provides radar and builds construction workers", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.has(:waypoint) entity.has(:waypoint)
entity.has(:spawner) entity.has(:spawner)

View File

@@ -6,7 +6,7 @@ tiles = [
[false, false, false, false, false], [false, false, false, false, false],
] ]
IMICRTS::Entity.define_entity(:helipad, :building, 1_000, "Builds and rearms helicopters", tiles) do |entity| IMICRTS::Entity.define_entity(:helipad, :building, 1_000, 100, "Builds and rearms helicopters", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.has(:waypoint) entity.has(:waypoint)
entity.has(:spawner) entity.has(:spawner)

View File

@@ -6,7 +6,7 @@ tiles = [
[false, false, :path, false, false], [false, false, :path, false, false],
] ]
IMICRTS::Entity.define_entity(:power_plant, :building, 800, "Generates power", tiles) do |entity| IMICRTS::Entity.define_entity(:power_plant, :building, 800, 45, "Generates power", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.radius = 24 entity.radius = 24

View File

@@ -6,7 +6,7 @@ tiles = [
[false, false, :path, :path, false], [false, false, :path, :path, false],
] ]
IMICRTS::Entity.define_entity(:refinery, :building, 1_400, "Generates credits", tiles) do |entity| IMICRTS::Entity.define_entity(:refinery, :building, 1_400, 200, "Generates credits", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.radius = 44 entity.radius = 44

View File

@@ -6,7 +6,7 @@ tiles = [
[false, :path, :path, :path, false], [false, :path, :path, :path, false],
] ]
IMICRTS::Entity.define_entity(:war_factory, :building, 2_000, "Builds units", tiles) do |entity| IMICRTS::Entity.define_entity(:war_factory, :building, 2_000, 310, "Builds units", tiles) do |entity|
entity.has(:building) entity.has(:building)
entity.has(:waypoint) entity.has(:waypoint)
entity.has(:spawner) entity.has(:spawner)

View File

@@ -1,4 +1,4 @@
IMICRTS::Entity.define_entity(:construction_worker, :unit, 1000, "Constructs buildings") do |entity| IMICRTS::Entity.define_entity(:construction_worker, :unit, 1000, 75, "Constructs buildings") do |entity|
entity.has(:movement) entity.has(:movement)
entity.has(:build_queue) entity.has(:build_queue)
entity.has(:sidebar_actions) entity.has(:sidebar_actions)

View File

@@ -1,4 +1,4 @@
IMICRTS::Entity.define_entity(:harvester, :unit, 1400, "Harvests ore") do |entity, director| IMICRTS::Entity.define_entity(:harvester, :unit, 1400, 140, "Harvests ore") do |entity, director|
entity.has(:movement) entity.has(:movement)
entity.radius = 10 entity.radius = 10

View File

@@ -1,6 +1,7 @@
IMICRTS::Entity.define_entity(:helicopter, :unit, 400, "Attacks ground targets") do |entity| IMICRTS::Entity.define_entity(:helicopter, :unit, 400, 40, "Attacks ground targets") do |entity|
entity.has(:movement) entity.has(:movement)
entity.speed = 2.5
entity.radius = 14 entity.radius = 14
entity.movement = :air entity.movement = :air
entity.max_health = 100.0 entity.max_health = 100.0

View File

@@ -1,7 +1,8 @@
IMICRTS::Entity.define_entity(:jeep, :unit, 400, "Attacks ground targets") do |entity| IMICRTS::Entity.define_entity(:jeep, :unit, 400, 40, "Attacks ground targets") do |entity|
entity.has(:movement) entity.has(:movement)
entity.has(:turret) entity.has(:turret)
entity.speed = 1.5
entity.radius = 14 entity.radius = 14
entity.movement = :ground entity.movement = :ground
entity.max_health = 100.0 entity.max_health = 100.0
@@ -14,4 +15,8 @@ IMICRTS::Entity.define_entity(:jeep, :unit, 400, "Attacks ground targets") do |e
entity.on_tick do entity.on_tick do
end end
entity.component(:movement).define_singleton_method(:rotate_towards) do |target|
entity.angle = Gosu.angle(target.x, target.y, entity.position.x, entity.position.y)
end
end end

View File

@@ -1,4 +1,4 @@
IMICRTS::Entity.define_entity(:tank, :unit, 800, "Attacks ground targets") do |entity| IMICRTS::Entity.define_entity(:tank, :unit, 800, 80, "Attacks ground targets") do |entity|
entity.has(:movement) entity.has(:movement)
entity.has(:turret) entity.has(:turret)

View File

@@ -1,24 +1,23 @@
class IMICRTS class IMICRTS
class Entity class Entity
Stub = Struct.new(:name, :type, :cost, :description, :tiles, :setup) include CyberarmEngine::Common
Stub = Struct.new(:name, :type, :cost, :build_steps, :description, :tiles, :setup)
@entities = {} @entities = {}
def self.get(name) def self.get(name)
@entities.dig(name) @entities.dig(name)
end end
def self.define_entity(name, type, cost, description, tiles = [[]], &block) def self.define_entity(name, type, cost, build_steps, description, tiles = [[]], &block)
if entity = get(name) raise "#{name.inspect} is already defined!" if get(name)
raise "#{name.inspect} is already defined!"
else @entities[name] = Stub.new(name, type, cost, build_steps, description, tiles, block)
@entities[name] = Stub.new(name, type, cost, description, tiles, block)
end
end end
attr_reader :director, :player, :id, :name, :type, :speed, :data attr_reader :director, :player, :id, :name, :type, :data
attr_accessor :position, :angle, :radius, :target, :state, attr_accessor :position, :angle, :radius, :target, :state, :movement, :health, :max_health,
:movement, :health, :max_health, :speed, :turret, :center, :particle_emitters, :color
:turret, :center, :particle_emitters, :color
def initialize(name:, player:, id:, position:, angle:, director:, proto_entity: false) def initialize(name:, player:, id:, position:, angle:, director:, proto_entity: false)
@player = player @player = player
@id = id @id = id
@@ -77,11 +76,9 @@ class IMICRTS
def has(symbol) def has(symbol)
component = Component.get(symbol) component = Component.get(symbol)
if component raise "Unknown component: #{symbol.inspect}" unless component
@components[symbol] = component.new(parent: self) @components[symbol] = component.new(parent: self)
else
raise "Unknown component: #{symbol.inspect}"
end
end end
def component(symbol) def component(symbol)
@@ -89,15 +86,15 @@ class IMICRTS
end end
def body_image=(image) def body_image=(image)
@body_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @body_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def shell_image=(image) def shell_image=(image)
@shell_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @shell_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def overlay_image=(image) def overlay_image=(image)
@overlay_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) @overlay_image = get_image("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true)
end end
def target=(entity) def target=(entity)
@@ -153,10 +150,11 @@ class IMICRTS
end end
def tick(tick_id) def tick(tick_id)
@components.values.each { |com| com.tick(tick_id) } @components.each_value { |com| com.tick(tick_id) }
@on_tick.call if @on_tick @on_tick&.call
data.assigned_construction_workers ||= 4
data.assigned_construction_workers ||= 1
data.construction_speed ||= 1 data.construction_speed ||= 1
component(:building).construction_work(data.assigned_construction_workers * data.construction_speed) if component(:building) component(:building).construction_work(data.assigned_construction_workers * data.construction_speed) if component(:building)
end end

View File

@@ -29,6 +29,7 @@ class IMICRTS
end end
attr_reader :id, :arguments attr_reader :id, :arguments
def initialize(id:, arguments:, &handler) def initialize(id:, arguments:, &handler)
@id = id @id = id
@arguments = arguments @arguments = arguments
@@ -36,7 +37,7 @@ class IMICRTS
end end
def execute(director, *arguments) def execute(director, *arguments)
pp Order.order_name(self.id) pp Order.order_name(id)
@handler.call(struct(arguments), director) @handler.call(struct(arguments), director)
end end
@@ -48,7 +49,7 @@ class IMICRTS
hash[key] = args[value] hash[key] = args[value]
end end
return hash hash
end end
def serialize(order, director) def serialize(order, director)
@@ -76,13 +77,18 @@ class IMICRTS
:ATTACK, :ATTACK,
:PATROL, :PATROL,
:BUILD_ORDER, :CONSTRUCT,
:CANCEL_BUILD_ORDER, :CANCEL_CONSTRUCTION,
:BUILD_ORDER_COMPLETE, :CONSTRUCTION_COMPLETE,
:BUILD_UNIT,
:CANCEL_BUILD_UNIT,
:BUILD_UNIT_COMPLETE,
:BUILDING_SET_WAYPOINT, :BUILDING_SET_WAYPOINT,
:BUILDING_POWER_STATE, :BUILDING_POWER_STATE,
:BUILDING_REPAIR, :REPAIR_BUILDING,
:CANCEL_BUILDING_REPAIR,
:BUILDING_SELL, :BUILDING_SELL,
:MESSAGE_BROADCAST, :MESSAGE_BROADCAST,

18
lib/orders/build_unit.rb Normal file
View File

@@ -0,0 +1,18 @@
IMICRTS::Order.define_handler(IMICRTS::Order::BUILD_UNIT, arguments: [:player_id, :entity_id, :unit_type]) do |order, director|
director.player(order.player_id).entity(order.entity_id).component(:build_queue)&.add(order.unit_type)
end
IMICRTS::Order.define_serializer(IMICRTS::Order::BUILD_UNIT) do |order, director|
# Order ID | Player ID | Entity ID | Unit Type
# char | char | integer | string
[IMICRTS::Order::BUILD_UNIT, order.player_id, order.entity_id, order.unit_type.to_s].pack("CCNA*")
end
IMICRTS::Order.define_deserializer(IMICRTS::Order::BUILD_UNIT) do |string, director|
# String fed into deserializer has Order ID removed
# Player ID |
# char | integer | string
data = string.unpack("CNA*")
[data[0], data[1], data[2].to_sym]
end

View File

@@ -0,0 +1,25 @@
IMICRTS::Order.define_handler(IMICRTS::Order::BUILD_UNIT_COMPLETE, arguments: [:player_id, :entity_id]) do |order, director|
entity = director.player(order.player_id).entity(order.entity_id)
item = entity.component(:build_queue).queue.shift
spawn_point = entity.position.clone
spawn_point.y += 96 # TODO: Use entity defined spawnpoint
ent = entity.director.spawn_entity(player_id: entity.player.id, name: item.entity.name, position: spawn_point)
ent.target = entity.component(:waypoint).waypoint if entity.component(:waypoint)
end
IMICRTS::Order.define_serializer(IMICRTS::Order::BUILD_UNIT_COMPLETE) do |order, director|
# Order ID | Player ID
# char | char
[IMICRTS::Order::BUILD_UNIT_COMPLETE, order.player_id, order.entity_id].pack("CCN")
end
IMICRTS::Order.define_deserializer(IMICRTS::Order::BUILD_UNIT_COMPLETE) do |string, director|
# String fed into deserializer has Order ID removed
# Player ID | Entity ID
# char | integer
data = string.unpack("CN")
[data[0], data[1]]
end

View File

@@ -1,4 +1,4 @@
IMICRTS::Order.define_handler(IMICRTS::Order::BUILD_ORDER, arguments: [:player_id, :vector, :building]) do |order, director| IMICRTS::Order.define_handler(IMICRTS::Order::CONSTRUCT, arguments: [:player_id, :vector, :building]) do |order, director|
tile = director.map.tile_at(order.vector.x, order.vector.y) tile = director.map.tile_at(order.vector.x, order.vector.y)
position = tile.position + director.map.tile_size / 2 position = tile.position + director.map.tile_size / 2
@@ -20,14 +20,14 @@ IMICRTS::Order.define_handler(IMICRTS::Order::BUILD_ORDER, arguments: [:player_i
end end
end end
IMICRTS::Order.define_serializer(IMICRTS::Order::BUILD_ORDER) do |order, director| IMICRTS::Order.define_serializer(IMICRTS::Order::CONSTRUCT) do |order, director|
# Order ID | Player ID | Vector X | Vector Y | Entity Name # Order ID | Player ID | Vector X | Vector Y | Entity Name
# char | char | integer | integer | string # char | char | integer | integer | string
[IMICRTS::Order::BUILD_ORDER, order.player_id, order.vector.x, order.vector.y, order.building.to_s].pack("CCNNA*") [IMICRTS::Order::CONSTRUCT, order.player_id, order.vector.x, order.vector.y, order.building.to_s].pack("CCNNA*")
end end
IMICRTS::Order.define_deserializer(IMICRTS::Order::BUILD_ORDER) do |string, director| IMICRTS::Order.define_deserializer(IMICRTS::Order::CONSTRUCT) do |string, director|
# String fed into deserializer has Order ID removed # String fed into deserializer has Order ID removed
# Player ID | Vector X | Vector Y | Entity Name # Player ID | Vector X | Vector Y | Entity Name
# char | integer | integer | string # char | integer | integer | string

View File

@@ -147,7 +147,6 @@ class IMICRTS
# DOWN # DOWN
add_node create_node(@current_node.tile.grid_position.x, @current_node.tile.grid_position.y + 1, @current_node) add_node create_node(@current_node.tile.grid_position.x, @current_node.tile.grid_position.y + 1, @current_node)
# TODO: Add diagonal nodes, if requested
if @allow_diagonal if @allow_diagonal
# LEFT-UP # LEFT-UP
if node_above? && node_above_left? if node_above? && node_above_left?

View File

@@ -4,7 +4,7 @@ class IMICRTS
@title = Gosu::Font.new(56, name: "Noto Sans Display", bold: true) @title = Gosu::Font.new(56, name: "Noto Sans Display", bold: true)
@text = Gosu::Font.new(18, name: "Noto Sans Thaana", bold: true) @text = Gosu::Font.new(18, name: "Noto Sans Thaana", bold: true)
@name = IMICRTS::NAME @name = IMICRTS::NAME
@logo = Gosu::Image.new("#{ASSETS_PATH}/logo.png") @logo = get_image("#{ASSETS_PATH}/logo.png")
@messages = ["Loading", "Compiling Protons", "Launching Warhead", "git push origin --force"] @messages = ["Loading", "Compiling Protons", "Launching Warhead", "git push origin --force"]
@messages_index = 0 @messages_index = 0

View File

@@ -2,7 +2,7 @@ class IMICRTS
class Closing < CyberarmEngine::GuiState class Closing < CyberarmEngine::GuiState
def setup def setup
window.show_cursor = false window.show_cursor = false
@logo = Gosu::Image.new("#{ASSETS_PATH}/logo.png") @logo = get_image("#{ASSETS_PATH}/logo.png")
@color = Gosu::Color.new(0xffffffff) @color = Gosu::Color.new(0xffffffff)
@started_at = Gosu.milliseconds @started_at = Gosu.milliseconds

View File

@@ -41,7 +41,7 @@ class IMICRTS
player_id: player.id, name: :construction_yard, player_id: player.id, name: :construction_yard,
position: CyberarmEngine::Vector.new(player.spawnpoint.x, player.spawnpoint.y, ZOrder::BUILDING) position: CyberarmEngine::Vector.new(player.spawnpoint.x, player.spawnpoint.y, ZOrder::BUILDING)
) )
construction_yard.component(:building).data.construction_progress = 100 construction_yard.component(:building).data.construction_progress = Entity.get(construction_yard.name).build_steps
@director.each_tile(@director.map.world_to_grid(construction_yard.position), construction_yard.name) do |tile, space_required| @director.each_tile(@director.map.world_to_grid(construction_yard.position), construction_yard.name) do |tile, space_required|
if space_required == true if space_required == true
tile.entity = construction_yard tile.entity = construction_yard

View File

@@ -1,5 +1,7 @@
class IMICRTS class IMICRTS
class Tool class Tool
include CyberarmEngine::Common
@@tools = {} @@tools = {}
def self.get(tool) def self.get(tool)
@@tools.dig(tool) @@tools.dig(tool)

View File

@@ -3,14 +3,17 @@ class IMICRTS
class EntityController < Tool class EntityController < Tool
def setup def setup
@drag_start = CyberarmEngine::Vector.new @drag_start = CyberarmEngine::Vector.new
@box_color = 0xaa99ff99
@box_border_size = 2
end end
def draw def draw
Gosu.draw_rect( return unless @box
@box.min.x, @box.min.y,
@box.width, @box.height, Gosu.draw_rect(@box.min.x, @box.min.y, @box.width, @box_border_size, @box_color, ZOrder::SELECTION_BOX)
Gosu::Color.rgba(50, 50, 50, 150), ZOrder::SELECTION_BOX Gosu.draw_rect(@box.min.x + @box.width, @box.min.y, @box_border_size, @box.height, @box_color, ZOrder::SELECTION_BOX)
) if @box Gosu.draw_rect(@box.min.x, @box.min.y + @box.height, @box.width, @box_border_size, @box_color, ZOrder::SELECTION_BOX)
Gosu.draw_rect(@box.min.x, @box.min.y, @box_border_size, @box.height, @box_color, ZOrder::SELECTION_BOX)
end end
def update def update
@@ -40,16 +43,16 @@ class IMICRTS
@selection_start = @player.camera.transform(@game.window.mouse) @selection_start = @player.camera.transform(@game.window.mouse)
end end
when Gosu::MS_RIGHT when Gosu::MS_RIGHT
if @player.selected_entities.size > 0 unless @player.selected_entities.empty?
if @player.selected_entities.any? { |ent| ent.component(:movement) } if @player.selected_entities.any? { |ent| ent.component(:movement) }
@director.schedule_order(Order::MOVE, @player.id, @player.camera.transform(@game.window.mouse)) @director.schedule_order(Order::MOVE, @player.id, @player.camera.transform(@game.window.mouse))
@game.overlays << Game::Overlay.new(Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/cursors/move.png"), @player.camera.transform(@game.window.mouse), 0, 255) @game.overlays << Game::Overlay.new(get_image("#{IMICRTS::ASSETS_PATH}/cursors/move.png"), @player.camera.transform(@game.window.mouse), 0, 255)
@game.overlays.last.position.z = ZOrder::OVERLAY @game.overlays.last.position.z = ZOrder::OVERLAY
elsif @player.selected_entities.size == 1 && @player.selected_entities.first.component(:waypoint) elsif @player.selected_entities.size == 1 && @player.selected_entities.first.component(:waypoint)
@director.schedule_order(Order::BUILDING_SET_WAYPOINT, @player.id, @player.selected_entities.first.id, @player.camera.transform(@game.window.mouse)) @director.schedule_order(Order::BUILDING_SET_WAYPOINT, @player.id, @player.selected_entities.first.id, @player.camera.transform(@game.window.mouse))
@game.overlays << Game::Overlay.new(Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/cursors/move.png"), @player.camera.transform(@game.window.mouse), 0, 255) @game.overlays << Game::Overlay.new(get_image("#{IMICRTS::ASSETS_PATH}/cursors/move.png"), @player.camera.transform(@game.window.mouse), 0, 255)
@game.overlays.last.position.z = ZOrder::OVERLAY @game.overlays.last.position.z = ZOrder::OVERLAY
end end
end end
@@ -63,11 +66,13 @@ class IMICRTS
@box = nil @box = nil
@selection_start = nil @selection_start = nil
return if @game.sidebar.hit?(@game.window.mouse_x, @game.window.mouse_y)
diff = (@player.selected_entities - @game.selected_entities) diff = (@player.selected_entities - @game.selected_entities)
@game.sidebar_actions.clear @game.sidebar_actions.clear
@director.schedule_order(Order::DESELECTED_UNITS, @player.id, diff) if diff.size > 0 @director.schedule_order(Order::DESELECTED_UNITS, @player.id, diff) if diff.size.positive?
if @game.selected_entities.size > 0 if @game.selected_entities.size.positive?
@director.schedule_order(Order::SELECTED_UNITS, @player.id, @game.selected_entities) @director.schedule_order(Order::SELECTED_UNITS, @player.id, @game.selected_entities)
else else
pick_entity pick_entity
@@ -79,7 +84,7 @@ class IMICRTS
@game.sidebar_actions.clear do @game.sidebar_actions.clear do
ent.component(:sidebar_actions).actions.each do |action| ent.component(:sidebar_actions).actions.each do |action|
@game.button action.label, tip: action.description, width: 1.0 do @game.button action.label, tip: action.description, width: 1.0 do
action.block.call if action.block action.block&.call
end end
end end
end end

View File

@@ -30,11 +30,10 @@ class IMICRTS
end end
def update def update
# TODO: ensure that construction worker is alive cancel_tool unless @construction_worker.player.entity(@construction_worker.id)
cancel_tool if @construction_worker.die?
vector = vector_to_grid(@game.window.mouse) vector = vector_to_grid(@game.window.mouse)
if tile = @director.map.tile_at(vector.x, vector.y) if (tile = @director.map.tile_at(vector.x, vector.y))
position = tile.position.clone position = tile.position.clone
@preview.position = position + @director.map.tile_size / 2 @preview.position = position + @director.map.tile_size / 2
@preview.position.z = ZOrder::OVERLAY @preview.position.z = ZOrder::OVERLAY
@@ -58,7 +57,7 @@ class IMICRTS
# position: CyberarmEngine::Vector.new(position.x, position.y, ZOrder::BUILDING) # position: CyberarmEngine::Vector.new(position.x, position.y, ZOrder::BUILDING)
# ) # )
@director.schedule_order(Order::BUILD_ORDER, @player.id, vector, @entity) @director.schedule_order(Order::CONSTRUCT, @player.id, vector, @entity)
# each_tile(vector) do |tile, space_required| # each_tile(vector) do |tile, space_required|
# if space_required == true # if space_required == true

View File

@@ -1,10 +1,11 @@
class IMICRTS class IMICRTS
class Window < CyberarmEngine::Window class Window < CyberarmEngine::Window
attr_reader :mouse attr_reader :mouse
def setup def setup
@last_update_time = Gosu.milliseconds @last_update_time = Gosu.milliseconds
@mouse = CyberarmEngine::Vector.new @mouse = CyberarmEngine::Vector.new
@cursor = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/cursors/pointer.png") @cursor = get_image("#{IMICRTS::ASSETS_PATH}/cursors/pointer.png")
self.caption = "#{IMICRTS::NAME} (#{IMICRTS::VERSION} #{IMICRTS::VERSION_NAME})" self.caption = "#{IMICRTS::NAME} (#{IMICRTS::VERSION} #{IMICRTS::VERSION_NAME})"
if ARGV.join.include?("--debug-game") if ARGV.join.include?("--debug-game")
@@ -14,6 +15,10 @@ class IMICRTS
else else
push_state(Boot) push_state(Boot)
end end
# TODO: Jukebox
s = get_song("#{GAME_ROOT_PATH}/assets/audio/music/EmptyCity.ogg")
s.play(true)
end end
def draw def draw
@@ -23,14 +28,16 @@ class IMICRTS
end end
def update def update
@mouse.x, @mouse.y = self.mouse_x, self.mouse_y @mouse.x = mouse_x
@mouse.y = mouse_y
super super
@last_update_time = Gosu.milliseconds @last_update_time = Gosu.milliseconds
end end
def needs_cursor? def needs_cursor?
return false false
end end
def close def close