Comment: | many bug fixers, some minor refactoring, allow non-drinkable potions to be empowered in various ways, allow gods to be petitioned for recipes (next up: cookbooks!) |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
c71731cf588f3c6b783992fc2455d645 |
User & Date: | lexi on 2021-07-03 02:25:42 |
Other Links: | manifest | tags |
2021-07-04
| ||
20:27 | add cool and informative visuals for taps, add more capacity to rune forge, many bug fixes, fixed some bugs, and fixed some bugs check-in: 94064fe5c9 user: lexi tags: trunk | |
2021-07-03
| ||
02:25 | many bug fixers, some minor refactoring, allow non-drinkable potions to be empowered in various ways, allow gods to be petitioned for recipes (next up: cookbooks!) check-in: c71731cf58 user: lexi tags: trunk | |
2021-06-28
| ||
18:31 | defuckulate markdown check-in: fa442a5d6a user: lexi tags: trunk | |
Modified altar.lua from [a7a1197203] to [080406f8d2].
1 1 local altar_item_offset = { 2 2 x = 0, y = -0.3, z = 0 3 3 } 4 -local log = function(...) sorcery.log('altar',...) end 4 +local log = sorcery.logger('altar') 5 5 6 6 local range = function(min, max) 7 7 local span = max - min 8 8 local val = math.random() * span 9 9 return val + min 10 10 end 11 11 ................................................................................ 73 73 74 74 after_place_node = function(pos, placer, stack, pointat) 75 75 local meta = minetest.get_meta(pos) 76 76 local stackmeta = stack:get_meta() 77 77 meta:set_int('favor', stackmeta:get_int('favor')) 78 78 meta:set_string('last_sacrifice', stackmeta:get_string('last_sacrifice')) 79 79 80 - minetest.get_node_timer(pos):start(60) 80 + minetest.get_node_timer(pos):start(1) 81 81 end; 82 82 83 83 drop = { 84 84 -- for some idiot reason this is necessary for 85 85 -- preserve_metadata to work right 86 86 max_items = 1; 87 87 items = { ................................................................................ 167 167 -- we pick a random gift and roll against its rarity 168 168 -- to determine if the god is feeling generous 169 169 local gift = sorcery.lib.tbl.pick(god.gifts) 170 170 local data = god.gifts[gift] 171 171 local value, rarity = data[1], data[2] 172 172 if value <= divine_favor and math.random(rarity) == 1 then 173 173 bestow(gift) 174 - log(god.name .. ' has produced ' .. gift .. ' upon an altar as a gift') 174 + log.act(god.name .. ' has produced ' .. gift .. ' upon an altar as a gift') 175 175 if math.random(god.generosity) == 1 then 176 176 -- unappreciated gifts may incur divine 177 177 -- irritation 178 178 divine_favor = divine_favor - 1 179 179 end 180 180 end 181 181 end ................................................................................ 215 215 goto refresh 216 216 end 217 217 end 218 218 219 219 -- loop through the list of things this god will consecrate and 220 220 -- check whether the item on the altar is any of them 221 221 for s, cons in pairs(god.consecrate) do 222 - local cost, tx = cons[1], cons[2] 223 - if type(tx) == "table" then 224 - tx = tx[math.random(#tx)] 225 - end 226 - -- preserve wear 227 - local gift = ItemStack(tx) 228 - local wear = stack:get_wear() 229 - if wear > 0 then 230 - gift:set_wear(wear) 231 - end 232 - -- preserve meta 233 - gift:get_meta():from_table(stack:get_meta():to_table()) 234 - -- reflash enchantments to ensure label is accurate 235 - local ench = sorcery.enchant.get(gift) 236 - if #ench.spells > 0 then 237 - -- add a bit of energy as a gift? 238 - if math.random(math.ceil(god.stinginess * 0.5)) == 1 then 239 - local max = 0.05 * god.generosity 240 - ench.energy = ench.energy * range(0.7*max,max) 222 + if itemname == s then 223 + local cost, tx 224 + if type(cons) == "table" then 225 + cost, tx = cons[1], cons[2] 226 + tx = tx[math.random(#tx)] 227 + elseif type(cons) == 'function' then 228 + cost, tx = cons { 229 + favor = divine_favor; 230 + pos = pos; 231 + altar = altarmeta; 232 + idol = idolmeta; 233 + god = god; 234 + } 235 + end 236 + -- preserve wear 237 + local gift 238 + if type(tx) == 'string' then 239 + gift = ItemStack(tx) 240 + else gift = tx end 241 + local wear = stack:get_wear() 242 + if wear > 0 then 243 + gift:set_wear(wear) 244 + end 245 + -- preserve meta 246 + local gm = gift:get_meta() 247 + gm:from_table( 248 + sorcery.lib.tbl.merge( 249 + stack:get_meta():to_table(), 250 + gm:to_table() 251 + ) 252 + ) -- oof 253 + -- reflash enchantments to ensure label is accurate 254 + local ench = sorcery.enchant.get(gift) 255 + if #ench.spells > 0 then 256 + -- add a bit of energy as a gift? 257 + if math.random(math.ceil(god.stinginess * 0.5)) == 1 then 258 + local max = 0.05 * god.generosity 259 + ench.energy = ench.energy * range(0.7*max,max) 260 + end 261 + sorcery.enchant.set(gift,ench) 241 262 end 242 - sorcery.enchant.set(gift,ench) 243 - end 244 - if itemname == s then 263 + 245 264 if divine_favor >= cost then 246 265 bestow(gift) 247 266 divine_favor = divine_favor - cost 248 - print(god.name..'has consecrated ' ..s.. ' into ' ..tx.. ', for the cost of ' ..cost.. ' points of divine favor') 267 + log.act(god.name, 'has consecrated', s, 'into', tx, 'for the cost of', cost, 'points of divine favor') 249 268 goto refresh 250 269 end 251 270 end 252 271 end 253 272 end 254 273 255 274 ::refresh::
Modified astrolabe.lua from [a9316d6c59] to [cc031237ac].
4 4 local r = {} 5 5 for i,v in ipairs(k) do 6 6 r[i] = { 7 7 id = k[i]; 8 8 name = sorcery.data.calendar.styles[v].name; 9 9 } 10 10 end 11 - print(dump(r)) 12 11 return r 13 12 end 14 13 local astrolabe_formspec = function(pos) 15 14 local m = minetest.get_meta(pos) 16 15 local i = m:get_inventory() 17 16 local datestamp = minetest.get_day_count() 18 17 local date = sorcery.calendar.date(datestamp)
Modified cookbook.lua from [e643a56c3c] to [aae72d93b8].
1 1 -- by use of the enchanter, it is possible to reveal a random 2 2 -- recipe and enscribe it on a sheet of paper. these sheets of 3 3 -- paper can then bound together into books, combining like 4 4 -- recipes 5 5 6 6 sorcery.cookbook = {} 7 +local log = sorcery.logger('cookbook') 8 + 7 9 local constants = { 8 10 -- do not show recipes for items in these groups 9 11 exclude_groups = { 10 12 }; 11 13 exclude_names = { 12 14 'stairs'; 13 15 'slab'; ................................................................................ 51 53 return {} 52 54 end 53 55 local modofname = function(id) 54 56 local sep = string.find(id,':') 55 57 if sep == nil then return nil end -- uh oh 56 58 return string.sub(id, 1, sep - 1) 57 59 end 60 +local item_restrict_eval = function(name, restrict) 61 + for _,n in pairs(constants.exclude_names) do 62 + if string.find(name,n) ~= nil then 63 + return false 64 + end 65 + end 66 + for _,g in pairs(constants.exclude_groups) do 67 + if minetest.get_item_group(name, g) > 0 then 68 + return false 69 + end 70 + end 71 + 72 + local props = minetest.registered_items[name]._sorcery 73 + local module = modofname(name) 74 + 75 + return not (excluded 76 + or sorcery.lib.tbl.has(constants.blacklist_mods,module) 77 + or (props and props.recipe and props.recipe.secret) 78 + or (restrict and ( 79 + (restrict.pred and restrict.pred { 80 + mod = module, item = name, props = props 81 + } ~= true) 82 + or (restrict.mod and module ~= restrict.mod) 83 + or (restrict.group and (minetest.get_item_group(name, restrict.group) == 0)) 84 + ))) 85 +end 86 + 58 87 local pick_builtin = function(kind) return function(restrict) 59 88 -- ow ow ow ow ow ow ow 60 89 local names = {} 61 90 for k in pairs(minetest.registered_items) do 62 91 local rec = minetest.get_craft_recipe(k) 63 92 if rec.items ~= nil and (rec.method == kind or (rec.method == 'shapeless' and kind == 'normal')) then -- is this last bit necessary? 64 - local excluded = false 65 - for _,n in pairs(constants.exclude_names) do 66 - if string.find(k,n) ~= nil then 67 - excluded = true break end 68 - end 69 - if not excluded then for _,g in pairs(constants.exclude_groups) do 70 - if minetest.get_item_group(k, g) > 0 then 71 - excluded = true break end 72 - end end 73 - local props = minetest.registered_items[k]._sorcery 74 - local module = modofname(k) 75 - if not (excluded 76 - or sorcery.lib.tbl.has(constants.blacklist_mods,module) 77 - or (props and props.recipe and props.recipe.secret) 78 - or (restrict and ( 79 - (restrict.mod and module ~= restrict.mod) 80 - or (restrict.group and (minetest.get_item_group(k, restrict.group) == 0)) 81 - ))) then names[#names + 1] = k end 93 + if item_restrict_eval(k, restrict) then names[#names + 1] = k end 82 94 end 83 95 end 84 96 return names[math.random(#names)] 85 97 end end 86 98 local find_builtin = function(method,kind) 87 99 return function(out) 88 100 local rec = {} ................................................................................ 219 231 chance = 4; 220 232 slots = { 221 233 {0,0}; 222 234 {0,1}; 223 235 }; 224 236 pick = function(restrict) 225 237 -- TODO make sure affinity restrictions match 226 - return sorcery.register.infusions.db[math.random(#sorcery.register.infusions.db)].output 238 + if restrict then 239 + local t = {} 240 + for _, i in pairs(sorcery.register.infusions.db) do 241 + if item_restrict_eval(i.output, restrict) and not ( 242 + -- conditions which cause failure of restriction test 243 + (restrict.ipred and restrict.ipred { 244 + mod = module; 245 + infusion = i; 246 + output = i.output; 247 + } ~= true) 248 + ) then t[#t+1] = i.output end 249 + end 250 + return select(2, sorcery.lib.tbl.pick(t)) 251 + else 252 + return sorcery.register.infusions.db[math.random(#sorcery.register.infusions.db)].output 253 + end 227 254 end; 228 255 title = function(output) 229 256 for _,i in pairs(sorcery.register.infusions.db) do 230 257 if i.output == output then 231 258 if i._proto and i._proto.name 232 259 then return i._proto.name 233 260 else break end ................................................................................ 254 281 name = 'Milling Guide'; 255 282 node = 'sorcery:mill'; 256 283 booksuf = 'Manual'; 257 284 chance = 1; 258 285 w = 1, h = 2; 259 286 pick = function(restrict) 260 287 cache:populate_grindables() 261 - local i = cache.grindables[math.random(#cache.grindables)] 262 - local pd = sorcery.itemclass.get(i, 'grindable') 263 - return pd.powder 288 + if restrict then 289 + local t = {} 290 + for _, i in pairs(cache.grindables) do 291 + local pd = sorcery.itemclass.get(i, 'grindable') 292 + if item_restrict_eval(pd.powder, restrict) then 293 + t[#t+1] = pd.powder 294 + end 295 + end 296 + return select(2, sorcery.lib.tbl.pick(t)) 297 + else 298 + local gd = cache.grindables[math.random(#cache.grindables)] 299 + local pd = sorcery.itemclass.get(gd, 'grindable') 300 + return pd.powder 301 + end 264 302 end; 265 303 props = props_builtin; 266 304 slots = { 267 305 {0,1}, 268 306 {0,0}; 269 307 }; 270 308 find = function(out) ................................................................................ 400 438 end 401 439 if kind == nil then -- oh well, we tried 402 440 local rks = sorcery.lib.tbl.keys(recipe_kinds) 403 441 kind = rks[math.random(#rks)] 404 442 end 405 443 end 406 444 445 + if not recipe_kinds[kind] then 446 + log.fatalf('attempted to pick recipe of unknown kind "%s"', kind) 447 + end 407 448 return recipe_kinds[kind].pick(restrict), kind 408 449 end 409 450 410 451 local render_recipe = function(kind,ingredients,result,notes_right) 411 452 local k = recipe_kinds[kind] 412 453 local t = '' 413 454 local props = k.props(result) ................................................................................ 464 505 local ing = rec.find(out) 465 506 return render_recipe(kind,ing,out,notes_right), rec.w, rec.h 466 507 end 467 508 468 509 sorcery.cookbook.setrecipe = function(stack,k,r,restrict) 469 510 local meta = stack:get_meta() 470 511 if not r then r,k = sorcery.cookbook.pickrecipe(k,restrict) end 512 + if not r then return false end 471 513 local t = recipe_kinds[k] 472 514 meta:set_string('recipe_kind', k) 473 515 meta:set_string('recipe_name', r) 474 516 meta:set_string('description', 475 517 (t.title and t.title(r) or desc_builtin(r)) .. ' ' .. t.name) 476 518 end 477 519
Modified data/draughts.lua from [ab3b6e4e1b] to [0a84465667].
6 6 style = 'sparkle'; 7 7 desc = "A potion that amps up your body's natural\nhealing abilities, causing you to heal rapidly\neven if you're starving"; 8 8 infusion = 'sorcery:blood'; 9 9 basis = 'sorcery:potion_luminous'; 10 10 duration = function(self,meta) 11 11 return 10 + meta:get_int('duration')*2 12 12 end; 13 + quals = { force = true, duration = true }; 13 14 effect = function(self, user, proto) 14 15 local meta = self:get_meta() 15 16 local force = 1 + meta:get_int('force') 16 17 late.new_effect(user, { 17 18 duration = proto:duration(meta); 18 19 raise = 4; fall = 4; 19 20 impacts = { ................................................................................ 27 28 color = {79,228,243}; style = 'sparkle'; 28 29 basis = 'sorcery:potion_luminous'; 29 30 desc = "Conserve your precious supply of oxygen when diving down into the ocean's depths"; 30 31 infusion = 'sorcery:extract_kelp'; 31 32 duration = function(self,meta) 32 33 return 20 + meta:get_int('duration')*30 33 34 end; 35 + quals = { force = true, duration = true }; 34 36 effect = function(self,user,proto) 35 37 local meta = self:get_meta() 36 38 local force = 1 + 2 * (meta:get_int('force')) 37 39 late.new_effect(user, { 38 40 duration = proto:duration(meta); 39 41 raise = 2; fall = 5; 40 42 impacts = { ................................................................................ 43 45 }) 44 46 end; 45 47 }; 46 48 heal = { 47 49 name = 'Healing'; 48 50 color = {243,44,58}; 49 51 style = 'sparkle'; 50 - no_duration = true; 52 + quals = { force = true }; 51 53 desc = 'This blood-red liquid glitters with an enchantment that rapidly knits torn flesh and broken bones'; 52 54 infusion = 'sorcery:oil_sanguine'; 53 55 basis = 'sorcery:potion_luminous'; 54 56 effect = function(self, user) 55 57 local meta = self:get_meta() 56 58 user:set_hp(user:get_hp() + (2 * (2 + meta:get_int('force')))) 57 59 end; ................................................................................ 61 63 62 64 stealth = { 63 65 name = 'Stealth'; 64 66 color = {184,106,224}; style = 'sparkle'; 65 67 infusion = 'default:coal_lump'; 66 68 basis = 'sorcery:potion_soft'; 67 69 desc = 'Drinking this dark, swirling draught will shelter you from the power of mortal perception for a time, even rendering you entirely invisible at full strength.'; 70 + quals = { force = true, duration = true }; 68 71 duration = function(self,meta) 69 72 return 30 + meta:get_int('duration')*30 70 73 end; 71 74 effect = function(self,user,proto) 72 75 local meta = self:get_meta() 73 76 local force = 1 + 1 * (meta:get_int('force')) 74 77 local opacity = 1.0 - (1.0 * (force / 4)) ................................................................................ 85 88 nightsight = { 86 89 name = 'Nightsight'; 87 90 color = {91,0,200}; style = 'sparkle'; 88 91 desc = 'While this potion flows through your veins, your vision will be strengthened against the darkness of the night'; 89 92 maxforce = 3; 90 93 infusion = 'sorcery:oil_dawn'; 91 94 basis = 'sorcery:potion_soft'; 95 + quals = { force = true, duration = true }; 92 96 duration = function(self,meta) 93 97 return 50 + meta:get_int('duration')*70 94 98 end; 95 99 effect = function(self,user,proto) 96 100 --TODO ensure it can only be drunk at night 97 101 --TODO ensure it can't last more than one night 98 102 local meta = self:get_meta() ................................................................................ 108 112 }; 109 113 antigravity = { 110 114 name = 'Antigravity'; 111 115 color = {240,59,255}; style = 'sparkle'; 112 116 desc = 'Loosen the crushing grip of the earth upon your tender mortal form with a few sips from this glittering phial'; 113 117 infusion = 'sorcery:oil_stone'; 114 118 basis = 'sorcery:potion_soft'; 119 + quals = { force = true, duration = true }; 115 120 duration = function(self,meta) 116 121 return 20 + meta:get_int('duration')*25 117 122 end; 118 123 effect = function(self,user,proto) 119 124 local meta = self:get_meta() 120 125 local force = 1 - 0.3 * (meta:get_int('force') + 1) 121 126 late.new_effect(user, { ................................................................................ 129 134 }; 130 135 gale = { 131 136 name = 'Gale'; 132 137 color = {187,176,203}; 133 138 desc = 'Move and strike with the speed of a hurricane as this enchanted fluid courses through your veins'; 134 139 infusion = 'sorcery:grease_storm'; 135 140 basis = 'sorcery:potion_soft'; 141 + quals = { force = true, duration = true }; 136 142 duration = function(self,meta) 137 143 return 10 + meta:get_int('duration')*15 138 144 end; 139 145 effect = function(self,user,proto) 140 146 local meta = self:get_meta() 141 147 local force = 2 + 0.7 * (meta:get_int('force')) 142 148 late.new_effect(user, { ................................................................................ 151 157 obsidian = { 152 158 name = 'Obsidian'; 153 159 infusion = 'default:obsidian_shard'; 154 160 color = {76,0,121}; style = 'sparkle'; 155 161 desc = 'Walk untroubled through volleys of arrows and maelstroms of swinging blades, for all will batter uselessly against skin protected by spellwork mightier than the doughtiest armor'; 156 162 infusion = 'default:obsidian_shard'; 157 163 basis = 'sorcery:potion_luminous'; 158 - no_force = true; 164 + quals = { duration = true }; 159 165 duration = function(self,meta) 160 166 return 5 + meta:get_int('duration')*7 161 167 end; 162 168 }; 163 169 lavabreathing = { 164 170 name = 'Lavabreathing'; 165 171 color = {243,118,79}; style = 'sparkle'; glow = 12; 166 172 basis = 'sorcery:potion_soft'; 167 173 desc = "Wade through seas of roiling lava as easily as though it were but a babbling brook"; 174 + quals = { duration = true }; 168 175 }; 169 176 -- mighty = { 170 177 -- name = 'Mighty'; 171 178 -- color = {255,0,119}; style = 'sparkle'; glow = 5; 172 179 -- infusion = 'sorcery:grease_war'; 173 180 -- basis = 'sorcery:potion_soft'; 174 181 -- desc = 'Amplify the power of your blows and crack steel armor with the force of your bare hands'; 175 182 -- }; 176 183 resilient = { 177 184 name = 'Resilient'; 178 185 color = {124,124,124}; style = 'dull'; 179 186 basis = 'sorcery:potion_soft'; 180 187 desc = 'Withstand greater damage and hold your ground even in face of tremendous force'; 188 + quals = { force = true, duration = true }; 181 189 }; 182 190 hover = { 183 191 name = 'Hover'; 184 192 color = {164,252,55}; style = 'sparkle'; 185 193 desc = 'Rise into the air for a time and stay there until the potion wears off'; 186 194 basis = 'sorcery:potion_soft'; 195 + quals = { force = true, duration = true }; 187 196 }; 188 197 flight = { 189 198 name = 'Flight'; 190 199 color = {143,35,255}; style = 'sparkle'; 191 200 desc = 'Free yourself totally from the shackles of gravity and soar through the air however you should will'; 192 201 basis = 'sorcery:potion_soft'; 193 202 infusion = 'sorcery:grease_lift'; 194 - no_force = true; 203 + quals = { duration = true }; 195 204 duration = function(self,meta) 196 205 return 40 + meta:get_int('duration')*55 197 206 end; 198 207 effect = function(self,user,proto) 199 208 late.new_effect(user, { 200 209 duration = proto:duration(self:get_meta()); 201 210 impacts = { ................................................................................ 206 215 }; 207 216 leap = { 208 217 name = 'Leap'; 209 218 color = {164,252,55}; 210 219 desc = 'Soar high into the air each time you jump (but may risk damage if used without a Feather Potion)'; 211 220 infusion = 'sorcery:oil_wind'; 212 221 basis = 'sorcery:potion_soft'; 222 + quals = { force = true, duration = true }; 213 223 duration = function(self,meta) 214 224 return 5 + meta:get_int('duration')*7 215 225 end; 216 226 effect = function(self,user,proto) 217 227 local meta = self:get_meta() 218 228 local force = 2 + (0.5 * meta:get_int('force')) 219 229 late.new_effect(user, {
Modified data/elixirs.lua from [b08a2041a5] to [ba37716134].
1 +local inc = function(prop, val) 2 + return function(potion, kind) 3 + local meta = potion:get_meta() 4 + meta:set_int(prop, meta:get_int(prop) + (val or 1)) 5 + end 6 +end 7 + 1 8 return { 2 9 Force = { 3 - color = {255,165,85}; flag = 'force'; 4 - apply = function(potion, kind) 5 - local meta = potion:get_meta() 6 - meta:set_int('force', meta:get_int('force') + 1) 7 - end; 10 + color = {255,165,85}; qual = 'force'; 11 + apply = inc('force'); 8 12 describe = function(potion) 9 13 return 'good', 'empowered', "The strength of this potion's effect has been alchemically amplified" 10 14 end; 11 15 infusion = 'sorcery:grease_thunder'; 12 16 }; 13 17 Longevity = { 14 - color = {255,85,216}; flag = 'duration'; 15 - apply = function(potion, kind) 16 - local meta = potion:get_meta() 17 - meta:set_int('duration', meta:get_int('duration') + 1) 18 - end; 18 + color = {255,85,216}; qual = 'duration'; 19 + apply = inc('duration'); 19 20 describe = function(potion) 20 21 return 'good', 'prolonged', 'The effects of this potion will last longer than normal' 21 22 end; 22 23 infusion = 'sorcery:grease_pine'; 23 24 }; 25 + Rapidity = { 26 + color = {183,28,238}; qual = 'speed'; 27 + apply = inc('speed'); 28 + describe = function(potion) 29 + return 'good', 'Quickened', 'This potion will take effect more quiclkly and easily' 30 + end; 31 + infusion = 'sorcery:liquid_sap_acacia_bottle'; 32 + }; 33 + Purity = { 34 + color = {244,255,255}; qual = 'purity'; 35 + apply = inc('purity'); 36 + describe = function(potion) 37 + return 'good', 'purified', 'This potion\'s impurities and undesirable side effects are diminished or eliminated' 38 + end; 39 + infusion = 'sorcery:oil_purifying'; 40 + }; 41 + Beauty = { 42 + color = {255,20,226}; qual = 'beauty'; 43 + apply = inc('beauty'); 44 + describe = function(potion) 45 + return 'good', 'beautified', 'The effects of this potion will be more vivid and spectacular than normal' 46 + end; 47 + infusion = 'sorcery:liquid_sap_apple_bottle'; 48 + }; 49 + -- Glory? 50 + -- Clarity? 24 51 }
Modified data/gods.lua from [4ff6f034b6] to [fc9658990d].
1 +local L = sorcery.lib 1 2 return { 2 3 harvest = { 3 4 name = "Irix Irimentari" --[[ 4 5 an old Elerian harvest goddess, Irix Irimentari has watched vigilantly over the fields of her worshippers since before the Second Age. she favors alcoholic beverages as tribute, and has been known to perform blessings for sorcerers when sufficiently inebriated. she harbors a particular hatred of daemons and those who spill the blood of farmers. 5 6 6 7 legend says that a barbarian lord high on opium once wandered into a temple of Irix and left the severed head of a local shepherd on the her altar. this desecration so enraged the goddess that the barbarian's entire tribe soon starved horribly to death, their crops refusing to take root, and their stolen breads turning to ash in their mouths. 8 + 9 + in the mystic arts, she is the patron of Alchemy. it is said that Irix 10 + Irimentari herself invented alchemy when she brewed the first mead. 7 11 ]]; 8 12 laziness = 5; 9 13 stinginess = 3; 10 14 generosity = 10; 11 15 color = {214, 255, 146}; 12 16 idol = { 13 17 desc = "Harvest Idol"; ................................................................................ 33 37 "flowerpot:flowers_chrysanthemum_green"; 34 38 "flowerpot:flowers_dandelion_white"; 35 39 "flowerpot:flowers_dandelion_yellow"; 36 40 }}; 37 41 ["sorcery:dagger"] = {17, "sorcery:dagger_consecrated"}; 38 42 ["sorcery:oil_mystic"] = {9, "sorcery:oil_purifying"}; 39 43 ["sorcery:potion_water"] = {4, "sorcery:holy_water"}; 44 + ["default:paper"] = function(ctx) 45 + local stack = ItemStack('sorcery:recipe') 46 + local mode = select(2,L.tbl.pick{'cook','craft','infuse','grind'}) 47 + sorcery.cookbook.setrecipe(stack, mode, nil, { 48 + pred = function(c) 49 + local me = ctx.god 50 + if c.mod == 'farming' or 51 + minetest.get_item_group(c.item, 'sorcery_potion') ~= 0 or 52 + minetest.get_item_group(c.item, 'sorcery_oil') ~= 0 or 53 + minetest.get_item_group(c.item, 'sorcery_grease') ~= 0 or 54 + minetest.get_item_group(c.item, 'sorcery_extract') ~= 0 or 55 + me.sacrifice [c.item] or 56 + me.consecrate[c.item] then 57 + print(' !! accepted') 58 + return true end 59 + print(' -- rejected') 60 + end; 61 + }) 62 + return 1, stack 63 + end; 40 64 -- ["default:steel_ingot"] = {15, "sorcery:holy_token_harvest"}; 41 65 }; 42 66 sacrifice = { 43 67 -- beattitudes 44 68 ["farming:straw" ] = 1; 45 69 ["farming:bread_slice" ] = 1; 46 70 ["farming:bread" ] = 2; ................................................................................ 130 154 Force = {favor=50, cost=5, chance=7}; 131 155 Longevity = {favor=65, cost=7, chance=3}; 132 156 }; 133 157 tools = { 134 158 rend = {favor=80, cost=15, chance=20}; 135 159 }; 136 160 }; 161 + laziness = 2; 137 162 generosity = 4; 138 163 stinginess = 9; 139 164 idol = { 140 165 desc = "Blood Idol"; 141 166 width = 0.7; 142 167 height = 1.3; 143 168 tex = {
Modified data/spells.lua from [2d770c6227] to [f6d0b8e638].
466 466 if div.restrict and not div.restrict(ctx) then 467 467 return false 468 468 end 469 469 470 470 local dst 471 471 local bonus = math.floor(ctx.stats.power or 1) 472 472 if div.mode == 'any' then 473 - local lst = sorcery.lib.tbl.cshuf(div.give) 473 + local lst = sorcery.lib.tbl.scramble(div.give) 474 474 dst = function(i) return lst[i] end 475 475 elseif div.mode == 'random' then 476 476 dst = function() return tblroll(bonus,div.give) end 477 477 elseif div.mode == 'set' then 478 478 dst = function(i) return div.give[i] end 479 479 elseif div.mode == 'all' then 480 480 dst = function() return div.give end
Modified entities.lua from [5b6d6366ce] to [76a0b3b59c].
78 78 ::collcheck:: do 79 79 -- if no collision then return end 80 80 -- local nname = minetest.get_node(pos).name 81 81 -- if nname == 'air' or minetest.registered_nodes[nname].walkable ~= true then return 82 82 -- elseif nname == 'ignore' then goto destroy end 83 83 -- else fall through to explode 84 84 if collision then -- since 5.3 only!! 85 - print('collision detected!',dump(collision)) 86 85 if collision.collides == false then return end 87 86 if #collision.collisions > 0 then 88 87 local col = collision.collisions[1] 89 88 if col.node_pos then 90 89 pos = col.node_pos 91 90 elseif col.object then 92 91 pos = col.object:get_pos()
Modified infuser.lua from [6c01c64259] to [0b21397e89].
101 101 end 102 102 103 103 local elixir_can_apply = function(elixir, potion) 104 104 -- accepts an elixir def and potion def 105 105 if elixir == nil or 106 106 potion == nil then return false end 107 107 108 - if elixir.apply and potion.on_use then 109 - -- the ingredient is an elixir and at least one potion 110 - -- is a fully enchanted, usable potion 111 - if elixir.flag and potion._proto and 112 - potion._proto['no_' .. elixir.flag] == true then 108 + if elixir.apply and potion._proto and potion._proto.quals then 109 + -- the ingredient is an elixir and at least one potion has a 110 + -- quality that can be enhanced 111 + if elixir.qual and potion._proto and not potion._proto.quals[elixir.qual] then 113 112 -- does the elixir have a property used to denote 114 113 -- compatibility? if so, check the potion to see if it's 115 114 -- marked as incompatible 116 115 return false 117 116 else 118 117 return true 119 118 end ................................................................................ 122 121 return false 123 122 end 124 123 125 124 local effects_table = function(potion) 126 125 local meta = potion:get_meta() 127 126 local tbl = {} 128 127 for k,v in pairs(sorcery.data.elixirs) do 129 - if not v.flag then goto skip end 130 - local val = meta:get_int(v.flag) 128 + if not v.qual then goto skip end 129 + local val = meta:get_int(v.qual) 131 130 if val > 0 then 132 131 local aff, title, desc = v.describe(potion) 133 132 if val > 3 then title = title .. ' x' .. val 134 133 elseif val == 3 then title = 'thrice-' .. title 135 134 elseif val == 2 then title = 'twice-' .. title 136 135 end 137 136 tbl[#tbl + 1] = { ................................................................................ 146 145 147 146 sorcery.alchemy.elixir_apply = function(elixir, potion) 148 147 if not potion then return end 149 148 local pdef = potion:get_definition() 150 149 if elixir_can_apply(elixir, pdef) then 151 150 elixir.apply(potion, pdef._proto) 152 151 potion:get_meta():set_string('description', sorcery.lib.ui.tooltip { 153 - title = pdef._proto.name .. ' Draught'; 152 + title = string.format('%s %s', pdef._proto.name, pdef._proto.kind.label); 154 153 desc = pdef._proto.desc; 155 154 color = sorcery.lib.color(pdef._proto.color):readable(); 156 155 props = effects_table(potion); 157 156 }); 158 157 end 159 158 return potion 160 159 end ................................................................................ 301 300 elseif r.enhance then 302 301 if fx.onenhance then out = fx.onenhance { 303 302 pos = pos; 304 303 stack = out; 305 304 potion = r.proto; 306 305 elixir = r.elixir; 307 306 } end 308 - log.act(dump(r)) 309 307 log.act(string.format('an infuser at %s has enhanced a %s potion with a %s elixir', 310 308 minetest.pos_to_string(pos), out:get_name(), infusion[1]:get_name())) 311 309 end 312 310 inv:set_stack('potions',i,discharge(out)) 313 311 end 314 312 315 313 inv:set_stack('infusion',1,residue)
Modified init.lua from [58ff591804] to [3b59932455].
19 19 argjoin(arg, nxt, ...) 20 20 if arg and not nxt then return tostring(arg) end 21 21 if not arg then return "(nil)" end 22 22 return tostring(arg) .. ' ' .. argjoin(nxt, ...) 23 23 end 24 24 25 25 local logger = function(module) 26 - local emit = function(lvl) 27 - return function(...) 28 - if module then 29 - minetest.log(lvl,string.format('[%s :: %s] %s',selfname,module,argjoin(...))) 30 - else 31 - minetest.log(lvl,string.format('[%s] %s',selfname,argjoin(...))) 26 + local lg = {} 27 + local setup = function(fn, lvl) 28 + lvl = lvl or fn 29 + local function emit(...) 30 + local call = (fn == 'fatal') and error 31 + or function(str) minetest.log(lvl, str) end 32 + if module 33 + then call(string.format('[%s :: %s] %s',selfname,module,argjoin(...))) 34 + else call(string.format('[%s] %s',selfname,argjoin(...))) 32 35 end 33 36 end 37 + lg[fn ] = function(...) emit(...) end 38 + lg[fn .. 'f'] = function(...) emit(string.format(...)) end -- convenience fn 34 39 end 35 - return { 36 - info = emit('info'); 37 - warn = emit('warning'); 38 - err = emit('error'); 39 - act = emit('action'); 40 - } 40 + setup('info') 41 + setup('warn','warning') 42 + setup('err','error') 43 + setup('act','action') 44 + setup('fatal') 45 + return lg 41 46 end; 42 47 43 48 local stage = function(s,...) 44 49 logger().info('entering stage',s) 45 50 local f = sorcery.cfg(s .. '.lua') 46 51 if test(f) then return loadfile(f)(...) or true end 47 52 return false
Modified keg.lua from [7838002de4] to [5c653d450d].
185 185 }) 186 186 187 187 minetest.register_craft { 188 188 output = "sorcery:keg"; 189 189 recipe = { 190 190 {'','screwdriver:screwdriver',''}; 191 191 {'sorcery:screw_bronze', 'sorcery:tap', 'sorcery:screw_bronze'}; 192 - {'', 'xdecor:barrel', ''}; 192 + {'sorcery:screw_bronze', 'xdecor:barrel', 'sorcery:screw_bronze'}; 193 193 }; 194 194 replacements = { 195 195 {'screwdriver:screwdriver', 'screwdriver:screwdriver'}; 196 196 }; 197 197 }
Modified lib/node.lua from [d8278e1811] to [087023acf7].
315 315 if n.name == 'ignore' then 316 316 minetest.load_area(sum) 317 317 n = minetest.get_node(sum) 318 318 end 319 319 fn(sum, n) 320 320 end 321 321 end; 322 + 323 + amass = amass; 322 324 323 325 force = force; 324 326 325 327 -- when items have already been removed; notify cannot be relied on 326 328 -- to reach the entire network; this function accounts for the gap 327 329 notifyneighbors = function(pos) 328 330 sorcery.lib.node.forneighbor(pos, sorcery.ley.txofs, function(sum,node)
Modified lib/tbl.lua from [990a6e8caf] to [0fb14e1ea3].
4 4 for i = #list, 2, -1 do 5 5 local j = math.random(i) 6 6 list[i], list[j] = list[j], list[i] 7 7 end 8 8 return list 9 9 end 10 10 11 -fn.cshuf = function(list) 11 +fn.scramble = function(list) 12 12 return fn.shuffle(table.copy(list)) 13 13 end 14 14 15 15 fn.urnd = function(min,max) 16 16 local r = {} 17 17 for i=min,max do r[1 + (i - min)] = i end 18 18 fn.shuffle(r) ................................................................................ 27 27 hash[v] = true 28 28 new[#new+1] = v 29 29 end 30 30 end 31 31 return new 32 32 end 33 33 34 -fn.scramble = function(list) 35 - local new = table.copy(list) 36 - fn.shuffle(new) 37 - return new 38 -end 39 - 40 34 fn.copy = function(t) 41 35 local new = {} 42 36 for i,v in pairs(t) do new[i] = v end 43 37 setmetatable(new,getmetatable(t)) 44 38 return new 45 39 end 46 40
Modified liquid.lua from [04ca2e071b] to [6a40bd16e3].
50 50 51 51 sorcery.liquid.mktrough = function(liq) 52 52 -- troughs are used for collecting liquid from the environment, 53 53 -- like rainwater and tree sap. they hold twice as much as a bucket 54 54 local Q = constants.glasses_per_bottle 55 55 local trough_mkid = function(l,i) 56 56 if type(l) == 'string' then l = sorcery.register.liquid.db[l] end 57 - if not l or not i then return 'sorcery:trough' end 57 + if (not l) or (not i) or i < 1 then return 'sorcery:trough' end 58 58 return string.format('%s:trough_%s_%u', l.mod,l.sid,i) 59 59 end 60 60 local lid = function(l) return trough_mkid(liq, l) end 61 61 62 62 local M = constants.bottles_per_trough 63 63 local mkbox = function(lvl) 64 64 local pxl = function(tbl) -- for mapping to txcoords ................................................................................ 161 161 end 162 162 end 163 163 sorcery.liquid.mktrough() 164 164 165 165 sorcery.liquid.measure_default = function(amt) 166 166 return string.format('%s drams', amt*constants.drams_per_glass) 167 167 end 168 + 169 +sorcery.liquid.container = function(liq, ctr) 170 + return liq.containers[({ 171 + bottle = 'vessels:glass_bottle'; 172 + glass = 'vessels:drinking_glass'; 173 + keg = 'sorcery:keg'; 174 + trough = 'sorcery:trough'; 175 + })[ctr] or ctr] 176 +end 177 + 168 178 sorcery.liquid.register = function(liq) 169 179 local fmt = string.format 170 180 local Q = constants.glasses_per_bottle 171 181 liq.sid = liq.sid or liq.id:gsub('^[^:]+:','') 172 182 liq.mod = liq.mod or liq.id:gsub('^([^:]+):.*','%1') 173 183 if not liq.measure then 174 184 liq.measure = sorcery.liquid.measure_default
Modified potions.lua from [a4fa9f9b09] to [0b54227d82].
52 52 53 53 sorcery.register_oil = function(name,label,desc,color,imgvariant,extra) 54 54 local image = 'xdecor_bowl.png^(sorcery_oil_' .. (imgvariant or 'dull') .. '.png^[colorize:'..tostring(color)..':140)' 55 55 sorcery.register.residue.link('sorcery:' .. name, 'xdecor:bowl') 56 56 extra.description = label; 57 57 extra.inventory_image = image; 58 58 if not extra.groups then extra.groups = {} end 59 + extra.groups.sorcery_oil = 1 59 60 minetest.register_craftitem('sorcery:' .. name, extra) 60 61 end 61 62 62 63 sorcery.register_potion('blood', 'Blood', 'A bottle of sacrificial blood, imbued with stolen (or perhaps donated) life force', u.color(219,19,14), nil, nil, { 63 64 _sorcery = { 64 65 life_store = 4; 65 66 container = { ................................................................................ 102 103 output = 'sorcery:' .. id; 103 104 _proto = proto; 104 105 } 105 106 end 106 107 end 107 108 108 109 -- for n,v in pairs(sorcery.data.potions) do 110 +local kind_potion = { 111 + label = 'Potion'; 112 + kind = 'A mystical liquid crucial to the art of alchemy'; 113 +} 109 114 sorcery.register.potions.foreach('sorcery:mknodes',{},function(n,v) 110 115 local color = u.color(v.color) 111 116 local kind = v.style 112 117 local glow = v.glow 113 118 local id = 'potion_' .. string.lower(n) 114 119 local desc = 'A ' .. ((glow and 'glowing ') or '') .. 115 120 'bottle of ' .. string.lower(n) .. 116 121 ((kind == 'sparkle' and ', fiercely bubbling') or '') .. 117 122 ' liquid' 118 123 local fullname = n .. ' Potion' 119 124 sorcery.register.liquid.link('sorcery:'..id, { 120 - name = 'Serene Potion'; 125 + name = fullname; 121 126 color = v.color; 122 127 proto = v; 123 128 kind = 'sorcery:potion'; 124 129 measure = function(amt) return string.format('%s draughts', amt / 3) end; 125 130 containers = { 126 131 ['vessels:glass_bottle'] = 'sorcery:' .. id; 127 132 }; 128 133 }) 134 + v.kind = kind_potion; 129 135 sorcery.register_potion(id, fullname, desc, color, kind, glow, { 130 136 groups = { 131 137 sorcery_potion = 1; 132 138 sorcery_magical = 1; 133 139 }; 134 140 _proto = v; 135 141 _sorcery = { ................................................................................ 142 148 }; 143 149 }; 144 150 }) 145 151 create_infusion_recipe(id,v,'sorcery:potion_serene',{data=v,name=fullname}) 146 152 end) 147 153 148 154 -- for n,potion in pairs(sorcery.data.draughts) do 155 +local kind_draught = { 156 + label = 'Draught'; 157 + desc = 'A drink that will suffuse your body and spirit with mystic energies'; 158 +} 149 159 sorcery.register.draughts.foreach('sorcery:mknodes',{},function(n,potion) 150 160 local name = 'draught_' .. n 161 + potion.kind = kind_draught 151 162 local behavior = { 152 163 _proto = potion; 153 164 groups = { 154 165 sorcery_potion = 2; 155 166 sorcery_draught = 1; 156 167 sorcery_magical = 1; 157 168 sorcery_usable_magic = 1; ................................................................................ 201 212 potion.style or 'dull', 202 213 potion.glow or 0, 203 214 behavior) 204 215 create_infusion_recipe(name,potion,'sorcery:potion_luminous',{data=potion,name=fullname}) 205 216 end) 206 217 207 218 -- for n,elixir in pairs(sorcery.data.elixirs) do 219 +local kind_elixir = { 220 + label = 'Elixir'; 221 + desc = 'A special kind of potion that enhances the particular qualities of other alchemical brews'; 222 +} 208 223 sorcery.register.elixirs.foreach('sorcery:mknodes',{},function(n,elixir) 209 224 local color = u.color(elixir.color) 210 225 local id = 'elixir_' .. string.lower(n) 211 226 local fullname = 'Elixir of ' .. n 227 + elixir.kind = kind_elixir; 212 228 sorcery.register_potion(id, fullname, nil, color, 'dull', false, { 213 229 _proto = elixir; 214 230 groups = { 215 231 sorcery_elixir = 1; 216 232 sorcery_magical = 1; 217 233 }; 218 234 }) ................................................................................ 236 252 local kind = v.style 237 253 sorcery.register_oil('grease_' .. n, u.str.capitalize(n) .. ' Grease', nil, color, kind, { 238 254 groups = { sorcery_grease = 1 } 239 255 }) 240 256 end) 241 257 242 258 -- for n,v in pairs(sorcery.data.philters) do 259 +local kind_philter = { 260 + label = 'Philter'; 261 + desc = 'A special kind of potion that wooden rods can be soaked in to imbue them with special powers and transform them into wands'; 262 +} 243 263 sorcery.register.philters.foreach('sorcery:mknodes',{},function(n,v) 244 264 local color = u.color(v.color) 245 265 local id = 'philter_' .. n 246 266 local name = v.name or u.str.capitalize(n) 267 + if not v.name then v.name = name end 247 268 local fullname = name .. ' Philter' 269 + v.kind = kind_philter 248 270 sorcery.register_potion(id, fullname, v.desc, color, 'sparkle',v.glow or 4, { 249 271 _proto = v; 250 272 _protoname = n; 251 273 groups = { 252 274 sorcery_magical = 1; 253 275 sorcery_philter = 1; 254 276 }; 255 277 }) 278 + v.quals = {force = true}; 256 279 create_infusion_recipe(id,v,'sorcery:potion_viscous',{data=v,name=fullname}) 257 280 end) 258 281 259 282 -- for n,v in pairs(sorcery.data.extracts) do 260 283 sorcery.register.extracts.foreach('sorcery:mknodes',{},function(n,v) 261 284 local item = v[1] 262 285 local color = u.color(v[2]) ................................................................................ 302 325 {"farming:mortar_pestle", "farming:mortar_pestle"}; 303 326 }; 304 327 } 305 328 end 306 329 -- need a relatively pure alcohol for this, tho other alcohols can be used 307 330 -- for potionmaking in other ways 308 331 add_alcohol('farming:bottle_ethanol') 309 - add_alcohol('wine:glass_vodka') 332 + if minetest.get_modpath('wine') then 333 + add_alcohol('wine:glass_vodka') 334 + end 310 335 end)
Modified runeforge.lua from [69ba246df3] to [65aa0a1ed6].
36 36 }; 37 37 supreme = {grade = 6, name = 'Supreme'; infusion = 'sorcery:powder_levitanium'; 38 38 dist = { Fragile = 0, Weak = 0, Ordinary = 1, Pristine = 0.7, Sublime = 0.4 }; 39 39 }; 40 40 }; 41 41 } 42 42 local calc_phial_props = function(phial) --> mine interval: float, time factor: float 43 + local m = phial:get_meta() 43 44 local g = phial:get_definition()._proto.data.grade 44 45 local i = constants.rune_mine_interval 45 46 local fac = (g-1) / 5 47 + fac = fac + 0.4 * m:get_int('speed') 46 48 return i - ((i*0.5) * fac), 0.5 * fac 47 49 end 48 50 sorcery.register.runes.foreach('sorcery:generate',{},function(name,rune) 49 51 local id = 'sorcery:rune_' .. name 50 52 rune.image = rune.image or string.format('sorcery_rune_%s.png',name) 51 53 rune.item = id 52 54 local c = sorcery.lib.color(rune.tone) ................................................................................ 55 57 short_description = rune.name .. ' Rune'; 56 58 inventory_image = rune.image; 57 59 stack_max = 1; 58 60 groups = { 59 61 sorcery_rune = 1; 60 62 not_in_creative_inventory = 1; 61 63 }; 62 - _proto = { id = name, data = rune; }; 64 + _proto = { id = name, data = rune }; 63 65 }) 64 66 end) 67 + 68 +local phkind = { 69 + label = 'Phial'; 70 + desc = 'An alchemical substance which rune forges consume while coalescing new runes'; 71 +} 65 72 66 73 for name,p in pairs(constants.phial_kinds) do 67 74 local f = string.format 68 75 local color = sorcery.lib.color(142,232,0) 69 76 local fac = p.grade / 6 70 77 local id = f('phial_%s', name); 78 + local fname = f('%s Phial',p.name); 79 + local desc = "A powerful liquid consumed in the operation of a rune forge. Its quality determines how fast new runes can be constructed and how much energy is required by the process, and affects your odds of getting a high-quality rune." 71 80 sorcery.register_potion_tbl { 72 81 name = id; 73 - label = f('%s Phial',p.name); 74 - desc = "A powerful liquid consumed in the operation of a rune forge. Its quality determines how fast new runes can be constructed and how much energy is required by the process, and affects your odds of getting a high-quality rune."; 82 + label = fname; 83 + desc = desc; 75 84 color = color:brighten(1 + fac*0.5); 76 85 imgvariant = (fac >= 5) and 'sparkle' or 'dull'; 77 86 glow = 5+p.grade; 78 87 extra = { 79 88 groups = { sorcery_phial = p.grade }; 80 - _proto = { id = name, data = p }; 89 + _proto = { id = name, desc = desc, name = p.name, kind = phkind, data = p, quals = {force = true, speed = true}, color = color }; 81 90 }; 82 91 } 83 92 sorcery.register.infusions.link { 84 93 infuse = p.infusion; 85 94 into = 'sorcery:potion_subtle'; 86 95 output = 'sorcery:'..id; 87 96 } ................................................................................ 255 264 local pow_min = l.self.powerdraw >= l.self.minpower 256 265 local pow_max = l.self.powerdraw >= l.self.maxpower 257 266 local has_phial = function() return not i:is_empty('phial') end 258 267 259 268 if time and has_phial() and pow_min and not probe.disjunction then -- roll for runes 260 269 local phial = i:get_stack('phial',1) 261 270 local int, powerfac = calc_phial_props(phial) 271 + local pf = phial:get_meta():get_int('force') 262 272 local rolls = math.floor(time/int) 263 273 local newrunes = {} 264 274 for _=1,rolls do 265 275 local choices = {} 266 276 for name,rune in pairs(sorcery.data.runes) do 267 277 -- print('considering',name) 268 278 -- print('-- power',rune.minpower,(rune.minpower*powerfac)*time,'//',l.self.powerdraw,l.self.powerdraw/time,'free',l.freepower,'max',l.maxpower) 269 - if (rune.minpower*powerfac)*time <= l.self.powerdraw and math.random(rune.rarity) == 1 then 279 + if (rune.minpower*powerfac)*time <= l.self.powerdraw and math.random(rune.rarity - pf) == 1 then 270 280 choices[#choices + 1] = rune 271 281 end 272 282 end 273 283 if #choices > 0 then 274 284 -- if multiple runes were rolled up, be nice to the player 275 285 -- and pick the rarest one to give them 276 286 local rare, choice = 0 ................................................................................ 491 501 local wrench if not inv:is_empty('wrench') then 492 502 wrench = inv:get_stack('wrench',1):get_definition()._proto 493 503 end 494 504 if fl == 'cache' then 495 505 if probe.disjunction then return 0 end 496 506 if tl == 'cache' then return 1 end 497 507 if tl == 'active' and inv:is_empty('active') then 498 - print(dump(wrench)) 499 508 if wrench and wrench.powers.imbue and not inv:is_empty('amulet') then 500 509 local amulet = inv:get_stack('amulet',1) 501 510 local rune = inv:get_stack(fl,fi) 502 511 local runeid = rune:get_definition()._proto.id 503 512 local runegrade = rune:get_meta():get_int('rune_grade') 504 513 if sorcery.data.runes[runeid].amulets[amulet:get_definition()._sorcery.amulet.base] then 505 514 local spell do -- haaaack
Modified sorcery.md from [5a3ebfda49] to [17b053c9d3].
57 57 * if you need to travel quickly between two distant places, and you're wealthy enough to afford it, you can build yourself one of the most powerful and complex of magitech devices — the **Teleporter**. it's no mean feat: even the smallest teleporter requires a teleport pad with a reflector above it and a portal node connected to one or the other. the teleporter will then need to be connected to its destination with cables or conduits, and if where you're travelling is very far away, you'll have to build two separate ley nets and bridge them by using an **Attunement Wand** on a pair of **Raycasters** — or perhaps even **Farcasters**. the power required to operate all of these devices is not trivial, and while a Farcaster's signal can pierce through any substance and cross any distance to reach its destination, the farther away each is from the other, the more power each side will consume. and casters can't send current, they can only send signals, so you may need a sizable power plant on both sides of the portal. 58 58 * if all you need to do is send small items, of course, a **Displacer** is much cheaper, and more flexible. if you're feeling particularly ambitious, you could use a Displacer net to connect your whole kingdom with instantaneous package service. 59 59 * stop your foes in their tracks by flipping a switch to turn on your **Force Field Emitters**, generating an impenetrable barrier wherever they aim. 60 60 * who needs elevators when you have **Gravitators**? float gently up a vast borehole, bring attackers crashing down to earth, or slow a fatal plunge to a soft and easy landing. 61 61 * build graven **Idols** to your gods and set sacrifices to them upon an altar. if they're feeling generous, they might start sending you presents of their own, or consecrating your offerings. but beware: different gods have different tastes (and different powers), and get bored quickly with repetitive offerings. 62 62 * to bend the ultimate arcane forces of the cosmos to your will, you'll need a **Rune Forge**. with a strong ley-current and a steady supply of **Phials** from an Infuser, a Rune Forge will crystallize thaumic impurities into Runes that can you can imbue into a gemstone **Amulet** with a **Rune Wrench**. each amulet can only be used once before it loses its charge, and it may be a long time before the same kind of rune happens to coalesce in your forge again, but the spells they unleash are unique and priceless boons — or weapons. teleport without a teleporter! purge your environs of all spellcraft no matter how fearsomely potent! surround yourself with a shimmering Disjunction Field that, for a short while, will snuff out any spell it touches and, rendering enemy mages utterly helpless and piercing otherwise impenetrable defenses! stride through solid stone like open air! carve huge tunnels deep into the rock with only a snap of your fingers! rain obliteration down upon a target of your choosing! send forth a titanic bolt of flame with the power to blast open mountainsides! tear the very life force straight from an enemy's body and use it to fortify your being! all this and more can be done with the power of rune magic. 63 63 64 -there's more as well. i have yet to figure out how i want to go about introducing users to the lore, but for now there's some information on the wiki and some things you can glean from creative mode; otherwise you'll have to read the source code. 64 +there's more as well. i have yet to figure out how i want to go about introducing users to the lore (although you can occasionally find random recipes in dungeon chests, and gods can be coaxed to bestow recipes and cookbooks), but for now there's some information on the wiki and some things you can glean from creative mode; otherwise you'll have to read the source code. 65 65 66 66 # lore 67 67 `sorcery` supplies a default system of lore (that is, the arbitrary objects that the basic principles of the setting operate over) but this can be augmented or replaced on a per-world basis. for instance, you can substitute your own gods for the Harvest Goddess, Blood God, change their names, and so on, or simply make your own additions to the pantheon. since lore overrides are stored outside the minetest tree, it can be updated without destroying your changes. 68 68 69 69 lore is stored separately from the rest of the game logic, in the 'data' directory of the `sorcery` mod. it is arranged in a hierarchy of thematically-organized tables. for instance, the table of gods can be found in `data/gods.lua`. ideally, lore tables should contain plain data, though they can also contain lambdas if necessary. lore files are evaluated in the second stage of the init process, after library code has been loaded but before any game logic has been instantiated. lore can thus depend on libraries where reasonable (though e.g. colors should be stored as 3-tuples rather than `sorcery.lib.color` objects, and images as texture strings, unless there is a very good reason to do otherwise). 70 70 71 71 lore files should never depend on functions in the `minetest` or `core` namespace! if you really need such functionality, gate it off with an if statement and be sure to return something useful in the event that the namespace isn't defined. *lore is just data:* as a general principle, non-minetest code should be able to evaluate and make use of the lore files, for instance to produce an HTML file tabulating the various potions and how to create them. lore should also not mutate the global environment: while there is currently nothing preventing it from doing so, steps will likely be taken in the future to give each lore module a clean environment to keep it from contaminating the global namespace. right now, all functions and variables declared in a lore file should be defined `local`. the only job of a lore file is to return a table.
Modified spell.lua from [92125c4f2c] to [4f39d5643f].
28 28 -- disjunction is cast on one of them, they will be removed from the 29 29 -- table. each entry should have at least a 'player' field; they can 30 30 -- also contain any other data useful to the spell. if a subject has 31 31 -- a 'disjoin' field it must be a function called when they are removed 32 32 -- from the list of spell targets. 33 33 -- * caster is the individual who cast the spell, if any. a disjunction 34 34 -- against their person will totally disrupt the spell. 35 -local log = function(...) sorcery.log('spell',...) end 35 +local log = sorcery.logger 'spell' 36 36 37 37 -- FIXME saving object refs is iffy, find a better alternative 38 38 sorcery.spell = { 39 39 active = {} 40 40 } 41 41 42 42 local get_spell_positions = function(spell) ................................................................................ 224 224 local t if type(when) == 'number' then 225 225 t = s.duration * when 226 226 else 227 227 t = (s.duration * (when.whence or 0)) + when.secs 228 228 end 229 229 if t then return math.min(s.duration,math.max(0,t)) end 230 230 231 - log('invalid timespec ' .. dump(when)) 231 + log.err('invalid timespec ' .. dump(when)) 232 232 return 0 233 233 end 234 234 s.queue = function(when,fn) 235 235 local elapsed = s.starttime and minetest.get_server_uptime() - s.starttime or 0 236 236 local timepast = interpret_timespec(when) 237 237 if not timepast then timepast = 0 end 238 238 local timeleft = s.duration - timepast 239 239 local howlong = (s.delay + timepast) - elapsed 240 240 if howlong < 0 then 241 - log('cannot time-travel! queue() called with `when` specifying timepoint that has already passed') 241 + log.err('cannot time-travel! queue() called with `when` specifying timepoint that has already passed') 242 242 howlong = 0 243 243 end 244 244 s.jobs[#s.jobs+1] = minetest.after(howlong, function() 245 245 -- this is somewhat awkward. since we're using a non-polling approach, we 246 246 -- need to find a way to account for a caster or subject walking into an 247 247 -- existing antimagic field, or someone with an existing antimagic aura 248 248 -- walking into range of the anchor. so every time a spell effect would ................................................................................ 334 334 termqueued = true 335 335 s.queue(1,function(s,...) 336 336 what(s,...) 337 337 if s.terminate then s:terminate() end 338 338 sorcery.spell.active[myid] = nil 339 339 end) 340 340 else 341 - log('multiple final timeline events not possible, ignoring') 341 + log.warn('multiple final timeline events not possible, ignoring') 342 342 end 343 343 elseif when == 0 and s.disjunction then 344 344 startqueued = true 345 345 s.queue(when_raw,function(...) 346 346 perform_disjunction_calls() 347 347 what(...) 348 348 end)
Modified tap.lua from [7b8c107461] to [17fb78473a].
1 1 local log = sorcery.logger('tap') 2 2 minetest.register_node('sorcery:tap',{ 3 3 description = 'Tree Tap'; 4 4 drawtype = 'mesh'; 5 5 mesh = 'sorcery-tap.obj'; 6 + inventory_image = 'sorcery_tap_inv.png'; 6 7 tiles = { 7 8 'default_copper_block.png'; 8 9 'default_steel_block.png'; 9 10 }; 10 11 groups = { 11 12 dig_immediate = 2; 12 13 attached_node = 1;
Added textures/sorcery_tap_inv.png version [0ade756825].
cannot compute difference between binary files