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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +675 -0
  3. data/README.md +155 -0
  4. data/amar-tui.rb +8195 -0
  5. data/cli_enc_output.rb +87 -0
  6. data/cli_enc_output_new.rb +433 -0
  7. data/cli_enc_output_new_3tier.rb +198 -0
  8. data/cli_enc_output_new_compact.rb +238 -0
  9. data/cli_name_gen.rb +21 -0
  10. data/cli_npc_output.rb +279 -0
  11. data/cli_npc_output_new.rb +700 -0
  12. data/cli_town_output.rb +39 -0
  13. data/cli_weather_output.rb +36 -0
  14. data/includes/class_enc.rb +341 -0
  15. data/includes/class_enc_new.rb +512 -0
  16. data/includes/class_monster_new.rb +551 -0
  17. data/includes/class_npc.rb +1378 -0
  18. data/includes/class_npc_new.rb +1187 -0
  19. data/includes/class_npc_new.rb.backup +706 -0
  20. data/includes/class_npc_new_skills.rb +153 -0
  21. data/includes/class_town.rb +237 -0
  22. data/includes/d6s.rb +40 -0
  23. data/includes/equipment_tables.rb +120 -0
  24. data/includes/functions.rb +67 -0
  25. data/includes/includes.rb +30 -0
  26. data/includes/randomizer.rb +15 -0
  27. data/includes/spell_catalog.rb +441 -0
  28. data/includes/tables/armour.rb +13 -0
  29. data/includes/tables/chartype.rb +4412 -0
  30. data/includes/tables/chartype_new.rb +765 -0
  31. data/includes/tables/chartype_new_full.rb +2713 -0
  32. data/includes/tables/enc_specific.rb +168 -0
  33. data/includes/tables/enc_type.rb +17 -0
  34. data/includes/tables/encounters.rb +99 -0
  35. data/includes/tables/magick.rb +169 -0
  36. data/includes/tables/melee.rb +36 -0
  37. data/includes/tables/missile.rb +17 -0
  38. data/includes/tables/monster_stats_new.rb +264 -0
  39. data/includes/tables/month.rb +18 -0
  40. data/includes/tables/names.rb +21 -0
  41. data/includes/tables/personality.rb +12 -0
  42. data/includes/tables/race_templates.rb +318 -0
  43. data/includes/tables/religions.rb +266 -0
  44. data/includes/tables/spells_new.rb +496 -0
  45. data/includes/tables/tier_system.rb +104 -0
  46. data/includes/tables/town.rb +71 -0
  47. data/includes/tables/weather.rb +41 -0
  48. data/includes/town_relations.rb +127 -0
  49. data/includes/weather.rb +108 -0
  50. data/includes/weather2latex.rb +114 -0
  51. data/lib/rcurses.rb +33 -0
  52. metadata +157 -0
