Files
by/script/build_roles_json.rb

257 lines
8.5 KiB
Ruby

# frozen_string_literal: true
require "json"
require_relative "../config/app"
Hanami.app.prepare
module ClashDeckGenerator2
module Scripts
class BuildRolesJson
OUTPUT_PATH = File.expand_path("../config/cards/roles.json", __dir__)
BASE_ROLES_BY_TYPE = {
"spell" => %w[spell],
"building" => %w[building defense],
"troop" => %w[support]
}.freeze
ROLE_OVERRIDES = {
# cycle
"Skeletons" => %w[cycle defense],
"Ice Spirit" => %w[cycle support],
"Electro Spirit" => %w[cycle support],
"Fire Spirit" => %w[cycle support splash],
"Heal Spirit" => %w[cycle support],
"Goblins" => %w[cycle defense],
"Spear Goblins" => %w[cycle support],
"Bats" => %w[cycle anti_air],
"Wall Breakers" => %w[cycle win_condition],
"Bomber" => %w[cycle splash support],
# win conditions
"Hog Rider" => %w[win_condition],
"Royal Giant" => %w[win_condition tank],
"Goblin Barrel" => %w[win_condition],
"Balloon" => %w[win_condition],
"Giant" => %w[win_condition tank],
"Golem" => %w[win_condition tank],
"Electro Giant" => %w[win_condition tank],
"Goblin Drill" => %w[win_condition],
"X-Bow" => %w[win_condition building defense],
"Mortar" => %w[win_condition building defense],
"Ram Rider" => %w[win_condition support],
"Graveyard" => %w[win_condition spell],
"Royal Hogs" => %w[win_condition],
"Battle Ram" => %w[win_condition],
"Elixir Golem" => %w[win_condition tank],
"Lava Hound" => %w[win_condition tank anti_air],
"Goblin Barrel" => %w[win_condition],
"Goblin Drill" => %w[win_condition building],
"Miner" => %w[win_condition support],
"Goblin Giant" => %w[win_condition tank],
"Three Musketeers" => %w[win_condition support anti_air],
"Skeleton Barrel" => %w[win_condition],
"Rocket" => %w[spell finisher],
"Fireball" => %w[spell finisher splash],
"Poison" => %w[spell finisher splash],
"Lightning" => %w[spell finisher],
"Void" => %w[spell finisher],
# anti air
"Archers" => %w[anti_air support cycle],
"Musketeer" => %w[anti_air support],
"Wizard" => %w[anti_air support splash],
"Baby Dragon" => %w[anti_air support splash],
"Electro Dragon" => %w[anti_air support splash],
"Inferno Dragon" => %w[anti_air defense],
"Mega Minion" => %w[anti_air support],
"Flying Machine" => %w[anti_air support],
"Hunter" => %w[anti_air defense],
"Firecracker" => %w[anti_air support splash],
"Minions" => %w[anti_air support],
"Minion Horde" => %w[anti_air support],
"Skeleton Dragons" => %w[anti_air support splash],
"Phoenix" => %w[anti_air support],
"Executioner" => %w[anti_air support splash],
"Tesla" => %w[anti_air building defense],
"Inferno Tower" => %w[building defense],
"Magic Archer" => %w[support anti_air],
"Zappies" => %w[support anti_air defense],
"Dart Goblin" => %w[support anti_air],
"Electro Wizard" => %w[support anti_air defense],
"Mother Witch" => %w[support anti_air],
"Little Prince" => %w[support anti_air],
# tanks / mini tanks
"Knight" => %w[tank defense],
"Valkyrie" => %w[tank defense splash],
"Ice Golem" => %w[tank cycle defense],
"P.E.K.K.A" => %w[tank defense],
"Mini P.E.K.K.A" => %w[defense tank],
"Mega Knight" => %w[tank defense splash],
"Royal Ghost" => %w[tank support splash],
"Dark Prince" => %w[tank support splash],
"Prince" => %w[tank support],
"Skeleton King" => %w[tank support],
"Golden Knight" => %w[tank support],
"Monk" => %w[tank defense],
"Mighty Miner" => %w[defense tank],
"Giant Skeleton" => %w[tank splash],
"Lumberjack" => %w[support tank],
"Bandit" => %w[support],
"Battle Healer" => %w[support tank],
"Goblin Giantess" => %w[tank support],
# buildings / defense
"Cannon" => %w[building defense],
"Tesla" => %w[building defense anti_air],
"Bomb Tower" => %w[building defense splash],
"Tombstone" => %w[building defense],
"Goblin Cage" => %w[building defense],
"Goblin Hut" => %w[building defense],
"Barbarian Hut" => %w[building defense],
"Furnace" => %w[building defense splash],
"Elixir Collector" => %w[building support],
"Goblin Drill" => %w[building win_condition],
"X-Bow" => %w[building win_condition defense],
"Mortar" => %w[building win_condition defense],
# splash / control
"Bowler" => %w[splash support defense],
"Witch" => %w[support splash],
"Bomber" => %w[support splash cycle],
"Arrows" => %w[spell splash],
"Zap" => %w[spell cycle],
"Giant Snowball" => %w[spell cycle],
"Royal Delivery" => %w[spell defense splash],
"Tornado" => %w[spell control defense],
"Rage" => %w[spell support],
"Freeze" => %w[spell control],
"Clone" => %w[spell support],
"Mirror" => %w[spell support],
"Earthquake" => %w[spell building_hate],
"The Log" => %w[spell cycle defense],
"Barbarian Barrel" => %w[spell cycle defense],
# support / utility
"Skeleton Army" => %w[defense],
"Guards" => %w[defense],
"Royal Recruits" => %w[defense],
"Rascals" => %w[defense support anti_air],
"Cannon Cart" => %w[support defense],
"Sparky" => %w[support defense],
"Night Witch" => %w[support],
"Princess" => %w[support splash],
"Ice Wizard" => %w[support defense splash],
"Fisherman" => %w[defense control],
"Goblin Demolisher" => %w[support splash],
"Suspicious Bush" => %w[support],
"Battle Ram" => %w[win_condition],
"Royal Hogs" => %w[win_condition],
"Royal Recruits" => %w[defense],
"Electro Giant" => %w[win_condition tank],
"Electro Dragon" => %w[anti_air support splash],
"Goblin Machine" => %w[support],
"Spirit Empress" => %w[support],
"Boss Bandit" => %w[support],
"Goblins" => %w[cycle defense]
}.freeze
def call
repo = ClashDeckGenerator2::Repos::CardsRepo.new
cards = unwrap(repo.all)
cards_by_name = {}
cards.each do |card|
cards_by_name[card.name] ||= card
end
result = {
"_meta" => {
"version" => 1,
"description" => "Card roles mapping for deck generation",
"generated_from_db" => true,
"cards_count" => cards_by_name.size,
"available_roles" => available_roles
},
"cards" => {}
}
cards_by_name.keys.sort.each do |card_name|
card = cards_by_name[card_name]
roles = roles_for(card)
result["cards"][card_name] = roles
end
FileUtils.mkdir_p(File.dirname(OUTPUT_PATH))
File.write(OUTPUT_PATH, JSON.pretty_generate(result))
puts "roles.json generated: #{OUTPUT_PATH}"
puts "Unique cards exported: #{cards_by_name.size}"
end
private
def unwrap(result)
if result.is_a?(Array) && result.first == :cards
result.last
else
result
end
end
def roles_for(card)
roles = []
roles.concat(BASE_ROLES_BY_TYPE.fetch(card.type, []))
base_name = base_card_name(card.name)
override_roles = ROLE_OVERRIDES[card.name] || ROLE_OVERRIDES[base_name] || []
roles.concat(override_roles)
roles = roles.map(&:to_s).map(&:strip).reject(&:empty?).uniq.sort
roles = fallback_roles(card) if roles.empty?
roles
end
def base_card_name(name)
name
.sub(/ Evolution\z/, "")
.sub(/ Hero\z/, "")
end
def fallback_roles(card)
case card.type
when "spell"
["spell"]
when "building"
%w[building defense]
when "troop"
["support"]
else
["support"]
end
end
def available_roles
%w[
anti_air
building
building_hate
control
cycle
defense
finisher
spell
splash
support
tank
win_condition
]
end
end
end
end
ClashDeckGenerator2::Scripts::BuildRolesJson.new.call