mirror of
https://github.com/cyberarm/i-mic-rts.git
synced 2025-12-15 15:52:34 +00:00
Building units now uses orders 😃
This commit is contained in:
BIN
assets/audio/music/EmptyCity.ogg
Normal file
BIN
assets/audio/music/EmptyCity.ogg
Normal file
Binary file not shown.
2
assets/audio/music/README.md
Normal file
2
assets/audio/music/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Music Source
|
||||||
|
* EmptyCity - CC0 - yd - https://opengameart.org/content/emptycity-background-music
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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])
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
18
lib/order.rb
18
lib/order.rb
@@ -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
18
lib/orders/build_unit.rb
Normal 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
|
||||||
25
lib/orders/build_unit_complete.rb
Normal file
25
lib/orders/build_unit_complete.rb
Normal 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
|
||||||
@@ -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
|
||||||
@@ -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?
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user