@@ -0,0 +1,153 @@
1
+ # Improved skill generation for experienced NPCs
2
+ def add_experience_skills
3
+ # Add additional skills for experienced characters
4
+ experience_bonus = @level - 3 # 1 for level 4, 2 for level 5, etc.
5
+
6
+ # Significantly expand skill generation based on level
7
+ skill_count = case @level
8
+ when 4 then rand(8..12)
9
+ when 5 then rand(12..18)
10
+ when 6 then rand(18..25)
11
+ else rand(20..30)
12
+ end
13
+
14
+ skills_added = 0
15
+
16
+ # Build skill pool based on actual tier system
17
+ skill_pool = []
18
+
19
+ # BODY skills
20
+ skill_pool += [
21
+ ["BODY", "Athletics", "Hide", rand(2..3) + experience_bonus],
22
+ ["BODY", "Athletics", "Move Quietly", rand(2..3) + experience_bonus],
23
+ ["BODY", "Athletics", "Climb", rand(1..3) + experience_bonus],
24
+ ["BODY", "Athletics", "Swim", rand(1..3) + experience_bonus],
25
+ ["BODY", "Athletics", "Ride", rand(1..2) + experience_bonus],
26
+ ["BODY", "Athletics", "Jump", rand(1..2) + experience_bonus],
27
+ ["BODY", "Athletics", "Balance", rand(2..3) + experience_bonus],
28
+ ["BODY", "Endurance", "Running", rand(2..3) + experience_bonus],
29
+ ["BODY", "Endurance", "Combat Tenacity", rand(1..3) + experience_bonus],
30
+ ["BODY", "Sleight", "Pick pockets", rand(1..2) + experience_bonus],
31
+ ["BODY", "Sleight", "Disarm Traps", rand(1..2) + experience_bonus]
32
+ ]
33
+
34
+ # MIND skills
35
+ skill_pool += [
36
+ ["MIND", "Awareness", "Tracking", rand(2..3) + experience_bonus],
37
+ ["MIND", "Awareness", "Detect Traps", rand(1..2) + experience_bonus],
38
+ ["MIND", "Awareness", "Sense Emotions", rand(1..2) + experience_bonus],
39
+ ["MIND", "Awareness", "Sense of Direction", rand(2..3) + experience_bonus],
40
+ ["MIND", "Awareness", "Listening", rand(2..3) + experience_bonus],
41
+ ["MIND", "Social Knowledge", "Social lore", rand(2..3) + experience_bonus],
42
+ ["MIND", "Social Knowledge", "Spoken Language", rand(1..3) + experience_bonus],
43
+ ["MIND", "Social Knowledge", "Literacy", rand(1..3) + experience_bonus],
44
+ ["MIND", "Nature Knowledge", "Medical lore", rand(1..2) + experience_bonus],
45
+ ["MIND", "Nature Knowledge", "Plant Lore", rand(1..2) + experience_bonus],
46
+ ["MIND", "Nature Knowledge", "Animal Lore", rand(1..2) + experience_bonus],
47
+ ["MIND", "Practical Knowledge", "Survival Lore", rand(2..3) + experience_bonus],
48
+ ["MIND", "Practical Knowledge", "Set traps", rand(1..2) + experience_bonus],
49
+ ["MIND", "Willpower", "Mental Fortitude", rand(2..3) + experience_bonus],
50
+ ["MIND", "Willpower", "Courage", rand(1..3) + experience_bonus]
51
+ ]
52
+
53
+ # Type-specific skills
54
+ if has_magic?
55
+ skill_pool += [
56
+ ["MIND", "Awareness", "Sense Magick", rand(3..4) + experience_bonus],
57
+ ["MIND", "Nature Knowledge", "Magick Rituals", rand(3..5) + experience_bonus],
58
+ ["MIND", "Social Knowledge", "Mythology", rand(2..3) + experience_bonus],
59
+ ["MIND", "Social Knowledge", "Legend Lore", rand(2..3) + experience_bonus],
60
+ ["SPIRIT", "Casting", "Range", rand(2..4) + experience_bonus],
61
+ ["SPIRIT", "Casting", "Duration", rand(2..4) + experience_bonus],
62
+ ["SPIRIT", "Casting", "Area of Effect", rand(1..3) + experience_bonus]
63
+ ]
64
+ end
65
+
66
+ # Physical combat types
67
+ if ["Warrior", "Guard", "Soldier", "Gladiator", "Body guard", "Ranger", "Hunter"].any? { |t| @type.include?(t) }
68
+ skill_pool += [
69
+ ["BODY", "Endurance", "Fortitude", rand(3..4) + experience_bonus],
70
+ ["BODY", "Endurance", "Combat Tenacity", rand(3..4) + experience_bonus],
71
+ ["MIND", "Practical Knowledge", "Ambush", rand(2..3) + experience_bonus],
72
+ ["MIND", "Awareness", "Sense Ambush", rand(2..3) + experience_bonus]
73
+ ]
74
+ end
75
+
76
+ # Scholarly types
77
+ if ["Scholar", "Sage", "Scribe", "Wizard", "Mage"].any? { |t| @type.include?(t) }
78
+ skill_pool += [
79
+ ["MIND", "Intelligence", "Innovation", rand(3..4) + experience_bonus],
80
+ ["MIND", "Intelligence", "Problem Solving", rand(3..4) + experience_bonus],
81
+ ["MIND", "Social Knowledge", "Literacy", rand(4..5) + experience_bonus],
82
+ ["MIND", "Nature Knowledge", "Alchemy", rand(2..3) + experience_bonus]
83
+ ]
84
+ end
85
+
86
+ # Rogueish types
87
+ if ["Thief", "Rogue", "Assassin", "Scout"].any? { |t| @type.include?(t) }
88
+ skill_pool += [
89
+ ["BODY", "Athletics", "Hide", rand(4..5) + experience_bonus],
90
+ ["BODY", "Athletics", "Move Quietly", rand(4..5) + experience_bonus],
91
+ ["BODY", "Sleight", "Pick pockets", rand(3..5) + experience_bonus],
92
+ ["BODY", "Sleight", "Disarm Traps", rand(3..4) + experience_bonus],
93
+ ["MIND", "Awareness", "Detect Traps", rand(3..4) + experience_bonus]
94
+ ]
95
+ end
96
+
97
+ # Now randomly select and add skills
98
+ skill_pool.shuffle!
99
+
100
+ skill_pool.each do |char_name, attr_name, skill_name, value|
101
+ break if skills_added >= skill_count
102
+
103
+ # Ensure the tier structure exists
104
+ next unless @tiers[char_name] && @tiers[char_name][attr_name]
105
+
106
+ # Initialize skills hash if needed
107
+ @tiers[char_name][attr_name]["skills"] ||= {}
108
+
109
+ # Convert array to hash if needed
110
+ if @tiers[char_name][attr_name]["skills"].is_a?(Array)
111
+ skill_list = @tiers[char_name][attr_name]["skills"]
112
+ @tiers[char_name][attr_name]["skills"] = {}
113
+ skill_list.each { |s| @tiers[char_name][attr_name]["skills"][s] = 0 }
114
+ end
115
+
116
+ # Add skill if it doesn't exist or is 0
117
+ if !@tiers[char_name][attr_name]["skills"][skill_name] ||
118
+ @tiers[char_name][attr_name]["skills"][skill_name] == 0
119
+ @tiers[char_name][attr_name]["skills"][skill_name] = value
120
+ skills_added += 1
121
+ end
122
+ end
123
+
124
+ # Fill remaining with random skills from existing structure
125
+ while skills_added < skill_count
126
+ char_name = ["BODY", "MIND"].sample
127
+ if @tiers[char_name]
128
+ attr_name = @tiers[char_name].keys.sample
129
+ if @tiers[char_name][attr_name] && @tiers[char_name][attr_name]["skills"]
130
+ @tiers[char_name][attr_name]["skills"] ||= {}
131
+
132
+ # Convert array to hash if needed
133
+ if @tiers[char_name][attr_name]["skills"].is_a?(Array)
134
+ skill_list = @tiers[char_name][attr_name]["skills"]
135
+ @tiers[char_name][attr_name]["skills"] = {}
136
+ skill_list.each { |s| @tiers[char_name][attr_name]["skills"][s] = 0 }
137
+ end
138
+
139
+ # Pick a random skill
140
+ if @tiers[char_name][attr_name]["skills"].any?
141
+ skill_name = @tiers[char_name][attr_name]["skills"].keys.sample
142
+ if @tiers[char_name][attr_name]["skills"][skill_name] == 0
143
+ @tiers[char_name][attr_name]["skills"][skill_name] = rand(1..3) + experience_bonus
144
+ skills_added += 1
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ # Prevent infinite loop
151
+ break if skills_added >= 50
152
+ end
153
+ end
@@ -0,0 +1,237 @@
1
+ # The Amar Tool class for generating random castles/villages/towns/cities.
2
+ #
3
+ # When the class is initialized, a random settlement (village/town/city) is generated.
4
+ #
5
+ # A pretty straight forward class, not in need of much comments
6
+
7
+ class Town
8
+
9
+ attr_reader :town, :town_name, :town_size, :town_residents
10
+
11
+ # Although there is a generic name function, the town creator needs to
12
+ # modify it to cater for a high chance of a household having the same surname
13
+ def name(race)
14
+ new_name = naming(race, @r_sex)
15
+ name_split = new_name.split
16
+ $Last_name = name_split[1].to_s if $Last_name == "" or /Soldier/ =~ @town[@h_index][0] or /residents/ =~ @town[@h_index][0]
17
+ name_split[1] = $Last_name if rand(1..4) > 1
18
+ new_name = name_split.join(" ").strip
19
+ return new_name
20
+ end
21
+
22
+ # Using the generic randomizer function to get random races based on weighted input
23
+ def race(var)
24
+ case var
25
+ when 0
26
+ @race = randomizer(
27
+ "Human" => 10,
28
+ "Other" => 1)
29
+ when 1
30
+ @race = randomizer(
31
+ "Human" => 10,
32
+ "Dwarf" => 4,
33
+ "Half-elf" => 2,
34
+ "Lizardfolk" => 1,
35
+ "Other" => 1)
36
+ when 2
37
+ @race = randomizer(
38
+ "Human" => 10,
39
+ "Dwarf" => 5,
40
+ "Half-elf" => 3,
41
+ "Lizardfolk" => 2,
42
+ "Lesser troll" => 2,
43
+ "Half-giant" => 1,
44
+ "Other" => 2)
45
+ when 3
46
+ @race = randomizer(
47
+ "Human" => 10,
48
+ "Dwarf" => 7,
49
+ "Half-elf" => 5,
50
+ "Lizardfolk" => 3,
51
+ "Lesser troll" => 3,
52
+ "Half-giant" => 2,
53
+ "Elf" => 1,
54
+ "Troll" => 1,
55
+ "Arax" => 1,
56
+ "Other" => 2)
57
+ when 4
58
+ @race = randomizer(
59
+ "Dwarf" => 15,
60
+ "Other" => 1)
61
+ when 5
62
+ @race = randomizer(
63
+ "Elf" => 12,
64
+ "Half-elf" => 3,
65
+ "Other" => 1)
66
+ when 6
67
+ @race = randomizer(
68
+ "Lizardfolk" => 15,
69
+ "Other" => 1)
70
+ end
71
+ return @race
72
+ end
73
+
74
+ # The function to add residents to houses
75
+ def add_resident(age)
76
+ @town_residents += 1
77
+ # Get race
78
+ if $Race == ""
79
+ @r_race = race(@town_var)
80
+ $Race = @r_race unless /residents/ =~ @town[@h_index][0]
81
+ elsif rand(5).to_i == 0
82
+ @r_race = race(@town_var)
83
+ else
84
+ @r_race = $Race
85
+ end
86
+ # Get sex
87
+ if $Sex == ""
88
+ @r_sex = randomizer( "M" => 1, "F" => 1 )
89
+ elsif $Sex == "M"
90
+ @r_sex = randomizer( "M" => 1, "F" => 3 )
91
+ elsif $Sex == "F"
92
+ @r_sex = randomizer( "M" => 3, "F" => 1 )
93
+ end
94
+ $Sex = @r_sex
95
+ # Get age
96
+ case age
97
+ when 0
98
+ @r_age = rand(70).to_i + 15
99
+ when 1
100
+ @r_age = rand(35).to_i + 50
101
+ when 2
102
+ @r_age = rand(30).to_i + 20
103
+ when 3
104
+ @r_age = rand(20).to_i
105
+ end
106
+ @r_age = @r_age*2 if $Race == "Dwarf"
107
+ @r_age = @r_age*1.5 if $Race == "Half-elf"
108
+ @r_age = @r_age*3 if $Race == "Elf"
109
+ @r_age = @r_age*0.8 if $Race == "Lizardfolk"
110
+ @r_age = @r_age*1.5 if $Race == "Lesser troll"
111
+ @r_age = @r_age*2 if $Race == "Troll"
112
+ @r_age = @r_age*0.5 if $Race == "Arax"
113
+ @r_age = @r_age.to_i
114
+ # Get name
115
+ @r_name = name(@r_race)
116
+ # Get personality
117
+ @r_pers = randomizer($Personality)
118
+ # Get skill
119
+ @r_skill = (rand(6) + rand(6) + @r_age/20).to_i
120
+ @r_skill += (@r_age/15).to_i if /Stronghold/ =~ @town[@h_index][0]
121
+ @r_skill += (@r_age/20).to_i if /Noble/ =~ @town[@h_index][0]
122
+ @town[@h_index][@r] = "#{@r_name} (#{@r_sex} #{@r_age}) #{@r_race} [#{@r_skill}] #{@r_pers}"
123
+ @r += 1
124
+ end
125
+
126
+ # The initializing method - generates houses
127
+ def initialize(town_name, town_size, town_var)
128
+
129
+ @town_size = town_size.to_i
130
+ @town_var = town_var.to_i
131
+ @town_name = town_name.to_s
132
+ if @town_name == ""
133
+ case @town_size
134
+ when 1..5
135
+ @town_name = naming("castle")
136
+ when 6..25
137
+ @town_name = naming("village")
138
+ when 26..99
139
+ @town_name = naming("town")
140
+ else
141
+ @town_name = naming("city")
142
+ end
143
+ end
144
+ @town_residents = 0
145
+
146
+ # Temple types (Amar Gods) used for randomizing temples
147
+ $Temple_types = {
148
+ "Walmaer" => 4,
149
+ "Alesia" => 4,
150
+ "Ikalio" => 3,
151
+ "Shalissa" => 3,
152
+ "Ielina" => 2,
153
+ "Cal Amae" => 2,
154
+ "Anashina" => 3,
155
+ "Gwendyll/MacGillan" => 4,
156
+ "Juba" => 1,
157
+ "Taroc" => 5,
158
+ "Recolar" => 1,
159
+ "Maleko" => 1,
160
+ "Fal Munir" => 2,
161
+ "Moltan" => 4,
162
+ "Kraagh" => 4,
163
+ "Lesser God" => 1}
164
+ #Initiate the Temple hash to be used if/when temples are picked
165
+ t = $Temple_types.dup
166
+
167
+ @town = []
168
+ @h_index = 0
169
+
170
+ # Load town table if not loaded
171
+ unless defined?($Town)
172
+ load File.join($pgmdir, "includes/tables/town.rb")
173
+ end
174
+
175
+ $Town[1..-1].each do | h_type |
176
+ #Iterate over the whole $Town array picking houses as we go and populating @town
177
+ h_number = ((rand(h_type[2]) + rand(h_type[2]) + rand()) * town_size / 100).to_i
178
+ h_number = h_type[3] if h_number < h_type[3]
179
+ h_number = h_number.to_i
180
+ # create that house types h_number of times
181
+ next if h_number == 0
182
+ h_number.times do
183
+ @town[@h_index] = []
184
+ @town[@h_index][0] = h_type[0]
185
+ #Pick opening hours if shop
186
+ if /Inn/ =~ h_type[0]
187
+ @town[@h_index][0] += ": Open 7/7, 06-00"
188
+ end
189
+ if h_type[1] == 1
190
+ @town[@h_index][0] += ": Open "
191
+ @town[@h_index][0] += randomizer(
192
+ "5/7, " => 1,
193
+ "6/7, " => 2,
194
+ "7/7, " => 1)
195
+ @town[@h_index][0] += randomizer(
196
+ "07-" => 1,
197
+ "08-" => 2,
198
+ "09-" => 1)
199
+ @town[@h_index][0] += randomizer(
200
+ "16" => 1,
201
+ "17" => 2,
202
+ "18" => 1)
203
+ end
204
+ if @town[@h_index][0] == "Temple"
205
+ t_type = randomizer(t)
206
+ @town[@h_index][0] += ": " + t_type unless t.empty?
207
+ t.delete(t_type)
208
+ end
209
+ r = 1 #residents counter
210
+ # Make the next into a function with age of no 1 as "0", then 1, 2, 3
211
+ $Race = ""
212
+ $Sex = ""
213
+ $Last_name = ""
214
+ @r = 1
215
+ add_resident(0)
216
+ (rand(h_type[4]) + rand(h_type[4])).to_i.times {add_resident(1)}
217
+ (rand(h_type[5]) + rand(h_type[5])).to_i.times {add_resident(2)}
218
+ ((town_size / 40) + 1).to_i.times {add_resident(2)} if /Stronghold/ =~ @town[@h_index][0]
219
+ (rand(h_type[6]) + rand(h_type[6])).to_i.times {add_resident(3)}
220
+ @h_index += 1
221
+ # Output progress for CLI
222
+ $stdout.puts "House #{@h_index}" if defined?($stdout) && $stdout.respond_to?(:puts)
223
+ # Send progress through pipe if available
224
+ if defined?($progress_pipe) && $progress_pipe
225
+ begin
226
+ $progress_pipe.puts @h_index
227
+ $progress_pipe.flush
228
+ rescue
229
+ # Pipe may be closed, ignore
230
+ end
231
+ end
232
+ break if @h_index > town_size
233
+ end
234
+ break if @h_index > town_size
235
+ end
236
+ end
237
+ end
data/includes/d6s.rb ADDED
@@ -0,0 +1,40 @@
1
+ # Dice-rolling for NPCg
2
+
3
+ # Simple multisided dice
4
+ def dX (x)
5
+ return rand(1..x)
6
+ end
7
+
8
+ # The normal d6
9
+ def d6
10
+ return rand(1..6)
11
+ end
12
+
13
+ # The open-ended d6
14
+ def oD6
15
+ result = d6
16
+ return result if result === (2..5)
17
+ if result == 1
18
+ down = d6
19
+ while down <= 3
20
+ down = d6
21
+ result -= 1
22
+ end
23
+ elsif result == 6
24
+ up = d6
25
+ while up >= 4
26
+ up = d6
27
+ result += 1
28
+ end
29
+ end
30
+ return result
31
+ end
32
+
33
+ # An average of two d6's
34
+ def aD6
35
+ result = ( d6 + oD6 ) / 2
36
+ result = result.to_i
37
+ return result
38
+ end
39
+
40
+
@@ -0,0 +1,120 @@
1
+ # Equipment tables based on d6gaming.org/index.php/Equipment
2
+
3
+ $EquipmentTables = {
4
+ # Basic adventuring gear (with costs in copper pieces)
5
+ "basic" => [
6
+ { name: "Backpack", cost: 30, weight: 1.0 },
7
+ { name: "Waterskin", cost: 20, weight: 0.5 },
8
+ { name: "Flint & steel", cost: 10, weight: 0.1 },
9
+ { name: "Blanket", cost: 120, weight: 2.0 }, # 6sp = 120cp
10
+ { name: "Torch", cost: 3, weight: 0.5 },
11
+ { name: "Oil lamp", cost: 100, weight: 0.5 }, # 5sp
12
+ { name: "Rope (10m)", cost: 60, weight: 5.0 }, # 3sp
13
+ { name: "Grappling hook", cost: 100, weight: 2.0 }, # 5sp
14
+ { name: "Canvas tent", cost: 200, weight: 8.0 }, # 10sp
15
+ { name: "Belt pouch", cost: 10, weight: 0.1 },
16
+ { name: "Whetstone", cost: 5, weight: 0.2 },
17
+ { name: "Fishing gear", cost: 40, weight: 1.0 }, # 2sp
18
+ { name: "Cooking pot", cost: 30, weight: 1.5 },
19
+ { name: "Rations (3 days)", cost: 30, weight: 1.5 }
20
+ ],
21
+
22
+ "warrior" => [
23
+ { name: "Shield strap", cost: 10, weight: 0.1 },
24
+ { name: "Weapon oil", cost: 5, weight: 0.1 },
25
+ { name: "Spare bowstring", cost: 5, weight: 0.05 },
26
+ { name: "Quiver", cost: 20, weight: 0.3 },
27
+ { name: "Armor repair kit", cost: 50, weight: 1.0 }
28
+ ],
29
+
30
+ "thief" => [
31
+ { name: "Lockpicks", cost: 100, weight: 0.1 }, # 5sp
32
+ { name: "Dark cloak", cost: 60, weight: 1.0 }, # 3sp
33
+ { name: "Caltrops", cost: 20, weight: 0.5 },
34
+ { name: "Smoke powder", cost: 40, weight: 0.2 },
35
+ { name: "Glass cutter", cost: 100, weight: 0.1 } # 5sp
36
+ ],
37
+
38
+ "mage" => [
39
+ { name: "Spell components", cost: 100, weight: 0.5 }, # 5sp
40
+ { name: "Scroll case", cost: 20, weight: 0.3 },
41
+ { name: "Ink & quill", cost: 20, weight: 0.1 },
42
+ { name: "Parchment (10)", cost: 40, weight: 0.2 }, # 2sp
43
+ { name: "Spellbook", cost: 300, weight: 2.0 }, # 15sp
44
+ { name: "Crystal focus", cost: 200, weight: 0.2 } # 10sp
45
+ ],
46
+
47
+ "ranger" => [
48
+ { name: "Tracking kit", cost: 60, weight: 0.5 }, # 3sp
49
+ { name: "Snares (5)", cost: 20, weight: 0.5 },
50
+ { name: "Camouflage net", cost: 40, weight: 1.0 }, # 2sp
51
+ { name: "Field guide", cost: 100, weight: 0.5 }, # 5sp
52
+ { name: "Hunting knife", cost: 40, weight: 0.3 } # 2sp
53
+ ],
54
+
55
+ "merchant" => [
56
+ { name: "Scales", cost: 100, weight: 2.0 }, # 5sp
57
+ { name: "Ledger", cost: 60, weight: 0.5 }, # 3sp
58
+ { name: "Money pouch", cost: 10, weight: 0.1 },
59
+ { name: "Merchant license", cost: 200, weight: 0.05 }, # 10sp
60
+ { name: "Sample case", cost: 100, weight: 1.0 } # 5sp
61
+ ],
62
+
63
+ "noble" => [
64
+ { name: "Signet ring", cost: 500, weight: 0.05 }, # 25sp
65
+ { name: "Fine clothes", cost: 400, weight: 2.0 }, # 20sp
66
+ { name: "Perfume", cost: 100, weight: 0.1 }, # 5sp
67
+ { name: "Silver flask", cost: 200, weight: 0.3 }, # 10sp
68
+ { name: "Writing kit", cost: 60, weight: 0.5 } # 3sp
69
+ ],
70
+
71
+ "priest" => [
72
+ { name: "Holy symbol", cost: 100, weight: 0.2 }, # 5sp
73
+ { name: "Prayer beads", cost: 20, weight: 0.1 },
74
+ { name: "Incense", cost: 40, weight: 0.2 }, # 2sp
75
+ { name: "Holy water", cost: 50, weight: 0.5 },
76
+ { name: "Religious texts", cost: 200, weight: 1.0 } # 10sp
77
+ ]
78
+ }
79
+
80
+ # Generate equipment based on character type and level
81
+ def generate_npc_equipment(type, level)
82
+ equipment = []
83
+
84
+ # Determine character archetype
85
+ type_str = type.to_s.downcase
86
+ archetype = case
87
+ when type_str.include?("warrior") || type_str.include?("guard") || type_str.include?("soldier")
88
+ "warrior"
89
+ when type_str.include?("thief") || type_str.include?("bandit") || type_str.include?("assassin")
90
+ "thief"
91
+ when type_str.include?("mage") || type_str.include?("wizard") || type_str.include?("sorcerer")
92
+ "mage"
93
+ when type_str.include?("ranger") || type_str.include?("hunter") || type_str.include?("scout")
94
+ "ranger"
95
+ when type_str.include?("merchant") || type_str.include?("trader")
96
+ "merchant"
97
+ when type_str.include?("noble") || type_str.include?("lord") || type_str.include?("lady")
98
+ "noble"
99
+ when type_str.include?("priest") || type_str.include?("cleric") || type_str.include?("monk")
100
+ "priest"
101
+ else
102
+ "basic"
103
+ end
104
+
105
+ # Add basic items (1-3 based on level)
106
+ basic_items = $EquipmentTables["basic"].sample([1 + level/3, 4].min)
107
+ equipment += basic_items.map { |item| item[:name] }
108
+
109
+ # Add archetype-specific items if applicable
110
+ if archetype != "basic" && $EquipmentTables[archetype]
111
+ specific_items = $EquipmentTables[archetype].sample([1 + level/4, 3].min)
112
+ equipment += specific_items.map { |item| item[:name] }
113
+ end
114
+
115
+ # Always have at least backpack and waterskin
116
+ equipment << "Backpack" unless equipment.any? { |e| e.include?("Backpack") }
117
+ equipment << "Waterskin" unless equipment.any? { |e| e.include?("Waterskin") }
118
+
119
+ equipment.uniq
120
+ end
@@ -0,0 +1,67 @@
1
+ # Get names from name generator
2
+ def naming(intype, sex="")
3
+ sex = sex.to_s.upcase
4
+ type = intype.sub(/(:| ).*/, '').to_s.downcase
5
+
6
+ # Get for race/sex filename for first name and last name (if any)
7
+ file1 = ""
8
+ file2 = ""
9
+ $Names.each do |m|
10
+ if m[4].include?(type) and m[3].include?(sex)
11
+ file1 = m[1]
12
+ file2 = m[2]
13
+ break
14
+ end
15
+ end
16
+
17
+ p = File.expand_path(File.dirname(__FILE__))
18
+ n = "/../name_generator/name_generator_main.rb -d"
19
+
20
+ result = ""
21
+ result += intype + " of " if ["Castle", "Village", "Town", "City"].include?(intype)
22
+ result += `#{p}#{n} #{file1}`.chomp
23
+ result += " " + `#{p}#{n} #{file2}`.chomp if file2 != ""
24
+ result = "" if result == "No such data file"
25
+ return result.strip
26
+ end
27
+
28
+ # Save temporary files
29
+ def save_temp_file(content, file_base, cli)
30
+ cli == "cli" ? file_ext = ".npc" : file_ext = ".txt"
31
+
32
+ tfile = "saved/" + file_base + file_ext
33
+ File.delete(tfile) if File.exist?(tfile)
34
+ begin
35
+ # Strip ANSI codes when saving to file for clean editing
36
+ clean_content = content.respond_to?(:pure) ? content.pure : content.gsub(/\e\[\d+(?:;\d+)*m/, '')
37
+ File.write(tfile, clean_content, perm: 0644)
38
+ rescue
39
+ if cli == "cli"
40
+ # Silent error - no puts in TUI mode
41
+ # gets removed for TUI compatibility
42
+ end
43
+ end
44
+ end
45
+
46
+ # Save named (specific) files
47
+ def save_named_file(content, file_base, cli)
48
+ cli == "cli" ? file_ext = ".npc" : file_ext = ".txt"
49
+
50
+ $nfile = "saved/" + file_base + file_ext
51
+ c = 1
52
+ while File.exist?($nfile)
53
+ $nfile = "saved/" + file_base + c.to_s + file_ext
54
+ c += 1
55
+ end
56
+ begin
57
+ File.write($nfile, content, perm: 0644)
58
+ rescue
59
+ if cli == "cli"
60
+ # Silent error - no puts in TUI mode
61
+ # gets removed for TUI compatibility
62
+ end
63
+ end
64
+
65
+ system("#{$editor} #{$nfile}") if cli == "cli"
66
+ end
67
+
@@ -0,0 +1,30 @@
1
+ # Including all needed modules/functions from this one file
2
+
3
+ require_relative "d6s.rb"
4
+ require_relative "functions.rb"
5
+ require_relative "randomizer.rb"
6
+
7
+ require_relative "class_enc.rb"
8
+ require_relative "class_npc.rb"
9
+ require_relative "class_town.rb"
10
+ require_relative "class_npc_new.rb"
11
+ require_relative "class_enc_new.rb"
12
+ require_relative "class_monster_new.rb"
13
+ require_relative "town_relations.rb"
14
+ require_relative "weather.rb"
15
+ require_relative "weather2latex.rb"
16
+
17
+ require_relative "tables/armour.rb"
18
+ require_relative "tables/chartype.rb"
19
+ require_relative "tables/chartype_new.rb"
20
+ require_relative "tables/enc_specific.rb"
21
+ require_relative "tables/enc_type.rb"
22
+ require_relative "tables/encounters.rb"
23
+ require_relative "tables/magick.rb"
24
+ require_relative "tables/melee.rb"
25
+ require_relative "tables/missile.rb"
26
+ require_relative "tables/month.rb"
27
+ require_relative "tables/names.rb"
28
+ require_relative "tables/personality.rb"
29
+ require_relative "tables/town.rb"
30
+ require_relative "tables/weather.rb"
@@ -0,0 +1,15 @@
1
+ # Randomize a value from a hash with weighted variables
2
+
3
+ def randomizer(params)
4
+ par = {}
5
+ par.merge!(params)
6
+ i = 1
7
+ par.each_key do |key|
8
+ par[key] += i
9
+ i = par[key]
10
+ end
11
+ result = rand(i).to_i
12
+ par.each_value do |value|
13
+ return par.key(value) if value > result
14
+ end
15
+ end