update 6.7

This commit is contained in:
chardub
2025-09-28 15:53:01 -04:00
parent ef5e023ae0
commit 318ff90d8d
696 changed files with 111759 additions and 198230 deletions

View File

@@ -0,0 +1,85 @@
# 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
attr_reader :location_name #Name of the Route where the secret base is in plain text
attr_reader :outside_entrance_position #Fly coordinates
attr_reader :inside_entrance_position #Where the player gets warped
attr_reader :biome_type #:CAVE, :TREE,
attr_reader :base_layout_type
attr_accessor :base_name
attr_accessor :base_message
attr_accessor :layout
attr_accessor :is_visitor
def initialize(biome:,outside_map_id:,outside_entrance_position:, inside_map_id:, base_layout_type:, is_visitor:, layout: nil, visitor_message:nil)
@biome_type = biome
@outside_map_id = outside_map_id
@inside_map_id = inside_map_id
@outside_entrance_position = outside_entrance_position
@base_layout_type = base_layout_type.to_sym
@inside_entrance_position = SecretBasesData::SECRET_BASE_ENTRANCES[@base_layout_type][:position]
@base_name=initializeBaseName
@base_message=visitor_message
initialize_base_message unless @base_message #Message that people see when visiting the secret base
@is_visitor=is_visitor
@layout = layout
initializeLayout unless @layout
end
def initializeBaseName
return _INTL("{1}'s secret base",$Trainer.name)
end
def initialize_base_message
return _INTL("Welcome to my secret base!")
end
def initializeLayout
@layout = SecretBaseLayout.new(@base_layout_type,!@is_visitor)
entrance_x = @inside_entrance_position[0]
entrance_y = @inside_entrance_position[1]
@layout.add_item(:PC,[entrance_x,entrance_y-3])
end
def load_furniture
@layout.items.each do |item_instance|
next unless item_instance.is_a?(SecretBaseItemInstance)
next unless SecretBasesData::SECRET_BASE_ITEMS[item_instance.itemId]
item_instance.direction = DIRECTION_DOWN
template = item_instance.itemTemplate
echoln template
item_instance.create_events
# event = $PokemonTemp.createTempEvent(TEMPLATE_EVENT_SECRET_BASE_FURNITURE, $game_map.map_id, item_instance.position, DIRECTION_DOWN)
# event.character_name = "player/SecretBases/#{template.graphics}"
# event.through = template.pass_through
# event.under_player = template.under_player
# event.direction = item_instance.direction
if item_instance.itemTemplate.id == :MANNEQUIN && @is_visitor
setEventAppearance(item_instance.main_event.id, @trainer_appearance) if @trainer_appearance
end
# item_instance.setMainEventId(event.id)
item_instance.refresh_events
#event.refresh
end
end
end

View File

