sc2ai 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|