open_dota_api 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 27e6de5245cfbbfb2198500daf1100ac4a0a36a3
4
+ data.tar.gz: 445de76394198e662bec06c96a8ad44f9735ceec
5
+ SHA512:
6
+ metadata.gz: 144462d5ff85254be1675d734f58258a0ad92b6b789e638066385323804b558d1aff53a4bba956dc19b9e2579b08b2c16ebf4db6e781a285ece395fa85ad38f4
7
+ data.tar.gz: 69bc1ac8454e5fbe99e030dc46279d787e8c8d3dc4d925cd7f082189e3565f4bee75ffa5af3c42abc5ae0ab319b6572ad7ca2c86fcc302739b946034768c9a39
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 YaroslavO
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'OpenDotaApi'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+ Bundler::GemHelper.install_tasks
19
+
20
+
21
+
22
+ task default: :test
@@ -0,0 +1,10 @@
1
+ require 'open_dota_api/client'
2
+
3
+ module OpenDotaApi
4
+ extend SingleForwardable
5
+ def_delegators :client, :leagues, :teams, :matches, :heroes
6
+
7
+ def self.client
8
+ @client ||= Client.new
9
+ end
10
+ end
@@ -0,0 +1,47 @@
1
+ require 'open_dota_api/connection'
2
+ require 'open_dota_api/league'
3
+ require 'open_dota_api/team'
4
+ require 'open_dota_api/match'
5
+ require 'open_dota_api/hero'
6
+
7
+ module OpenDotaApi
8
+ class Client
9
+ INTERFACE = 'api'
10
+
11
+ def leagues
12
+ leagues_data = request(League::ENDPOINT)
13
+ return {} unless leagues_data
14
+ League.instantiate(leagues_data)
15
+ end
16
+
17
+ def teams
18
+ teams_data = request(Team::ENDPOINT)
19
+ return {} unless teams_data
20
+ Team.instantiate(teams_data)
21
+ end
22
+
23
+ def matches(match_id = nil)
24
+ match_data = request(Match::ENDPOINT, match_id)
25
+ return {} unless match_data
26
+ Match.new(match_data)
27
+ end
28
+
29
+ def heroes
30
+ heroes_data = request(Hero::ENDPOINT)
31
+ return {} unless heroes_data
32
+ Hero.instantiate(heroes_data)
33
+ end
34
+
35
+ private
36
+
37
+ def connection
38
+ @connection ||= Connection.new
39
+ end
40
+
41
+ def request(method, argument = nil)
42
+ argument = argument ? argument.to_s.concat('/') : nil
43
+ pathname = "/#{INTERFACE}/#{method}/#{argument}"
44
+ connection.get(pathname)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ require 'httparty'
2
+
3
+ module OpenDotaApi
4
+ class Connection
5
+ include HTTParty
6
+ base_uri 'api.opendota.com'
7
+
8
+ def get(pathname, options = {})
9
+ self.class.get(pathname, options)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module OpenDotaApi
2
+ module Entities
3
+ module Instantiatable
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def instantiate(data)
10
+ data.map { |data_instance| new(data_instance) }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ require 'open_dota_api/entities/instantiable'
2
+ require 'hashable'
3
+
4
+ module OpenDotaApi
5
+ class Entity
6
+ include ::Hashable
7
+
8
+ def initialize(data)
9
+ @data = data
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :data
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ require 'open_dota_api/entity'
2
+
3
+ module OpenDotaApi
4
+ class Hero < Entity
5
+ include Entities::Instantiatable
6
+
7
+ ENDPOINT = 'heroes'
8
+
9
+ def id
10
+ data['id']
11
+ end
12
+
13
+ def name
14
+ data['name']
15
+ end
16
+
17
+ def localized_name
18
+ data['localized_name']
19
+ end
20
+
21
+ def primary_attr
22
+ data['primary_attr']
23
+ end
24
+
25
+ def attack_type
26
+ data['attack_type']
27
+ end
28
+
29
+ def roles
30
+ data['roles']
31
+ end
32
+
33
+ def legs
34
+ data['legs']
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ require 'open_dota_api/entity'
2
+
3
+ module OpenDotaApi
4
+ class League < Entity
5
+ include Entities::Instantiatable
6
+
7
+ ENDPOINT = 'leagues'
8
+
9
+ def league_id
10
+ data['leagueid']
11
+ end
12
+
13
+ def ticket
14
+ data['ticket']
15
+ end
16
+
17
+ def banner
18
+ data['banner']
19
+ end
20
+
21
+ def tier
22
+ data['tier']
23
+ end
24
+
25
+ def name
26
+ data['name']
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,70 @@
1
+ require 'open_dota_api/entity'
2
+ require 'open_dota_api/matches/player'
3
+
4
+ module OpenDotaApi
5
+ class Match < Entity
6
+ ENDPOINT = 'matches'
7
+
8
+ def match_id
9
+ data['match_id']
10
+ end
11
+
12
+ def start_time
13
+ data['start_time']
14
+ end
15
+
16
+ def duration
17
+ data['duration']
18
+ end
19
+
20
+ def series_id
21
+ data['series_id']
22
+ end
23
+
24
+ def series_type
25
+ data['series_type']
26
+ end
27
+
28
+ def radiant_team_id
29
+ data['radiant_team']['team_id']
30
+ end
31
+
32
+ def dire_team_id
33
+ data['dire_team']['team_id']
34
+ end
35
+
36
+ def match_seq_num
37
+ data['match_seq_num']
38
+ end
39
+
40
+ def league_id
41
+ data['leagueid']
42
+ end
43
+
44
+ def first_blood_time
45
+ data['first_blood_time']
46
+ end
47
+
48
+ def winner
49
+ data['radiant_win'] ? :radiant : :dire
50
+ end
51
+
52
+ def cluster
53
+ data['cluster']
54
+ end
55
+
56
+ def replay_salt
57
+ data['replay_salt']
58
+ end
59
+
60
+ def replay_url
61
+ "http://replay#{ cluster }.valve.net/570/#{ match_id }_#{ replay_salt }.dem.bz2"
62
+ end
63
+
64
+ def players
65
+ data['players'].map { |player| Player.new(player) }
66
+ end
67
+
68
+ class Player < Matches::Player; end
69
+ end
70
+ end
@@ -0,0 +1,92 @@
1
+ require 'open_dota_api/entity'
2
+
3
+ module OpenDotaApi
4
+ module Matches
5
+ class Player < Entity
6
+
7
+ def match_id
8
+ data['match_id']
9
+ end
10
+
11
+ def player_slot
12
+ data['player_slot']
13
+ end
14
+
15
+ def account_id
16
+ data['account_id']
17
+ end
18
+
19
+ def assists
20
+ data['assists']
21
+ end
22
+
23
+ def camps_stacked
24
+ data['camps_stacked']
25
+ end
26
+
27
+ def deaths
28
+ data['deaths']
29
+ end
30
+
31
+ def denies
32
+ data['denies']
33
+ end
34
+
35
+ def gold_per_min
36
+ data['gold_per_min']
37
+ end
38
+
39
+ def hero_id
40
+ data['hero_id']
41
+ end
42
+
43
+ def kills
44
+ data['kills']
45
+ end
46
+
47
+ def obs_placed
48
+ data['obs_placed']
49
+ end
50
+
51
+ def sen_placed
52
+ data['sen_placed']
53
+ end
54
+
55
+ def rune_pickups
56
+ data['rune_pickups']
57
+ end
58
+
59
+ def stuns
60
+ data['stuns']
61
+ end
62
+
63
+ def xp_per_min
64
+ data['xp_per_min']
65
+ end
66
+
67
+ def name
68
+ data['name']
69
+ end
70
+
71
+ def side
72
+ data['isRadiant'] ? :radiant : :dire
73
+ end
74
+
75
+ def kda
76
+ data['kda']
77
+ end
78
+
79
+ def tower_kills
80
+ data['tower_kills']
81
+ end
82
+
83
+ def roshan_kills
84
+ data['roshan_kills']
85
+ end
86
+
87
+ def hero_healing
88
+ data['hero_healing']
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,37 @@
1
+ require 'open_dota_api/entity'
2
+
3
+ module OpenDotaApi
4
+ class Team < Entity
5
+ include Entities::Instantiatable
6
+
7
+ ENDPOINT = 'teams'
8
+
9
+ def team_id
10
+ data['team_id']
11
+ end
12
+
13
+ def rating
14
+ data['rating']
15
+ end
16
+
17
+ def wins
18
+ data['wins']
19
+ end
20
+
21
+ def losses
22
+ data['losses']
23
+ end
24
+
25
+ def last_match_time
26
+ data['last_match_time']
27
+ end
28
+
29
+ def name
30
+ data['name']
31
+ end
32
+
33
+ def tag
34
+ data['tag']
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module OpenDotaApi
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,1580 @@
1
+ [
2
+ {
3
+ "id": 1,
4
+ "name": "npc_dota_hero_antimage",
5
+ "localized_name": "Anti-Mage",
6
+ "primary_attr": "agi",
7
+ "attack_type": "Melee",
8
+ "roles": [
9
+ "Carry",
10
+ "Escape",
11
+ "Nuker"
12
+ ],
13
+ "legs": 2
14
+ },
15
+ {
16
+ "id": 2,
17
+ "name": "npc_dota_hero_axe",
18
+ "localized_name": "Axe",
19
+ "primary_attr": "str",
20
+ "attack_type": "Melee",
21
+ "roles": [
22
+ "Initiator",
23
+ "Durable",
24
+ "Disabler",
25
+ "Jungler"
26
+ ],
27
+ "legs": 2
28
+ },
29
+ {
30
+ "id": 3,
31
+ "name": "npc_dota_hero_bane",
32
+ "localized_name": "Bane",
33
+ "primary_attr": "int",
34
+ "attack_type": "Ranged",
35
+ "roles": [
36
+ "Support",
37
+ "Disabler",
38
+ "Nuker",
39
+ "Durable"
40
+ ],
41
+ "legs": 4
42
+ },
43
+ {
44
+ "id": 4,
45
+ "name": "npc_dota_hero_bloodseeker",
46
+ "localized_name": "Bloodseeker",
47
+ "primary_attr": "agi",
48
+ "attack_type": "Melee",
49
+ "roles": [
50
+ "Carry",
51
+ "Disabler",
52
+ "Jungler",
53
+ "Nuker",
54
+ "Initiator"
55
+ ],
56
+ "legs": 2
57
+ },
58
+ {
59
+ "id": 5,
60
+ "name": "npc_dota_hero_crystal_maiden",
61
+ "localized_name": "Crystal Maiden",
62
+ "primary_attr": "int",
63
+ "attack_type": "Ranged",
64
+ "roles": [
65
+ "Support",
66
+ "Disabler",
67
+ "Nuker",
68
+ "Jungler"
69
+ ],
70
+ "legs": 2
71
+ },
72
+ {
73
+ "id": 6,
74
+ "name": "npc_dota_hero_drow_ranger",
75
+ "localized_name": "Drow Ranger",
76
+ "primary_attr": "agi",
77
+ "attack_type": "Ranged",
78
+ "roles": [
79
+ "Carry",
80
+ "Disabler",
81
+ "Pusher"
82
+ ],
83
+ "legs": 2
84
+ },
85
+ {
86
+ "id": 7,
87
+ "name": "npc_dota_hero_earthshaker",
88
+ "localized_name": "Earthshaker",
89
+ "primary_attr": "str",
90
+ "attack_type": "Melee",
91
+ "roles": [
92
+ "Support",
93
+ "Initiator",
94
+ "Disabler",
95
+ "Nuker"
96
+ ],
97
+ "legs": 2
98
+ },
99
+ {
100
+ "id": 8,
101
+ "name": "npc_dota_hero_juggernaut",
102
+ "localized_name": "Juggernaut",
103
+ "primary_attr": "agi",
104
+ "attack_type": "Melee",
105
+ "roles": [
106
+ "Carry",
107
+ "Pusher",
108
+ "Escape"
109
+ ],
110
+ "legs": 2
111
+ },
112
+ {
113
+ "id": 9,
114
+ "name": "npc_dota_hero_mirana",
115
+ "localized_name": "Mirana",
116
+ "primary_attr": "agi",
117
+ "attack_type": "Ranged",
118
+ "roles": [
119
+ "Carry",
120
+ "Support",
121
+ "Escape",
122
+ "Nuker",
123
+ "Disabler"
124
+ ],
125
+ "legs": 2
126
+ },
127
+ {
128
+ "id": 10,
129
+ "name": "npc_dota_hero_morphling",
130
+ "localized_name": "Morphling",
131
+ "primary_attr": "agi",
132
+ "attack_type": "Ranged",
133
+ "roles": [
134
+ "Carry",
135
+ "Escape",
136
+ "Durable",
137
+ "Nuker",
138
+ "Disabler"
139
+ ],
140
+ "legs": 0
141
+ },
142
+ {
143
+ "id": 11,
144
+ "name": "npc_dota_hero_nevermore",
145
+ "localized_name": "Shadow Fiend",
146
+ "primary_attr": "agi",
147
+ "attack_type": "Ranged",
148
+ "roles": [
149
+ "Carry",
150
+ "Nuker"
151
+ ],
152
+ "legs": 0
153
+ },
154
+ {
155
+ "id": 12,
156
+ "name": "npc_dota_hero_phantom_lancer",
157
+ "localized_name": "Phantom Lancer",
158
+ "primary_attr": "agi",
159
+ "attack_type": "Melee",
160
+ "roles": [
161
+ "Carry",
162
+ "Escape",
163
+ "Pusher",
164
+ "Nuker"
165
+ ],
166
+ "legs": 2
167
+ },
168
+ {
169
+ "id": 13,
170
+ "name": "npc_dota_hero_puck",
171
+ "localized_name": "Puck",
172
+ "primary_attr": "int",
173
+ "attack_type": "Ranged",
174
+ "roles": [
175
+ "Initiator",
176
+ "Disabler",
177
+ "Escape",
178
+ "Nuker"
179
+ ],
180
+ "legs": 2
181
+ },
182
+ {
183
+ "id": 14,
184
+ "name": "npc_dota_hero_pudge",
185
+ "localized_name": "Pudge",
186
+ "primary_attr": "str",
187
+ "attack_type": "Melee",
188
+ "roles": [
189
+ "Disabler",
190
+ "Initiator",
191
+ "Durable",
192
+ "Nuker"
193
+ ],
194
+ "legs": 2
195
+ },
196
+ {
197
+ "id": 15,
198
+ "name": "npc_dota_hero_razor",
199
+ "localized_name": "Razor",
200
+ "primary_attr": "agi",
201
+ "attack_type": "Ranged",
202
+ "roles": [
203
+ "Carry",
204
+ "Durable",
205
+ "Nuker",
206
+ "Pusher"
207
+ ],
208
+ "legs": 0
209
+ },
210
+ {
211
+ "id": 16,
212
+ "name": "npc_dota_hero_sand_king",
213
+ "localized_name": "Sand King",
214
+ "primary_attr": "str",
215
+ "attack_type": "Melee",
216
+ "roles": [
217
+ "Initiator",
218
+ "Disabler",
219
+ "Nuker",
220
+ "Escape",
221
+ "Jungler"
222
+ ],
223
+ "legs": 6
224
+ },
225
+ {
226
+ "id": 17,
227
+ "name": "npc_dota_hero_storm_spirit",
228
+ "localized_name": "Storm Spirit",
229
+ "primary_attr": "int",
230
+ "attack_type": "Ranged",
231
+ "roles": [
232
+ "Carry",
233
+ "Escape",
234
+ "Nuker",
235
+ "Initiator",
236
+ "Disabler"
237
+ ],
238
+ "legs": 2
239
+ },
240
+ {
241
+ "id": 18,
242
+ "name": "npc_dota_hero_sven",
243
+ "localized_name": "Sven",
244
+ "primary_attr": "str",
245
+ "attack_type": "Melee",
246
+ "roles": [
247
+ "Carry",
248
+ "Disabler",
249
+ "Initiator",
250
+ "Durable",
251
+ "Nuker"
252
+ ],
253
+ "legs": 2
254
+ },
255
+ {
256
+ "id": 19,
257
+ "name": "npc_dota_hero_tiny",
258
+ "localized_name": "Tiny",
259
+ "primary_attr": "str",
260
+ "attack_type": "Melee",
261
+ "roles": [
262
+ "Carry",
263
+ "Nuker",
264
+ "Pusher",
265
+ "Initiator",
266
+ "Durable",
267
+ "Disabler"
268
+ ],
269
+ "legs": 2
270
+ },
271
+ {
272
+ "id": 20,
273
+ "name": "npc_dota_hero_vengefulspirit",
274
+ "localized_name": "Vengeful Spirit",
275
+ "primary_attr": "agi",
276
+ "attack_type": "Ranged",
277
+ "roles": [
278
+ "Support",
279
+ "Initiator",
280
+ "Disabler",
281
+ "Nuker",
282
+ "Escape"
283
+ ],
284
+ "legs": 2
285
+ },
286
+ {
287
+ "id": 21,
288
+ "name": "npc_dota_hero_windrunner",
289
+ "localized_name": "Windranger",
290
+ "primary_attr": "int",
291
+ "attack_type": "Ranged",
292
+ "roles": [
293
+ "Carry",
294
+ "Support",
295
+ "Disabler",
296
+ "Escape",
297
+ "Nuker"
298
+ ],
299
+ "legs": 2
300
+ },
301
+ {
302
+ "id": 22,
303
+ "name": "npc_dota_hero_zuus",
304
+ "localized_name": "Zeus",
305
+ "primary_attr": "int",
306
+ "attack_type": "Ranged",
307
+ "roles": [
308
+ "Nuker"
309
+ ],
310
+ "legs": 2
311
+ },
312
+ {
313
+ "id": 23,
314
+ "name": "npc_dota_hero_kunkka",
315
+ "localized_name": "Kunkka",
316
+ "primary_attr": "str",
317
+ "attack_type": "Melee",
318
+ "roles": [
319
+ "Carry",
320
+ "Disabler",
321
+ "Initiator",
322
+ "Durable",
323
+ "Nuker"
324
+ ],
325
+ "legs": 2
326
+ },
327
+ {
328
+ "id": 25,
329
+ "name": "npc_dota_hero_lina",
330
+ "localized_name": "Lina",
331
+ "primary_attr": "int",
332
+ "attack_type": "Ranged",
333
+ "roles": [
334
+ "Support",
335
+ "Carry",
336
+ "Nuker",
337
+ "Disabler"
338
+ ],
339
+ "legs": 2
340
+ },
341
+ {
342
+ "id": 26,
343
+ "name": "npc_dota_hero_lion",
344
+ "localized_name": "Lion",
345
+ "primary_attr": "int",
346
+ "attack_type": "Ranged",
347
+ "roles": [
348
+ "Support",
349
+ "Disabler",
350
+ "Nuker",
351
+ "Initiator"
352
+ ],
353
+ "legs": 2
354
+ },
355
+ {
356
+ "id": 27,
357
+ "name": "npc_dota_hero_shadow_shaman",
358
+ "localized_name": "Shadow Shaman",
359
+ "primary_attr": "int",
360
+ "attack_type": "Ranged",
361
+ "roles": [
362
+ "Support",
363
+ "Pusher",
364
+ "Disabler",
365
+ "Nuker",
366
+ "Initiator"
367
+ ],
368
+ "legs": 2
369
+ },
370
+ {
371
+ "id": 28,
372
+ "name": "npc_dota_hero_slardar",
373
+ "localized_name": "Slardar",
374
+ "primary_attr": "str",
375
+ "attack_type": "Melee",
376
+ "roles": [
377
+ "Carry",
378
+ "Durable",
379
+ "Initiator",
380
+ "Disabler",
381
+ "Escape"
382
+ ],
383
+ "legs": 0
384
+ },
385
+ {
386
+ "id": 29,
387
+ "name": "npc_dota_hero_tidehunter",
388
+ "localized_name": "Tidehunter",
389
+ "primary_attr": "str",
390
+ "attack_type": "Melee",
391
+ "roles": [
392
+ "Initiator",
393
+ "Durable",
394
+ "Disabler",
395
+ "Nuker"
396
+ ],
397
+ "legs": 2
398
+ },
399
+ {
400
+ "id": 30,
401
+ "name": "npc_dota_hero_witch_doctor",
402
+ "localized_name": "Witch Doctor",
403
+ "primary_attr": "int",
404
+ "attack_type": "Ranged",
405
+ "roles": [
406
+ "Support",
407
+ "Nuker",
408
+ "Disabler"
409
+ ],
410
+ "legs": 2
411
+ },
412
+ {
413
+ "id": 31,
414
+ "name": "npc_dota_hero_lich",
415
+ "localized_name": "Lich",
416
+ "primary_attr": "int",
417
+ "attack_type": "Ranged",
418
+ "roles": [
419
+ "Support",
420
+ "Nuker"
421
+ ],
422
+ "legs": 2
423
+ },
424
+ {
425
+ "id": 32,
426
+ "name": "npc_dota_hero_riki",
427
+ "localized_name": "Riki",
428
+ "primary_attr": "agi",
429
+ "attack_type": "Melee",
430
+ "roles": [
431
+ "Carry",
432
+ "Escape",
433
+ "Disabler"
434
+ ],
435
+ "legs": 2
436
+ },
437
+ {
438
+ "id": 33,
439
+ "name": "npc_dota_hero_enigma",
440
+ "localized_name": "Enigma",
441
+ "primary_attr": "int",
442
+ "attack_type": "Ranged",
443
+ "roles": [
444
+ "Disabler",
445
+ "Jungler",
446
+ "Initiator",
447
+ "Pusher"
448
+ ],
449
+ "legs": 0
450
+ },
451
+ {
452
+ "id": 34,
453
+ "name": "npc_dota_hero_tinker",
454
+ "localized_name": "Tinker",
455
+ "primary_attr": "int",
456
+ "attack_type": "Ranged",
457
+ "roles": [
458
+ "Carry",
459
+ "Nuker",
460
+ "Pusher"
461
+ ],
462
+ "legs": 2
463
+ },
464
+ {
465
+ "id": 35,
466
+ "name": "npc_dota_hero_sniper",
467
+ "localized_name": "Sniper",
468
+ "primary_attr": "agi",
469
+ "attack_type": "Ranged",
470
+ "roles": [
471
+ "Carry",
472
+ "Nuker"
473
+ ],
474
+ "legs": 2
475
+ },
476
+ {
477
+ "id": 36,
478
+ "name": "npc_dota_hero_necrolyte",
479
+ "localized_name": "Necrophos",
480
+ "primary_attr": "int",
481
+ "attack_type": "Ranged",
482
+ "roles": [
483
+ "Carry",
484
+ "Nuker",
485
+ "Durable",
486
+ "Disabler"
487
+ ],
488
+ "legs": 2
489
+ },
490
+ {
491
+ "id": 37,
492
+ "name": "npc_dota_hero_warlock",
493
+ "localized_name": "Warlock",
494
+ "primary_attr": "int",
495
+ "attack_type": "Ranged",
496
+ "roles": [
497
+ "Support",
498
+ "Initiator",
499
+ "Disabler"
500
+ ],
501
+ "legs": 2
502
+ },
503
+ {
504
+ "id": 38,
505
+ "name": "npc_dota_hero_beastmaster",
506
+ "localized_name": "Beastmaster",
507
+ "primary_attr": "str",
508
+ "attack_type": "Melee",
509
+ "roles": [
510
+ "Initiator",
511
+ "Disabler",
512
+ "Durable",
513
+ "Nuker"
514
+ ],
515
+ "legs": 2
516
+ },
517
+ {
518
+ "id": 39,
519
+ "name": "npc_dota_hero_queenofpain",
520
+ "localized_name": "Queen of Pain",
521
+ "primary_attr": "int",
522
+ "attack_type": "Ranged",
523
+ "roles": [
524
+ "Carry",
525
+ "Nuker",
526
+ "Escape"
527
+ ],
528
+ "legs": 2
529
+ },
530
+ {
531
+ "id": 40,
532
+ "name": "npc_dota_hero_venomancer",
533
+ "localized_name": "Venomancer",
534
+ "primary_attr": "agi",
535
+ "attack_type": "Ranged",
536
+ "roles": [
537
+ "Support",
538
+ "Nuker",
539
+ "Initiator",
540
+ "Pusher",
541
+ "Disabler"
542
+ ],
543
+ "legs": 0
544
+ },
545
+ {
546
+ "id": 41,
547
+ "name": "npc_dota_hero_faceless_void",
548
+ "localized_name": "Faceless Void",
549
+ "primary_attr": "agi",
550
+ "attack_type": "Melee",
551
+ "roles": [
552
+ "Carry",
553
+ "Initiator",
554
+ "Disabler",
555
+ "Escape",
556
+ "Durable"
557
+ ],
558
+ "legs": 2
559
+ },
560
+ {
561
+ "id": 42,
562
+ "name": "npc_dota_hero_skeleton_king",
563
+ "localized_name": "Wraith King",
564
+ "primary_attr": "str",
565
+ "attack_type": "Melee",
566
+ "roles": [
567
+ "Carry",
568
+ "Support",
569
+ "Durable",
570
+ "Disabler",
571
+ "Initiator"
572
+ ],
573
+ "legs": 2
574
+ },
575
+ {
576
+ "id": 43,
577
+ "name": "npc_dota_hero_death_prophet",
578
+ "localized_name": "Death Prophet",
579
+ "primary_attr": "int",
580
+ "attack_type": "Ranged",
581
+ "roles": [
582
+ "Carry",
583
+ "Pusher",
584
+ "Nuker",
585
+ "Disabler"
586
+ ],
587
+ "legs": 2
588
+ },
589
+ {
590
+ "id": 44,
591
+ "name": "npc_dota_hero_phantom_assassin",
592
+ "localized_name": "Phantom Assassin",
593
+ "primary_attr": "agi",
594
+ "attack_type": "Melee",
595
+ "roles": [
596
+ "Carry",
597
+ "Escape"
598
+ ],
599
+ "legs": 2
600
+ },
601
+ {
602
+ "id": 45,
603
+ "name": "npc_dota_hero_pugna",
604
+ "localized_name": "Pugna",
605
+ "primary_attr": "int",
606
+ "attack_type": "Ranged",
607
+ "roles": [
608
+ "Nuker",
609
+ "Pusher"
610
+ ],
611
+ "legs": 2
612
+ },
613
+ {
614
+ "id": 46,
615
+ "name": "npc_dota_hero_templar_assassin",
616
+ "localized_name": "Templar Assassin",
617
+ "primary_attr": "agi",
618
+ "attack_type": "Ranged",
619
+ "roles": [
620
+ "Carry",
621
+ "Escape"
622
+ ],
623
+ "legs": 2
624
+ },
625
+ {
626
+ "id": 47,
627
+ "name": "npc_dota_hero_viper",
628
+ "localized_name": "Viper",
629
+ "primary_attr": "agi",
630
+ "attack_type": "Ranged",
631
+ "roles": [
632
+ "Carry",
633
+ "Durable",
634
+ "Initiator",
635
+ "Disabler"
636
+ ],
637
+ "legs": 0
638
+ },
639
+ {
640
+ "id": 48,
641
+ "name": "npc_dota_hero_luna",
642
+ "localized_name": "Luna",
643
+ "primary_attr": "agi",
644
+ "attack_type": "Ranged",
645
+ "roles": [
646
+ "Carry",
647
+ "Nuker",
648
+ "Pusher"
649
+ ],
650
+ "legs": 2
651
+ },
652
+ {
653
+ "id": 49,
654
+ "name": "npc_dota_hero_dragon_knight",
655
+ "localized_name": "Dragon Knight",
656
+ "primary_attr": "str",
657
+ "attack_type": "Melee",
658
+ "roles": [
659
+ "Carry",
660
+ "Pusher",
661
+ "Durable",
662
+ "Disabler",
663
+ "Initiator",
664
+ "Nuker"
665
+ ],
666
+ "legs": 2
667
+ },
668
+ {
669
+ "id": 50,
670
+ "name": "npc_dota_hero_dazzle",
671
+ "localized_name": "Dazzle",
672
+ "primary_attr": "int",
673
+ "attack_type": "Ranged",
674
+ "roles": [
675
+ "Support",
676
+ "Nuker",
677
+ "Disabler"
678
+ ],
679
+ "legs": 2
680
+ },
681
+ {
682
+ "id": 51,
683
+ "name": "npc_dota_hero_rattletrap",
684
+ "localized_name": "Clockwerk",
685
+ "primary_attr": "str",
686
+ "attack_type": "Melee",
687
+ "roles": [
688
+ "Initiator",
689
+ "Disabler",
690
+ "Durable",
691
+ "Nuker"
692
+ ],
693
+ "legs": 2
694
+ },
695
+ {
696
+ "id": 52,
697
+ "name": "npc_dota_hero_leshrac",
698
+ "localized_name": "Leshrac",
699
+ "primary_attr": "int",
700
+ "attack_type": "Ranged",
701
+ "roles": [
702
+ "Carry",
703
+ "Support",
704
+ "Nuker",
705
+ "Pusher",
706
+ "Disabler"
707
+ ],
708
+ "legs": 4
709
+ },
710
+ {
711
+ "id": 53,
712
+ "name": "npc_dota_hero_furion",
713
+ "localized_name": "Nature's Prophet",
714
+ "primary_attr": "int",
715
+ "attack_type": "Ranged",
716
+ "roles": [
717
+ "Carry",
718
+ "Jungler",
719
+ "Pusher",
720
+ "Escape",
721
+ "Nuker"
722
+ ],
723
+ "legs": 2
724
+ },
725
+ {
726
+ "id": 54,
727
+ "name": "npc_dota_hero_life_stealer",
728
+ "localized_name": "Lifestealer",
729
+ "primary_attr": "str",
730
+ "attack_type": "Melee",
731
+ "roles": [
732
+ "Carry",
733
+ "Durable",
734
+ "Jungler",
735
+ "Escape",
736
+ "Disabler"
737
+ ],
738
+ "legs": 2
739
+ },
740
+ {
741
+ "id": 55,
742
+ "name": "npc_dota_hero_dark_seer",
743
+ "localized_name": "Dark Seer",
744
+ "primary_attr": "int",
745
+ "attack_type": "Melee",
746
+ "roles": [
747
+ "Initiator",
748
+ "Jungler",
749
+ "Escape",
750
+ "Disabler"
751
+ ],
752
+ "legs": 2
753
+ },
754
+ {
755
+ "id": 56,
756
+ "name": "npc_dota_hero_clinkz",
757
+ "localized_name": "Clinkz",
758
+ "primary_attr": "agi",
759
+ "attack_type": "Ranged",
760
+ "roles": [
761
+ "Carry",
762
+ "Escape",
763
+ "Pusher"
764
+ ],
765
+ "legs": 2
766
+ },
767
+ {
768
+ "id": 57,
769
+ "name": "npc_dota_hero_omniknight",
770
+ "localized_name": "Omniknight",
771
+ "primary_attr": "str",
772
+ "attack_type": "Melee",
773
+ "roles": [
774
+ "Support",
775
+ "Durable",
776
+ "Nuker"
777
+ ],
778
+ "legs": 2
779
+ },
780
+ {
781
+ "id": 58,
782
+ "name": "npc_dota_hero_enchantress",
783
+ "localized_name": "Enchantress",
784
+ "primary_attr": "int",
785
+ "attack_type": "Ranged",
786
+ "roles": [
787
+ "Support",
788
+ "Jungler",
789
+ "Pusher",
790
+ "Durable",
791
+ "Disabler"
792
+ ],
793
+ "legs": 4
794
+ },
795
+ {
796
+ "id": 59,
797
+ "name": "npc_dota_hero_huskar",
798
+ "localized_name": "Huskar",
799
+ "primary_attr": "str",
800
+ "attack_type": "Ranged",
801
+ "roles": [
802
+ "Carry",
803
+ "Durable",
804
+ "Initiator"
805
+ ],
806
+ "legs": 2
807
+ },
808
+ {
809
+ "id": 60,
810
+ "name": "npc_dota_hero_night_stalker",
811
+ "localized_name": "Night Stalker",
812
+ "primary_attr": "str",
813
+ "attack_type": "Melee",
814
+ "roles": [
815
+ "Carry",
816
+ "Initiator",
817
+ "Durable",
818
+ "Disabler",
819
+ "Nuker"
820
+ ],
821
+ "legs": 2
822
+ },
823
+ {
824
+ "id": 61,
825
+ "name": "npc_dota_hero_broodmother",
826
+ "localized_name": "Broodmother",
827
+ "primary_attr": "agi",
828
+ "attack_type": "Melee",
829
+ "roles": [
830
+ "Carry",
831
+ "Pusher",
832
+ "Escape",
833
+ "Nuker"
834
+ ],
835
+ "legs": 8
836
+ },
837
+ {
838
+ "id": 62,
839
+ "name": "npc_dota_hero_bounty_hunter",
840
+ "localized_name": "Bounty Hunter",
841
+ "primary_attr": "agi",
842
+ "attack_type": "Melee",
843
+ "roles": [
844
+ "Escape",
845
+ "Nuker"
846
+ ],
847
+ "legs": 2
848
+ },
849
+ {
850
+ "id": 63,
851
+ "name": "npc_dota_hero_weaver",
852
+ "localized_name": "Weaver",
853
+ "primary_attr": "agi",
854
+ "attack_type": "Ranged",
855
+ "roles": [
856
+ "Carry",
857
+ "Escape"
858
+ ],
859
+ "legs": 4
860
+ },
861
+ {
862
+ "id": 64,
863
+ "name": "npc_dota_hero_jakiro",
864
+ "localized_name": "Jakiro",
865
+ "primary_attr": "int",
866
+ "attack_type": "Ranged",
867
+ "roles": [
868
+ "Support",
869
+ "Nuker",
870
+ "Pusher",
871
+ "Disabler"
872
+ ],
873
+ "legs": 2
874
+ },
875
+ {
876
+ "id": 65,
877
+ "name": "npc_dota_hero_batrider",
878
+ "localized_name": "Batrider",
879
+ "primary_attr": "int",
880
+ "attack_type": "Ranged",
881
+ "roles": [
882
+ "Initiator",
883
+ "Jungler",
884
+ "Disabler",
885
+ "Escape"
886
+ ],
887
+ "legs": 2
888
+ },
889
+ {
890
+ "id": 66,
891
+ "name": "npc_dota_hero_chen",
892
+ "localized_name": "Chen",
893
+ "primary_attr": "int",
894
+ "attack_type": "Ranged",
895
+ "roles": [
896
+ "Support",
897
+ "Jungler",
898
+ "Pusher"
899
+ ],
900
+ "legs": 2
901
+ },
902
+ {
903
+ "id": 67,
904
+ "name": "npc_dota_hero_spectre",
905
+ "localized_name": "Spectre",
906
+ "primary_attr": "agi",
907
+ "attack_type": "Melee",
908
+ "roles": [
909
+ "Carry",
910
+ "Durable",
911
+ "Escape"
912
+ ],
913
+ "legs": 0
914
+ },
915
+ {
916
+ "id": 68,
917
+ "name": "npc_dota_hero_ancient_apparition",
918
+ "localized_name": "Ancient Apparition",
919
+ "primary_attr": "int",
920
+ "attack_type": "Ranged",
921
+ "roles": [
922
+ "Support",
923
+ "Disabler",
924
+ "Nuker"
925
+ ],
926
+ "legs": 2
927
+ },
928
+ {
929
+ "id": 69,
930
+ "name": "npc_dota_hero_doom_bringer",
931
+ "localized_name": "Doom",
932
+ "primary_attr": "str",
933
+ "attack_type": "Melee",
934
+ "roles": [
935
+ "Carry",
936
+ "Disabler",
937
+ "Initiator",
938
+ "Durable",
939
+ "Nuker"
940
+ ],
941
+ "legs": 2
942
+ },
943
+ {
944
+ "id": 70,
945
+ "name": "npc_dota_hero_ursa",
946
+ "localized_name": "Ursa",
947
+ "primary_attr": "agi",
948
+ "attack_type": "Melee",
949
+ "roles": [
950
+ "Carry",
951
+ "Jungler",
952
+ "Durable",
953
+ "Disabler"
954
+ ],
955
+ "legs": 2
956
+ },
957
+ {
958
+ "id": 71,
959
+ "name": "npc_dota_hero_spirit_breaker",
960
+ "localized_name": "Spirit Breaker",
961
+ "primary_attr": "str",
962
+ "attack_type": "Melee",
963
+ "roles": [
964
+ "Carry",
965
+ "Initiator",
966
+ "Disabler",
967
+ "Durable",
968
+ "Escape"
969
+ ],
970
+ "legs": 2
971
+ },
972
+ {
973
+ "id": 72,
974
+ "name": "npc_dota_hero_gyrocopter",
975
+ "localized_name": "Gyrocopter",
976
+ "primary_attr": "agi",
977
+ "attack_type": "Ranged",
978
+ "roles": [
979
+ "Carry",
980
+ "Nuker",
981
+ "Disabler"
982
+ ],
983
+ "legs": 2
984
+ },
985
+ {
986
+ "id": 73,
987
+ "name": "npc_dota_hero_alchemist",
988
+ "localized_name": "Alchemist",
989
+ "primary_attr": "str",
990
+ "attack_type": "Melee",
991
+ "roles": [
992
+ "Carry",
993
+ "Support",
994
+ "Durable",
995
+ "Disabler",
996
+ "Initiator",
997
+ "Nuker"
998
+ ],
999
+ "legs": 2
1000
+ },
1001
+ {
1002
+ "id": 74,
1003
+ "name": "npc_dota_hero_invoker",
1004
+ "localized_name": "Invoker",
1005
+ "primary_attr": "int",
1006
+ "attack_type": "Ranged",
1007
+ "roles": [
1008
+ "Carry",
1009
+ "Nuker",
1010
+ "Disabler",
1011
+ "Escape",
1012
+ "Pusher"
1013
+ ],
1014
+ "legs": 2
1015
+ },
1016
+ {
1017
+ "id": 75,
1018
+ "name": "npc_dota_hero_silencer",
1019
+ "localized_name": "Silencer",
1020
+ "primary_attr": "int",
1021
+ "attack_type": "Ranged",
1022
+ "roles": [
1023
+ "Carry",
1024
+ "Support",
1025
+ "Disabler",
1026
+ "Initiator",
1027
+ "Nuker"
1028
+ ],
1029
+ "legs": 2
1030
+ },
1031
+ {
1032
+ "id": 76,
1033
+ "name": "npc_dota_hero_obsidian_destroyer",
1034
+ "localized_name": "Outworld Devourer",
1035
+ "primary_attr": "int",
1036
+ "attack_type": "Ranged",
1037
+ "roles": [
1038
+ "Carry",
1039
+ "Nuker",
1040
+ "Disabler"
1041
+ ],
1042
+ "legs": 4
1043
+ },
1044
+ {
1045
+ "id": 77,
1046
+ "name": "npc_dota_hero_lycan",
1047
+ "localized_name": "Lycan",
1048
+ "primary_attr": "str",
1049
+ "attack_type": "Melee",
1050
+ "roles": [
1051
+ "Carry",
1052
+ "Pusher",
1053
+ "Jungler",
1054
+ "Durable",
1055
+ "Escape"
1056
+ ],
1057
+ "legs": 2
1058
+ },
1059
+ {
1060
+ "id": 78,
1061
+ "name": "npc_dota_hero_brewmaster",
1062
+ "localized_name": "Brewmaster",
1063
+ "primary_attr": "str",
1064
+ "attack_type": "Melee",
1065
+ "roles": [
1066
+ "Carry",
1067
+ "Initiator",
1068
+ "Durable",
1069
+ "Disabler",
1070
+ "Nuker"
1071
+ ],
1072
+ "legs": 2
1073
+ },
1074
+ {
1075
+ "id": 79,
1076
+ "name": "npc_dota_hero_shadow_demon",
1077
+ "localized_name": "Shadow Demon",
1078
+ "primary_attr": "int",
1079
+ "attack_type": "Ranged",
1080
+ "roles": [
1081
+ "Support",
1082
+ "Disabler",
1083
+ "Initiator",
1084
+ "Nuker"
1085
+ ],
1086
+ "legs": 2
1087
+ },
1088
+ {
1089
+ "id": 80,
1090
+ "name": "npc_dota_hero_lone_druid",
1091
+ "localized_name": "Lone Druid",
1092
+ "primary_attr": "agi",
1093
+ "attack_type": "Ranged",
1094
+ "roles": [
1095
+ "Carry",
1096
+ "Pusher",
1097
+ "Jungler",
1098
+ "Durable"
1099
+ ],
1100
+ "legs": 2
1101
+ },
1102
+ {
1103
+ "id": 81,
1104
+ "name": "npc_dota_hero_chaos_knight",
1105
+ "localized_name": "Chaos Knight",
1106
+ "primary_attr": "str",
1107
+ "attack_type": "Melee",
1108
+ "roles": [
1109
+ "Carry",
1110
+ "Disabler",
1111
+ "Durable",
1112
+ "Pusher",
1113
+ "Initiator"
1114
+ ],
1115
+ "legs": 2
1116
+ },
1117
+ {
1118
+ "id": 82,
1119
+ "name": "npc_dota_hero_meepo",
1120
+ "localized_name": "Meepo",
1121
+ "primary_attr": "agi",
1122
+ "attack_type": "Melee",
1123
+ "roles": [
1124
+ "Carry",
1125
+ "Escape",
1126
+ "Nuker",
1127
+ "Disabler",
1128
+ "Initiator",
1129
+ "Pusher"
1130
+ ],
1131
+ "legs": 2
1132
+ },
1133
+ {
1134
+ "id": 83,
1135
+ "name": "npc_dota_hero_treant",
1136
+ "localized_name": "Treant Protector",
1137
+ "primary_attr": "str",
1138
+ "attack_type": "Melee",
1139
+ "roles": [
1140
+ "Support",
1141
+ "Initiator",
1142
+ "Durable",
1143
+ "Disabler",
1144
+ "Escape"
1145
+ ],
1146
+ "legs": 2
1147
+ },
1148
+ {
1149
+ "id": 84,
1150
+ "name": "npc_dota_hero_ogre_magi",
1151
+ "localized_name": "Ogre Magi",
1152
+ "primary_attr": "int",
1153
+ "attack_type": "Melee",
1154
+ "roles": [
1155
+ "Support",
1156
+ "Nuker",
1157
+ "Disabler",
1158
+ "Durable",
1159
+ "Initiator"
1160
+ ],
1161
+ "legs": 2
1162
+ },
1163
+ {
1164
+ "id": 85,
1165
+ "name": "npc_dota_hero_undying",
1166
+ "localized_name": "Undying",
1167
+ "primary_attr": "str",
1168
+ "attack_type": "Melee",
1169
+ "roles": [
1170
+ "Support",
1171
+ "Durable",
1172
+ "Disabler",
1173
+ "Nuker"
1174
+ ],
1175
+ "legs": 2
1176
+ },
1177
+ {
1178
+ "id": 86,
1179
+ "name": "npc_dota_hero_rubick",
1180
+ "localized_name": "Rubick",
1181
+ "primary_attr": "int",
1182
+ "attack_type": "Ranged",
1183
+ "roles": [
1184
+ "Support",
1185
+ "Disabler",
1186
+ "Nuker"
1187
+ ],
1188
+ "legs": 2
1189
+ },
1190
+ {
1191
+ "id": 87,
1192
+ "name": "npc_dota_hero_disruptor",
1193
+ "localized_name": "Disruptor",
1194
+ "primary_attr": "int",
1195
+ "attack_type": "Ranged",
1196
+ "roles": [
1197
+ "Support",
1198
+ "Disabler",
1199
+ "Nuker",
1200
+ "Initiator"
1201
+ ],
1202
+ "legs": 2
1203
+ },
1204
+ {
1205
+ "id": 88,
1206
+ "name": "npc_dota_hero_nyx_assassin",
1207
+ "localized_name": "Nyx Assassin",
1208
+ "primary_attr": "agi",
1209
+ "attack_type": "Melee",
1210
+ "roles": [
1211
+ "Disabler",
1212
+ "Nuker",
1213
+ "Initiator",
1214
+ "Escape"
1215
+ ],
1216
+ "legs": 6
1217
+ },
1218
+ {
1219
+ "id": 89,
1220
+ "name": "npc_dota_hero_naga_siren",
1221
+ "localized_name": "Naga Siren",
1222
+ "primary_attr": "agi",
1223
+ "attack_type": "Melee",
1224
+ "roles": [
1225
+ "Carry",
1226
+ "Support",
1227
+ "Pusher",
1228
+ "Disabler",
1229
+ "Initiator",
1230
+ "Escape"
1231
+ ],
1232
+ "legs": 0
1233
+ },
1234
+ {
1235
+ "id": 90,
1236
+ "name": "npc_dota_hero_keeper_of_the_light",
1237
+ "localized_name": "Keeper of the Light",
1238
+ "primary_attr": "int",
1239
+ "attack_type": "Ranged",
1240
+ "roles": [
1241
+ "Support",
1242
+ "Nuker",
1243
+ "Disabler",
1244
+ "Jungler"
1245
+ ],
1246
+ "legs": 2
1247
+ },
1248
+ {
1249
+ "id": 91,
1250
+ "name": "npc_dota_hero_wisp",
1251
+ "localized_name": "Io",
1252
+ "primary_attr": "str",
1253
+ "attack_type": "Ranged",
1254
+ "roles": [
1255
+ "Support",
1256
+ "Escape",
1257
+ "Nuker"
1258
+ ],
1259
+ "legs": 0
1260
+ },
1261
+ {
1262
+ "id": 92,
1263
+ "name": "npc_dota_hero_visage",
1264
+ "localized_name": "Visage",
1265
+ "primary_attr": "int",
1266
+ "attack_type": "Ranged",
1267
+ "roles": [
1268
+ "Support",
1269
+ "Nuker",
1270
+ "Durable",
1271
+ "Disabler",
1272
+ "Pusher"
1273
+ ],
1274
+ "legs": 2
1275
+ },
1276
+ {
1277
+ "id": 93,
1278
+ "name": "npc_dota_hero_slark",
1279
+ "localized_name": "Slark",
1280
+ "primary_attr": "agi",
1281
+ "attack_type": "Melee",
1282
+ "roles": [
1283
+ "Carry",
1284
+ "Escape",
1285
+ "Disabler",
1286
+ "Nuker"
1287
+ ],
1288
+ "legs": 2
1289
+ },
1290
+ {
1291
+ "id": 94,
1292
+ "name": "npc_dota_hero_medusa",
1293
+ "localized_name": "Medusa",
1294
+ "primary_attr": "agi",
1295
+ "attack_type": "Ranged",
1296
+ "roles": [
1297
+ "Carry",
1298
+ "Disabler",
1299
+ "Durable"
1300
+ ],
1301
+ "legs": 0
1302
+ },
1303
+ {
1304
+ "id": 95,
1305
+ "name": "npc_dota_hero_troll_warlord",
1306
+ "localized_name": "Troll Warlord",
1307
+ "primary_attr": "agi",
1308
+ "attack_type": "Ranged",
1309
+ "roles": [
1310
+ "Carry",
1311
+ "Pusher",
1312
+ "Disabler",
1313
+ "Durable"
1314
+ ],
1315
+ "legs": 2
1316
+ },
1317
+ {
1318
+ "id": 96,
1319
+ "name": "npc_dota_hero_centaur",
1320
+ "localized_name": "Centaur Warrunner",
1321
+ "primary_attr": "str",
1322
+ "attack_type": "Melee",
1323
+ "roles": [
1324
+ "Durable",
1325
+ "Initiator",
1326
+ "Disabler",
1327
+ "Nuker",
1328
+ "Escape"
1329
+ ],
1330
+ "legs": 4
1331
+ },
1332
+ {
1333
+ "id": 97,
1334
+ "name": "npc_dota_hero_magnataur",
1335
+ "localized_name": "Magnus",
1336
+ "primary_attr": "str",
1337
+ "attack_type": "Melee",
1338
+ "roles": [
1339
+ "Initiator",
1340
+ "Disabler",
1341
+ "Nuker",
1342
+ "Escape"
1343
+ ],
1344
+ "legs": 4
1345
+ },
1346
+ {
1347
+ "id": 98,
1348
+ "name": "npc_dota_hero_shredder",
1349
+ "localized_name": "Timbersaw",
1350
+ "primary_attr": "str",
1351
+ "attack_type": "Melee",
1352
+ "roles": [
1353
+ "Nuker",
1354
+ "Durable",
1355
+ "Escape"
1356
+ ],
1357
+ "legs": 2
1358
+ },
1359
+ {
1360
+ "id": 99,
1361
+ "name": "npc_dota_hero_bristleback",
1362
+ "localized_name": "Bristleback",
1363
+ "primary_attr": "str",
1364
+ "attack_type": "Melee",
1365
+ "roles": [
1366
+ "Carry",
1367
+ "Durable",
1368
+ "Initiator",
1369
+ "Nuker"
1370
+ ],
1371
+ "legs": 2
1372
+ },
1373
+ {
1374
+ "id": 100,
1375
+ "name": "npc_dota_hero_tusk",
1376
+ "localized_name": "Tusk",
1377
+ "primary_attr": "str",
1378
+ "attack_type": "Melee",
1379
+ "roles": [
1380
+ "Initiator",
1381
+ "Disabler",
1382
+ "Nuker"
1383
+ ],
1384
+ "legs": 2
1385
+ },
1386
+ {
1387
+ "id": 101,
1388
+ "name": "npc_dota_hero_skywrath_mage",
1389
+ "localized_name": "Skywrath Mage",
1390
+ "primary_attr": "int",
1391
+ "attack_type": "Ranged",
1392
+ "roles": [
1393
+ "Support",
1394
+ "Nuker",
1395
+ "Disabler"
1396
+ ],
1397
+ "legs": 2
1398
+ },
1399
+ {
1400
+ "id": 102,
1401
+ "name": "npc_dota_hero_abaddon",
1402
+ "localized_name": "Abaddon",
1403
+ "primary_attr": "str",
1404
+ "attack_type": "Melee",
1405
+ "roles": [
1406
+ "Support",
1407
+ "Carry",
1408
+ "Durable"
1409
+ ],
1410
+ "legs": 2
1411
+ },
1412
+ {
1413
+ "id": 103,
1414
+ "name": "npc_dota_hero_elder_titan",
1415
+ "localized_name": "Elder Titan",
1416
+ "primary_attr": "str",
1417
+ "attack_type": "Melee",
1418
+ "roles": [
1419
+ "Initiator",
1420
+ "Disabler",
1421
+ "Nuker",
1422
+ "Durable"
1423
+ ],
1424
+ "legs": 2
1425
+ },
1426
+ {
1427
+ "id": 104,
1428
+ "name": "npc_dota_hero_legion_commander",
1429
+ "localized_name": "Legion Commander",
1430
+ "primary_attr": "str",
1431
+ "attack_type": "Melee",
1432
+ "roles": [
1433
+ "Carry",
1434
+ "Disabler",
1435
+ "Initiator",
1436
+ "Durable",
1437
+ "Nuker"
1438
+ ],
1439
+ "legs": 2
1440
+ },
1441
+ {
1442
+ "id": 105,
1443
+ "name": "npc_dota_hero_techies",
1444
+ "localized_name": "Techies",
1445
+ "primary_attr": "int",
1446
+ "attack_type": "Ranged",
1447
+ "roles": [
1448
+ "Nuker",
1449
+ "Disabler"
1450
+ ],
1451
+ "legs": 6
1452
+ },
1453
+ {
1454
+ "id": 106,
1455
+ "name": "npc_dota_hero_ember_spirit",
1456
+ "localized_name": "Ember Spirit",
1457
+ "primary_attr": "agi",
1458
+ "attack_type": "Melee",
1459
+ "roles": [
1460
+ "Carry",
1461
+ "Escape",
1462
+ "Nuker",
1463
+ "Disabler",
1464
+ "Initiator"
1465
+ ],
1466
+ "legs": 2
1467
+ },
1468
+ {
1469
+ "id": 107,
1470
+ "name": "npc_dota_hero_earth_spirit",
1471
+ "localized_name": "Earth Spirit",
1472
+ "primary_attr": "str",
1473
+ "attack_type": "Melee",
1474
+ "roles": [
1475
+ "Nuker",
1476
+ "Escape",
1477
+ "Disabler",
1478
+ "Initiator",
1479
+ "Durable"
1480
+ ],
1481
+ "legs": 2
1482
+ },
1483
+ {
1484
+ "id": 108,
1485
+ "name": "npc_dota_hero_abyssal_underlord",
1486
+ "localized_name": "Underlord",
1487
+ "primary_attr": "str",
1488
+ "attack_type": "Melee",
1489
+ "roles": [
1490
+ "Support",
1491
+ "Nuker",
1492
+ "Disabler",
1493
+ "Durable",
1494
+ "Escape"
1495
+ ],
1496
+ "legs": 2
1497
+ },
1498
+ {
1499
+ "id": 109,
1500
+ "name": "npc_dota_hero_terrorblade",
1501
+ "localized_name": "Terrorblade",
1502
+ "primary_attr": "agi",
1503
+ "attack_type": "Melee",
1504
+ "roles": [
1505
+ "Carry",
1506
+ "Pusher",
1507
+ "Nuker"
1508
+ ],
1509
+ "legs": 2
1510
+ },
1511
+ {
1512
+ "id": 110,
1513
+ "name": "npc_dota_hero_phoenix",
1514
+ "localized_name": "Phoenix",
1515
+ "primary_attr": "str",
1516
+ "attack_type": "Ranged",
1517
+ "roles": [
1518
+ "Support",
1519
+ "Nuker",
1520
+ "Initiator",
1521
+ "Escape",
1522
+ "Disabler"
1523
+ ],
1524
+ "legs": 2
1525
+ },
1526
+ {
1527
+ "id": 111,
1528
+ "name": "npc_dota_hero_oracle",
1529
+ "localized_name": "Oracle",
1530
+ "primary_attr": "int",
1531
+ "attack_type": "Ranged",
1532
+ "roles": [
1533
+ "Support",
1534
+ "Nuker",
1535
+ "Disabler",
1536
+ "Escape"
1537
+ ],
1538
+ "legs": 2
1539
+ },
1540
+ {
1541
+ "id": 112,
1542
+ "name": "npc_dota_hero_winter_wyvern",
1543
+ "localized_name": "Winter Wyvern",
1544
+ "primary_attr": "int",
1545
+ "attack_type": "Ranged",
1546
+ "roles": [
1547
+ "Support",
1548
+ "Disabler",
1549
+ "Nuker"
1550
+ ],
1551
+ "legs": 2
1552
+ },
1553
+ {
1554
+ "id": 113,
1555
+ "name": "npc_dota_hero_arc_warden",
1556
+ "localized_name": "Arc Warden",
1557
+ "primary_attr": "agi",
1558
+ "attack_type": "Ranged",
1559
+ "roles": [
1560
+ "Carry",
1561
+ "Escape",
1562
+ "Nuker"
1563
+ ],
1564
+ "legs": 2
1565
+ },
1566
+ {
1567
+ "id": 114,
1568
+ "name": "npc_dota_hero_monkey_king",
1569
+ "localized_name": "Monkey King",
1570
+ "primary_attr": "agi",
1571
+ "attack_type": "Melee",
1572
+ "roles": [
1573
+ "Carry",
1574
+ "Escape",
1575
+ "Disabler",
1576
+ "Initiator"
1577
+ ],
1578
+ "legs": 2
1579
+ }
1580
+ ]