mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2026-07-22 07:37:00 +00:00
Update 6.8
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SecretBase
|
||||
attr_reader :outside_map_id #Id of the map where the secret base is
|
||||
attr_reader :inside_map_id #Id of the secret base's map itself
|
||||
|
||||
@@ -61,6 +61,9 @@ class SecretBaseItemInstance
|
||||
end
|
||||
|
||||
def interactable?(position = [0,0])
|
||||
return true#
|
||||
|
||||
#TODO
|
||||
return get_interactable_positions.include?(position)
|
||||
end
|
||||
|
||||
@@ -79,6 +82,7 @@ class SecretBaseItemInstance
|
||||
end
|
||||
|
||||
def calculate_occupied_volume_positions(main_event_position)
|
||||
return [] #TODO
|
||||
template = get_item_template
|
||||
|
||||
item_x, item_y = main_event_position
|
||||
|
||||
@@ -12,25 +12,21 @@ class SecretBaseItem
|
||||
attr_reader :pass_through # for carpets, etc.
|
||||
attr_reader :under_player # for carpets, etc.
|
||||
|
||||
attr_reader :height
|
||||
attr_reader :width
|
||||
#todo: instead of this, have a 2d array that represents the layout visually and shows which tiles are interactable and which aren't
|
||||
# ex:
|
||||
# [
|
||||
# [[x],[x],[x]],
|
||||
# [[i],[i],[i]
|
||||
# ]
|
||||
# -> 2 rows, only interactable from the bottom
|
||||
#
|
||||
attr_reader :collision_map #SecretBaseItemCollisionMap object
|
||||
|
||||
# Secret base object attributes
|
||||
attr_reader :deletable
|
||||
attr_reader :behavior # Lambda function that's defined when initializing the items. Some secret bases can have special effects when you interact with them (ex: a berry pot to grow berries, a bed, etc.)
|
||||
# -> This is the function that will be called when the player interacts with the item in the base.
|
||||
# Should just display flavor text for most basic items.
|
||||
attr_reader :uninteractable_positions #Positions at which the behavior won't trigger (relative to the center) ex: [[-1,0],[1,0]] in a 3x1 object will trigger in the center, but not on the sides
|
||||
attr_reader :trigger #Can define a different event trigger (Action Button by default)
|
||||
|
||||
def initialize(id:, graphics:, real_name:, price:, deletable: true, pass_through: false, under_player: false, behavior: nil, height:1, width:1, uninteractable_positions:[], trigger:TRIGGER_ACTION_BUTTON)
|
||||
attr_reader :uninteractable_positions # Positions at which the behavior won't trigger (relative to the center) ex: [[-1,0],[1,0]] in a 3x1 object will trigger in the center, but not on the sides
|
||||
attr_reader :trigger # Can define a different event trigger (Action Button by default)
|
||||
attr_reader :under_player # for carpets, etc.
|
||||
def initialize(id:, graphics:, real_name:, price:, deletable: true, pass_through: false, under_player: false,
|
||||
behavior: nil,
|
||||
trigger: TRIGGER_ACTION_BUTTON,
|
||||
collision_map: SecretBaseItemCollisionMap.new(:i))
|
||||
@id = id
|
||||
@graphics = graphics
|
||||
@real_name = real_name
|
||||
@@ -39,14 +35,16 @@ class SecretBaseItem
|
||||
@pass_through = pass_through
|
||||
@under_player = under_player
|
||||
|
||||
#Parts of the item that the player shouldn't be able to pass through
|
||||
@height = height
|
||||
@width = width
|
||||
# Parts of the item that the player shouldn't be able to pass through
|
||||
# @height = height
|
||||
# @width = width
|
||||
|
||||
# Default behavior just shows text if none provided
|
||||
@behavior = behavior
|
||||
@uninteractable_positions = uninteractable_positions
|
||||
@trigger = trigger
|
||||
|
||||
@collision_map = collision_map
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
# [:i]: Unpassable and Interactable
|
||||
# [:x]: Unpassable
|
||||
# [] : Passable
|
||||
|
||||
# ex:
|
||||
# [
|
||||
# [[:x],[:x],[:x]],
|
||||
# [[:i],[:i],[:i]
|
||||
# ]
|
||||
# -> 2 rows, only interactable from the bottom
|
||||
|
||||
|
||||
class SecretBaseItemCollisionMap
|
||||
attr_accessor :collision_map
|
||||
def initialize(collisions_array = [])
|
||||
@collision_map = collisions_array
|
||||
end
|
||||
|
||||
#todo
|
||||
def get_interactable_tiles
|
||||
|
||||
end
|
||||
#todo
|
||||
def get passable_tiles
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -71,7 +71,7 @@ class SecretBaseController
|
||||
rotateSecretBaseItem(item.getMainEvent)
|
||||
furnitureInteract(position,commandIndex)
|
||||
when :delete
|
||||
if pbConfirmMessage(_INTL("Put away the #{item.name}?"))
|
||||
if pbConfirmMessage(_INTL("Put away the {1}?",item.name))
|
||||
pbSEPlay("GUI storage put down", 80, 100)
|
||||
resetFurniture(item.instanceId)
|
||||
else
|
||||
|
||||
@@ -16,13 +16,14 @@ module SecretBasesData
|
||||
behavior: ->(event = nil) {
|
||||
#Behavior for PC is handled in SecretBasesController
|
||||
#useSecretBasePC
|
||||
}
|
||||
},
|
||||
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:MANNEQUIN,
|
||||
graphics: "Furniture/mannequin.png",
|
||||
real_name: _INTL("Mannequin"),
|
||||
real_name: "Mannequin",
|
||||
price: 500,
|
||||
behavior: ->(event = nil) {
|
||||
useSecretBaseMannequin
|
||||
@@ -33,25 +34,25 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:PLANT,
|
||||
graphics: "Furniture/plant.png",
|
||||
real_name: _INTL("Decorative Plant"),
|
||||
real_name: "Decorative Plant",
|
||||
price: 500
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:RED_CHAIR,
|
||||
graphics: "Furniture/red_chair.png",
|
||||
real_name: _INTL("Red Chair"),
|
||||
real_name: "Red Chair",
|
||||
price: 350,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
}
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:FANCY_CARPET,
|
||||
graphics: "Carpets/fancy_carpet.png",
|
||||
real_name: _INTL("Fancy Carpet"),
|
||||
real_name: "Fancy Carpet",
|
||||
price: 5000,
|
||||
pass_through: true,
|
||||
under_player: true
|
||||
@@ -60,7 +61,7 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:FANCY_CARPET_CONNECT,
|
||||
graphics: "Carpets/fancy_carpet_connect.png",
|
||||
real_name: _INTL("Fancy Carpet (Connection)"),
|
||||
real_name: "Fancy Carpet (Connection)",
|
||||
price: 100,
|
||||
pass_through: true,
|
||||
under_player: true
|
||||
@@ -69,7 +70,7 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:BOULDER,
|
||||
graphics: "Furniture/boulder.png",
|
||||
real_name: _INTL("Boulder"),
|
||||
real_name: "Boulder",
|
||||
price: 600,
|
||||
under_player: false,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
@@ -85,63 +86,50 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:SKITTY_CHAIR_3x3,
|
||||
graphics: "skittySet/deco_3x3chair_skitty.png",
|
||||
real_name: _INTL("Skitty Armchair"),
|
||||
real_name: "Skitty Armchair",
|
||||
price: 1000,
|
||||
height: 1,
|
||||
width: 3,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
},
|
||||
uninteractable_positions: [[-1,0],[1,0]]
|
||||
collision_map: SecretBaseItemCollisionMap.new(
|
||||
[[:x, :i, :x]]
|
||||
),
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:SKITTY_CHAIR_3x3,
|
||||
graphics: "skittySet/deco_3x3chair_skitty.png",
|
||||
real_name: _INTL("Skitty Armchair"),
|
||||
price: 1000,
|
||||
height: 1,
|
||||
width: 3,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
},
|
||||
uninteractable_positions: [[-1,0],[1,0]]
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:SKITTY_COUCH_3x4,
|
||||
graphics: "skittySet/deco_3x4chair_skitty.png",
|
||||
real_name: _INTL("Skitty Couch"),
|
||||
real_name: "Skitty Couch",
|
||||
price: 2000,
|
||||
height: 1,
|
||||
width: 4,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
},
|
||||
uninteractable_positions: [[-2,0],[2,0]]
|
||||
collision_map: SecretBaseItemCollisionMap.new(
|
||||
[:x, :i, :x]
|
||||
),
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:SKITTY_COUCH_3x5,
|
||||
graphics: "skittySet/deco_3x5couch_skitty.png",
|
||||
real_name: _INTL("Wide Skitty Couch"),
|
||||
real_name: "Wide Skitty Couch",
|
||||
price: 2000,
|
||||
height: 1,
|
||||
width: 5,
|
||||
#height: 1,
|
||||
#width: 5,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
},
|
||||
uninteractable_positions: [[-2,0],[2,0]]
|
||||
#uninteractable_positions: [[-2,0],[2,0]]
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:SKITTY_RUG_3x3,
|
||||
graphics: "skittySet/deco_3x3rug_skitty.png",
|
||||
real_name: _INTL("Large Skitty Rug"),
|
||||
real_name: "Large Skitty Rug",
|
||||
price: 3000,
|
||||
pass_through: true,
|
||||
under_player: true
|
||||
@@ -151,62 +139,62 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:ROCK_CHAIR_1x1,
|
||||
graphics: "rockSet/deco_1x1chair_rock.png",
|
||||
real_name: _INTL("Rocky Stool"),
|
||||
real_name: "Rocky Stool",
|
||||
price: 350,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
}
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK,
|
||||
graphics: "rockSet/deco_1x1deco_rock.png",
|
||||
real_name: _INTL("Rock"),
|
||||
real_name: "Rock",
|
||||
price: 50
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK_STATUE,
|
||||
graphics: "rockSet/deco_1x1statue_rock.png",
|
||||
real_name: _INTL("Rocky Statue"),
|
||||
real_name: "Rocky Statue",
|
||||
price: 50
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK_WALL,
|
||||
graphics: "rockSet/deco_1x2wall_rock.png",
|
||||
real_name: _INTL("Rocky Wall"),
|
||||
real_name: "Rocky Wall",
|
||||
price: 50
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK_TABLE_2x3,
|
||||
graphics: "rockSet/deco_2x3table_rock.png",
|
||||
real_name: _INTL("Large Rocky Table"),
|
||||
width:3,
|
||||
height:2,
|
||||
real_name: "Large Rocky Table",
|
||||
#width:3,
|
||||
#height:2,
|
||||
price: 5000
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK_CHAIR_3x3,
|
||||
graphics: "rockSet/deco_3x3chair_rock.png",
|
||||
real_name: _INTL("Rocky Armchair"),
|
||||
real_name: "Rocky Armchair",
|
||||
price: 1000,
|
||||
height: 1,
|
||||
width: 3,
|
||||
#height: 1,
|
||||
#width: 3,
|
||||
trigger: TRIGGER_PLAYER_TOUCH,
|
||||
behavior: ->(itemInstance = nil) {
|
||||
sit_on_chair(itemInstance)
|
||||
sit_on_chair_item(itemInstance)
|
||||
},
|
||||
uninteractable_positions: [[-1,0],[1,0]]
|
||||
#uninteractable_positions: [[-1,0],[1,0]]
|
||||
)
|
||||
|
||||
register_base_item(
|
||||
:ROCK_RUG_1x1,
|
||||
graphics: "rockSet/deco_1x1rug_rock.png",
|
||||
real_name: _INTL("Small Rocky Rug"),
|
||||
real_name: "Small Rocky Rug",
|
||||
price: 500,
|
||||
pass_through: true,
|
||||
under_player: true
|
||||
@@ -215,7 +203,7 @@ module SecretBasesData
|
||||
register_base_item(
|
||||
:ROCK_RUG_3x3,
|
||||
graphics: "rockSet/deco_3x3rug_rock.png",
|
||||
real_name: _INTL("Large Rocky Rug"),
|
||||
real_name: "Large Rocky Rug",
|
||||
price: 2000,
|
||||
pass_through: true,
|
||||
under_player: true
|
||||
|
||||
@@ -98,7 +98,7 @@ def input_friend_code()
|
||||
clipboard_text = clipboard_text.slice(0, 10)
|
||||
|
||||
if numeric_string?(clipboard_text) && clipboard_text.length == 10 && !check_copied_own_trainerId(clipboard_text)
|
||||
message = _INTL("Is this your friend's Trainer ID? \\C[1]#{clipboard_text}\\C[0]")
|
||||
message = _INTL("Is this your friend's Trainer ID? \\C[1]{1}\\C[0]",clipboard_text)
|
||||
commands << cmd_refresh
|
||||
commands << cmd_confirm
|
||||
commands << cmd_manual
|
||||
@@ -171,10 +171,12 @@ def pushEvent(itemInstance)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def sit_on_chair(itemInstance)
|
||||
def sit_on_chair_item(itemInstance)
|
||||
event=itemInstance.getMainEvent
|
||||
sit_on_chair_event(event)
|
||||
end
|
||||
|
||||
def sit_on_chair_event(event)
|
||||
pbSEPlay("jump", 80, 100)
|
||||
$game_player.always_on_top=true
|
||||
$game_player.through =true
|
||||
@@ -197,4 +199,5 @@ def sit_on_chair(itemInstance)
|
||||
end
|
||||
end
|
||||
end
|
||||
# PC behavior set directly in SecretBaseController
|
||||
|
||||
# PC behavior set directly in SecretBaseController
|
||||
|
||||
@@ -7,6 +7,9 @@ class SecretBaseLoader
|
||||
end
|
||||
|
||||
def load_visitor_bases
|
||||
return #DISABLED FOR NOW
|
||||
|
||||
#todo
|
||||
visitor_bases = @importer.load_bases(SecretBaseImporter::VISITOR_BASES_FILE)
|
||||
friend_bases = @importer.load_bases(SecretBaseImporter::FRIEND_BASES_FILE)
|
||||
all_bases = visitor_bases + friend_bases
|
||||
|
||||
+20
-13
@@ -94,6 +94,14 @@ class SecretBaseExporter
|
||||
item: pokemon.item ? pokemon.item.id.to_s : "",
|
||||
ability: pokemon.ability ? pokemon.ability.id.to_s : "",
|
||||
level: pokemon.level || 1,
|
||||
owner: pokemon.owner,
|
||||
ball: pokemon.poke_ball,
|
||||
|
||||
hat: pokemon.hat,
|
||||
hat_x: pokemon.hat_x,
|
||||
hat_y: pokemon.hat_y,
|
||||
steps_to_hatch: pokemon.steps_to_hatch,
|
||||
alt_sprite: pokemon.pif_sprite&.alt_letter,
|
||||
evs: {
|
||||
hp: pokemon.ev[:HP] || 0,
|
||||
atk: pokemon.ev[:ATTACK] || 0,
|
||||
@@ -116,18 +124,17 @@ class SecretBaseExporter
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Recursively replace nils with empty strings (or zero if numeric leaf)
|
||||
def sanitize_string(obj)
|
||||
case obj
|
||||
when Hash
|
||||
obj.transform_values { |v| sanitize_string(v) }
|
||||
when Array
|
||||
obj.map { |v| sanitize_string(v) }
|
||||
when NilClass
|
||||
""
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
# Recursively replace nils with empty strings (or zero if numeric leaf)
|
||||
def sanitize_string(obj)
|
||||
case obj
|
||||
when Hash
|
||||
obj.transform_values { |v| sanitize_string(v) }
|
||||
when Array
|
||||
obj.map { |v| sanitize_string(v) }
|
||||
when NilClass
|
||||
""
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
+59
-41
@@ -40,7 +40,6 @@ class SecretBaseImporter
|
||||
trainer_data: import_trainer_from_json(trainer_data),
|
||||
base_message: base_data[:base_message],
|
||||
)
|
||||
echoln base.layout
|
||||
visitor_bases << base
|
||||
#base.dump_info
|
||||
rescue Exception => e
|
||||
@@ -64,11 +63,9 @@ class SecretBaseImporter
|
||||
direction = item_data[:direction]
|
||||
item_instance = SecretBaseItemInstance.new(id,position,direction)
|
||||
|
||||
echoln item_instance.direction
|
||||
items << item_instance
|
||||
end
|
||||
|
||||
echoln items
|
||||
layout.items = items
|
||||
return layout
|
||||
end
|
||||
@@ -82,44 +79,7 @@ class SecretBaseImporter
|
||||
app[:hat2], app[:hat2_color]
|
||||
)
|
||||
|
||||
team = trainer_json[:team].map do |poke_json|
|
||||
pokemon = Pokemon.new(poke_json[:species], poke_json[:level])
|
||||
pokemon.name = poke_json[:name]
|
||||
pokemon.item = poke_json[:item]
|
||||
pokemon.ability = poke_json[:ability]
|
||||
pokemon.nature = poke_json[:nature]
|
||||
pokemon.moves = poke_json[:moves]
|
||||
|
||||
if poke_json[:ivs]
|
||||
poke_json[:ivs].each do |stat, value|
|
||||
case stat.to_s.downcase
|
||||
when "hp" then pokemon.iv[:HP] = value
|
||||
when "atk" then pokemon.iv[:ATTACK] = value
|
||||
when "def" then pokemon.iv[:DEFENSE] = value
|
||||
when "spe" then pokemon.iv[:SPEED] = value
|
||||
when "spa" then pokemon.iv[:SPECIAL_ATTACK] = value
|
||||
when "spd" then pokemon.iv[:SPECIAL_DEFENSE] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if poke_json[:evs]
|
||||
poke_json[:evs].each do |stat, value|
|
||||
case stat.to_s.downcase
|
||||
when "hp" then pokemon.ev[:HP] = value
|
||||
when "atk" then pokemon.ev[:ATTACK] = value
|
||||
when "def" then pokemon.ev[:DEFENSE] = value
|
||||
when "spe" then pokemon.ev[:SPEED] = value
|
||||
when "spa" then pokemon.ev[:SPECIAL_ATTACK] = value
|
||||
when "spd" then pokemon.ev[:SPECIAL_DEFENSE] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pokemon.calc_stats
|
||||
pokemon
|
||||
end
|
||||
|
||||
team = trainer_json[:team].map { |poke_json| import_pokemon_from_json(poke_json) }
|
||||
SecretBaseTrainer.new(
|
||||
trainer_json[:name],
|
||||
trainer_json[:nb_badges],
|
||||
@@ -129,6 +89,64 @@ class SecretBaseImporter
|
||||
)
|
||||
end
|
||||
|
||||
def import_pokemon_from_json(poke_json)
|
||||
pokemon = Pokemon.new(poke_json[:species], poke_json[:level])
|
||||
pokemon.name = poke_json[:name]
|
||||
pokemon.item = poke_json[:item]
|
||||
pokemon.ability = poke_json[:ability]
|
||||
pokemon.nature = poke_json[:nature]
|
||||
pokemon.ot = poke_json[:owner] if poke_json[:owner]
|
||||
pokemon.hat = poke_json[:hat]
|
||||
pokemon.hat_x = poke_json[:hat_x]
|
||||
pokemon.hat_y = poke_json[:hat_y]
|
||||
pokemon.steps_to_hatch = poke_json[:steps_to_hatch] || 0
|
||||
pokemon.poke_ball = poke_json[:ball]
|
||||
if poke_json[:alt_sprite] && poke_json[:alt_sprite] != ""
|
||||
if pokemon.isFusion?
|
||||
pokemon.pif_sprite = PIFSprite.new(:CUSTOM, pokemon.get_head_num,pokemon.get_body_num,poke_json[:alt_sprite])
|
||||
else
|
||||
pokemon.pif_sprite = PIFSprite.new(:BASE, pokemon.id_number,nil,poke_json[:alt_sprite])
|
||||
end
|
||||
end
|
||||
moves = poke_json[:moves]
|
||||
pokemon_moves = []
|
||||
moves.each do |move_id|
|
||||
move = Pokemon::Move.new(move_id)
|
||||
pokemon_moves << Pokemon::Move.new(move_id)
|
||||
pokemon.add_learned_move(move)
|
||||
end
|
||||
pokemon.moves = pokemon_moves
|
||||
|
||||
if poke_json[:ivs]
|
||||
poke_json[:ivs].each do |stat, value|
|
||||
case stat.to_s.downcase
|
||||
when "hp" then pokemon.iv[:HP] = value
|
||||
when "atk" then pokemon.iv[:ATTACK] = value
|
||||
when "def" then pokemon.iv[:DEFENSE] = value
|
||||
when "spe" then pokemon.iv[:SPEED] = value
|
||||
when "spa" then pokemon.iv[:SPECIAL_ATTACK] = value
|
||||
when "spd" then pokemon.iv[:SPECIAL_DEFENSE] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if poke_json[:evs]
|
||||
poke_json[:evs].each do |stat, value|
|
||||
case stat.to_s.downcase
|
||||
when "hp" then pokemon.ev[:HP] = value
|
||||
when "atk" then pokemon.ev[:ATTACK] = value
|
||||
when "def" then pokemon.ev[:DEFENSE] = value
|
||||
when "spe" then pokemon.ev[:SPEED] = value
|
||||
when "spa" then pokemon.ev[:SPECIAL_ATTACK] = value
|
||||
when "spd" then pokemon.ev[:SPECIAL_DEFENSE] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pokemon.calc_stats
|
||||
pokemon
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Recursively converts "" → nil, but keeps keys as symbols
|
||||
|
||||
Reference in New Issue
Block a user