오픈 소스 모험: 에피소드 56: BATTLETECH 무기 데이터 내보내기 확장

23705 단어 rubygamedev
앱에 몇 가지 기능을 추가하고 싶었지만 이를 위해서는 데이터가 조금 더 필요합니다. 데이터 내보내기에 필요한 변경 사항은 다음과 같습니다.
  • Flamers 및 Infernos 필터링
  • name 필드 (like SRM6+ (+2 Dmg) )를 baseName (like SRM6+ ) 및 bonus ( +2 Dmg )
  • 로 분할
  • 추가됨 category
  • 추가됨 baseStabDamage

  • 앞으로 몇 가지 더 변경해야 할 수도 있습니다. 지금은 그렇게 할 것입니다.

    한 가지 유의할 점은 bonus 필드는 순전히 시각적이며 모든 보너스 정보가 이미 데이터에 포함되어 있다는 것입니다.

    생성된 JSON 예시




    {
      "baseName": "Gauss Rifle+",
      "bonus": "-2 Tons",
      "tonnage": 13,
      "heat": 5,
      "shots": 1,
      "baseDamage": 75,
      "ammoTonnagePerShot": 0.125,
      "minRange": 180,
      "maxRange": 660,
      "indirectFire": false,
      "baseStabDamage": 40,
      "category": "Ballistic"
    }
    


    스크립트



    이전 버전의 변경 사항은 매우 사소합니다.

    #!/usr/bin/env ruby
    
    require "json"
    require "memoist"
    require "pathname"
    require "pry"
    
    class String
      def camelize
        gsub(/_([a-z])/) { $1.upcase }
      end
    end
    
    class AmmoBox
      extend Memoist
      attr_reader :data, :path
    
      def initialize(path)
        @path = path
        @data = JSON.parse(path.read)
      end
    
      memoize def id
        @data["AmmoID"].sub(/\AAmmunition_/, "")
      end
    
      def tonnage
        @data["Tonnage"]
      end
    
      def capacity
        @data["Capacity"]
      end
    end
    
    class Weapon
      extend Memoist
      attr_reader :game, :data, :path
    
      def initialize(game, path)
        @game = game
        @path = path
        @data = JSON.parse(path.read)
      end
    
      memoize def name
        if has_bonus?
          "#{base_name} (#{bonus})"
        else
          base_name
        end
      end
    
      memoize def has_bonus?
        [bonus_a, bonus_b].any?
      end
    
      memoize def bonus
        [bonus_a, bonus_b].compact.join(", ")
      end
    
      memoize def base_name
        [
          data["Description"]["Name"],
          data["Description"]["UIName"],
        ].compact.last.gsub(" +", "+")
      end
    
      memoize def bonus_a
        data["BonusValueA"] == "" ? nil : data["BonusValueA"].gsub(/[a-z]\K\./, "").gsub(/[\+\-]\K /, "")
      end
    
      memoize def bonus_b
        data["BonusValueB"] == "" ? nil : data["BonusValueB"].gsub(/[a-z]\K\./, "").gsub(/[\+\-]\K /, "")
      end
    
      def category
        @data["Category"]
      end
    
      def subtype
        @data["WeaponSubType"]
      end
    
      def tonnage
        @data["Tonnage"]
      end
    
      def damage
        shots * base_damage
      end
    
      def base_damage
        @data["Damage"]
      end
    
      def shots
        @data["ShotsWhenFired"]
      end
    
      def heat
        @data["HeatGenerated"]
      end
    
      def ammo_per_shot
        @data["ShotsWhenFired"] * data["ProjectilesPerShot"]
      end
    
      def heat_tonnage
        heat / 3.0
      end
    
      # 10 rounds of shootnig at target
      def ammo_tonnage_per_shot
        @game.ammo_weights.fetch(ammo_category) * ammo_per_shot
      end
    
      def total_tonnage
        tonnage + heat_tonnage + ammo_tonnage
      end
    
      def ammo_category
        @data["ammoCategoryID"] || @data["AmmoCategory"]
      end
    
      def purchasable?
        @data["Description"]["Purchasable"]
      end
    
      def weapon_effect
        @data["WeaponEffectID"]
      end
    
      def ignore?
        [
          category == "Melee",
          name == "AI Laser",
          base_name =~ /Flamer/,
          base_name =~ /Infernos/,
          subtype == "TAG",
          subtype == "Narc",
          subtype =~ /\ACOIL/,
          weapon_effect == "WeaponEffect-Artillery_MechMortar",
          weapon_effect == "WeaponEffect-Artillery_Thumper",
        ].any?
      end
    
      def min_range
        @data["MinRange"]
      end
    
      def max_range
        @data["MaxRange"]
      end
    
      def indirect_fire
        @data["IndirectFireCapable"]
      end
    
      def base_stab_damage
        @data["Instability"]
      end
    
      def as_json
        {
          base_name:,
          bonus:,
          tonnage:,
          heat:,
          shots:,
          base_damage:,
          ammo_tonnage_per_shot:,
          min_range:,
          max_range:,
          indirect_fire:,
          base_stab_damage:,
          category:,
        }.transform_keys(&:to_s).transform_keys(&:camelize)
      end
    end
    
    class BattleTechGame
      extend Memoist
    
      def initialize(game_root, *dlc_roots)
        @game_root = Pathname(game_root)
        @dlc_roots = dlc_roots.map{|path| Pathname(path)}
      end
    
      memoize def data_root
        @game_root + "BattleTech_Data/StreamingAssets/data"
      end
    
      def roots
        [data_root, *@dlc_roots]
      end
    
      memoize def weapon_files
        roots
          .flat_map{|root| root.glob("weapon/*.json")}
          .select{|n| n.basename.to_s != "WeaponTemplate.json"}
      end
    
      memoize def weapons
        weapon_files.map{|path| Weapon.new(self, path)}
      end
    
      memoize def ammobox_files
        roots
          .flat_map{|root| root.glob("ammunitionBox/*.json")}
          .select{|n| n.basename.to_s != "AmmoBoxTemplate.json"}
      end
    
      memoize def ammoboxes
        ammobox_files.map{|path| AmmoBox.new(path)}
      end
    
      memoize def ammo_weights
        # MG box occurs twice, but with same ratio
        ammoboxes.to_h{|a| [a.id, a.tonnage.to_f/a.capacity]}.merge("NotSet" => 0.0)
      end
    
      def inspect
        "BattechGame"
      end
    
      def as_json
        weapons
          .reject(&:ignore?)
          .map(&:as_json)
      end
    end
    
    game = BattleTechGame.new(*ARGV)
    puts JSON.pretty_generate(game.as_json)
    


    지금까지의 이야기



    All the code is on GitHub .

    다음에 온다



    다음 에피소드에서는 이러한 변경 사항을 사용하여 앱에 추가 기능을 추가하겠습니다.

    좋은 웹페이지 즐겨찾기