amar-rpg 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +675 -0
- data/README.md +155 -0
- data/amar-tui.rb +8195 -0
- data/cli_enc_output.rb +87 -0
- data/cli_enc_output_new.rb +433 -0
- data/cli_enc_output_new_3tier.rb +198 -0
- data/cli_enc_output_new_compact.rb +238 -0
- data/cli_name_gen.rb +21 -0
- data/cli_npc_output.rb +279 -0
- data/cli_npc_output_new.rb +700 -0
- data/cli_town_output.rb +39 -0
- data/cli_weather_output.rb +36 -0
- data/includes/class_enc.rb +341 -0
- data/includes/class_enc_new.rb +512 -0
- data/includes/class_monster_new.rb +551 -0
- data/includes/class_npc.rb +1378 -0
- data/includes/class_npc_new.rb +1187 -0
- data/includes/class_npc_new.rb.backup +706 -0
- data/includes/class_npc_new_skills.rb +153 -0
- data/includes/class_town.rb +237 -0
- data/includes/d6s.rb +40 -0
- data/includes/equipment_tables.rb +120 -0
- data/includes/functions.rb +67 -0
- data/includes/includes.rb +30 -0
- data/includes/randomizer.rb +15 -0
- data/includes/spell_catalog.rb +441 -0
- data/includes/tables/armour.rb +13 -0
- data/includes/tables/chartype.rb +4412 -0
- data/includes/tables/chartype_new.rb +765 -0
- data/includes/tables/chartype_new_full.rb +2713 -0
- data/includes/tables/enc_specific.rb +168 -0
- data/includes/tables/enc_type.rb +17 -0
- data/includes/tables/encounters.rb +99 -0
- data/includes/tables/magick.rb +169 -0
- data/includes/tables/melee.rb +36 -0
- data/includes/tables/missile.rb +17 -0
- data/includes/tables/monster_stats_new.rb +264 -0
- data/includes/tables/month.rb +18 -0
- data/includes/tables/names.rb +21 -0
- data/includes/tables/personality.rb +12 -0
- data/includes/tables/race_templates.rb +318 -0
- data/includes/tables/religions.rb +266 -0
- data/includes/tables/spells_new.rb +496 -0
- data/includes/tables/tier_system.rb +104 -0
- data/includes/tables/town.rb +71 -0
- data/includes/tables/weather.rb +41 -0
- data/includes/town_relations.rb +127 -0
- data/includes/weather.rb +108 -0
- data/includes/weather2latex.rb +114 -0
- data/lib/rcurses.rb +33 -0
- metadata +157 -0
data/cli_enc_output.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# The CLI encounter output module for Amar Tools
|
2
|
+
|
3
|
+
def enc_output(anENC, cli)
|
4
|
+
|
5
|
+
e = anENC.encounter
|
6
|
+
|
7
|
+
# Start creating the output text
|
8
|
+
f = "############################<By Amar Tools>############################\n"
|
9
|
+
|
10
|
+
$Day == 1 ? f += "Day: " : f += "Night: "
|
11
|
+
case $Terrain
|
12
|
+
when 0
|
13
|
+
f += "City "
|
14
|
+
when 1
|
15
|
+
f += "Rural "
|
16
|
+
when 2
|
17
|
+
f += "Road "
|
18
|
+
when 3
|
19
|
+
f += "Plains "
|
20
|
+
when 4
|
21
|
+
f += "Hills "
|
22
|
+
when 5
|
23
|
+
f += "Mountains "
|
24
|
+
when 6
|
25
|
+
f += "Woods "
|
26
|
+
when 7
|
27
|
+
f += "Wilderness"
|
28
|
+
end
|
29
|
+
|
30
|
+
f += " (Level mod = " + $Level.to_s + ")"
|
31
|
+
f += "Created: #{Date.today.to_s}".rjust(38) + "\n\n"
|
32
|
+
|
33
|
+
if e[0]["string"] == "NO ENCOUNTER"
|
34
|
+
f += "\nNO ENCOUNTER\n\n"
|
35
|
+
else
|
36
|
+
f += anENC.enc_attitude
|
37
|
+
f += ":\n"
|
38
|
+
anENC.enc_number.times do |i|
|
39
|
+
f += " "
|
40
|
+
if e[i]["string"] =~ /animal/
|
41
|
+
e[i]["string"] += " (" + e[i]["sex"] + ")"
|
42
|
+
else
|
43
|
+
e[i]["string"] += " (#{e[i]["sex"]}, #{e[i]["name"]})" unless e[i]["string"] =~ /Event/
|
44
|
+
end
|
45
|
+
f += e[i]["string"]
|
46
|
+
if e[i]["string"] =~ /Event:/
|
47
|
+
f += "\n\n"
|
48
|
+
break
|
49
|
+
else
|
50
|
+
f += " [Lvl " + e[i]["level"].to_s + "]\n"
|
51
|
+
f += "".ljust(15)
|
52
|
+
f += " SIZ=" + e[i]["size"].to_s
|
53
|
+
f += " STR=" + e[i]["strength"].to_s
|
54
|
+
f += " END=" + e[i]["endurance"].to_s
|
55
|
+
f += " AWR=" + e[i]["awareness"].to_s
|
56
|
+
f += " MAG=" + e[i]["mag"].to_s
|
57
|
+
f += " RS=" + e[i]["reaction"].to_s
|
58
|
+
f += " Ddg=" + e[i]["dodge"].to_s
|
59
|
+
f += " (S:" + e[i]["status"].to_s + ")"
|
60
|
+
if e[i]["mag_lore"]
|
61
|
+
f += "\n".ljust(17) + e[i]["mag_type"] + " Lore=" + e[i]["mag_lore"].to_s
|
62
|
+
f += ", # of spells: " + e[i]["spells"].to_s
|
63
|
+
end
|
64
|
+
f += "\n"
|
65
|
+
|
66
|
+
f += " " + e[i]["wpn_name"].ljust(14) + "Skill=" + e[i]["wpn_skill"].to_s.rjust(2) + ", Ini:" + e[i]["wpn_ini"].to_s
|
67
|
+
f += ", Off:" + e[i]["wpn_off"].to_s.rjust(2) + ", Def:" + e[i]["wpn_def"].to_s.rjust(2) + ", Dam:" + e[i]["wpn_dam"].to_s.rjust(2)
|
68
|
+
f += " AP:" + e[i]["ap"].to_s + ", BP:" + e[i]["bp"].to_s + "\n"
|
69
|
+
|
70
|
+
if e[i]["msl_name"]
|
71
|
+
f += " " + e[i]["msl_name"].ljust(14) + "Skill=" + e[i]["msl_skill"].to_s.rjust(2) + ", Ini:" + e[i]["msl_ini"].to_s
|
72
|
+
f += ", Off:" + e[i]["msl_off"].to_s.rjust(2) + ", Dam:" + e[i]["msl_dam"].to_s.rjust(2) + ", Rng:" + e[i]["msl_rng"].to_s + "\n"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
f += "\n"
|
77
|
+
f += "\n" if e[0]["string"] =~ /Event/
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
f += "#######################################################################\n\n"
|
82
|
+
|
83
|
+
# Save text in file
|
84
|
+
save_temp_file(f, "encounter", cli)
|
85
|
+
system("#{$editor} saved/encounter.npc") if cli == "cli"
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,433 @@
|
|
1
|
+
# Encounter output module showing full 3-tier system format
|
2
|
+
require 'io/console'
|
3
|
+
|
4
|
+
# Try to load string_extensions for color support
|
5
|
+
begin
|
6
|
+
require 'string_extensions'
|
7
|
+
rescue LoadError
|
8
|
+
# Define a fallback pure method if string_extensions is not available
|
9
|
+
class String
|
10
|
+
def pure
|
11
|
+
self.gsub(/\e\[[0-9;]*m/, '')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def enc_output_new(e, cli, custom_width = nil)
|
17
|
+
# Clear screen before output if direct CLI mode
|
18
|
+
if cli == "cli_direct"
|
19
|
+
system("clear") || system("cls")
|
20
|
+
end
|
21
|
+
|
22
|
+
f = ""
|
23
|
+
|
24
|
+
# Get terminal width or use default
|
25
|
+
if custom_width
|
26
|
+
width = custom_width
|
27
|
+
elsif cli == "cli_direct"
|
28
|
+
width = `tput cols`.to_i rescue 120
|
29
|
+
width = 120 if width < 120 # Minimum width
|
30
|
+
elsif cli == "cli"
|
31
|
+
# For TUI, use a narrower width that fits in the content pane
|
32
|
+
width = 80
|
33
|
+
else
|
34
|
+
width = 80
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define colors if terminal output
|
38
|
+
if cli == "cli"
|
39
|
+
# Colors for different elements
|
40
|
+
@header_color = "\e[1;36m" # Bright cyan
|
41
|
+
@char_color = "\e[1;33m" # Bright yellow
|
42
|
+
@attr_color = "\e[1;35m" # Bright magenta
|
43
|
+
@skill_color = "\e[0;37m" # White
|
44
|
+
@stat_color = "\e[1;32m" # Bright green
|
45
|
+
@special_color = "\e[38;5;202m" # Orange for special abilities
|
46
|
+
@name_color = "\e[38;5;111m" # Light blue for names
|
47
|
+
@gray = "\e[38;5;240m" # Gray for explanatory text
|
48
|
+
@reset = "\e[0m"
|
49
|
+
else
|
50
|
+
@header_color = @char_color = @attr_color = @skill_color = ""
|
51
|
+
@stat_color = @special_color = @name_color = @gray = @reset = ""
|
52
|
+
end
|
53
|
+
|
54
|
+
# Day/Night and Terrain
|
55
|
+
day_str = $Day == 1 ? "Day: " : "Night: "
|
56
|
+
terrain_str = case $Terrain
|
57
|
+
when 0 then "City "
|
58
|
+
when 1 then "Rural "
|
59
|
+
when 2 then "Road "
|
60
|
+
when 3 then "Plains "
|
61
|
+
when 4 then "Hills "
|
62
|
+
when 5 then "Mountains "
|
63
|
+
when 6 then "Woods "
|
64
|
+
when 7 then "Wilderness"
|
65
|
+
end
|
66
|
+
|
67
|
+
level_mod_str = "(Level mod = #{$Level || 0})"
|
68
|
+
require 'date'
|
69
|
+
date_str = "Created: #{Date.today.to_s}"
|
70
|
+
|
71
|
+
f += "#{day_str}#{terrain_str}#{level_mod_str}#{date_str.rjust(width - day_str.length - terrain_str.length - level_mod_str.length)}\n"
|
72
|
+
f += "─" * width + "\n"
|
73
|
+
|
74
|
+
# Check for no encounter
|
75
|
+
if e.is_no_encounter?
|
76
|
+
f += "\n#{@desc_color}NO ENCOUNTER#{@reset}\n\n"
|
77
|
+
else
|
78
|
+
# Show attitude and summary with color based on attitude
|
79
|
+
attitude_color = case e.enc_attitude
|
80
|
+
when "HOSTILE" then "\e[1;31m" # Red
|
81
|
+
when "ANTAGONISTIC" then "\e[38;5;208m" # Orange
|
82
|
+
when "NEUTRAL" then "\e[1;37m" # White
|
83
|
+
when "POSITIVE" then "\e[1;32m" # Green
|
84
|
+
when "FRIENDLY" then "\e[1;36m" # Cyan
|
85
|
+
else "\e[0;37m"
|
86
|
+
end if cli == "cli"
|
87
|
+
attitude_color ||= ""
|
88
|
+
|
89
|
+
# Use color 229 for the encounter line
|
90
|
+
f += "\e[38;5;229m#{e.enc_attitude}: #{e.summary}#{@reset}\n" if cli == "cli"
|
91
|
+
f += "#{e.enc_attitude}: #{e.summary}\n" unless cli == "cli"
|
92
|
+
f += "─" * width + "\n"
|
93
|
+
|
94
|
+
# List all NPCs in the encounter with 3-tier format
|
95
|
+
e.encounter.each_with_index do |enc_data, index|
|
96
|
+
break if enc_data["string"] =~ /Event:/
|
97
|
+
|
98
|
+
npc = enc_data["npc"]
|
99
|
+
next unless npc
|
100
|
+
|
101
|
+
# NPC header with color
|
102
|
+
name_str = npc.name.empty? ? enc_data["string"] : npc.name
|
103
|
+
type_str = npc.respond_to?(:type) ? npc.type : "Unknown"
|
104
|
+
age_str = npc.respond_to?(:age) ? npc.age : "Unknown"
|
105
|
+
f += "\n#{@name_color}#{index + 1}. #{name_str} (#{npc.sex}, #{age_str}) - #{type_str} [Level #{npc.level}]#{@reset}\n"
|
106
|
+
f += " " + "─" * (width - 10) + "\n"
|
107
|
+
|
108
|
+
# Show 3-tier stats in reorganized format
|
109
|
+
if npc.respond_to?(:tiers) && npc.tiers
|
110
|
+
body = npc.get_characteristic("BODY")
|
111
|
+
mind = npc.get_characteristic("MIND")
|
112
|
+
spirit = npc.get_characteristic("SPIRIT")
|
113
|
+
|
114
|
+
# Get all key stats
|
115
|
+
str_attr = npc.get_attribute("BODY", "Strength")
|
116
|
+
end_attr = npc.get_attribute("BODY", "Endurance")
|
117
|
+
awareness_attr = npc.get_attribute("MIND", "Awareness")
|
118
|
+
reaction_speed = mind + awareness_attr + npc.get_skill("MIND", "Awareness", "Reaction speed")
|
119
|
+
|
120
|
+
# Calculate derived values
|
121
|
+
bp_value = npc.BP.respond_to?(:round) ? npc.BP.round : npc.BP.to_i
|
122
|
+
db_value = npc.DB.respond_to?(:round) ? npc.DB.round : npc.DB.to_i
|
123
|
+
md_value = npc.MD.respond_to?(:round) ? npc.MD.round : npc.MD.to_i
|
124
|
+
|
125
|
+
# Line 1: SIZE, Characteristics and key attributes
|
126
|
+
# Format SIZE for display
|
127
|
+
size_display = npc.SIZE % 1 == 0.5 ? "#{npc.SIZE.floor}½" : npc.SIZE.to_s
|
128
|
+
f += " SIZE:#{size_display} BODY:#{body} Str:#{body + str_attr} End:#{body + end_attr}"
|
129
|
+
f += " | MIND:#{mind} Awr:#{mind + awareness_attr} RS:#{reaction_speed}"
|
130
|
+
if spirit > 0
|
131
|
+
f += " | SPIRIT:#{spirit}"
|
132
|
+
end
|
133
|
+
f += "\n"
|
134
|
+
|
135
|
+
# Line 2: Derived stats and armor with combat totals (highlight BP/DB/MD/Reaction/Dodge)
|
136
|
+
dodge_total = npc.get_skill_total("BODY", "Athletics", "Dodge") rescue 0
|
137
|
+
reaction_total = npc.get_skill_total("BODY", "Athletics", "Reaction Speed") rescue 0
|
138
|
+
|
139
|
+
f += " #{@skill_color}BP:#{@reset}#{@stat_color}#{bp_value}#{@reset} #{@skill_color}DB:#{@reset}#{@stat_color}#{db_value}#{@reset} #{@skill_color}MD:#{@reset}#{@stat_color}#{md_value}#{@reset} #{@skill_color}Reaction:#{@reset}#{@stat_color}#{reaction_total}#{@reset} #{@skill_color}Dodge:#{@reset}#{@stat_color}#{dodge_total}#{@reset}"
|
140
|
+
if npc.armor
|
141
|
+
f += " Armor:#{npc.armor[:name]}(#{npc.armor[:ap]})"
|
142
|
+
end
|
143
|
+
|
144
|
+
# Calculate dodge bonus for defense
|
145
|
+
athletics_attr = npc.get_attribute("BODY", "Athletics")
|
146
|
+
dodge = npc.get_skill("BODY", "Athletics", "Dodge")
|
147
|
+
dodge_total = body + athletics_attr + dodge
|
148
|
+
dodge_bonus = (dodge_total / 5).to_i
|
149
|
+
|
150
|
+
# Line 3: Skills and spells
|
151
|
+
hide = npc.get_skill("BODY", "Athletics", "Hide")
|
152
|
+
move_quietly = npc.get_skill("BODY", "Athletics", "Move Quietly")
|
153
|
+
alertness = npc.get_skill("MIND", "Awareness", "Alertness")
|
154
|
+
|
155
|
+
hide_total = body + athletics_attr + hide
|
156
|
+
move_total = body + athletics_attr + move_quietly
|
157
|
+
alertness_total = mind + awareness_attr + alertness
|
158
|
+
|
159
|
+
f += " Skills: #{@skill_color}Dodge:#{@reset}#{@stat_color}#{dodge_total}#{@reset} #{@skill_color}Hide:#{@reset}#{@stat_color}#{hide_total}#{@reset} #{@skill_color}MoveQ:#{@reset}#{@stat_color}#{move_total}#{@reset} #{@skill_color}Alert:#{@reset}#{@stat_color}#{alertness_total}#{@reset}"
|
160
|
+
|
161
|
+
# Add tracking if non-zero
|
162
|
+
tracking = npc.get_skill("MIND", "Awareness", "Tracking")
|
163
|
+
if tracking > 0
|
164
|
+
tracking_total = mind + awareness_attr + tracking
|
165
|
+
f += " #{@skill_color}Track:#{@reset}#{@stat_color}#{tracking_total}#{@reset}"
|
166
|
+
end
|
167
|
+
|
168
|
+
# Show spells if any
|
169
|
+
if npc.respond_to?(:spells) && npc.spells && npc.spells.length > 0
|
170
|
+
spell_names = npc.spells.take(2).map{|s| s['name']}.join(', ')
|
171
|
+
f += " Spells(#{npc.spells.length}): #{spell_names}#{'...' if npc.spells.length > 2}"
|
172
|
+
end
|
173
|
+
f += "\n"
|
174
|
+
|
175
|
+
# Line 4 & 5: Weapons (melee and missile on separate lines)
|
176
|
+
melee_weapons = []
|
177
|
+
missile_weapons = []
|
178
|
+
|
179
|
+
# Melee combat - use ORIGINAL weapon names with NEW skill calculations
|
180
|
+
if npc.respond_to?(:melee1) && npc.melee1 && !npc.melee1.strip.empty?
|
181
|
+
weapon_name = npc.melee1.strip
|
182
|
+
skill = npc.melee1s || 0
|
183
|
+
ini = npc.melee1i || 0
|
184
|
+
off = npc.melee1o || 0
|
185
|
+
def_val = npc.melee1d || 0
|
186
|
+
dmg = npc.melee1dam || 0
|
187
|
+
|
188
|
+
melee_weapons << "#{weapon_name} (#{skill}) I:#{ini} #{@stat_color}O:#{off}#{@reset} #{@stat_color}D:#{def_val}#{@reset} #{@stat_color}d:#{dmg}#{@reset}"
|
189
|
+
end
|
190
|
+
|
191
|
+
if npc.respond_to?(:melee2) && npc.melee2 && !npc.melee2.strip.empty?
|
192
|
+
weapon_name = npc.melee2.strip
|
193
|
+
skill = npc.melee2s || 0
|
194
|
+
ini = npc.melee2i || 0
|
195
|
+
off = npc.melee2o || 0
|
196
|
+
def_val = npc.melee2d || 0
|
197
|
+
dmg = npc.melee2dam || 0
|
198
|
+
|
199
|
+
melee_weapons << "#{weapon_name} (#{skill}) I:#{ini} #{@stat_color}O:#{off}#{@reset} #{@stat_color}D:#{def_val}#{@reset} #{@stat_color}d:#{dmg}#{@reset}"
|
200
|
+
end
|
201
|
+
|
202
|
+
# Missile combat - use ORIGINAL weapon names
|
203
|
+
if npc.respond_to?(:missile) && npc.missile && !npc.missile.strip.empty?
|
204
|
+
weapon_name = npc.missile.strip
|
205
|
+
skill = npc.missiles || 0
|
206
|
+
off = npc.missileo || 0
|
207
|
+
dmg = npc.missiledam || 0
|
208
|
+
range = npc.missilerange ? "#{npc.missilerange}m" : "30m"
|
209
|
+
|
210
|
+
missile_weapons << "#{weapon_name} (#{skill}) O:#{off} R:#{range} #{@stat_color}d:#{dmg}#{@reset}"
|
211
|
+
end
|
212
|
+
|
213
|
+
# Display weapons
|
214
|
+
if melee_weapons.any?
|
215
|
+
f += " Weapons: #{melee_weapons.join(' | ')}\n"
|
216
|
+
end
|
217
|
+
if missile_weapons.any?
|
218
|
+
f += " Missile: #{missile_weapons.join(' | ')}"
|
219
|
+
# Add spell lore info on same line as missile if applicable
|
220
|
+
if npc.respond_to?(:spells) && npc.spells && npc.spells.length > 0
|
221
|
+
domain = nil
|
222
|
+
domain_skill = 0
|
223
|
+
|
224
|
+
if npc.tiers["SPIRIT"] && npc.tiers["SPIRIT"]["Attunement"] && npc.tiers["SPIRIT"]["Attunement"]["skills"]
|
225
|
+
npc.tiers["SPIRIT"]["Attunement"]["skills"].each do |dom, val|
|
226
|
+
if val > domain_skill
|
227
|
+
domain = dom
|
228
|
+
domain_skill = val
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
if domain && domain_skill > 0
|
234
|
+
total_lore = spirit + npc.get_attribute("SPIRIT", "Attunement") + domain_skill
|
235
|
+
f += " | #{domain}Lore:#{total_lore}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
f += "\n"
|
239
|
+
elsif npc.respond_to?(:spells) && npc.spells && npc.spells.length > 0
|
240
|
+
# If no missile weapons but has spells, add lore info on its own line
|
241
|
+
domain = nil
|
242
|
+
domain_skill = 0
|
243
|
+
|
244
|
+
if npc.tiers["SPIRIT"] && npc.tiers["SPIRIT"]["Attunement"] && npc.tiers["SPIRIT"]["Attunement"]["skills"]
|
245
|
+
npc.tiers["SPIRIT"]["Attunement"]["skills"].each do |dom, val|
|
246
|
+
if val > domain_skill
|
247
|
+
domain = dom
|
248
|
+
domain_skill = val
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
if domain && domain_skill > 0
|
254
|
+
total_lore = spirit + npc.get_attribute("SPIRIT", "Attunement") + domain_skill
|
255
|
+
f += " MagicLore: #{domain}Lore:#{total_lore}\n"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Equipment and money for humanoids (not monsters)
|
261
|
+
if npc.respond_to?(:type) && !npc.type.to_s.match(/Monster:|Animal:|monster/i)
|
262
|
+
# Load equipment generation if not loaded
|
263
|
+
unless defined?(generate_npc_equipment)
|
264
|
+
load File.join($pgmdir, "includes/equipment_tables.rb")
|
265
|
+
end
|
266
|
+
|
267
|
+
# Generate equipment and money
|
268
|
+
equipment = generate_npc_equipment(npc.type, npc.level)
|
269
|
+
|
270
|
+
# Determine social status for money calculation
|
271
|
+
social_status = case npc.type
|
272
|
+
when /Noble/ then "N"
|
273
|
+
when /Merchant/ then "UC"
|
274
|
+
when /Priest/ then "MC"
|
275
|
+
when /Smith/, /Bard/ then "LMC"
|
276
|
+
else "LC"
|
277
|
+
end
|
278
|
+
|
279
|
+
money = generate_money(social_status, npc.level)
|
280
|
+
money_value = money.split(' ').first.to_i
|
281
|
+
|
282
|
+
# Compact money format
|
283
|
+
money_str = ""
|
284
|
+
if money_value >= 100
|
285
|
+
gp = money_value / 100
|
286
|
+
money_str += "#{gp}g"
|
287
|
+
end
|
288
|
+
if money_value >= 10
|
289
|
+
sp = (money_value % 100) / 10
|
290
|
+
money_str += "#{sp}s" if sp > 0
|
291
|
+
end
|
292
|
+
cp = money_value % 10
|
293
|
+
money_str += "#{cp}c" if cp > 0
|
294
|
+
|
295
|
+
# Shorten equipment list
|
296
|
+
equip_short = equipment.take(3).join(', ')
|
297
|
+
equip_short += "..." if equipment.length > 3
|
298
|
+
|
299
|
+
f += " #{@stat_color}Equip: #{equip_short} | $: #{money_str}#{@reset}\n"
|
300
|
+
end
|
301
|
+
|
302
|
+
# Special abilities for monsters (skip generic/unknown text)
|
303
|
+
if npc.respond_to?(:special_abilities) && npc.special_abilities &&
|
304
|
+
!npc.special_abilities.to_s.downcase.include?("unknown")
|
305
|
+
f += " Special: #{npc.special_abilities}\n"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
f += "\n" + ("═" * width) + "\n"
|
311
|
+
|
312
|
+
# Output handling
|
313
|
+
if cli == "cli_direct"
|
314
|
+
# Direct CLI mode - save and print
|
315
|
+
# Save clean version without ANSI codes for editing
|
316
|
+
File.write("saved/encounter_new.npc", f.pure, perm: 0644)
|
317
|
+
# Display version with colors
|
318
|
+
print f
|
319
|
+
|
320
|
+
if !e.is_no_encounter? && e.npcs.length > 0
|
321
|
+
# Loop to allow viewing multiple NPCs
|
322
|
+
loop do
|
323
|
+
# Option to view detailed NPC
|
324
|
+
puts "\nEnter NPC number (1-#{e.npcs.length}) for details, 'e' to edit, or press Enter to exit"
|
325
|
+
input = STDIN.gets.chomp
|
326
|
+
|
327
|
+
if input.match?(/^\d+$/) && input.to_i.between?(1, e.npcs.length)
|
328
|
+
# Load the NPC output module if not loaded
|
329
|
+
unless defined?(npc_output_new)
|
330
|
+
load File.join($pgmdir, "cli_npc_output_new.rb")
|
331
|
+
end
|
332
|
+
npc_output_new(e.get_npc(input.to_i - 1), "cli_direct")
|
333
|
+
|
334
|
+
# After viewing NPC, redisplay the encounter
|
335
|
+
system("clear") || system("cls")
|
336
|
+
print f
|
337
|
+
elsif input == "e"
|
338
|
+
# Use vim with settings to avoid binary file warnings
|
339
|
+
if $editor.include?("vim") || $editor.include?("vi")
|
340
|
+
system("#{$editor} -c 'set fileformat=unix' saved/encounter_new.npc")
|
341
|
+
else
|
342
|
+
system("#{$editor} saved/encounter_new.npc")
|
343
|
+
end
|
344
|
+
# Redisplay after editing
|
345
|
+
system("clear") || system("cls")
|
346
|
+
print f
|
347
|
+
else
|
348
|
+
# Exit the loop on any other key
|
349
|
+
break
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
return f
|
355
|
+
elsif cli == "cli"
|
356
|
+
# TUI mode - just return the colored string without printing
|
357
|
+
return f
|
358
|
+
else
|
359
|
+
# Plain mode - return without colors
|
360
|
+
return f
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# Get weapon stats from tables
|
365
|
+
def get_weapon_stats(weapon)
|
366
|
+
# Default values for weapons based on name patterns
|
367
|
+
case weapon.downcase
|
368
|
+
when /sword/
|
369
|
+
{ off: 0, def: 0, dmg: 1, ini: 0 }
|
370
|
+
when /dagger/, /knife/
|
371
|
+
{ off: 1, def: -1, dmg: -1, ini: 1 }
|
372
|
+
when /axe/
|
373
|
+
{ off: 0, def: -1, dmg: 2, ini: -1 }
|
374
|
+
when /spear/, /pike/
|
375
|
+
{ off: 0, def: 1, dmg: 0, ini: 0 }
|
376
|
+
when /mace/, /club/, /hammer/
|
377
|
+
{ off: -1, def: 0, dmg: 1, ini: -1 }
|
378
|
+
when /staff/, /quarterstaff/
|
379
|
+
{ off: 0, def: 2, dmg: -1, ini: 0 }
|
380
|
+
when /natural/, /claw/, /bite/, /tail/, /tusk/
|
381
|
+
{ off: 0, def: -2, dmg: 0, ini: 1 }
|
382
|
+
when /unarmed/
|
383
|
+
{ off: -2, def: -4, dmg: -4, ini: 2 }
|
384
|
+
when /grappl/
|
385
|
+
{ off: 0, def: 0, dmg: -2, ini: 0 }
|
386
|
+
else
|
387
|
+
{ off: 0, def: 0, dmg: 0, ini: 0 }
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def get_missile_stats(weapon)
|
392
|
+
# Default values for missile weapons
|
393
|
+
case weapon.downcase
|
394
|
+
when /longbow/
|
395
|
+
{ range: "150m", dmg: 1, sr: "1" }
|
396
|
+
when /bow/
|
397
|
+
{ range: "100m", dmg: 0, sr: "1" }
|
398
|
+
when /x-bow/, /crossbow/
|
399
|
+
{ range: "150m", dmg: 2, sr: "1/2" }
|
400
|
+
when /sling/
|
401
|
+
{ range: "50m", dmg: -1, sr: "1" }
|
402
|
+
when /throwing/, /javelin/
|
403
|
+
{ range: "30m", dmg: 0, sr: "1" }
|
404
|
+
when /blowgun/
|
405
|
+
{ range: "20m", dmg: -5, sr: "2" }
|
406
|
+
else
|
407
|
+
{ range: "30m", dmg: 0, sr: "1" }
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
# Missing function from npc_output_new.rb
|
412
|
+
def generate_money(status, level)
|
413
|
+
base = case status
|
414
|
+
when "N" then 100 * level # Noble
|
415
|
+
when "UC" then 50 * level # Upper Class
|
416
|
+
when "MC" then 30 * level # Middle Class
|
417
|
+
when "LMC" then 15 * level # Lower Middle Class
|
418
|
+
when "LC" then 8 * level # Lower Class
|
419
|
+
when "S" then 2 * level # Slave
|
420
|
+
else 10 * level
|
421
|
+
end
|
422
|
+
|
423
|
+
variance = rand(base / 2) - base / 4
|
424
|
+
total = base + variance
|
425
|
+
"#{total} silver"
|
426
|
+
end
|
427
|
+
|
428
|
+
# Keep the old compact format as an alternative
|
429
|
+
def enc_output_new_compact(e, cli)
|
430
|
+
# This would be the current enc_output_new function
|
431
|
+
# Keeping it for quick combat reference
|
432
|
+
enc_output_new(e, cli)
|
433
|
+
end
|