@@ -0,0 +1,172 @@
# frozen_string_literal: true
class SecretBaseItemInstance
attr_reader :itemId
attr_reader :instanceId
attr_accessor :position
attr_accessor :direction
attr_accessor :itemTemplate
attr_accessor :main_event_id
attr_reader :disposed
attr_reader :main_event
RANDOM_ID_LENGTH = 6
def initialize(itemId, position = [0, 0], direction = DIRECTION_DOWN)
@itemId = itemId
@instanceId = generate_new_instance_id()
@direction = direction
@position = position
@main_event = nil # Objects that are wider or taller than 1 tile work by duplicating the object, but making only the middle instance visible. This contains the id of the middle instance
end
def create_events()
template = get_item_template
@volume_events = []
main_event = $PokemonTemp.createTempEvent(TEMPLATE_EVENT_SECRET_BASE_FURNITURE, $game_map.map_id, @position, @direction)
main_event.character_name = "player/SecretBases/#{template.graphics}"
main_event.through = template.pass_through
main_event.under_player = template.under_player
main_event.trigger = template.trigger
@main_event = main_event
occupied_positions = calculate_occupied_volume_positions(@position)
occupied_positions.each do |position|
event = $PokemonTemp.createTempEvent(TEMPLATE_EVENT_SECRET_BASE_FURNITURE, $game_map.map_id, position)
event.character_name = "player/SecretBases/empty" # Game will consider it passable if we don't put anything here
event.through = template.pass_through
event.trigger = template.trigger
@volume_events << event
end
end
# Use this - can't save it into the object because of proc
def get_item_template
return SecretBasesData::SECRET_BASE_ITEMS[@itemId]
end
# fake accessor
def itemTemplate
return get_item_template
end
def get_occupied_positions()
occupied_positions = []
occupied_positions << [@main_event.x, @main_event.y]
@volume_events.each do |event|
occupied_positions << [event.x, event.y]
end
return occupied_positions
end
def interactable?(position = [0,0])
return get_interactable_positions.include?(position)
end
def get_interactable_positions()
all_positions = get_occupied_positions
uninteractable_positions = get_item_template.uninteractable_positions
main_x, main_y = @main_event.x, @main_event.y
uninteractable_absolute_positions = uninteractable_positions.map do |dx, dy|
[main_x + dx, main_y + dy]
end
interactable_positions = all_positions.reject do |pos|
uninteractable_absolute_positions.include?(pos)
end
return interactable_positions
end
def calculate_occupied_volume_positions(main_event_position)
template = get_item_template
item_x, item_y = main_event_position
item_height = template.height || 1
item_width = template.width || 1
direction = @direction
# Flip width/height if rotated sideways
if direction == DIRECTION_LEFT || direction == DIRECTION_RIGHT
item_width, item_height = item_height, item_width
end
half_width = (item_width - 1) / 2
half_height = (item_height - 1) / 2
occupied_positions = []
x_range = (item_x - half_width..item_x + half_width)
y_range = (item_y - half_height..item_y + half_height)
x_range.each do |x|
y_range.each do |y|
is_main_event = (x == item_x && y == item_y)
next if is_main_event
occupied_positions << [x, y]
end
end
return occupied_positions
end
def refresh_events
@main_event.refresh
@volume_events.each do |event|
event.refresh
end
end
def name
return itemTemplate&.real_name
end
def getGraphics()
return itemTemplate.graphics
end
def height
return itemTemplate.height
end
def width
return itemTemplate.width
end
def generate_new_instance_id()
randomId = rand(36 ** RANDOM_ID_LENGTH).to_s(36)
return "#{@itemId}_#{randomId}"
end
def getMainEvent()
return @main_event
end
def disposed?
return @disposed
end
def dispose
@itemId = nil
@position = nil
@direction = nil
@main_event_id = nil
@itemTemplate = nil
@disposed = true
@main_event.erase
@main_event = nil
@volume_events.each do |event|
event.erase
end
@volume_events = nil
end
def connect_to_other_instance(instance_id)
@volume_events << instance_id
end
def set_main_instance(instance_id)
@main_event = instance_id
end
end

View File

@@ -0,0 +1,52 @@
# frozen_string_literal: true
# wrapper for secret base items
class SecretBaseItem
attr_reader :id # Symbol. Used for manipulating in other classes (trainer.unlockedBaseItems is an array of these, etc.)
attr_reader :graphics # File path to the item's graphics
attr_reader :real_name # Name displayed in-game
attr_reader :price
# Event attributes
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
# 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)
@id = id
@graphics = graphics
@real_name = real_name
@price = price
@deletable = deletable
@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
# Default behavior just shows text if none provided
@behavior = behavior
@uninteractable_positions = uninteractable_positions
@trigger = trigger
end
end

View File

