# Development-only shortcut so any screen can be opened directly instead of
|
|
# playing the game from the start. Creates a player on demand and back-fills
|
|
# whatever progress the requested screen expects to find.
|
|
#
|
|
# ?dev=good|bad|chance|chance_bad picks which answer the back-fill records and
|
|
# always starts from a fresh player, so the whole run leading up to the screen
|
|
# is answered that way. Without it an existing session player is kept and only
|
|
# the gaps are filled, so a jump can be played on from. ?dev_last_save=1 also
|
|
# answers the last-save question.
|
|
module DevJump
|
|
extend ActiveSupport::Concern
|
|
|
|
SCREENS = %w[index facts intro stage stage_result last_save done results].freeze
|
|
|
|
included do
|
|
prepend_before_action :dev_jump!, only: SCREENS.map(&:to_sym), if: :dev_jump?
|
|
end
|
|
|
|
|
|
private
|
|
|
|
|
|
def dev_jump?
|
|
Rails.env.development?
|
|
end
|
|
|
|
|
|
def dev_jump!
|
|
set_locale
|
|
|
|
# The start screen is the one place a leftover player is in the way: it
|
|
# would show the debug panel a first-time visitor never sees.
|
|
return session.delete(:player_id) if action_name == "index"
|
|
|
|
session.delete(:player_id) if params[:dev]
|
|
dev_player
|
|
dev_seed_progress
|
|
end
|
|
|
|
|
|
def dev_player
|
|
Current.player = Player.find_by(id: session[:player_id])
|
|
return Current.player if Current.player
|
|
|
|
Current.player = Player.create(locale: I18n.locale.to_s,
|
|
country: Player.valid_country_code(params[:country]),
|
|
device: Player.device_from_user_agent(request.user_agent))
|
|
session[:player_id] = Current.player.id
|
|
Current.player
|
|
end
|
|
|
|
|
|
def dev_seed_progress
|
|
case action_name
|
|
when "stage" then dev_fill_stages(params[:id].to_i - 1)
|
|
when "stage_result" then dev_fill_stages(params[:id].to_i)
|
|
when "last_save" then dev_fill_stages(n_stages)
|
|
when "done", "results"
|
|
dev_fill_stages(n_stages)
|
|
dev_fill_last_save if params[:dev_last_save]
|
|
end
|
|
end
|
|
|
|
|
|
# Answers every stage up to `upto` that the player hasn't answered yet, scoring
|
|
# each one the way the real answer action would.
|
|
def dev_fill_stages(upto)
|
|
return if upto < 1
|
|
|
|
stages.first(upto).each_with_index do |stage_node, i|
|
|
index = i + 1
|
|
next if current_player.answer_id_for(index)
|
|
|
|
answer = dev_answer_for(stage_node)
|
|
next unless answer
|
|
|
|
current_player.record_answer(index, answer.id)
|
|
apply_score(score_entry_for(index, answer))
|
|
end
|
|
end
|
|
|
|
|
|
def dev_fill_last_save
|
|
return if current_player.last_save_answer_id
|
|
|
|
node = last_save_node
|
|
return unless node
|
|
|
|
answer = dev_pick_from(node.children.ordered)
|
|
return unless answer
|
|
|
|
current_player.record_last_save_answer(answer.id)
|
|
apply_score(last_save_score_entry_for(answer))
|
|
end
|
|
|
|
|
|
# A chance answer is only ever recorded through one of its outcomes, so it
|
|
# resolves one level deeper -- ?dev=chance lands on the good outcome,
|
|
# ?dev=chance_bad on the bad one.
|
|
def dev_answer_for(stage_node)
|
|
answer = dev_pick_from(stage_node.children.ordered)
|
|
return answer unless answer&.chance?
|
|
|
|
outcomes = answer.children.ordered.to_a
|
|
wanted = params[:dev] == "chance_bad" ? :bad_answer? : :good_answer?
|
|
outcomes.find(&wanted) || outcomes.first
|
|
end
|
|
|
|
|
|
# Not every stage offers every kind -- stage 5 has no bad answer, stage 1's
|
|
# chance cannot go wrong -- so an unavailable pick settles for the first
|
|
# answer rather than leaving the stage unanswered.
|
|
def dev_pick_from(nodes)
|
|
nodes = nodes.to_a
|
|
|
|
case params[:dev]
|
|
when "bad" then nodes.find(&:bad_answer?)
|
|
when "chance", "chance_bad" then nodes.find(&:chance?)
|
|
else nodes.find(&:good_answer?)
|
|
end || nodes.first
|
|
end
|
|
end
|