sc2ai 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/sc2ai/protocol/common.proto +6 -6
- data/data/sc2ai/protocol/data.proto +23 -20
- data/data/sc2ai/protocol/debug.proto +25 -21
- data/data/sc2ai/protocol/error.proto +217 -215
- data/data/sc2ai/protocol/query.proto +1 -1
- data/data/sc2ai/protocol/raw.proto +16 -14
- data/data/sc2ai/protocol/sc2api.proto +108 -94
- data/data/sc2ai/protocol/score.proto +4 -3
- data/data/sc2ai/protocol/spatial.proto +6 -5
- data/data/sc2ai/protocol/ui.proto +17 -14
- data/exe/sc2ai +0 -3
- data/lib/docker_build/Dockerfile.ruby +4 -2
- data/lib/sc2ai/api/ability_id.rb +6 -1
- data/lib/sc2ai/api/data.rb +18 -3
- data/lib/sc2ai/api/tech_tree.rb +1 -1
- data/lib/sc2ai/api/tech_tree_data.rb +54 -3
- data/lib/sc2ai/connection/connection_listener.rb +3 -3
- data/lib/sc2ai/connection/requests.rb +31 -35
- data/lib/sc2ai/connection/status_listener.rb +1 -1
- data/lib/sc2ai/connection.rb +1 -2
- data/lib/sc2ai/local_play/client.rb +2 -2
- data/lib/sc2ai/local_play/match.rb +7 -2
- data/lib/sc2ai/overrides/async/process/child.rb +1 -1
- data/lib/sc2ai/paths.rb +12 -2
- data/lib/sc2ai/player/actions.rb +54 -35
- data/lib/sc2ai/player/debug.rb +54 -20
- data/lib/sc2ai/player/game_state.rb +11 -18
- data/lib/sc2ai/player/geo.rb +56 -66
- data/lib/sc2ai/player/units.rb +41 -17
- data/lib/sc2ai/player.rb +104 -47
- data/lib/sc2ai/ports.rb +1 -2
- data/lib/sc2ai/protocol/_meta_documentation.rb +270 -25
- data/lib/sc2ai/protocol/common_pb.rb +3862 -33
- data/lib/sc2ai/protocol/data_pb.rb +9106 -36
- data/lib/sc2ai/protocol/debug_pb.rb +10434 -45
- data/lib/sc2ai/protocol/error_pb.rb +1084 -29
- data/lib/sc2ai/protocol/extensions/ability_remapable.rb +9 -9
- data/lib/sc2ai/protocol/extensions/action.rb +60 -0
- data/lib/sc2ai/protocol/extensions/point_2_d.rb +9 -0
- data/lib/sc2ai/protocol/extensions/position.rb +11 -36
- data/lib/sc2ai/protocol/extensions/power_source.rb +3 -0
- data/lib/sc2ai/protocol/extensions/unit.rb +61 -36
- data/lib/sc2ai/protocol/extensions/unit_type_data.rb +8 -0
- data/lib/sc2ai/protocol/query_pb.rb +5022 -36
- data/lib/sc2ai/protocol/raw_pb.rb +18347 -46
- data/lib/sc2ai/protocol/sc2api_pb.rb +48424 -126
- data/lib/sc2ai/protocol/score_pb.rb +5965 -30
- data/lib/sc2ai/protocol/spatial_pb.rb +11941 -37
- data/lib/sc2ai/protocol/ui_pb.rb +12924 -46
- data/lib/sc2ai/unit_group/action_ext.rb +0 -2
- data/lib/sc2ai/unit_group/filter_ext.rb +24 -8
- data/lib/sc2ai/unit_group/geo_ext.rb +0 -2
- data/lib/sc2ai/unit_group.rb +1 -1
- data/lib/sc2ai/version.rb +2 -3
- data/lib/sc2ai.rb +10 -11
- data/lib/templates/ladderzip/bin/ladder.tt +0 -3
- data/lib/templates/new/.ladderignore +15 -5
- data/lib/templates/new/api/common.proto +6 -6
- data/lib/templates/new/api/data.proto +23 -20
- data/lib/templates/new/api/debug.proto +25 -21
- data/lib/templates/new/api/error.proto +217 -215
- data/lib/templates/new/api/query.proto +1 -1
- data/lib/templates/new/api/raw.proto +16 -14
- data/lib/templates/new/api/sc2api.proto +108 -94
- data/lib/templates/new/api/score.proto +4 -3
- data/lib/templates/new/api/spatial.proto +6 -5
- data/lib/templates/new/api/ui.proto +17 -14
- data/lib/templates/new/boot.rb.tt +1 -1
- data/lib/templates/new/my_bot.rb.tt +2 -2
- data/lib/templates/new/run_example_match.rb.tt +2 -2
- data/sig/sc2ai.rbs +11072 -1651
- metadata +31 -26
- data/lib/sc2ai/overrides/kernel.rb +0 -33
- data/lib/sc2ai/protocol/extensions/unit_type.rb +0 -9
@@ -5,18 +5,18 @@ module Api
|
|
5
5
|
# i.e. Api::AbilityId::ATTACK_BATTLECRUISER returns generic Api::AbilityId::ATTACK
|
6
6
|
# @return [Integer]
|
7
7
|
def ability_id
|
8
|
-
@
|
8
|
+
@_ability_id ||= Api::AbilityId.generic_id(@ability_id)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
# AbilityData should not include, since it holds exact info and contains the remap id as attr
|
14
14
|
# Similarly Request* methods only do requests and ew supply correct id's.
|
15
|
-
Api::AvailableAbility.
|
16
|
-
Api::UnitOrder.
|
17
|
-
Api::ActionRawUnitCommand.
|
18
|
-
Api::ActionRawToggleAutocast.
|
19
|
-
Api::ActionError.
|
20
|
-
Api::ActionSpatialUnitCommand.
|
21
|
-
Api::BuildItem.
|
22
|
-
Api::ActionToggleAutocast.
|
15
|
+
Api::AvailableAbility.prepend Api::AbilityRemapable
|
16
|
+
Api::UnitOrder.prepend Api::AbilityRemapable
|
17
|
+
Api::ActionRawUnitCommand.prepend Api::AbilityRemapable
|
18
|
+
Api::ActionRawToggleAutocast.prepend Api::AbilityRemapable
|
19
|
+
Api::ActionError.prepend Api::AbilityRemapable
|
20
|
+
Api::ActionSpatialUnitCommand.prepend Api::AbilityRemapable
|
21
|
+
Api::BuildItem.prepend Api::AbilityRemapable
|
22
|
+
Api::ActionToggleAutocast.prepend Api::AbilityRemapable
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Api
|
2
|
+
# Adds additional functionality and fixes quirks with color specifically pertaining to debug commands
|
3
|
+
module ActionExtension
|
4
|
+
# Checks the action type and returns corresponding class
|
5
|
+
# @return [Class] class of type, i.e. Api::ActionRaw
|
6
|
+
def action_type
|
7
|
+
@action_type ||= if has_action_raw?
|
8
|
+
Api::ActionRaw
|
9
|
+
elsif has_action_chat?
|
10
|
+
Api::ActionChat
|
11
|
+
elsif has_action_feature_layer?
|
12
|
+
Api::ActionSpatial
|
13
|
+
elsif has_action_ui?
|
14
|
+
Api::ActionUI
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Finds unit tags for action, if applicable
|
19
|
+
# @return [Array<Integer>] an array of unit tags
|
20
|
+
def unit_tags
|
21
|
+
tags = []
|
22
|
+
if action_type == Api::ActionRaw
|
23
|
+
case action_raw.action
|
24
|
+
when :unit_command # ActionRawUnitCommand
|
25
|
+
tags = action_raw.unit_command.unit_tags
|
26
|
+
when :toggle_autocast # ActionRawToggleAutocast
|
27
|
+
tags = action_raw.toggle_autocast.unit_tags
|
28
|
+
end
|
29
|
+
# when Api::ActionSpatial
|
30
|
+
# if action == :unit_command # ActionSpatialUnitCommand
|
31
|
+
# # For spatial unit commands, one _could_ assume the errors came from
|
32
|
+
# # the last selected allied units on the previous frame.
|
33
|
+
# # Since we don't have bot access here, leaving this empty.
|
34
|
+
# # tags = @bot.previous.all_units.owned.select(&:is_selected).tags
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
|
38
|
+
tags
|
39
|
+
end
|
40
|
+
|
41
|
+
# Finds ability_id for the action, if applicable
|
42
|
+
# @return [Integer, nil] Api::AbilityID::* or nil if n/a
|
43
|
+
def ability_id
|
44
|
+
if action_type == Api::ActionRaw
|
45
|
+
case action_raw.action
|
46
|
+
when :unit_command # ActionRawUnitCommand
|
47
|
+
return action_raw.unit_command.ability_id
|
48
|
+
when :toggle_autocast # ActionRawToggleAutocast
|
49
|
+
return action_raw.toggle_autocast.ability_id
|
50
|
+
end
|
51
|
+
elsif action_type == Api::ActionSpatial && action_ui.action == :unit_command # ActionSpatialUnitCommand
|
52
|
+
return action_ui.unit_command.ability_id
|
53
|
+
end
|
54
|
+
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Api::Action.include Api::ActionExtension
|
@@ -2,15 +2,22 @@ module Api
|
|
2
2
|
# Adds additional functionality to message object Api::Point2D
|
3
3
|
module Point2DExtension
|
4
4
|
# @private
|
5
|
+
# Hashes on x and y
|
5
6
|
def hash
|
6
7
|
[x, y].hash
|
7
8
|
end
|
8
9
|
|
10
|
+
# @private
|
9
11
|
def eql?(other)
|
10
12
|
self.class == other.class && hash == other.hash
|
11
13
|
end
|
12
14
|
|
15
|
+
# Returns self
|
16
|
+
# @return [self]
|
17
|
+
def to_p2d = self
|
18
|
+
|
13
19
|
# Create a new 3d Point, by adding a y axis.
|
20
|
+
# @param z [Float, Integer]
|
14
21
|
# @return [Api::Point]
|
15
22
|
def to_3d(z: 0)
|
16
23
|
Api::Point[x, y, z]
|
@@ -21,6 +28,8 @@ module Api
|
|
21
28
|
# Shorthand for creating an instance for [x, y]
|
22
29
|
# @example
|
23
30
|
# Api::Point2D[2,4] # Where x is 2.0 and y is 4.0
|
31
|
+
# @param x [Float, Integer]
|
32
|
+
# @param y [Float, Integer]
|
24
33
|
# @return [Api::Point2D]
|
25
34
|
def [](x, y)
|
26
35
|
Api::Point2D.new(x: x, y: y)
|
@@ -10,6 +10,8 @@ module Sc2
|
|
10
10
|
# Loose equality matches on floats x and y.
|
11
11
|
# We never check z-axis, because the map is single-level.
|
12
12
|
# TODO: We should almost certainly introduce TOLERANCE here, but verify it's cost first.
|
13
|
+
# @param [Sc2::Position] other
|
14
|
+
# @return [Boolean]
|
13
15
|
def ==(other)
|
14
16
|
if other.is_a? Position
|
15
17
|
x == other.x && y == other.y
|
@@ -61,39 +63,6 @@ module Sc2
|
|
61
63
|
# @see #divide
|
62
64
|
alias_method :/, :divide
|
63
65
|
|
64
|
-
# Returns x coordinate
|
65
|
-
# @return [Float]
|
66
|
-
def x
|
67
|
-
# Perf: Memoizing attributes which are hit hard, show gain
|
68
|
-
@x ||= send(:method_missing, :x)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Sets x coordinate
|
72
|
-
# @return [Float]
|
73
|
-
def x=(x)
|
74
|
-
send(:method_missing, :x=, x)
|
75
|
-
@x = x
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns y coordinate
|
79
|
-
# @return [Float]
|
80
|
-
def y
|
81
|
-
# Bug: Psych implements method 'y' on Kernel, but protobuf uses method_missing to read AbstractMethod
|
82
|
-
# We send method missing ourselves when y to fix this chain.
|
83
|
-
# This is correct, but an unnecessary conditional:
|
84
|
-
# raise NoMethodError unless location == self
|
85
|
-
|
86
|
-
# Perf: Memoizing attributes which are hit hard, show gain
|
87
|
-
@y ||= send(:method_missing, :y)
|
88
|
-
end
|
89
|
-
|
90
|
-
# Sets y coordinate
|
91
|
-
# @return [Float]
|
92
|
-
def y=(y)
|
93
|
-
send(:method_missing, :y=, y)
|
94
|
-
@y = y
|
95
|
-
end
|
96
|
-
|
97
66
|
# Randomly adjusts both x and y by a range of: -offset..offset
|
98
67
|
# @param offset [Float]
|
99
68
|
# @return [Sc2::Position] new Position
|
@@ -105,18 +74,22 @@ module Sc2
|
|
105
74
|
# @return [Sc2::Position] self
|
106
75
|
def random_offset!(offset)
|
107
76
|
offset = offset.to_f
|
108
|
-
range =
|
77
|
+
range = -offset..offset
|
109
78
|
offset!(rand(range), rand(range))
|
110
79
|
self
|
111
80
|
end
|
112
81
|
|
113
82
|
# Creates a new point with x and y which is offset
|
83
|
+
# @param x [Float, Integer]
|
84
|
+
# @param y [Float, Integer]
|
114
85
|
# @return [Sc2::Position] new Position
|
115
86
|
def offset(x = 0, y = 0)
|
116
87
|
dup.offset!(x, y)
|
117
88
|
end
|
118
89
|
|
119
90
|
# Changes this point's x and y by the supplied offset
|
91
|
+
# @param x [Float, Integer]
|
92
|
+
# @param y [Float, Integer]
|
120
93
|
# @return [Sc2::Position] self
|
121
94
|
def offset!(x = 0, y = 0)
|
122
95
|
self.x += x
|
@@ -182,7 +155,7 @@ module Sc2
|
|
182
155
|
end
|
183
156
|
|
184
157
|
# The squared distance between this point and the other point.
|
185
|
-
# @param other [Point2D] The other point to calculate the squared distance to.
|
158
|
+
# @param other [Api::Point2D] The other point to calculate the squared distance to.
|
186
159
|
# @return [Float]
|
187
160
|
def distance_squared_to(other)
|
188
161
|
if other.nil? || other == self
|
@@ -192,13 +165,15 @@ module Sc2
|
|
192
165
|
end
|
193
166
|
|
194
167
|
# Distance between this point and coordinate of x and y
|
168
|
+
# @param x [Float, Integer]
|
169
|
+
# @param y [Float, Integer]
|
195
170
|
# @return [Float]
|
196
171
|
def distance_to_coordinate(x:, y:)
|
197
172
|
Math.hypot(self.x - x, self.y - y)
|
198
173
|
end
|
199
174
|
|
200
175
|
# The distance from this point to the circle.
|
201
|
-
# @param center [Point2D] The center of the circle.
|
176
|
+
# @param center [Api::Point2D] The center of the circle.
|
202
177
|
# @param radius [Float] The radius of the circle.
|
203
178
|
# @return [Float]
|
204
179
|
def distance_to_circle(center, radius)
|
@@ -9,6 +9,9 @@ module Api
|
|
9
9
|
# @example
|
10
10
|
# Api::Point[1,2,3] # Where x is 1.0, y is 2.0 and z is 3.0
|
11
11
|
# @return [Api::Point]
|
12
|
+
# @param x [Float, Integer]
|
13
|
+
# @param y [Float, Integer]
|
14
|
+
# @param z [Float, Integer]
|
12
15
|
def [](x, y, z)
|
13
16
|
Api::Point.new(x: x, y: y, z: z)
|
14
17
|
end
|
@@ -9,22 +9,6 @@ module Api
|
|
9
9
|
tag || super
|
10
10
|
end
|
11
11
|
|
12
|
-
# Returns an integer unique identifier
|
13
|
-
# If the unit goes out of vision and is snapshot-able, they get a random id
|
14
|
-
# - Such a unit gets the same unit tag when it re-enters vision
|
15
|
-
# @return [Integer]
|
16
|
-
def tag
|
17
|
-
# Perf: This speeds up hash and therefore common UnitGroup operations. Sometimes 3x!
|
18
|
-
@tag ||= send(:method_missing, :tag)
|
19
|
-
end
|
20
|
-
|
21
|
-
# Sets unit tag
|
22
|
-
# @return [Integer]
|
23
|
-
def tag=(tag)
|
24
|
-
send(:method_missing, :tag=, tag)
|
25
|
-
@tag = tag
|
26
|
-
end
|
27
|
-
|
28
12
|
# Every unit gets access back to the bot to allow api access.
|
29
13
|
# For your own units, this allows API access.
|
30
14
|
# @return [Sc2::Player] player with active connection
|
@@ -42,6 +26,26 @@ module Api
|
|
42
26
|
@bot.previous.all_units[tag]
|
43
27
|
end
|
44
28
|
|
29
|
+
# Returns whether a unit is alive or not
|
30
|
+
# Useful for cached Unit objects to see if they are still relevant.
|
31
|
+
# @return [Boolean] alive
|
32
|
+
def is_alive?
|
33
|
+
!@bot.all_units[tag].nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Replaces protobuf values with latest from game
|
37
|
+
# @return [Boolean] true if refreshed or false unchanged
|
38
|
+
def refresh!
|
39
|
+
new_unit = @bot.all_units[tag]
|
40
|
+
return false if new_unit.nil? || new_unit == self
|
41
|
+
|
42
|
+
method(:initialize).parameters.each do |_, entry|
|
43
|
+
send(:"#{entry.name}=", new_unit.send(entry))
|
44
|
+
end
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
45
49
|
# Attributes ---
|
46
50
|
|
47
51
|
# Returns static [Api::UnitTypeData] for a unit
|
@@ -53,8 +57,8 @@ module Api
|
|
53
57
|
# Checks unit data for an attribute value
|
54
58
|
# @return [Boolean] whether unit has attribute
|
55
59
|
# @example
|
56
|
-
# unit.has_attribute?(Api::Attribute::
|
57
|
-
# unit.has_attribute?(:
|
60
|
+
# unit.has_attribute?(Api::Attribute::MECHANICAL)
|
61
|
+
# unit.has_attribute?(:MECHANICAL)
|
58
62
|
def has_attribute?(attribute)
|
59
63
|
attributes.include? attribute
|
60
64
|
end
|
@@ -62,67 +66,67 @@ module Api
|
|
62
66
|
# Checks if unit is light
|
63
67
|
# @return [Boolean] whether unit has attribute :Light
|
64
68
|
def is_light?
|
65
|
-
has_attribute?(:
|
69
|
+
has_attribute?(:LIGHT)
|
66
70
|
end
|
67
71
|
|
68
72
|
# Checks if unit is armored
|
69
73
|
# @return [Boolean] whether unit has attribute :Armored
|
70
74
|
def is_armored?
|
71
|
-
has_attribute?(:
|
75
|
+
has_attribute?(:ARMORED)
|
72
76
|
end
|
73
77
|
|
74
78
|
# Checks if unit is biological
|
75
79
|
# @return [Boolean] whether unit has attribute :Biological
|
76
80
|
def is_biological?
|
77
|
-
has_attribute?(:
|
81
|
+
has_attribute?(:BIOLOGICAL)
|
78
82
|
end
|
79
83
|
|
80
84
|
# Checks if unit is mechanical
|
81
85
|
# @return [Boolean] whether unit has attribute :Mechanical
|
82
86
|
def is_mechanical?
|
83
|
-
has_attribute?(:
|
87
|
+
has_attribute?(:MECHANICAL)
|
84
88
|
end
|
85
89
|
|
86
90
|
# Checks if unit is robotic
|
87
91
|
# @return [Boolean] whether unit has attribute :Robotic
|
88
92
|
def is_robotic?
|
89
|
-
has_attribute?(:
|
93
|
+
has_attribute?(:ROBOTIC)
|
90
94
|
end
|
91
95
|
|
92
96
|
# Checks if unit is psionic
|
93
97
|
# @return [Boolean] whether unit has attribute :Psionic
|
94
98
|
def is_psionic?
|
95
|
-
has_attribute?(:
|
99
|
+
has_attribute?(:PSIONIC)
|
96
100
|
end
|
97
101
|
|
98
102
|
# Checks if unit is massive
|
99
103
|
# @return [Boolean] whether unit has attribute :Massive
|
100
104
|
def is_massive?
|
101
|
-
has_attribute?(:
|
105
|
+
has_attribute?(:MASSIVE)
|
102
106
|
end
|
103
107
|
|
104
108
|
# Checks if unit is structure
|
105
109
|
# @return [Boolean] whether unit has attribute :Structure
|
106
110
|
def is_structure?
|
107
|
-
has_attribute?(:
|
111
|
+
has_attribute?(:STRUCTURE)
|
108
112
|
end
|
109
113
|
|
110
114
|
# Checks if unit is hover
|
111
115
|
# @return [Boolean] whether unit has attribute :Hover
|
112
116
|
def is_hover?
|
113
|
-
has_attribute?(:
|
117
|
+
has_attribute?(:HOVER)
|
114
118
|
end
|
115
119
|
|
116
120
|
# Checks if unit is heroic
|
117
121
|
# @return [Boolean] whether unit has attribute :Heroic
|
118
122
|
def is_heroic?
|
119
|
-
has_attribute?(:
|
123
|
+
has_attribute?(:HEROIC)
|
120
124
|
end
|
121
125
|
|
122
126
|
# Checks if unit is summoned
|
123
127
|
# @return [Boolean] whether unit has attribute :Summoned
|
124
128
|
def is_summoned?
|
125
|
-
has_attribute?(:
|
129
|
+
has_attribute?(:SUMMONED)
|
126
130
|
end
|
127
131
|
|
128
132
|
# @!group Virtual properties
|
@@ -375,7 +379,13 @@ module Api
|
|
375
379
|
)
|
376
380
|
end
|
377
381
|
|
378
|
-
# Checks whether
|
382
|
+
# Checks whether a unit is gathering or returning gathered minerals/gas
|
383
|
+
# @return [Boolean] true if either gathering or returning, false otherwise
|
384
|
+
def is_harvesting?
|
385
|
+
is_performing_ability?([Api::AbilityId::HARVEST_GATHER, Api::AbilityId::HARVEST_RETURN])
|
386
|
+
end
|
387
|
+
|
388
|
+
# Checks whether a unit's first order for ability
|
379
389
|
# @param ability_ids [Integer, Array<Integer>] accepts one or an array of Api::AbilityId
|
380
390
|
def is_performing_ability?(ability_ids)
|
381
391
|
return false if orders.empty?
|
@@ -431,15 +441,15 @@ module Api
|
|
431
441
|
end
|
432
442
|
|
433
443
|
# Checks whether a weapon can target a unit
|
434
|
-
# @param unit [Api::
|
444
|
+
# @param unit [Api::Unit]
|
435
445
|
# @param weapon [Api::Weapon]
|
436
446
|
# @return [Boolean]
|
437
447
|
def can_weapon_target_unit?(unit:, weapon:)
|
438
448
|
# false if enemy is air and we can only shoot ground
|
439
|
-
return false if unit.is_flying && weapon.type == :
|
449
|
+
return false if unit.is_flying && weapon.type == :GROUND # Api::Weapon::TargetType::GROUND
|
440
450
|
|
441
451
|
# false if enemy is ground and we can only shoot air
|
442
|
-
return false if unit.is_ground? && weapon.type == :
|
452
|
+
return false if unit.is_ground? && weapon.type == :AIR # Api::Weapon::TargetType::AIR
|
443
453
|
|
444
454
|
# Check if weapon and unit models are in range
|
445
455
|
in_attack_range?(unit:, range: weapon.range)
|
@@ -447,7 +457,7 @@ module Api
|
|
447
457
|
|
448
458
|
def can_ability_target_unit?(unit:, ability:)
|
449
459
|
# false if enemy is air and we can only shoot ground
|
450
|
-
return false if ability.target == Api::AbilityData::Target::
|
460
|
+
return false if ability.target == Api::AbilityData::Target::NONE
|
451
461
|
|
452
462
|
# Check if weapon and unit models are in range
|
453
463
|
in_attack_range?(unit:, range: ability.cast_range)
|
@@ -538,7 +548,8 @@ module Api
|
|
538
548
|
when Api::UnitTypeId::STARPORT, Api::UnitTypeId::STARPORTFLYING
|
539
549
|
Api::UnitTypeId::STARPORTREACTOR
|
540
550
|
end
|
541
|
-
|
551
|
+
|
552
|
+
build(unit_type_id: unit_type_id, target: target_for_addon_placement, queue_command:)
|
542
553
|
end
|
543
554
|
|
544
555
|
# For Terran builds a tech lab add-on on the current structure
|
@@ -552,7 +563,21 @@ module Api
|
|
552
563
|
when Api::UnitTypeId::STARPORT, Api::UnitTypeId::STARPORTFLYING
|
553
564
|
Api::UnitTypeId::STARPORTTECHLAB
|
554
565
|
end
|
555
|
-
build(unit_type_id: unit_type_id, queue_command:)
|
566
|
+
build(unit_type_id: unit_type_id, target: target_for_addon_placement, queue_command:)
|
567
|
+
end
|
568
|
+
|
569
|
+
private def target_for_addon_placement
|
570
|
+
# Attempts to auto-move left if not placeable
|
571
|
+
x = pos.x.floor
|
572
|
+
y = pos.y.floor
|
573
|
+
if !bot.geo.placeable?(x: x + 3, y: y - 1) ||
|
574
|
+
!bot.geo.placeable?(x: x + 3, y: y) ||
|
575
|
+
!bot.geo.placeable?(x: x + 2, y: y - 1) ||
|
576
|
+
!bot.geo.placeable?(x: x + 2, y: y)
|
577
|
+
return Api::Point2D[pos.x - 1, pos.y]
|
578
|
+
end
|
579
|
+
|
580
|
+
nil
|
556
581
|
end
|
557
582
|
|
558
583
|
# PROTOSS Convenience functions ---
|
@@ -15,6 +15,14 @@ module Api
|
|
15
15
|
# i.e. 250G Broodlord = 100G Corruptor + 150G Morph
|
16
16
|
# @return [Integer] sum of vespene gas costs
|
17
17
|
attr_accessor :vespene_cost_sum
|
18
|
+
|
19
|
+
# @!attribute placement_length
|
20
|
+
# Length of tiles to build.
|
21
|
+
# i.e. 5 for any Base-type (5x5)
|
22
|
+
# i.e. 3 for Barracks (3x3)
|
23
|
+
# i.e. 2 for Supply Depot (2x2)
|
24
|
+
# @return [Integer] side-length for placement
|
25
|
+
attr_accessor :placement_length
|
18
26
|
end
|
19
27
|
end
|
20
28
|
Api::UnitTypeData.include Api::UnitTypeDataExtension
|