sc2ai 0.6.2 → 0.7.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/data.json +1 -1
- data/data/data_readable.json +185 -144
- data/data/stableid.json +4392 -942
- data/data/versions.json +16 -0
- data/docker_build/Dockerfile.ruby +1 -1
- data/lib/sc2ai/api/ability_id.rb +14 -745
- data/lib/sc2ai/api/buff_id.rb +8 -1
- data/lib/sc2ai/api/data.rb +0 -6
- data/lib/sc2ai/api/tech_tree_data.rb +30 -32
- data/lib/sc2ai/api/unit_type_id.rb +58 -6
- data/lib/sc2ai/api/upgrade_id.rb +7 -188
- data/lib/sc2ai/cli/cli.rb +5 -1
- data/lib/sc2ai/cli/ladderzip.rb +1 -1
- data/lib/sc2ai/local_play/client.rb +14 -3
- data/lib/sc2ai/player/geo.rb +77 -2
- data/lib/sc2ai/player/units.rb +19 -0
- data/lib/sc2ai/protocol/extensions/unit.rb +22 -23
- data/lib/sc2ai/unit_group/filter_ext.rb +13 -2
- data/lib/sc2ai/version.rb +1 -1
- data/lib/templates/new/run_example_match.rb.tt +1 -1
- data/sig/sc2ai.rbs +128 -858
- metadata +36 -21
data/lib/sc2ai/player/geo.rb
CHANGED
@@ -520,11 +520,11 @@ module Sc2
|
|
520
520
|
point_search_offsets = (-7..7).to_a.product((-7..7).to_a)
|
521
521
|
point_search_offsets.select! do |x, y|
|
522
522
|
dist = Math.hypot(x, y)
|
523
|
-
dist > 4 && dist <= 8
|
523
|
+
dist > 4.0 && dist <= 8.0
|
524
524
|
end
|
525
525
|
|
526
526
|
# Split resources by Z axis
|
527
|
-
resources = bot.neutral.minerals
|
527
|
+
resources = bot.neutral.minerals - mineral_walls + bot.neutral.geysers
|
528
528
|
resource_group_z = resources.group_by do |resource|
|
529
529
|
resource.pos.z.round # 32 units of Y, most maps will have use 3. round to nearest.
|
530
530
|
end
|
@@ -591,11 +591,86 @@ module Sc2
|
|
591
591
|
# Choose best fitting point
|
592
592
|
best_point = possible_points.keys[possible_points.values.find_index(possible_points.values.min)]
|
593
593
|
@expansions[best_point.to_p2d] = UnitGroup.new(clustered_resources)
|
594
|
+
|
595
|
+
# Check if this might be a mirrored base.
|
596
|
+
best_mirror_point = nil
|
597
|
+
geysers = clustered_resources.select { |res| Sc2::UnitGroup::TYPE_GEYSER.include?(res.unit_type) }
|
598
|
+
if geysers.size == 2
|
599
|
+
if geysers[0].pos.y == geysers[1].pos.y || geysers[0].pos.x == geysers[1].pos.x
|
600
|
+
# Mirrored vertical, potentially
|
601
|
+
best_mirror_point = [
|
602
|
+
best_point[0],
|
603
|
+
best_point[1] - (best_point[1] - (geysers[0].pos.y + geysers[1].pos.y) / 2.0) * 2.0
|
604
|
+
]
|
605
|
+
if best_mirror_point != best_point && possible_points.has_key?(best_mirror_point)
|
606
|
+
@expansions[best_mirror_point.to_p2d] = UnitGroup.new(clustered_resources)
|
607
|
+
else
|
608
|
+
# Wasn't mirrored the one way. How about the other?...
|
609
|
+
# Mirrored horizontal, potentially
|
610
|
+
best_mirror_point = [
|
611
|
+
best_point[0] - (best_point[0] - (geysers[0].pos.x + geysers[1].pos.x) / 2.0) * 2.0,
|
612
|
+
best_point[1]
|
613
|
+
]
|
614
|
+
if best_mirror_point != best_point && possible_points.has_key?(best_mirror_point)
|
615
|
+
@expansions[best_mirror_point.to_p2d] = UnitGroup.new(clustered_resources)
|
616
|
+
end
|
617
|
+
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
594
621
|
end
|
595
622
|
end
|
596
623
|
@expansions
|
597
624
|
end
|
598
625
|
|
626
|
+
# @private
|
627
|
+
# Mineral walls. Defined once upon start of game, mostly based on layout.
|
628
|
+
# @return [Sc2::UnitGroup]
|
629
|
+
private def mineral_walls
|
630
|
+
return @mineral_walls unless @mineral_walls.nil?
|
631
|
+
|
632
|
+
# Find mineral walls.
|
633
|
+
@mineral_walls = []
|
634
|
+
minerals_by_pos = {}
|
635
|
+
bot.neutral.minerals.reject_type(Api::UnitTypeId::MINERALFIELD450)
|
636
|
+
.each do |mineral|
|
637
|
+
minerals_by_pos[mineral.pos.to_axy] = mineral
|
638
|
+
end
|
639
|
+
minerals_by_pos.each do |xy, mineral|
|
640
|
+
x, y = xy
|
641
|
+
# Test X
|
642
|
+
if (side1 = minerals_by_pos[[x - 2, y]]) && (side2 = minerals_by_pos[[x + 2, y]])
|
643
|
+
@mineral_walls << side1
|
644
|
+
@mineral_walls << mineral
|
645
|
+
@mineral_walls << side2
|
646
|
+
end
|
647
|
+
|
648
|
+
# # Test Y
|
649
|
+
if (side1 = minerals_by_pos[[x, y - 1]]) && (side2 = minerals_by_pos[[x, y + 1]])
|
650
|
+
@mineral_walls << side1
|
651
|
+
@mineral_walls << mineral
|
652
|
+
@mineral_walls << side2
|
653
|
+
end
|
654
|
+
|
655
|
+
# Test \
|
656
|
+
if (side1 = minerals_by_pos[[x - 2, y + 1]]) && (side2 = minerals_by_pos[[x + 2, y - 1]])
|
657
|
+
@mineral_walls << side1
|
658
|
+
@mineral_walls << mineral
|
659
|
+
@mineral_walls << side2
|
660
|
+
end
|
661
|
+
|
662
|
+
# Test /
|
663
|
+
if (side1 = minerals_by_pos[[x - 2, y - 1]]) && (side2 = minerals_by_pos[[x + 2, y + 1]])
|
664
|
+
@mineral_walls << side1
|
665
|
+
@mineral_walls << mineral
|
666
|
+
@mineral_walls << side2
|
667
|
+
end
|
668
|
+
end
|
669
|
+
@mineral_walls.uniq!
|
670
|
+
|
671
|
+
@mineral_walls = UnitGroup.new(@mineral_walls) + bot.neutral.minerals.select_type(Api::UnitTypeId::MINERALFIELD450)
|
672
|
+
end
|
673
|
+
|
599
674
|
# Returns a list of 2d points for expansion build locations
|
600
675
|
# Does not contain mineral info, but the value can be checked against geo.expansions
|
601
676
|
#
|
data/lib/sc2ai/player/units.rb
CHANGED
@@ -304,6 +304,25 @@ module Sc2
|
|
304
304
|
true
|
305
305
|
end
|
306
306
|
|
307
|
+
# Checks whether you have met the tech requirements for building a specific unit type
|
308
|
+
# @param [Integer] unit_type_id
|
309
|
+
# @return [Boolean]
|
310
|
+
def tech_requirement_met?(unit_type_id)
|
311
|
+
created_from_unit_type = Api::TechTree.unit_created_from(unit_type_id: unit_type_id)
|
312
|
+
required_building = Api::TechTree.unit_type_creation_abilities(
|
313
|
+
source: created_from_unit_type.first,
|
314
|
+
target: unit_type_id
|
315
|
+
)[:required_building]
|
316
|
+
|
317
|
+
# Ensure we have required building, if there's such a requirement
|
318
|
+
if required_building
|
319
|
+
return false unless all_units.owned.select_type(required_building).completed.size > 0
|
320
|
+
end
|
321
|
+
|
322
|
+
# Ensure we have a completed source which it's created from
|
323
|
+
all_units.owned.select_type(created_from_unit_type).completed.size > 0
|
324
|
+
end
|
325
|
+
|
307
326
|
# Micro/Unit-Specific ------
|
308
327
|
|
309
328
|
# Returns whether Query Available Ability is true for unit and tag
|
@@ -58,75 +58,74 @@ module Api
|
|
58
58
|
# @return [Boolean] whether unit has attribute
|
59
59
|
# @example
|
60
60
|
# unit.has_attribute?(Api::Attribute::MECHANICAL)
|
61
|
-
# unit.has_attribute?(:MECHANICAL)
|
62
61
|
def has_attribute?(attribute)
|
63
62
|
attributes.include? attribute
|
64
63
|
end
|
65
64
|
|
66
65
|
# Checks if unit is light
|
67
|
-
# @return [Boolean] whether unit has attribute :
|
66
|
+
# @return [Boolean] whether unit has attribute :LIGHT
|
68
67
|
def is_light?
|
69
|
-
has_attribute?(
|
68
|
+
has_attribute?(Api::Attribute::LIGHT)
|
70
69
|
end
|
71
70
|
|
72
71
|
# Checks if unit is armored
|
73
|
-
# @return [Boolean] whether unit has attribute :
|
72
|
+
# @return [Boolean] whether unit has attribute :ARMORED
|
74
73
|
def is_armored?
|
75
|
-
has_attribute?(
|
74
|
+
has_attribute?(Api::Attribute::ARMORED)
|
76
75
|
end
|
77
76
|
|
78
77
|
# Checks if unit is biological
|
79
|
-
# @return [Boolean] whether unit has attribute :
|
78
|
+
# @return [Boolean] whether unit has attribute :BIOLOGICAL
|
80
79
|
def is_biological?
|
81
|
-
has_attribute?(
|
80
|
+
has_attribute?(Api::Attribute::BIOLOGICAL)
|
82
81
|
end
|
83
82
|
|
84
83
|
# Checks if unit is mechanical
|
85
|
-
# @return [Boolean] whether unit has attribute :
|
84
|
+
# @return [Boolean] whether unit has attribute :MECHANICAL
|
86
85
|
def is_mechanical?
|
87
|
-
has_attribute?(
|
86
|
+
has_attribute?(Api::Attribute::MECHANICAL)
|
88
87
|
end
|
89
88
|
|
90
89
|
# Checks if unit is robotic
|
91
|
-
# @return [Boolean] whether unit has attribute :
|
90
|
+
# @return [Boolean] whether unit has attribute :ROBOTIC
|
92
91
|
def is_robotic?
|
93
|
-
has_attribute?(
|
92
|
+
has_attribute?(Api::Attribute::ROBOTIC)
|
94
93
|
end
|
95
94
|
|
96
95
|
# Checks if unit is psionic
|
97
|
-
# @return [Boolean] whether unit has attribute :
|
96
|
+
# @return [Boolean] whether unit has attribute :PSIONIC
|
98
97
|
def is_psionic?
|
99
|
-
has_attribute?(
|
98
|
+
has_attribute?(Api::Attribute::PSIONIC)
|
100
99
|
end
|
101
100
|
|
102
101
|
# Checks if unit is massive
|
103
|
-
# @return [Boolean] whether unit has attribute :
|
102
|
+
# @return [Boolean] whether unit has attribute :MASSIVE
|
104
103
|
def is_massive?
|
105
|
-
has_attribute?(
|
104
|
+
has_attribute?(Api::Attribute::MASSIVE)
|
106
105
|
end
|
107
106
|
|
108
107
|
# Checks if unit is structure
|
109
|
-
# @return [Boolean] whether unit has attribute :
|
108
|
+
# @return [Boolean] whether unit has attribute :STRUCTURE
|
110
109
|
def is_structure?
|
111
|
-
has_attribute?(
|
110
|
+
has_attribute?(Api::Attribute::STRUCTURE)
|
112
111
|
end
|
113
112
|
|
114
113
|
# Checks if unit is hovering
|
115
|
-
# @return [Boolean] whether unit has attribute :
|
114
|
+
# @return [Boolean] whether unit has attribute :HOVER
|
116
115
|
def is_hover?
|
117
|
-
has_attribute?(
|
116
|
+
has_attribute?(Api::Attribute::HOVER)
|
118
117
|
end
|
119
118
|
|
120
119
|
# Checks if unit is heroic
|
121
|
-
# @return [Boolean] whether unit has attribute :
|
120
|
+
# @return [Boolean] whether unit has attribute :HEROIC
|
122
121
|
def is_heroic?
|
123
|
-
has_attribute?(
|
122
|
+
has_attribute?(Api::Attribute::HEROIC)
|
124
123
|
end
|
125
124
|
|
126
125
|
# Checks if unit is summoned
|
127
|
-
# @return [Boolean] whether unit has attribute :
|
126
|
+
# @return [Boolean] whether unit has attribute :SUMMONED
|
128
127
|
def is_summoned?
|
129
|
-
has_attribute?(
|
128
|
+
has_attribute?(Api::Attribute::SUMMONED)
|
130
129
|
end
|
131
130
|
|
132
131
|
# @!group Virtual properties
|
@@ -86,6 +86,17 @@ module Sc2
|
|
86
86
|
Api::UnitTypeId::SPORECRAWLER
|
87
87
|
].freeze
|
88
88
|
|
89
|
+
# Protoss: An array of unit types warped from Warp Gate.
|
90
|
+
# @return [Array<Integer>]
|
91
|
+
TYPE_WARPGATE_UNIT = [
|
92
|
+
Api::UnitTypeId::ZEALOT,
|
93
|
+
Api::UnitTypeId::STALKER,
|
94
|
+
Api::UnitTypeId::HIGHTEMPLAR,
|
95
|
+
Api::UnitTypeId::DARKTEMPLAR,
|
96
|
+
Api::UnitTypeId::SENTRY,
|
97
|
+
Api::UnitTypeId::ADEPT
|
98
|
+
].freeze
|
99
|
+
|
89
100
|
# Returns a new UnitGroup containing all units matching unit type id(s)
|
90
101
|
# Multiple values work as an "OR" filter
|
91
102
|
# @example
|
@@ -172,7 +183,7 @@ module Sc2
|
|
172
183
|
def select_attribute(attributes)
|
173
184
|
cached("#{__method__}:#{attributes.hash}") do
|
174
185
|
attributes = [attributes] unless attributes.is_a? Array
|
175
|
-
attributes = attributes.map { |a| a.is_a?(Symbol) ?
|
186
|
+
attributes = attributes.map { |a| a.is_a?(Symbol) ? Api::Attribute.lookup(a) : a }
|
176
187
|
select do |unit|
|
177
188
|
attributes & unit.attributes == attributes
|
178
189
|
end
|
@@ -192,7 +203,7 @@ module Sc2
|
|
192
203
|
def reject_attribute(attributes)
|
193
204
|
cached("#{__method__}:#{attributes.hash}") do
|
194
205
|
attributes = [attributes] unless attributes.is_a? Array
|
195
|
-
attributes = attributes.map { |a| a.is_a?(Symbol) ?
|
206
|
+
attributes = attributes.map { |a| a.is_a?(Symbol) ? Api::Attribute.lookup(a) : a }
|
196
207
|
reject do |unit|
|
197
208
|
unit.attributes & attributes == attributes
|
198
209
|
end
|
data/lib/sc2ai/version.rb
CHANGED