Module: Natural20::ActionUI

Included in:
CommandlineUI
Defined in:
lib/natural_20/cli/action_ui.rb

Constant Summary collapse

TTY_PROMPT_PER_PAGE =
20

Instance Method Summary collapse

Instance Method Details

#action_ui(action, entity) ⇒ Object

Show action UI

Parameters:



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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/natural_20/cli/action_ui.rb', line 7

def action_ui(action, entity)
  return :stop if action == :stop

  cont = action.build_map
  loop do
    param = cont.param&.map do |p|
      case (p[:type])
      when :look
        self
      when :movement
        move_path, jump_index = move_ui(entity, p)
        return nil if move_path.nil?

        [move_path, jump_index]
      when :target, :select_target
        targets = attack_ui(entity, action, p)
        return nil if targets.nil? || targets.empty?

        p[:num] > 1 ? targets : targets.first
      when :select_spell
        spell_slots_ui(entity)

        spell = prompt.select("#{entity.name} cast Spell", per_page: TTY_PROMPT_PER_PAGE) do |q|
          spell_choice(entity, battle, q)
          q.choice t(:back).colorize(:blue), :back
        end

        return nil if spell == :back

        spell
      when :select_weapon
        action.using || action.npc_action
      when :select_item
        item = prompt.select("#{entity.name} use item", per_page: TTY_PROMPT_PER_PAGE) do |menu|
          entity.usable_items.each do |d|
            if d[:consumable]
              menu.choice "#{d[:label].colorize(:blue)} (#{d[:qty]})", d[:name]
            else
              menu.choice d[:label].colorize(:blue).to_s, d[:name]
            end
          end
          menu.choice t(:back).colorize(:blue), :back
        end

        return nil if item == :back

        item
      when :select_ground_items
        selected_items = prompt.multi_select("Items on the ground around #{entity.name}") do |menu|
          map.items_on_the_ground(entity).each do |ground_item|
            ground, items = ground_item
            items.each do |t|
              item_label = t("object.#{t.label}", default: t.label)
              menu.choice t('inventory.inventory_items', name: item_label, qty: t.qty), [ground, t]
            end
          end
        end

        return nil if selected_items.empty?

        item_selection = {}
        selected_items.each do |s_item|
          ground, item = s_item

          qty = how_many?(item)
          item_selection[ground] ||= []
          item_selection[ground] << [item, qty]
        end

        item_selection.map do |k, v|
          [k, v]
        end
      when :select_object
        target_objects = entity.usable_objects(map, battle)
        item = prompt.select("#{entity.name} interact with") do |menu|
          target_objects.each do |d|
            menu.choice d.name.humanize.to_s, d
          end
          menu.choice t(:manual_target), :manual_target
          menu.choice t(:back).colorize(:blue), :back
        end

        return nil if item == :back

        if item == :manual_target
          item = target_ui(entity, num_select: 1, validation: lambda { |selected|
            selected_entities = map.thing_at(*selected)

            return false if selected_entities.empty?

            selected_entities.detect do |selected_entity|
              target_objects.include?(selected_entity)
            end
          }).first
        end

        item
      when :select_items
        selected_items = prompt.multi_select(p[:label], per_page: TTY_PROMPT_PER_PAGE) do |menu|
          p[:items].each do |m|
            item_label = t("object.#{m.label}", default: m.label)
            if m.try(:equipped)
              menu.choice t('inventory.equiped_items', name: item_label), m
            else
              menu.choice t('inventory.inventory_items', name: item_label, qty: m.qty), m
            end
          end
          menu.choice t(:back).colorize(:blue), :back
        end

        return nil if selected_items.include?(:back)

        selected_items = selected_items.map do |m|
          count = how_many?(m)
          [m, count]
        end
        selected_items
      when :interact
        object_action = prompt.select("#{entity.name} will") do |menu|
          interactions = p[:target].available_interactions(entity)
          class_key = p[:target].class.to_s
          if interactions.is_a?(Array)
            interactions.each do |k|
              menu.choice t(:"object.#{class_key}.#{k}", default: k.to_s.humanize), k
            end
          else
            interactions.each do |k, options|
              label = options[:label] || t(:"object.#{class_key}.#{k}", default: k.to_s.humanize)
              if options[:disabled]
                menu.choice label, k, disabled: options[:disabled_text]
              else
                menu.choice label, k
              end
            end
          end
          menu.choice 'Back', :back
        end

        return nil if item == :back

        object_action
      when :show_inventory
        inventory_ui(entity)
      else
        raise "unknown #{p[:type]}"
      end
    end
    cont = cont.next.call(*param)
    break if param.nil?
  end
  @action = cont
end

#spell_choice(entity, battle, menu) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/natural_20/cli/action_ui.rb', line 160

def spell_choice(entity, battle, menu)
  entity.available_spells(battle).each do |k, details|
    available_levels = if details[:higher_level]
                         (details[:level]..9).select { |lvl| entity.max_spell_slots(lvl).positive? }
                       else
                         [details[:level]]
                       end
    available_levels.each do |spell_level|
      level_str = spell_level.zero? ? 'cantrip' : "lvl. #{spell_level}"
      choice_label = t(:"action.spell_choice", spell: t("spell.#{k}"), level: level_str,
                                              description: details[:description])
      if details[:disabled].empty?
        menu.choice(choice_label, [k, spell_level])
      else
        disable_reason = details[:disabled].map { |d| t("spells.disabled.#{d}") }.join(', ')
        menu.choice(choice_label, k, disabled: disable_reason)
      end
    end
  end
end