amar-tui 2.0.0 → 2.1.0
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 +4 -4
- data/README.md +7 -2
- data/amar-tui.rb +1 -1
- data/cli_npc_output_new.rb +44 -44
- data/includes/class_npc_new.rb +42 -8
- data/includes/spell_catalog.rb +12 -7
- metadata +9 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f7cb9713df0714bb8a88ac5df6a747a59d38e6662b3973fec420a433bdf102e
|
|
4
|
+
data.tar.gz: 45d1b65f5843cd246bc859e4401096eabb501e2d7afc627fa77e9fb824fac0e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 739c135e0766e52a4fbc11aa907607ade259d460a8f8fa8ff6c88521ec92645721e7c4988db001ad904a3303ec1fc79178aefc25b49ed123a28aa96f2fa1745a
|
|
7
|
+
data.tar.gz: cea4d789ae52ab397e5d4cff7a3ccf5856a77ed4e1415ae53d70bd4819514bab17edf2c971597c005a01d94f9e78bf56959b83e1573b24d7c65802546b4a8fbc
|
data/README.md
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
<img src="images/amarcover.jpg" align="left" width="150" height="150"> Welcome to the swiss army knife for the Amar Role-Playing Game (http://d6gaming.org).
|
|
9
9
|
|
|
10
|
+
## Version 2.0 Released!
|
|
11
|
+
|
|
12
|
+
Complete rewrite with both Terminal User Interface (TUI) and Web interface.
|
|
13
|
+
Install the gem with `gem install amar-tui` and run with `amar-tui`.
|
|
14
|
+
|
|
10
15
|
This program suite runs on any GNU/Linux system where the scripting
|
|
11
16
|
language Ruby is installed. Ruby is available as tar.gz, rpm packages or
|
|
12
17
|
deb-packages as needed for your specific Linux distribution. For more info
|
|
@@ -15,7 +20,7 @@ on Ruby, see http://www.ruby-lang.org.
|
|
|
15
20
|
This tool box for the Amar RPG is designed for generating random
|
|
16
21
|
or specific encounters and Non-Player Characters for the Amar RPG, random
|
|
17
22
|
settlements and relationship maps for inhabitants of villages/towns/cities
|
|
18
|
-
as well as random names for various races and for making Open Ended Dice Rolls.
|
|
23
|
+
as well as random names for various races and for making Open Ended Dice Rolls.
|
|
19
24
|
|
|
20
25
|
In order to make real use of this program, you should be running an Amar
|
|
21
26
|
game as the Game Master.
|
|
@@ -23,7 +28,7 @@ game as the Game Master.
|
|
|
23
28
|
For more info on the Amar RPG, game rules, adventures and more, see
|
|
24
29
|
http://www.d6gaming.org/.
|
|
25
30
|
|
|
26
|
-
For an online version of this program, go to
|
|
31
|
+
For an online version of this program, go to https://isene.com/amar3.html
|
|
27
32
|
|
|
28
33
|
## Requirements
|
|
29
34
|
GraphViz is a requirement for generating relationship maps for towns and
|
data/amar-tui.rb
CHANGED
data/cli_npc_output_new.rb
CHANGED
|
@@ -231,8 +231,9 @@ def npc_output_new(n, cli, custom_width = nil)
|
|
|
231
231
|
end
|
|
232
232
|
|
|
233
233
|
# Check if we have original weapon data and display it
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
# DISABLED: Old weapon format only shows 2-3 weapons, new format shows all skills
|
|
235
|
+
if false && n.respond_to?(:melee1) && !n.melee1.to_s.empty?
|
|
236
|
+
# Display ORIGINAL weapon format (DEPRECATED)
|
|
236
237
|
f += "─" * width + "\n"
|
|
237
238
|
f += "#{@weapon_color}WEAPON SKILL INI OFF DEF DAM HP RANGE#{@reset}\n"
|
|
238
239
|
|
|
@@ -273,68 +274,67 @@ def npc_output_new(n, cli, custom_width = nil)
|
|
|
273
274
|
f += "\n"
|
|
274
275
|
end
|
|
275
276
|
else
|
|
276
|
-
#
|
|
277
|
-
melee_weapons = n.tiers["BODY"]["Melee Combat"]["skills"].select { |_, v| v > 0 }
|
|
278
|
-
missile_weapons = n.tiers["BODY"]["Missile Combat"]["skills"].select { |_, v| v > 0 }
|
|
279
|
-
|
|
277
|
+
# 3-tier weapon display - show ALL weapon skills
|
|
278
|
+
melee_weapons = n.tiers["BODY"]["Melee Combat"]["skills"].select { |_, v| v > 0 } rescue {}
|
|
279
|
+
missile_weapons = n.tiers["BODY"]["Missile Combat"]["skills"].select { |_, v| v > 0 } rescue {}
|
|
280
|
+
|
|
280
281
|
if melee_weapons.any? || missile_weapons.any?
|
|
281
282
|
f += "─" * width + "\n"
|
|
282
|
-
f += "#{@weapon_color}
|
|
283
|
-
|
|
284
|
-
# Headers
|
|
285
|
-
melee_header = "Melee Weapon".ljust(15) + "Skill Init Off Def Damage"
|
|
286
|
-
missile_header = "Missile Weapon".ljust(15) + "Skill Range Damage"
|
|
287
|
-
f += "#{melee_header.ljust(60)} │ #{missile_header}\n"
|
|
288
|
-
f += "─" * 61 + "┼" + "─" * 58 + "\n"
|
|
289
|
-
|
|
290
|
-
# Format weapons with calculated totals
|
|
291
|
-
melee_lines = []
|
|
292
|
-
missile_lines = []
|
|
293
|
-
|
|
283
|
+
f += "#{@weapon_color}WEAPON SKILL INI OFF DEF DAM HP RANGE#{@reset}\n"
|
|
284
|
+
|
|
294
285
|
body_char = n.get_characteristic("BODY")
|
|
295
|
-
|
|
286
|
+
|
|
296
287
|
# Calculate Dodge bonus for defense (Dodge/5 rounded down)
|
|
297
288
|
dodge_total = n.get_skill_total("BODY", "Athletics", "Dodge") || 0
|
|
298
289
|
dodge_bonus = (dodge_total / 5).to_i
|
|
299
|
-
|
|
300
|
-
|
|
290
|
+
|
|
291
|
+
# Get reaction speed for initiative
|
|
292
|
+
reaction_speed = n.get_skill_total("MIND", "Awareness", "Reaction speed") || 0
|
|
293
|
+
|
|
294
|
+
# Display melee weapons
|
|
295
|
+
melee_weapons.sort_by { |_, skill| -skill }.each do |weapon, skill|
|
|
301
296
|
wpn_stats = get_weapon_stats(weapon)
|
|
302
297
|
attr = n.get_attribute("BODY", "Melee Combat") || 0
|
|
303
298
|
skill_total = body_char + attr + skill
|
|
304
|
-
|
|
305
|
-
# Calculate weapon totals with correct initiative formula
|
|
306
|
-
# Initiative = Weapon Init + Reaction Speed skill total
|
|
307
|
-
reaction_speed = n.get_skill_total("MIND", "Awareness", "Reaction speed") || 0
|
|
299
|
+
|
|
308
300
|
init = reaction_speed + (wpn_stats[:init] || 0)
|
|
309
301
|
off = skill_total + (wpn_stats[:off] || 0)
|
|
310
|
-
defense = skill_total + (wpn_stats[:def] || 0) + dodge_bonus
|
|
302
|
+
defense = skill_total + (wpn_stats[:def] || 0) + dodge_bonus
|
|
311
303
|
dmg_mod = wpn_stats[:dmg].to_s =~ /special/ ? 0 : (wpn_stats[:dmg].to_s.to_i || 0)
|
|
312
304
|
dmg = (n.DB || 0) + dmg_mod
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
305
|
+
hp = wpn_stats[:hp] || 0
|
|
306
|
+
|
|
307
|
+
f += "#{weapon.ljust(19)}"
|
|
308
|
+
f += "#{skill_total.to_s.ljust(9)}"
|
|
309
|
+
f += "#{init.to_s.ljust(8)}"
|
|
310
|
+
f += "#{off.to_s.ljust(7)}"
|
|
311
|
+
f += "#{defense.to_s.ljust(7)}"
|
|
312
|
+
f += "#{dmg.to_s.ljust(7)}"
|
|
313
|
+
f += "#{hp.to_s.ljust(6)}"
|
|
314
|
+
f += "\n"
|
|
316
315
|
end
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
|
|
317
|
+
# Display missile weapons
|
|
318
|
+
missile_weapons.sort_by { |_, skill| -skill }.each do |weapon, skill|
|
|
319
319
|
wpn_stats = get_missile_stats(weapon)
|
|
320
320
|
attr = n.get_attribute("BODY", "Missile Combat") || 0
|
|
321
321
|
skill_total = body_char + attr + skill
|
|
322
|
-
|
|
322
|
+
|
|
323
|
+
off = skill_total + (wpn_stats[:off] || 0)
|
|
323
324
|
range = wpn_stats[:range] || "30m"
|
|
324
325
|
dmg_mod = wpn_stats[:dmg].to_s =~ /special/ ? 0 : (wpn_stats[:dmg].to_s.to_i || 0)
|
|
325
326
|
dmg = (n.DB || 0) + dmg_mod
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
f += "#{melee_lines[i].ljust(60)} │ #{missile_lines[i]}\n"
|
|
327
|
+
hp = wpn_stats[:hp] || 0
|
|
328
|
+
|
|
329
|
+
f += "#{weapon.ljust(19)}"
|
|
330
|
+
f += "#{skill_total.to_s.ljust(9)}"
|
|
331
|
+
f += "#{' '.ljust(8)}" # No init for missile
|
|
332
|
+
f += "#{off.to_s.ljust(7)}"
|
|
333
|
+
f += "#{' '.ljust(7)}" # No def for missile
|
|
334
|
+
f += "#{dmg.to_s.ljust(7)}"
|
|
335
|
+
f += "#{hp.to_s.ljust(6)}"
|
|
336
|
+
f += "#{range}"
|
|
337
|
+
f += "\n"
|
|
338
338
|
end
|
|
339
339
|
end
|
|
340
340
|
end # Close the original/3-tier weapon display if/else block
|
data/includes/class_npc_new.rb
CHANGED
|
@@ -406,10 +406,22 @@ class NpcNew
|
|
|
406
406
|
else 0.5
|
|
407
407
|
end
|
|
408
408
|
|
|
409
|
-
# Use
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
409
|
+
# Use scaling that produces desired total skill progression
|
|
410
|
+
# Target totals: L1: 4-5, L2: 6-7, L3: 8-9, L4: 10-11, L5: 12-13, L6: 14+
|
|
411
|
+
# Typical warrior has BODY 1-2, Melee Combat 2-3, Weapon skill 2-3 at mid-levels
|
|
412
|
+
level_multiplier = case npc_level
|
|
413
|
+
when 1 then 0.7
|
|
414
|
+
when 2 then 0.95
|
|
415
|
+
when 3 then 1.2
|
|
416
|
+
when 4 then 1.45
|
|
417
|
+
when 5 then 1.7
|
|
418
|
+
when 6 then 1.95
|
|
419
|
+
else 2.2
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
level = (base * level_multiplier * growth_rate).to_i
|
|
423
|
+
|
|
424
|
+
# Add variation ONLY if base > 0
|
|
413
425
|
if base > 0
|
|
414
426
|
variation = rand(3) - 1 # -1, 0, or 1
|
|
415
427
|
level += variation
|
|
@@ -449,20 +461,42 @@ class NpcNew
|
|
|
449
461
|
end
|
|
450
462
|
|
|
451
463
|
def add_weapon_skills(template)
|
|
452
|
-
# Add melee weapon skills
|
|
464
|
+
# Add melee weapon skills with primary weapon specialization
|
|
453
465
|
if template["melee_weapons"]
|
|
454
466
|
@tiers["BODY"]["Melee Combat"]["skills"] ||= {}
|
|
455
|
-
|
|
467
|
+
|
|
468
|
+
# Find primary weapon (highest base value)
|
|
469
|
+
primary_weapon = template["melee_weapons"].max_by { |_, v| v }
|
|
470
|
+
|
|
471
|
+
template["melee_weapons"].each_with_index do |(weapon, skill_level), index|
|
|
456
472
|
base_level = calculate_tier_level(skill_level, @level, 0.6)
|
|
473
|
+
|
|
474
|
+
# Boost primary weapon by 1-2 points for specialization
|
|
475
|
+
if weapon == primary_weapon[0] && skill_level >= 4
|
|
476
|
+
boost = rand(2) + 1 # +1 or +2
|
|
477
|
+
base_level += boost
|
|
478
|
+
end
|
|
479
|
+
|
|
457
480
|
@tiers["BODY"]["Melee Combat"]["skills"][weapon] = base_level
|
|
458
481
|
end
|
|
459
482
|
end
|
|
460
|
-
|
|
483
|
+
|
|
461
484
|
# Add missile weapon skills
|
|
462
485
|
if template["missile_weapons"]
|
|
463
486
|
@tiers["BODY"]["Missile Combat"]["skills"] ||= {}
|
|
487
|
+
|
|
488
|
+
# Find primary missile weapon
|
|
489
|
+
primary_missile = template["missile_weapons"].max_by { |_, v| v }
|
|
490
|
+
|
|
464
491
|
template["missile_weapons"].each do |weapon, skill_level|
|
|
465
492
|
base_level = calculate_tier_level(skill_level, @level, 0.6)
|
|
493
|
+
|
|
494
|
+
# Boost primary missile weapon
|
|
495
|
+
if weapon == primary_missile[0] && skill_level >= 3
|
|
496
|
+
boost = rand(2) + 1 # +1 or +2
|
|
497
|
+
base_level += boost
|
|
498
|
+
end
|
|
499
|
+
|
|
466
500
|
@tiers["BODY"]["Missile Combat"]["skills"][weapon] = base_level
|
|
467
501
|
end
|
|
468
502
|
end
|
|
@@ -787,7 +821,7 @@ class NpcNew
|
|
|
787
821
|
get_skill_total("BODY", "Missile Combat", "Sling")
|
|
788
822
|
when /javelin/
|
|
789
823
|
get_skill_total("BODY", "Missile Combat", "Javelin")
|
|
790
|
-
when /rock|stone|throwing/
|
|
824
|
+
when /rock|stone|throwing|th\s|knife/
|
|
791
825
|
get_skill_total("BODY", "Missile Combat", "Throwing")
|
|
792
826
|
else
|
|
793
827
|
get_skill_total("BODY", "Missile Combat", "Bow") || 0
|
data/includes/spell_catalog.rb
CHANGED
|
@@ -369,11 +369,13 @@ def assign_spells_to_npc(npc)
|
|
|
369
369
|
|
|
370
370
|
max_spells = case magic_skill
|
|
371
371
|
when 0..5 then 0 # No spells for beginners
|
|
372
|
-
when 6..
|
|
373
|
-
when 11
|
|
374
|
-
when
|
|
375
|
-
when
|
|
376
|
-
|
|
372
|
+
when 6..8 then 2 # 2 spells for novices
|
|
373
|
+
when 9..11 then 4 # 4 spells for apprentices
|
|
374
|
+
when 12..14 then 6 # 6 spells for competent
|
|
375
|
+
when 15..17 then 8 # 8 spells for skilled
|
|
376
|
+
when 18..20 then 10 # 10 spells for experts
|
|
377
|
+
when 21..25 then 12 # 12 spells for masters
|
|
378
|
+
else 15 # 15 spells for legendary
|
|
377
379
|
end
|
|
378
380
|
|
|
379
381
|
# Get character's strongest magical domains
|
|
@@ -388,6 +390,7 @@ def assign_spells_to_npc(npc)
|
|
|
388
390
|
can_cast = true
|
|
389
391
|
spell_data[:skill_path].each do |skill_part|
|
|
390
392
|
# Simplified check - character should have some relevant skills
|
|
393
|
+
# Also check abbreviated names (e.g., "Prot." for "Protection")
|
|
391
394
|
case skill_part
|
|
392
395
|
when "Fire" then can_cast &&= (all_magic_skills["Fire"] || 0) > 0
|
|
393
396
|
when "Water" then can_cast &&= (all_magic_skills["Water"] || 0) > 0
|
|
@@ -395,11 +398,13 @@ def assign_spells_to_npc(npc)
|
|
|
395
398
|
when "Earth" then can_cast &&= (all_magic_skills["Earth"] || 0) > 0
|
|
396
399
|
when "Mind" then can_cast &&= (all_magic_skills["Mind"] || 0) > 0
|
|
397
400
|
when "Nature" then can_cast &&= (all_magic_skills["Nature"] || 0) > 0
|
|
398
|
-
when "Protection" then can_cast &&= (all_magic_skills["Protection"] || 0) > 0
|
|
399
|
-
when "Illusion" then can_cast &&= (all_magic_skills["Illusion"] || 0) > 0
|
|
401
|
+
when "Protection" then can_cast &&= ((all_magic_skills["Protection"] || 0) > 0 || (all_magic_skills["Prot."] || 0) > 0)
|
|
402
|
+
when "Illusion" then can_cast &&= ((all_magic_skills["Illusion"] || 0) > 0 || (all_magic_skills["Ill."] || 0) > 0)
|
|
400
403
|
when "Shadow" then can_cast &&= (all_magic_skills["Shadow"] || 0) > 0
|
|
401
404
|
when "Self" then can_cast &&= (all_magic_skills["Self"] || 0) > 0
|
|
402
405
|
when "Life" then can_cast &&= (all_magic_skills["Life"] || 0) > 0
|
|
406
|
+
when "Time" then can_cast &&= (all_magic_skills["Time"] || 0) > 0
|
|
407
|
+
when "Death" then can_cast &&= (all_magic_skills["Death"] || 0) > 0
|
|
403
408
|
end
|
|
404
409
|
end
|
|
405
410
|
can_cast
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: amar-tui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: "."
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-10-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rcurses
|
|
@@ -122,9 +122,13 @@ metadata:
|
|
|
122
122
|
changelog_uri: https://github.com/isene/Amar-Tools/blob/master/README.md
|
|
123
123
|
post_install_message: |2+
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
AMAR Tools TUI v2.0 has been installed!
|
|
127
|
-
|
|
125
|
+
==========================================
|
|
126
|
+
AMAR Tools TUI v2.1.0 has been installed!
|
|
127
|
+
==========================================
|
|
128
|
+
|
|
129
|
+
NOTE: This gem has been renamed to 'amar-rpg'.
|
|
130
|
+
Please install 'amar-rpg' instead:
|
|
131
|
+
gem install amar-rpg
|
|
128
132
|
|
|
129
133
|
To start the TUI application:
|
|
130
134
|
amar-tui.rb
|