amar-rpg 2.0.1 → 2.1.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 +4 -4
- data/amar-tui.rb +1 -1
- data/cli_npc_output_new.rb +94 -53
- data/includes/class_npc_new.rb +135 -7
- data/includes/spell_catalog.rb +12 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58d7a7e1e8688949f6e0beed811aeab31928d09cd6a2c7b602aba9706b617b5d
|
4
|
+
data.tar.gz: 776ed77dce45af1ab2d8eb412beebf733e7ba509738c8b7328fe048e32227913
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc917d0a80ff2b84a2aa2a87196609fc880aeca6f9f267b60492e523c41860bc529af1d73885942c7030c4fed07eb7869dcce7c4a4fd6cf76764babdbd05c1de
|
7
|
+
data.tar.gz: c5e7639280c0aa684396b6b669ff0a5d5d0301b16b6c0408f3a3bb2b7409fbb2d0e7eebe0471679cb643d7c3f404bacf78610e854a67ed374356d7bb444e400b
|
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,108 @@ 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 with actual weapon names
|
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
|
+
actual_melee = n.tiers["BODY"]["Melee Combat"]["actual_weapons"] rescue {}
|
281
|
+
actual_missile = n.tiers["BODY"]["Missile Combat"]["actual_weapons"] rescue {}
|
282
|
+
|
280
283
|
if melee_weapons.any? || missile_weapons.any?
|
284
|
+
# Load weapon tables for stats lookup
|
285
|
+
unless defined?($Melee)
|
286
|
+
load File.join($pgmdir, "includes/tables/melee.rb")
|
287
|
+
end
|
288
|
+
unless defined?($Missile)
|
289
|
+
load File.join($pgmdir, "includes/tables/missile.rb")
|
290
|
+
end
|
291
|
+
|
281
292
|
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
|
-
|
293
|
+
f += "#{@weapon_color}WEAPON SKILL INI OFF DEF DAM HP RANGE#{@reset}\n"
|
294
|
+
|
294
295
|
body_char = n.get_characteristic("BODY")
|
295
|
-
|
296
|
+
|
296
297
|
# Calculate Dodge bonus for defense (Dodge/5 rounded down)
|
297
298
|
dodge_total = n.get_skill_total("BODY", "Athletics", "Dodge") || 0
|
298
299
|
dodge_bonus = (dodge_total / 5).to_i
|
299
|
-
|
300
|
-
|
301
|
-
|
300
|
+
|
301
|
+
# Get reaction speed for initiative
|
302
|
+
reaction_speed = n.get_skill_total("MIND", "Awareness", "Reaction speed") || 0
|
303
|
+
|
304
|
+
# Display melee weapons
|
305
|
+
melee_weapons.sort_by { |_, skill| -skill }.each do |weapon_skill, skill|
|
306
|
+
# Get actual weapon name
|
307
|
+
actual_weapon_name = actual_melee[weapon_skill] || weapon_skill
|
308
|
+
|
309
|
+
# Find weapon in $Melee table
|
310
|
+
weapon_data = $Melee.find { |w| w && w[0] && w[0].strip == actual_weapon_name.strip }
|
311
|
+
|
302
312
|
attr = n.get_attribute("BODY", "Melee Combat") || 0
|
303
313
|
skill_total = body_char + attr + skill
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
314
|
+
|
315
|
+
if weapon_data
|
316
|
+
# Use actual weapon stats from table: [Name, Type, Str, Dam, Init, Off, Def, HP, Wt]
|
317
|
+
init = reaction_speed + weapon_data[4]
|
318
|
+
off = skill_total + weapon_data[5]
|
319
|
+
defense = skill_total + weapon_data[6] + dodge_bonus
|
320
|
+
dmg = (n.DB || 0) + weapon_data[3]
|
321
|
+
hp = weapon_data[7]
|
322
|
+
else
|
323
|
+
# Fallback to pattern matching
|
324
|
+
wpn_stats = get_weapon_stats(actual_weapon_name)
|
325
|
+
init = reaction_speed + (wpn_stats[:init] || 0)
|
326
|
+
off = skill_total + (wpn_stats[:off] || 0)
|
327
|
+
defense = skill_total + (wpn_stats[:def] || 0) + dodge_bonus
|
328
|
+
dmg_mod = wpn_stats[:dmg].to_s =~ /special/ ? 0 : (wpn_stats[:dmg].to_s.to_i || 0)
|
329
|
+
dmg = (n.DB || 0) + dmg_mod
|
330
|
+
hp = wpn_stats[:hp] || 0
|
331
|
+
end
|
332
|
+
|
333
|
+
f += "#{actual_weapon_name.ljust(19)}"
|
334
|
+
f += "#{skill_total.to_s.ljust(9)}"
|
335
|
+
f += "#{init.to_s.ljust(8)}"
|
336
|
+
f += "#{off.to_s.ljust(7)}"
|
337
|
+
f += "#{defense.to_s.ljust(7)}"
|
338
|
+
f += "#{dmg.to_s.ljust(7)}"
|
339
|
+
f += "#{hp.to_s.ljust(6)}"
|
340
|
+
f += "\n"
|
316
341
|
end
|
317
|
-
|
318
|
-
|
319
|
-
|
342
|
+
|
343
|
+
# Display missile weapons
|
344
|
+
missile_weapons.sort_by { |_, skill| -skill }.each do |weapon_skill, skill|
|
345
|
+
# Get actual weapon name
|
346
|
+
actual_weapon_name = actual_missile[weapon_skill] || weapon_skill
|
347
|
+
|
348
|
+
# Find weapon in $Missile table
|
349
|
+
weapon_data = $Missile.find { |w| w && w[0] && w[0].strip == actual_weapon_name.strip }
|
350
|
+
|
320
351
|
attr = n.get_attribute("BODY", "Missile Combat") || 0
|
321
352
|
skill_total = body_char + attr + skill
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
353
|
+
|
354
|
+
if weapon_data
|
355
|
+
# Use actual weapon stats from table: [Name, Type, Str, Dam, Off, Rng, Max, Init, Wt]
|
356
|
+
off = skill_total + weapon_data[4]
|
357
|
+
dmg = (n.DB || 0) + weapon_data[3]
|
358
|
+
range = "#{weapon_data[5]}m"
|
359
|
+
hp = weapon_data[7]
|
360
|
+
else
|
361
|
+
# Fallback to pattern matching
|
362
|
+
wpn_stats = get_missile_stats(actual_weapon_name)
|
363
|
+
off = skill_total + (wpn_stats[:off] || 0)
|
364
|
+
range = wpn_stats[:range] || "30m"
|
365
|
+
dmg_mod = wpn_stats[:dmg].to_s =~ /special/ ? 0 : (wpn_stats[:dmg].to_s.to_i || 0)
|
366
|
+
dmg = (n.DB || 0) + dmg_mod
|
367
|
+
hp = wpn_stats[:hp] || 0
|
368
|
+
end
|
369
|
+
|
370
|
+
f += "#{actual_weapon_name.ljust(19)}"
|
371
|
+
f += "#{skill_total.to_s.ljust(9)}"
|
372
|
+
f += "#{' '.ljust(8)}" # No init for missile
|
373
|
+
f += "#{off.to_s.ljust(7)}"
|
374
|
+
f += "#{' '.ljust(7)}" # No def for missile
|
375
|
+
f += "#{dmg.to_s.ljust(7)}"
|
376
|
+
f += "#{hp.to_s.ljust(6)}"
|
377
|
+
f += "#{range}"
|
378
|
+
f += "\n"
|
338
379
|
end
|
339
380
|
end
|
340
381
|
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
|
@@ -448,22 +460,138 @@ class NpcNew
|
|
448
460
|
level
|
449
461
|
end
|
450
462
|
|
463
|
+
def select_actual_weapon(skill_name, strength_total, is_missile = false)
|
464
|
+
# Map skill name to actual weapon from $Melee or $Missile table
|
465
|
+
# Load weapon tables if needed
|
466
|
+
unless defined?($Melee)
|
467
|
+
load File.join($pgmdir, "includes/tables/melee.rb")
|
468
|
+
end
|
469
|
+
unless defined?($Missile)
|
470
|
+
load File.join($pgmdir, "includes/tables/missile.rb")
|
471
|
+
end
|
472
|
+
|
473
|
+
if is_missile
|
474
|
+
# Map missile skill names to actual weapons
|
475
|
+
case skill_name.downcase
|
476
|
+
when /bow/
|
477
|
+
# Select bow based on strength: L(2), M(4), H(6), H2(8), H3(10)
|
478
|
+
if strength_total >= 10
|
479
|
+
"Bow(H3) [1]"
|
480
|
+
elsif strength_total >= 8
|
481
|
+
"Bow(H2) [1]"
|
482
|
+
elsif strength_total >= 6
|
483
|
+
"Bow(H) [1]"
|
484
|
+
elsif strength_total >= 4
|
485
|
+
"Bow(M) [1]"
|
486
|
+
else
|
487
|
+
"Bow(L) [1]"
|
488
|
+
end
|
489
|
+
when /crossbow|x-bow/
|
490
|
+
# Select crossbow based on strength
|
491
|
+
if strength_total >= 4
|
492
|
+
"X-bow(H) [¼]"
|
493
|
+
elsif strength_total >= 3
|
494
|
+
"X-bow(M) [⅓]"
|
495
|
+
else
|
496
|
+
"X-bow(L) [½]"
|
497
|
+
end
|
498
|
+
when /throwing|knife/
|
499
|
+
"Th Knife [2]"
|
500
|
+
when /javelin/
|
501
|
+
"Javelin [1]"
|
502
|
+
when /sling/
|
503
|
+
"Sling [1]"
|
504
|
+
when /net/
|
505
|
+
skill_name # Net is just "Net"
|
506
|
+
when /spear/
|
507
|
+
"Javelin [1]" # Thrown spear = javelin
|
508
|
+
else
|
509
|
+
"Rock [2]" # Default
|
510
|
+
end
|
511
|
+
else
|
512
|
+
# Map melee skill names to actual weapons from $Melee table
|
513
|
+
case skill_name.downcase
|
514
|
+
when /sword/
|
515
|
+
strength_total >= 4 ? "Longsword" : "Short sword"
|
516
|
+
when /axe/
|
517
|
+
strength_total >= 4 ? "B. axe 2H" : "Hatchet"
|
518
|
+
when /spear/
|
519
|
+
strength_total >= 4 ? "Spear 2H" : "Spear"
|
520
|
+
when /mace/
|
521
|
+
strength_total >= 4 ? "H. mace 2H" : "Light mace"
|
522
|
+
when /dagger|knife/
|
523
|
+
"Knife"
|
524
|
+
when /staff/
|
525
|
+
"Staff"
|
526
|
+
when /club/
|
527
|
+
"Club"
|
528
|
+
when /net/
|
529
|
+
"Net"
|
530
|
+
when /shield/
|
531
|
+
"Buckler"
|
532
|
+
when /unarmed/
|
533
|
+
"Unarmed"
|
534
|
+
else
|
535
|
+
skill_name # Return as-is if no match
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
451
540
|
def add_weapon_skills(template)
|
452
|
-
# Add melee weapon skills
|
541
|
+
# Add melee weapon skills with primary weapon specialization
|
542
|
+
# Also store actual weapon selections based on skill names
|
453
543
|
if template["melee_weapons"]
|
454
544
|
@tiers["BODY"]["Melee Combat"]["skills"] ||= {}
|
455
|
-
|
545
|
+
@tiers["BODY"]["Melee Combat"]["actual_weapons"] ||= {}
|
546
|
+
|
547
|
+
# Find primary weapon (highest base value)
|
548
|
+
primary_weapon = template["melee_weapons"].max_by { |_, v| v }
|
549
|
+
|
550
|
+
# Get strength total for weapon selection
|
551
|
+
strength_total = get_skill_total("BODY", "Strength", "Wield weapon") rescue 3
|
552
|
+
|
553
|
+
template["melee_weapons"].each_with_index do |(weapon, skill_level), index|
|
456
554
|
base_level = calculate_tier_level(skill_level, @level, 0.6)
|
555
|
+
|
556
|
+
# Boost primary weapon by 1-2 points for specialization
|
557
|
+
if weapon == primary_weapon[0] && skill_level >= 4
|
558
|
+
boost = rand(2) + 1 # +1 or +2
|
559
|
+
base_level += boost
|
560
|
+
end
|
561
|
+
|
457
562
|
@tiers["BODY"]["Melee Combat"]["skills"][weapon] = base_level
|
563
|
+
|
564
|
+
# Select actual weapon based on skill name and strength
|
565
|
+
actual_weapon = select_actual_weapon(weapon, strength_total, false)
|
566
|
+
@tiers["BODY"]["Melee Combat"]["actual_weapons"][weapon] = actual_weapon
|
458
567
|
end
|
459
568
|
end
|
460
|
-
|
569
|
+
|
461
570
|
# Add missile weapon skills
|
462
571
|
if template["missile_weapons"]
|
463
572
|
@tiers["BODY"]["Missile Combat"]["skills"] ||= {}
|
573
|
+
@tiers["BODY"]["Missile Combat"]["actual_weapons"] ||= {}
|
574
|
+
|
575
|
+
# Find primary missile weapon
|
576
|
+
primary_missile = template["missile_weapons"].max_by { |_, v| v }
|
577
|
+
|
578
|
+
# Get strength total for missile weapon selection
|
579
|
+
strength_total = get_skill_total("BODY", "Strength", "Wield weapon") rescue 3
|
580
|
+
|
464
581
|
template["missile_weapons"].each do |weapon, skill_level|
|
465
582
|
base_level = calculate_tier_level(skill_level, @level, 0.6)
|
583
|
+
|
584
|
+
# Boost primary missile weapon
|
585
|
+
if weapon == primary_missile[0] && skill_level >= 3
|
586
|
+
boost = rand(2) + 1 # +1 or +2
|
587
|
+
base_level += boost
|
588
|
+
end
|
589
|
+
|
466
590
|
@tiers["BODY"]["Missile Combat"]["skills"][weapon] = base_level
|
591
|
+
|
592
|
+
# Select actual weapon based on skill name and strength
|
593
|
+
actual_weapon = select_actual_weapon(weapon, strength_total, true)
|
594
|
+
@tiers["BODY"]["Missile Combat"]["actual_weapons"][weapon] = actual_weapon
|
467
595
|
end
|
468
596
|
end
|
469
597
|
|
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,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amar-rpg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geir Isene
|
@@ -123,7 +123,7 @@ metadata:
|
|
123
123
|
post_install_message: |2+
|
124
124
|
|
125
125
|
===========================================
|
126
|
-
AMAR RPG Tools v2.
|
126
|
+
AMAR RPG Tools v2.1.1 has been installed!
|
127
127
|
===========================================
|
128
128
|
|
129
129
|
To start the application:
|