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
@@ -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
|