summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gay <david@davidgay.org>2021-05-31 16:51:47 -0400
committerDavid Gay <david@davidgay.org>2021-05-31 16:51:47 -0400
commitdcbb8efcde93af6452af77fea6b1038784db477e (patch)
tree476f1ccde46a663f27a3183e5fa9b202fce89f39
parent99e2507bea007e4aac17cf562139f53f7f9da9bf (diff)
Character resting
-rw-r--r--CHANGELOG.md14
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/game_controller.rb29
-rw-r--r--app/models/character.rb37
-rw-r--r--app/views/characters/show.html.erb11
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/20210531192205_add_resting_to_characters.rb8
-rw-r--r--db/schema.rb4
8 files changed, 106 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54f8ce2..579f35b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
+- Characters can now rest.
+ - To make your character rest, click the button on the Character screen. To stop resting, click the button again.
+ - While resting, you will be unable to perform activities, but you will accumulate rested time. This time is
+ automatially spent to lower your timers on activities, down to a minimum timer of 10 seconds.
+ - The normal minimum timer for an activity can be broken in this way, but other timer reductions are still held
+ to the minimum timer. For example, if the minimum timer is 35 seconds and your base timer after level adjustments
+ is 40 seconds, but you have a buff that reduces the timer by 10 seconds, the final timer before rested time will
+ still be only 35 seconds, the minimum for that activity. Then, 25 seconds of your rested time will be spent
+ lowering the absolute final timer to 10 seconds.
+ - You get 1 second of rested time for each second of time you spend resting.
+ - Only time that is actually reduced will be consumed from your rested time. If you lose any rested time that you
+ do not see a timer reduction for, it's a bug.
+ - Rested time is used at the end of the activity, when the timer runs out, like other calculations. If you stop
+ your activity before it finishes, rested time will not be used.
- New beastslay activity: the Hopegraves
- New fluxseethe activity: brew trawling draught
- New monsters: bollyrot, crypt writhe
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 0fc78a8..f28d30b 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -17,6 +17,10 @@ class ApplicationController < ActionController::Base
private
def start_activity(activity)
+ if current_char.resting?
+ flash[:alert] = "You can't do anything while you're resting. Go to the Character page to stop resting."
+ redirect_to character_path(current_char) and return
+ end
if current_char.start_activity(activity, queued_actions: params[:queued_actions])
redirect_to look_path
else
diff --git a/app/controllers/game_controller.rb b/app/controllers/game_controller.rb
index 9de6e8f..f6bb7b8 100644
--- a/app/controllers/game_controller.rb
+++ b/app/controllers/game_controller.rb
@@ -1,4 +1,21 @@
class GameController < ApplicationController
+ def toggle_resting
+ if current_char.resting?
+ if current_char.stop_resting
+ flash[:notice] = "You stop resting. You now have #{current_char.rested_duration} seconds of rest."
+ else
+ flash[:alert] = "Failed to stop resting. Are you sure you're resting?"
+ end
+ else
+ if current_char.start_resting
+ flash[:notice] = "You are now resting."
+ else
+ flash[:alert] = "Failed to start resting. Are you already resting?"
+ end
+ end
+ redirect_to character_path(current_char)
+ end
+
def stop_activity
current_char.stop_activity
redirect_to locations_path
@@ -9,6 +26,13 @@ class GameController < ApplicationController
return unless current_char.activity_time_remaining <= 0
activity = current_char.activity
+ if current_char.resting?
+ @results.replace([{ type: "error", message: "You can't do anything while you're resting. Go to the Character" \
+ " page to stop resting." }])
+ current_char.stop_activity
+ return
+ end
+
unless current_char.can_do_activity?(activity)
message = "You can't do this right now."
message += " (requires #{activity.requirements&.join(", ")})" if activity.requirements.any?
@@ -19,6 +43,11 @@ class GameController < ApplicationController
end
Character.transaction do
+ if current_char.rested_duration > 0
+ remaining_rested_duration = current_char.rested_duration - current_char.rested_duration_to_spend_on_activity
+ current_char.update!(rested_duration: remaining_rested_duration)
+ end
+
current_char.pay_cost_for(activity)
activity.whatnot[:results].each do |result|
diff --git a/app/models/character.rb b/app/models/character.rb
index 56be0c0..5b3a4ab 100644
--- a/app/models/character.rb
+++ b/app/models/character.rb
@@ -15,11 +15,14 @@ class Character < ApplicationRecord
has_many :chat_messages
has_many :bazaar_orders
validates :name, presence: true
+ # TODO: Make defaults better. This has to allow nil so the `attribute` default works, and I don't like that.
+ validates :rested_duration, numericality: { greater_than_or_equal_to: 0, only_integer: true }, allow_nil: true
validates_length_of :name, maximum: 15, message: "can't be longer than 15 characters"
validates_uniqueness_of :name, message: "is already being used"
validates_format_of :name, with: /\A[a-z]+\z/i, message: "must consist of letters only"
attribute :wounds, :integer, default: 0
+ attribute :rested_duration, :integer, default: 0
enum offensive_style: [:balanced, :precise, :brutal], _default: "balanced"
enum defensive_style: [:centered, :elusive, :protective], _default: "centered"
@@ -180,6 +183,12 @@ class Character < ApplicationRecord
end
def activity_time_remaining
+ time = duration_of_activity - (Time.now - self.activity_started_at)
+ time -= rested_duration_to_spend_on_activity if self.rested_duration > 0
+ time
+ end
+
+ def duration_of_activity
return nil unless self.activity
duration_data = self.activity.whatnot[:duration]
duration = duration_data[:base]
@@ -193,8 +202,12 @@ class Character < ApplicationRecord
raise "Invalid scaling type." # TODO: Improve this
end
end
- duration = [duration, duration_data[:minimum] || 10].max
- duration - (Time.now - self.activity_started_at)
+ [duration, duration_data[:minimum] || 10].max
+ end
+
+ def rested_duration_to_spend_on_activity
+ return nil unless self.activity
+ [duration_of_activity - 10, self.rested_duration].min
end
def can_do_activity?(activity, ignore_cost: false, ignore_requirements: false)
@@ -238,6 +251,26 @@ class Character < ApplicationRecord
self.update(activity: nil, activity_started_at: nil, queued_actions: nil)
end
+ def resting?
+ self.started_resting_at
+ end
+
+ def start_resting
+ return false if self.started_resting_at
+ self.update(started_resting_at: Time.now)
+ end
+
+ def stop_resting
+ return false unless self.started_resting_at
+ Character.transaction do
+ byebug
+ seconds_of_this_rest = (Time.now - self.started_resting_at).to_i
+ # Maximum rested duration is 10 days.
+ new_rested_duration = [(seconds_of_this_rest + self.rested_duration), (60 * 60 * 24 * 10)].min
+ self.update(started_resting_at: nil, rested_duration: new_rested_duration)
+ end
+ end
+
def award_title(title)
title = Title.find_by_gid(title) if title.is_a? String
# TODO: Simplify these lines?
diff --git a/app/views/characters/show.html.erb b/app/views/characters/show.html.erb
index 71d75a5..b2e8f94 100644
--- a/app/views/characters/show.html.erb
+++ b/app/views/characters/show.html.erb
@@ -106,5 +106,16 @@
</div>
<% if @character == current_char %>
+ <div class="my-6">
+ <h2 class="text-2xl mb-4">Rest</h2>
+ <p class="mb-4">
+ You have <%= @character.rested_duration %> seconds of rested time stored.
+ <% if current_char.resting? %>
+ This does not include time from your current rest. That time will be added when you stop resting.
+ <% end %>
+ </p>
+ <%= button_to current_char.resting? ? "Stop Resting" : "Start Resting", toggle_resting_path %>
+ </div>
+
<%= link_to "Manage account", edit_user_registration_path, class: "text-sm" %>
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index a860321..88d75ef 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -47,4 +47,6 @@ Rails.application.routes.draw do
post "/start_activity", to: "activities#start"
post "/stop_activity", to: "game#stop_activity"
post "/finish_activity", to: "game#finish_activity"
+
+ post "/toggle_resting", to: "game#toggle_resting"
end
diff --git a/db/migrate/20210531192205_add_resting_to_characters.rb b/db/migrate/20210531192205_add_resting_to_characters.rb
new file mode 100644
index 0000000..a53e4fa
--- /dev/null
+++ b/db/migrate/20210531192205_add_resting_to_characters.rb
@@ -0,0 +1,8 @@
+class AddRestingToCharacters < ActiveRecord::Migration[6.1]
+ def change
+ add_column :characters, :rested_duration, :integer
+ add_column :characters, :started_resting_at, :timestamp
+
+ Character.update_all(rested_duration: 0)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5d9fffe..2a0b30a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2021_05_29_195809) do
+ActiveRecord::Schema.define(version: 2021_05_31_192205) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -84,6 +84,8 @@ ActiveRecord::Schema.define(version: 2021_05_29_195809) do
t.integer "queued_actions"
t.integer "offensive_style"
t.integer "defensive_style"
+ t.integer "rested_duration"
+ t.datetime "started_resting_at"
t.index ["active_title_id"], name: "index_characters_on_active_title_id"
t.index ["activity_id"], name: "index_characters_on_activity_id"
t.index ["user_id"], name: "index_characters_on_user_id"