Freeform RPG Add-On PackVersion: 0.9IntroductionThis script is a compilation of various features found in freeform RPGs. Basically, it has encounter ranges, alignment, and fame.
Features- Encounter Range. This feature allows you to give each monster in the database a level, and then random encounters become dependent on these levels, based upon a range that you set. Basically, the hero will always be fighting within his level range. Thus, if your party is level 14 (calculated by summing the levels of each individual party member), they will only be fighting monster troops between level 9 and 24 (by default. The range can be set by you). For further details, see inside the script.
- Alignment. A.K.A a good-evil bar controlled by an in-game variable which you set. You can access the bar by looking in the Status Window
- Enemy Alignment. This is an additional feature of the Encounter Range Script. You can set the alignment of all the enemies. The system will average the alignment of a troop of enemies, and if it is positive, then they won't attack your party unless it is below a certain value (the value is different for each troop alignment. So an enemy troop with alignment of 10 won't attack your party as long as your alignment is above 0. An enemy troop of alignment 5 will only attack your party if your alignment is less than -30, etc...)
- Advanced Fame. What this is is it is a fame system, but one that is separated into regions. Thus, actions you do in country A will make you famous in country A, but in country B that same action won't make you as famous. The script will allow you to choose how much fame translates between regions. See script for details.
ScreenshotsN/A for the most part. I will show off the gradient bars though:
DemoSee attachment for demo
ScriptPlace this script right above main
#===============================================================================
# Freeform Game Starter's Pack v. 0.9
# Author: Modern Algebra
#-------------------------------------------------------------------------------
# Instructions
# Set up each map with all types of enemies you want to appear in that map at
# any point in the game. Read the comments in the EDITABLE AREA for instructions
# on setting up monster levels.
#===============================================================================
class Scene_Map
#============================================================================
# Determines if any battles in the event listing are within the party's level
# range
#============================================================================
def determine_encounter_range
#==========================================================================
# CONFIGURATION:
#--------------------------------------------------------------------------
# Each number in @enemy_level is the level of the corresponding monster
# in the database. Thus, right now, Monster 1 is Level 1, Monster 2 is
# Level 2, etc... If you change the array, to this:
# @enemy_level = [7,6,12,8...] then Monster 1 is level 7, Monster 2 is level
# 6, Monster 3 is Level 12, Monster 4 is Level 8, etc...
# For more than 50 monsters, just continue the array by adding ,(level of
# next monster)
#
# The level range is determined by $min_fight_level and $max_fight level. Right
# now, min is 5 and max is 10, so the party can only fight troops if the enemy
# troop level is greater than or equal to 5 levels below the party, and less than
# or equal to 10 levels above the hero party. Thus, if the party level (calculated
# by summing up the levels of each party member) is 35, then under these max
# and min values, they can only fight monster whose level is between 30 and 45.
# (and troop level is calculated by summing up the levels of each enemy in the
# troop). The min and max levels can be changed at any time to make an area
# harder or easier with a simple call script:
#
# $min_fight_level = ??? (whatever you want new min to be)
# $max_fight_level = ??? (whatever you want new max to be)
#
# To disable this feature, just change @encounter_disabled=false to @encounter_disabled=true
#---------------------------------------------------------------------------
@enemy_level = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,
44,45,46,47,48,49,50]
$min_fight_level = 5
$max_fight_level = 10
#--------------------------------------------------------------------------
# Each number in @enemy_alignment is the alignment of the corresponding monster
# in the database. 10 is the most good, and -10 is the most evil. Thus,
# right now, Monster 1 is mildly good, Monster 2 is a little more good, Monster
# 3 is more evil than either Monster 1 or Monster 2 are good. While you see
# that I have numbers going up to 50, that is meant only as a reference for
# you. You must set the numbers up so that none of those numbers exceed 10
# or are less than -10, as that could result in a bug. In any case, this
# works in a similar way to @enemy_level., so you can look up there if you
# still have trouble understanding.
#
# $alignment_variable. Just set this value to the in-game variable that you
# want to control alignment with. In other words. If you set it to 3, as it
# is now, then using the event command Control Variable: [003: Alignment]
# will control your alignment. So if you add to it, your alignment moves to
# good side, and if you subtract from it, you become more evil. Maximum is
# 100, both ways, but you can add to it, it just will not show up on the bar.
#
# Set $main_hero to be the ID of your hero in the database.
#---------------------------------------------------------------------------
@enemy_alignment = [-1,-2,-3,-4,10,-6,-7,8,9,10,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,
1,2,3,4,5,6,7,8,9,10,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,
1,2,3,4,5,6,7,8,9,10]
$alignment_variable = 3
$main_hero = 1
#----------------------------------------------------------------------------
# In region_maps, you define which maps are contained in each region by using
# their map ids. As it is now, Region 1 contains Maps 1 and 4. Region 2 contains
# maps 2, 3, and 5, and Region 3 contains Map 6
#
# $region_adjacency determines how fame translates to other regions. Basically,
# the numbers are percentile, from 0 to 100. You can consider this as being
# how open the borders are, how close they are to another country, etc... 100
# means the fame translates intp the region entirely. 50 means that half the
# fame is translated into the other region, etc... Basically, you set it up
# like this:
# $region_adjacency = [[100, 20, 35], [20, 100, 65], [35, 65, 100]
# 1 2 3 1 2 3 1 2 3
# 1 2 3
# As you see by my amazing diagram, Region 1's relationship to regions 1, 2,
# and 3 are defined in the first array. Region 2's relationship to regions 1, 2,
# and 3 are defined in the second array, and Region 3's relationship to
# regions 1, 2, and 3 are defined in the third array.
# For example, let's say you just performed some amazing feat in Region 1
# which won you 10 fame. The array for Region 1 is [100, 20, 35]. This means
# that in Region 1, your fame will increase by 10, since it translates 100%.
# But, Region 2 is across the ocean, so while a few people there might have
# heard about your deed, in general not so much. Thus, fame translates to 20%
# over there, and so you only win 2 fame there. Region 3 is a little closer,
# and so 35% fame translates, which rounds to 4 fame gained in Region 3. Just
# remember, when you are setting this up, you need to have each relationship
# to each region defined in each array. Thus, if you have 5 regions, then your
# array will look like this:
# $region_adjacency = [[100,20,35,45,85], [20,100,65,75,80], [35,65,100,90,75], [45,75,90,100,0], [85,80,75,0,100]
#
# Now, to increase fame, merely use this call script at the place you want
# to affect your fame:
#
# $scene = Fame.new(???)
# where ??? is the amount of fame you want that actionto gain you. Thus, if
# you had $scene = Fame.new(5), then you would get 5 fame added to your variable.
#
# To use your fame (i.e., have your fame effect events), use a conditional
# branch conditioned on this script:
# $region[$region_index] == or > or < or != or >= or <= ???, where ??? is the value
# of the fame you are conditioning on, and ==,<,>,!=, >=, <= are the
# comparisons. i.e.equals, less than, greater than, not equal to, greater
# than or equal to, less than or equal to.
#
# $region_names is optional, but it allows you to give the regions names. To
# remove this option just replace that line with: $region_names = []
#
# Hopefully you understood all that. If not, contact me and I will
# try to explain it better.
#--------------------------------------------------------------------------
region_maps = [[1,3],[2]]
$region_adjacency = [[100,35],[35,100]]
$region_names = ["Country A", "Country B"]
#--------------------------------------------------------------------------
# END CONFIGURATION
#==========================================================================
# Set up regional data
#=================================
map_ID = $game_map.map_id
for i in 0...(region_maps.size)
for j in 0...(region_maps[i].size)
if region_maps[i][j] == map_ID
$region_index = i
end
end
end
viable_encounter_levels = []
for i in 0 ... 396
viable_encounter_levels[i] = false
end
@flip_array = []
for i in 0...11
@flip_array[i] = -(2 * (i+1)/3).round
end
@flip_array.reverse!
sum2 = 0
for i in 0...$game_party.actors.size
sum2 = sum2 + $game_actors[$game_party.actors[i].id].level
end
for i in 0 ... $game_map.encounter_list.size
sum = 0
al_average = 0
troop = $data_troops[$game_map.encounter_list[i]]
for j in 0 ... (troop.members.size)
sum = sum + @enemy_level[troop.members[j].enemy_id - 1]
al_average = al_average + @enemy_alignment[troop.members[j].enemy_id - 1]
end
al_average = (al_average / troop.members.size).round
if al_average <= 0 || ($game_variables[$alignment_variable]/10) <= @flip_array[al_average-1]
if sum > $min_fight_level
if sum < 396 - $max_fight_level
for k in (sum-$min_fight_level)...(sum+$max_fight_level)
viable_encounter_levels[k] = true
end
else
for k in (sum-$min_fight_level)...396
viable_encounter_levels[k] = true
end
end
else
for h in 0...(sum+$max_fight_level)
if (viable_encounter_levels % 2) == 0
viable_encounter_levels[k] = true
end
end
end
end
if viable_encounter_levels[sum2] == true
@disable_encounters = false
else
@disable_encounters = true
end
end
end
#=============================================================================
# Determines if the troop selected is within party's level range
#=============================================================================
def enemy_hero_comparison (troop_id)
sum = 0
sum2 = 0
alignment_average = 0
for i in 0...$game_party.actors.size
sum2 = sum2 + $game_actors[$game_party.actors[i].id].level
end
for i in 0 ... $data_troops[troop_id].members.size
sum = sum + @enemy_level[$data_troops[troop_id].members[i].enemy_id - 1]
alignment_average = alignment_average + @enemy_alignment[$data_troops[troop_id].members[i].enemy_id - 1]
end
sum = sum - sum2
alignment_average = (alignment_average / $data_troops[troop_id].members.size).round
if troop_id == 2
p alignment_average
p $game_variables[$alignment_variable]/10
p @flip_array[alignment_average]
end
if alignment_average <= 0
@alignment_factor = true
else
if (($game_variables[$alignment_variable])/10) <= @flip_array[alignment_average]
@alignment_factor = true
else
@alignment_factor = false
end
end
return sum
end
end
#====================================================
# Adding a couple of methods to Window_Base
#====================================================
class Window_Base
# draw alignment
def draw_alignment_bar(x, y)
# drawing the alignment bar
self.contents.font.color = system_color
self.contents.draw_text(x, y - 28, 160, 32, "Alignment")
self.contents.fill_rect(x-1, y - 1, 202, 17, Color.new(-255, -255, -255, 255))
for i in 0...100
self.contents.fill_rect((x+i), y, 1, 15, Color.new(255, 55 + (2*i), 55 + (2*i), 255))
self.contents.fill_rect((x+100+i), y, 1, 15, Color.new(255 - (2*i), 255 - (2*i), 255, 255))
end
# drawing the arrow
for i in 1...12
self.contents.fill_rect(x+89+$game_variables[$alignment_variable]+i,
y-6, 1, i, Color.new(-255,-255,-255,255))
self.contents.fill_rect(x+99+$game_variables[$alignment_variable]+i,
y-6, 1, 12-i,Color.new(-255,-255,-255,255))
end
for i in 1...10
if $game_variables[$alignment_variable] < 100
if $game_variables[$alignment_variable] > -100
self.contents.fill_rect(x+91+$game_variables[$alignment_variable]+i,
y - 5, 1, i, Color.new(255, 255, 0, 255))
self.contents.fill_rect(x+99+$game_variables[$alignment_variable]+i,
y - 5, 1, 10-i, Color.new(255, 255, 0, 255))
else
self.contents.fill_rect(x-9+i, y - 5, 1, i, Color.new(255, 255, 0, 255))
self.contents.fill_rect(x+-1+i, y - 5, 1, 10-i, Color.new(255, 255, 0, 255))
end
else
self.contents.fill_rect(x+191+i, y - 5, 1, i, Color.new(255, 255, 0, 255))
self.contents.fill_rect(x+199+i, y - 5, 1, 10-i, Color.new(255, 255, 0, 255))
end
end
end
# draw fame
def draw_fame_bar (x,y)
# if region has name
self.contents.font.color = system_color
if $region_names[$region_index] == nil
self.contents.draw_text(x, y - 28, 200, 32, "Regional Reknown")
else
self.contents.draw_text(x, y - 28, 200, 32, "Fame in " + $region_names[$region_index])
end
# drawing the background bar
self.contents.fill_rect(x-1, y - 1, 202, 17, Color.new(-255, -255, -255, 255))
# drawing the filler bar
if $region[$region_index] < 200
for i in 0...$region[$region_index]
self.contents.fill_rect((x+i), y, 1, 15, Color.new(200 - i, 255, 200 - i, 255))
end
else
for i in 0...200
self.contents.fill_rect((x+i), y, 1, 15, Color.new(200 - i, 255, 200 - i, 255))
end
end
end
end
class Fame
def initialize(fame)
@fame=fame
end
def main
for i in 0...$region_adjacency.size
$region[i] += (($region_adjacency[$region_index][i]) * @fame/100).round
end
$scene = Scene_Map.new
end
end
class Scene_Title
alias region_set_up command_new_game
def command_new_game
region_set_up
$region = []
for i in 0...100
$region[i] = 0
end
end
end
Also, I edited a little bit in Scene_Map and Window_Status. While these edits were minor, it's easier just to post the entire edited class then it is to have you add the little bits I edited, so replace your Scene_Map with this:
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
# This class performs map screen processing.
#==============================================================================
class Scene_Map
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
# Make sprite set
@spriteset = Spriteset_Map.new
# Make message window
@message_window = Window_Message.new
# Transition run
Graphics.transition
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of sprite set
@spriteset.dispose
# Dispose of message window
@message_window.dispose
# If switching to title screen
if $scene.is_a?(Scene_Title)
# Fade out screen
Graphics.transition
Graphics.freeze
end
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Loop
# Check for possible encounters
determine_encounter_range
loop do
# Update map, interpreter, and player order
# (this update order is important for when conditions are fulfilled
# to run any event, and the player isn't provided the opportunity to
# move in an instant)
$game_map.update
$game_system.map_interpreter.update
$game_player.update
# Update system (timer), screen
$game_system.update
$game_screen.update
# Abort loop if player isn't place moving
unless $game_temp.player_transferring
break
end
# Run place move
transfer_player
# Abort loop if transition processing
if $game_temp.transition_processing
break
end
end
# Update sprite set
@spriteset.update
# Update message window
@message_window.update
# If game over
if $game_temp.gameover
# Switch to game over screen
$scene = Scene_Gameover.new
return
end
# If returning to title screen
if $game_temp.to_title
# Change to title screen
$scene = Scene_Title.new
return
end
# If transition processing
if $game_temp.transition_processing
# Clear transition processing flag
$game_temp.transition_processing = false
# Execute transition
if $game_temp.transition_name == ""
Graphics.transition(20)
else
Graphics.transition(40, "Graphics/Transitions/" +
$game_temp.transition_name)
end
end
# If showing message window
if $game_temp.message_window_showing
return
end
# If there are troops specified which are within level range of the party
if @disable_encounters == false
# If encounter list isn't empty, and encounter count is 0
if $game_player.encounter_count == 0 and $game_map.encounter_list != []
# If event is running or encounter is not forbidden
unless $game_system.map_interpreter.running? or
$game_system.encounter_disabled
ehp = 99999
# Confirm troop
while (ehp < -$min_fight_level || ehp > $max_fight_level) || @alignment_factor = false
n = rand($game_map.encounter_list.size)
troop_id = $game_map.encounter_list[n]
ehp = enemy_hero_comparison(troop_id)
end
# If troop is valid
if $data_troops[troop_id] != nil
# Set battle calling flag
$game_temp.battle_calling = true
$game_temp.battle_troop_id = troop_id
$game_temp.battle_can_escape = true
$game_temp.battle_can_lose = false
$game_temp.battle_proc = nil
end
end
end
end
# If B button was pressed
if Input.trigger?(Input::B)
# If event is running, or menu is not forbidden
unless $game_system.map_interpreter.running? or
$game_system.menu_disabled
# Set menu calling flag or beep flag
$game_temp.menu_calling = true
$game_temp.menu_beep = true
end
end
# If debug mode is ON and F9 key was pressed
if $DEBUG and Input.press?(Input::F9)
# Set debug calling flag
$game_temp.debug_calling = true
end
# If player is not moving
unless $game_player.moving?
# Run calling of each screen
if $game_temp.battle_calling
call_battle
elsif $game_temp.shop_calling
call_shop
elsif $game_temp.name_calling
call_name
elsif $game_temp.menu_calling
call_menu
elsif $game_temp.save_calling
call_save
elsif $game_temp.debug_calling
call_debug
end
end
end
#--------------------------------------------------------------------------
# * Battle Call
#--------------------------------------------------------------------------
def call_battle
# Clear battle calling flag
$game_temp.battle_calling = false
# Clear menu calling flag
$game_temp.menu_calling = false
$game_temp.menu_beep = false
# Make encounter count
$game_player.make_encounter_count
# Memorize map BGM and stop BGM
$game_temp.map_bgm = $game_system.playing_bgm
$game_system.bgm_stop
# Play battle start SE
$game_system.se_play($data_system.battle_start_se)
# Play battle BGM
$game_system.bgm_play($game_system.battle_bgm)
# Straighten player position
$game_player.straighten
# Switch to battle screen
$scene = Scene_Battle.new
end
#--------------------------------------------------------------------------
# * Shop Call
#--------------------------------------------------------------------------
def call_shop
# Clear shop call flag
$game_temp.shop_calling = false
# Straighten player position
$game_player.straighten
# Switch to shop screen
$scene = Scene_Shop.new
end
#--------------------------------------------------------------------------
# * Name Input Call
#--------------------------------------------------------------------------
def call_name
# Clear name input call flag
$game_temp.name_calling = false
# Straighten player position
$game_player.straighten
# Switch to name input screen
$scene = Scene_Name.new
end
#--------------------------------------------------------------------------
# * Menu Call
#--------------------------------------------------------------------------
def call_menu
# Clear menu call flag
$game_temp.menu_calling = false
# If menu beep flag is set
if $game_temp.menu_beep
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Clear menu beep flag
$game_temp.menu_beep = false
end
# Straighten player position
$game_player.straighten
# Switch to menu screen
$scene = Scene_Menu.new
end
#--------------------------------------------------------------------------
# * Save Call
#--------------------------------------------------------------------------
def call_save
# Straighten player position
$game_player.straighten
# Switch to save screen
$scene = Scene_Save.new
end
#--------------------------------------------------------------------------
# * Debug Call
#--------------------------------------------------------------------------
def call_debug
# Clear debug call flag
$game_temp.debug_calling = false
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Straighten player position
$game_player.straighten
# Switch to debug screen
$scene = Scene_Debug.new
end
#--------------------------------------------------------------------------
# * Player Place Move
#--------------------------------------------------------------------------
def transfer_player
# Clear player place move call flag
$game_temp.player_transferring = false
# If move destination is different than current map
if $game_map.map_id != $game_temp.player_new_map_id
# Set up a new map
$game_map.setup($game_temp.player_new_map_id)
end
# Set up player position
$game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y)
# Set player direction
case $game_temp.player_new_direction
when 2 # down
$game_player.turn_down
when 4 # left
$game_player.turn_left
when 6 # right
$game_player.turn_right
when 8 # up
$game_player.turn_up
end
# Straighten player position
$game_player.straighten
# Update map (run parallel process event)
$game_map.update
# Remake sprite set
@spriteset.dispose
@spriteset = Spriteset_Map.new
# If processing transition
if $game_temp.transition_processing
# Clear transition processing flag
$game_temp.transition_processing = false
# Execute transition
Graphics.transition(20)
end
# Run automatic change for BGM and BGS set on the map
$game_map.autoplay
# Frame reset
Graphics.frame_reset
# Update input information
Input.update
end
end
And replace Window_Status with this:
#==============================================================================
# ** Window_Status
#------------------------------------------------------------------------------
# This window displays full status specs on the status screen.
#==============================================================================
class Window_Status < Window_Base
#--------------------------------------------------------------------------
# * Object Initialization
# actor : actor
#--------------------------------------------------------------------------
def initialize(actor)
super(0, 0, 640, 480)
self.contents = Bitmap.new(width - 32, height - 32)
@actor = actor
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
draw_actor_graphic(@actor, 40, 112)
draw_actor_name(@actor, 4, 0)
draw_actor_class(@actor, 4 + 144, 0)
draw_actor_level(@actor, 96, 32)
draw_actor_state(@actor, 96, 64)
draw_actor_hp(@actor, 96, 112, 172)
draw_actor_sp(@actor, 96, 144, 172)
draw_actor_parameter(@actor, 96, 192, 0)
draw_actor_parameter(@actor, 96, 224, 1)
draw_actor_parameter(@actor, 96, 256, 2)
draw_actor_parameter(@actor, 96, 304, 3)
draw_actor_parameter(@actor, 96, 336, 4)
draw_actor_parameter(@actor, 96, 368, 5)
draw_actor_parameter(@actor, 96, 400, 6)
if @actor.id == $main_hero
draw_alignment_bar (320, 110)
draw_fame_bar (320, 152)
end
self.contents.font.color = system_color
self.contents.draw_text(320, 28, 80, 32, "EXP")
self.contents.draw_text(320, 57, 80, 32, "NEXT")
self.contents.font.color = normal_color
self.contents.draw_text(320 + 80, 28, 84, 32, @actor.exp_s, 2)
self.contents.draw_text(320 + 80, 57, 84, 32, @actor.next_rest_exp_s, 2)
self.contents.font.color = system_color
self.contents.draw_text(320, 165, 96, 32, "equipment")
draw_item_name($data_weapons[@actor.weapon_id], 320 + 16, 213)
draw_item_name($data_armors[@actor.armor1_id], 320 + 16, 261)
draw_item_name($data_armors[@actor.armor2_id], 320 + 16, 309)
draw_item_name($data_armors[@actor.armor3_id], 320 + 16, 357)
draw_item_name($data_armors[@actor.armor4_id], 320 + 16, 405)
end
def dummy
self.contents.font.color = system_color
self.contents.draw_text(320, 112, 96, 32, $data_system.words.weapon)
self.contents.draw_text(320, 176, 96, 32, $data_system.words.armor1)
self.contents.draw_text(320, 240, 96, 32, $data_system.words.armor2)
self.contents.draw_text(320, 304, 96, 32, $data_system.words.armor3)
self.contents.draw_text(320, 368, 96, 32, $data_system.words.armor4)
draw_item_name($data_weapons[@actor.weapon_id], 320 + 24, 144)
draw_item_name($data_armors[@actor.armor1_id], 320 + 24, 208)
draw_item_name($data_armors[@actor.armor2_id], 320 + 24, 272)
draw_item_name($data_armors[@actor.armor3_id], 320 + 24, 336)
draw_item_name($data_armors[@actor.armor4_id], 320 + 24, 400)
end
end
If you have a custom Window_Status, then just post that and I will add the alignment and fame bars in their appropriate places. Similarly, if you have a custom Scene_Map, just show it to me and I will do the appropriate editing.
InstructionsInside the script, there is a huge commented section (takes up over a third of the entire script. Read that for instructions on how to configure. I will say this here though: when you are setting up your maps, put every monster you ever want to be in that map
at any point in the game. That is the point of the Encounter Range Script, so that you can re-visit any area and still be able to fight monsters which are reflective of your level.
CompatibilityAny Custom Status Screen Script
Scripts which allow your maximum level to be greater than 99.
No others known (yet)
Also, for any of those problems, just post the scripts you are using and I will make them compatible
Credits and ThanksAuthor's NotesThis script is far from optimized. It may even have bugs. If you find any bugs, or see any huge efficiency problems with my script, please notify me. Any help you give me will be appreciated and you will get credit in the script as a tester. Thank you. The script is free to use in any game, and all I require is credit. These are my first scripts, so any constructive criticism is appreciated. Any feedback is appreciated.