@@ -0,0 +1,81 @@
class SecretBaseLayout
attr_accessor :items #SecretBaseItemInstance
attr_accessor :tileset #todo Reuse the same layouts map for all bases and change the tileset depending on the type
attr_accessor :biome_type #:TREES, :CLIFF, :CLIFF_BEACH, :BUSH, etc. -> Determines which tiles are used in the base
attr_accessor :is_player_base
def initialize(layout_biome,is_player_base=false)
@biome_type = layout_biome
@items = []
@is_player_base = is_player_base
end
def add_item(itemId, position = [0, 0])
new_item = SecretBaseItemInstance.new(itemId, position)
@items << new_item
return new_item.instanceId
end
def get_item_at_position(position = [0,0])
@items.each do |item|
return item if item.get_occupied_positions.include?(position)
end
return nil
end
def get_item_by_id(instanceId)
@items.each do |item|
return item if item.instanceId == instanceId
end
return nil
end
def remove_item_by_instance(instanceId)
@items.each do |item|
if item.instanceId == instanceId
@items.delete(item)
end
end
return nil
end
def remove_item_at_position(position = [0, 0])
@items.each do |item|
if item.position == position
@items.delete(item)
end
end
end
# returns a list of ids of the items that are currently in the base's layout
def list_items_instances()
list = []
@items.each do |item|
list << item.instanceId
end
end
def get_all_occupied_positions()
occupied_positions = []
@items.each do |item|
occupied_positions << get_occupied_positions_for_item(item)
end
return occupied_positions
end
def check_position_available_for_item(itemInstance,position)
#placed_item_positions = get_all_occupied_positions
item_occupied_positions = itemInstance.calculate_occupied_volume_positions(position)
item_occupied_positions.each do |position|
x, y = position
#return false if placed_item_positions.include?(position)
return false if !$game_map.passableStrict?(x, y, DIRECTION_ALL)
end
return true
end
end

View File

@@ -0,0 +1,15 @@
class SecretBaseTrainer
attr_accessor :name
attr_accessor :nb_badges
attr_accessor :game_mode
attr_accessor :appearance #TrainerAppearance
attr_accessor :team #Array of Pokemon
def initialize(name, nb_badges, game_mode, appearance, team)
@name = name
@nb_badges = nb_badges
@game_mode = game_mode
@appearance = appearance
@team = team
end
end

View File

@@ -0,0 +1,52 @@
class VisitorSecretBase < SecretBase
attr_reader :trainer_name, :trainer_badges, :trainer_game_mode
attr_reader :trainer_appearance, :trainer_team
def initialize(biome:, outside_map_id:, outside_entrance_position:, inside_map_id:, layout:, base_layout_type:, base_message:, trainer_data:)
super(biome: biome,
outside_map_id: outside_map_id,
outside_entrance_position: outside_entrance_position,
inside_map_id: inside_map_id,
layout: layout,
base_layout_type: base_layout_type,
visitor_message: base_message,
is_visitor: true,)
@trainer_name = trainer_data.name
@trainer_badges = trainer_data.nb_badges || 0
@trainer_game_mode = trainer_data.game_mode || 0
@trainer_appearance = trainer_data.appearance
@trainer_team = trainer_data.team
end
def dump_info
echoln "=== Visitor Secret Base ==="
echoln "Biome: #{@biome_type}"
echoln "Outside Map ID: #{@outside_map_id}"
echoln "Inside Map ID: #{@inside_map_id}"
echoln "Outside Entrance Position: #{@outside_entrance_position.inspect}"
echoln "Inside Entrance Position: #{@inside_entrance_position.inspect}"
echoln "Layout Type: #{@base_layout_type}"
echoln "Base Name: #{@base_name}"
echoln "Base Message: #{@base_message}"
echoln "Visitor?: #{@is_visitor}"
echoln "--- Trainer Info ---"
echoln "Name: #{@trainer_name}"
echoln "Badges: #{@trainer_badges}"
echoln "Game Mode: #{@trainer_game_mode}"
echoln "Appearance: #{@trainer_appearance.inspect}"
echoln "--- Trainer Team ---"
if @trainer_team && !@trainer_team.empty?
@trainer_team.each_with_index do |pokemon, i|
echoln " #{i + 1}. #{pokemon.name} (#{pokemon.species}, Lv#{pokemon.level})"
end
else
echoln " (No Pokémon)"
end
echoln "============================="
end
end