amar-rpg 2.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36fcd5d2e4b7db6ac279f1f301aff82718adb4d86dd29b9574c93104b4abe5e0
4
- data.tar.gz: c6d0940d54cb054f26dbd4f3f98e88ead1175dcaac640a9d72819e0d1bbaa1bf
3
+ metadata.gz: 536b86190b86f88e7cf0fbcb996b3777d763db1355cf7d00c5888ace8215cae5
4
+ data.tar.gz: 2e5b19fc161bc0075360119726e8ae7ff6afcdf845569400276e4015fea4b536
5
5
  SHA512:
6
- metadata.gz: 6fb4c2d0a34065cfc99ba6bda571522bb081d516dc34d2d6b90d170ac9484511cbf757c69a2b7aa3126a8d79ea798360cf1d56018d7dcbf0bcf87fdbd622310b
7
- data.tar.gz: 60bbe96c3c52e38cdf0a86abf5d093f131fea507e1c1aa9bd37c81a6cd84f62258540afa9f4b7563e49fa08283ce750ab8e1d5ce27ad0a3e364d7a77d74151f7
6
+ metadata.gz: 15600fb55d0b19e8b27cdde1714f33d94fb9a2129b41017241a158c3d4346a3b1418bcd6361905394c6b0daaca433b32395a65469ebbf0207ff37f3f73c23b57
7
+ data.tar.gz: ded060cb9604355162869df99af628daa0e51f4bba38178d092579ce9776e5807d3d488e11280f993db53fd1978e2132e59a1a6d46b3459db84ff61e6ddbc36f
data/amar-tui.rb CHANGED
@@ -60,7 +60,7 @@ require 'stringio' # For suppressing output
60
60
  require 'fcntl' # For non-blocking IO
61
61
 
62
62
  # GLOBAL VARS & CONSTANTS
63
- @version = "2.0.1"
63
+ @version = "2.1.0"
64
64
  $pgmdir = File.dirname(__FILE__) # Global for includes
65
65
 
66
66
  # Debug logging
@@ -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
- if n.respond_to?(:melee1) && !n.melee1.to_s.empty?
235
- # Display ORIGINAL weapon format
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
- # Fall back to 3-tier weapon display
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}WEAPONS:#{@reset}\n"
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
- melee_weapons.each do |weapon, skill|
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 # Include Dodge/5
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
- line = "#{weapon.ljust(15)} #{skill_total.to_s.rjust(3)} #{init.to_s.rjust(4)} #{off.to_s.rjust(3)} #{defense.to_s.rjust(3)} #{dmg.to_s.rjust(3)}"
315
- melee_lines << line
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
- missile_weapons.each do |weapon, skill|
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
- line = "#{weapon.ljust(15)} #{skill_total.to_s.rjust(3)} #{range.ljust(10)} #{dmg.to_s.rjust(3)}"
328
- missile_lines << line
329
- end
330
-
331
- # Balance weapon columns
332
- max_wpn_lines = [melee_lines.length, missile_lines.length].max
333
- melee_lines += [""] * (max_wpn_lines - melee_lines.length)
334
- missile_lines += [""] * (max_wpn_lines - missile_lines.length)
335
-
336
- max_wpn_lines.times do |i|
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
@@ -406,10 +406,22 @@ class NpcNew
406
406
  else 0.5
407
407
  end
408
408
 
409
- # Use square root for more realistic progression
410
- level = (base * Math.sqrt(npc_level + 1) * growth_rate).to_i
411
-
412
- # Add minimal variation ONLY if base > 0
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
- template["melee_weapons"].each do |weapon, skill_level|
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
@@ -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..10 then 1 # 1 spell for novices
373
- when 11..15 then 2 # 2 spells for competent
374
- when 16..20 then 3 # 3 spells for skilled
375
- when 21..25 then 4 # 4 spells for experts
376
- else 5 # 5 spells for masters
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.0.1
4
+ version: 2.1.0
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.0.1 has been installed!
126
+ AMAR RPG Tools v2.1.0 has been installed!
127
127
  ===========================================
128
128
 
129
129
  To start the application: