Comment: | fix some showstopping bugs, more amulet spells, add sound effects, improve teleportation visuals |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
90e64c483cf23b6ba5b92e8987d2e92c |
User & Date: | lexi on 2020-10-23 00:08:30 |
Other Links: | manifest | tags |
2020-10-24
| ||
01:21 | add some more spells, add spell infrastructure to support metamagic, especially disjunction, various tweaks and bugfixes. [emergency commit] check-in: 00922196a9 user: lexi tags: trunk | |
2020-10-23
| ||
00:08 | fix some showstopping bugs, more amulet spells, add sound effects, improve teleportation visuals check-in: 90e64c483c user: lexi tags: trunk | |
2020-10-22
| ||
15:51 | balance amulets better, add sound effects, add debugging privilege for runes, swat various glitches and bugs check-in: 83426a2748 user: lexi tags: trunk | |
Modified altar.lua from [f718356661] to [71f6a713cb].
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 5 5 6 local range = function(min, max) 6 7 local span = max - min 7 8 local val = math.random() * span 8 9 return val + min 9 10 end 10 11 ................................................................................ 166 167 -- we pick a random gift and roll against its rarity 167 168 -- to determine if the god is feeling generous 168 169 local gift = sorcery.lib.tbl.pick(god.gifts) 169 170 local data = god.gifts[gift] 170 171 local value, rarity = data[1], data[2] 171 172 if value <= divine_favor and math.random(rarity) == 1 then 172 173 bestow(gift) 173 - print(god.name .. ' has produced ' .. gift .. ' upon an altar as a gift') 174 + log(god.name .. ' has produced ' .. gift .. ' upon an altar as a gift') 174 175 if math.random(god.generosity) == 1 then 175 176 -- unappreciated gifts may incur divine 176 177 -- irritation 177 178 divine_favor = divine_favor - 1 178 179 end 179 180 end 180 181 end
Modified cookbook.lua from [fe2bed6abe] to [604c53eb6c].
82 82 end 83 83 return names[math.random(#names)] 84 84 end end 85 85 local find_builtin = function(method,kind) 86 86 return function(out) 87 87 local rec = {} 88 88 local crec = sorcery.lib.tbl.walk(minetest.registered_items[out],{'_sorcery','recipe','canonical',kind}) 89 - local w=0, lst 89 + local w, lst = 0 90 90 if crec then 91 91 lst = {} 92 92 for i,v in pairs(crec) do 93 93 if #v > w then w = #v end 94 94 for j,n in pairs(v) do 95 95 lst[#lst+1] = n 96 96 end ................................................................................ 108 108 w = (i.width == 0) and 3 or i.width 109 109 lst = i.items 110 110 end 111 111 -- for j=1,#i.items do 112 112 for j,item in pairs(lst) do 113 113 local row = math.floor((j-1) / w) 114 114 local col = (j-1) % w 115 - if item then 116 - rec[1 + (row * 3) + col] = item 117 - end 115 + if item then rec[1 + (row * 3) + col] = item end 118 116 end 119 117 return rec 120 118 end 121 119 end 122 120 local function group_eval(i) 123 121 if string.sub(i,1,6) == 'group:' then 124 122 local g = string.sub(i,7) ................................................................................ 218 216 chance = 4; 219 217 slots = { 220 218 {0,0}; 221 219 {0,1}; 222 220 }; 223 221 pick = function(restrict) 224 222 -- TODO make sure affinity restrictions match 225 - return sorcery.data.infusions[math.random(#sorcery.data.infusions)].output 223 + return sorcery.register.infusions.db[math.random(#sorcery.register.infusions.db)].output 226 224 end; 227 225 title = function(output) 228 - for _,i in pairs(sorcery.data.infusions) do 226 + for _,i in pairs(sorcery.register.infusions.db) do 229 227 if i.output == output then 230 228 if i._proto and i._proto.name 231 229 then return i._proto.name 232 230 else break end 233 231 end 234 232 end 235 233 return 'Mysterious Potion' 236 234 end; 237 235 find = function(out) 238 - for _,i in pairs(sorcery.data.infusions) do 236 + for _,i in pairs(sorcery.register.infusions.db) do 239 237 if i.output == out then 240 238 return { i.infuse, i.into } 241 239 end 242 240 end 243 241 end; 244 242 props = function(out) 245 - for _,i in pairs(sorcery.data.infusions) do 243 + for _,i in pairs(sorcery.register.infusions.db) do 246 244 if i.output == out then 247 245 if i.recipe then return i.recipe else return {} end 248 246 end 249 247 end 250 248 end; 251 249 }; 252 250 grind = {
Modified data/extracts.lua from [c62e0cc7f2] to [442aef28cd].
13 13 raspberry = {"group:food_raspberries", {228,51,210}}; 14 14 chili = {"farming:chili_pepper", {243,75,49}}; 15 15 pine = {"default:pine_sapling", {41,166,80}}; 16 16 cocoa = {"farming:cocoa_beans", {146,38,0}}; 17 17 grape = {"farming:grapes", {206,56,214}}; 18 18 kelp = {"default:sand_with_kelp", {109,185,145}}; 19 19 fern = {"default:fern_1", {164,238,47}}; 20 + greengrass = {"default:grass_1", {185,255,115}}; 20 21 marram = {"default:marram_grass_1", {127,255,210}}; 22 + shrub = {"default:dry_shrub", {187,149,76}}; 21 23 };
Modified data/oils.lua from [fb12becfb1] to [6619d22587].
99 99 'farming:peas'; 100 100 'farming:peas'; 101 101 }; 102 102 }; 103 103 luscious = { 104 104 color = {10,255,10}; 105 105 mix = { 106 - 'sorcery:extract_marram'; 106 + 'sorcery:extract_greengrass'; 107 107 'sorcery:extract_grape'; 108 108 'farming:cocoa_beans'; 109 109 'farming:sugar'; 110 110 'farming:sugar'; 111 111 }; 112 112 }; 113 113 }
Modified data/resonance.lua from [436a325bac] to [c464435f82].
42 42 'sorcery:essence_flame'; 43 43 'sorcery:gem_ruby'; 44 44 }; 45 45 }; 46 46 ['default:mese_crystal'] = { 47 47 mode = 'random'; 48 48 give = { 49 - {value = 1; item = 'default:mese_fragment'}; 49 + {value = 1; item = 'default:mese_crystal_fragment'}; 50 50 {value = 2; item = 'sorcery:essence_force'}; 51 51 }; 52 52 }; 53 53 }; 54 54 55 55 meld = { 56 56 {
Modified data/runes.lua from [720c3d8102] to [47aa367750].
32 32 name = 'Arrival'; 33 33 desc = "Give this amulet to another and they will be able to arrive at your side in a flash from anywhere in the world, carrying others with them in the spell's grip"; 34 34 }; 35 35 }; 36 36 }; 37 37 sapphire = { 38 38 name = 'Return'; 39 - desc = 'Use this amulet once to bind it to a particular point in the world, then discharge its spell to return instantly to that point.'; 39 + desc = 'Use this amulet once to bind it to a particular place, then discharge its spell to translocate yourself back to that point from anywhere in the world.'; 40 40 remove = function(ctx) 41 41 ctx.meta:set_string('rune_return_dest','') 42 42 end; 43 43 cast = function(ctx) 44 44 if not ctx.meta:contains('rune_return_dest') then 45 45 local pos = ctx.caster:get_pos() 46 46 ctx.meta:set_string('rune_return_dest',minetest.pos_to_string(pos)) ................................................................................ 47 47 return true -- play effects but do not break spell 48 48 else 49 49 local pos = minetest.string_to_pos(ctx.meta:get_string('rune_return_dest')) 50 50 ctx.meta:set_string('rune_return_dest','') 51 51 local subjects = { ctx.caster } 52 52 local center = ctx.caster:get_pos() 53 53 ctx.sparkle = false 54 + local delay = math.max(3,10 - ctx.stats.power) + 3*(math.random()*2-1) 55 + print('teledelay',delay,ctx.stats.power) 54 56 for _,s in pairs(subjects) do 55 57 local offset = vector.subtract(s:get_pos(), center) 56 58 local pt = sorcery.lib.node.get_arrival_point(vector.add(pos,offset)) 57 59 if pt then 58 - sorcery.vfx.body_sparkle(s,sorcery.lib.color(20,120,255),2) 59 - sorcery.vfx.body_sparkle(nil,sorcery.lib.color(20,255,120),2,pt) 60 - s:set_pos(pt) 60 + minetest.sound_play('sorcery_stutter', { 61 + object = s, gain = 0.8; 62 + },true) 63 + local windup = minetest.sound_play('sorcery_windup',{ 64 + object = s, gain = 0.4; 65 + }) 66 + local mydelay = delay + math.random(-10,10)*.1; 67 + local spark = sorcery.lib.image('sorcery_spark.png') 68 + local sh = s:get_properties().eye_height 69 + local sparkle = function(amt,time,minsize,maxsize) 70 + minetest.add_particlespawner { 71 + amount = amt, time = time, attached = s; 72 + minpos = { x = -0.3, y = -0.5, z = -0.3 }; 73 + maxpos = { x = 0.3, y = sh*1.1, z = 0.3 }; 74 + minvel = { x = -0.4, y = -0.2, z = -0.4 }; 75 + maxvel = { x = 0.4, y = 0.2, z = 0.4 }; 76 + minacc = { x = -0.5, y = -0.4, z = -0.5 }; 77 + maxacc = { x = 0.5, y = 0.4, z = 0.5 }; 78 + minexptime = 1.0, maxexptime = 2.0; 79 + minsize = minsize, maxsize = maxsize, glow = 14; 80 + texture = spark:blit(spark:multiply(sorcery.lib.color(29,205,247))):render(); 81 + animation = { 82 + type = 'vertical_frames'; 83 + aspect_w = 16, aspect_h = 16; 84 + }; 85 + } 86 + end 87 + sparkle(mydelay*100,mydelay,0.3,1.3) 88 + minetest.after(mydelay*0.4, function() 89 + local timeleft = mydelay - (mydelay*0.4) 90 + sparkle(timeleft*150, timeleft, 0.6,1.8) 91 + end) 92 + minetest.after(mydelay*0.7, function() 93 + local timeleft = mydelay - (mydelay*0.7) 94 + sparkle(timeleft*80, timeleft, 2,4) 95 + end) 96 + sorcery.lib.node.preload(pt,s) 97 + minetest.after(mydelay, function() 98 + minetest.sound_stop(windup) 99 + minetest.sound_play('sorcery_zap', { pos = pt, gain = 0.4 },true) 100 + minetest.sound_play('sorcery_zap', { pos = s:get_pos(), gain = 0.4 },true) 101 + sorcery.vfx.body_sparkle(nil,sorcery.lib.color(20,255,120),2,s:get_pos()) 102 + s:set_pos(pt) 103 + sorcery.vfx.body_sparkle(s,sorcery.lib.color(20,120,255),2) 104 + end) 61 105 end 62 106 end 63 107 end 64 108 end; 65 109 frame = { 66 110 iridium = { 67 111 name = 'Mass Return'; 68 - desc = 'Use this amulet once to bind it to a particular point in the world, then carry yourself and everyone around you back to that point in a flash simply by using it again'; 112 + desc = 'Use this amulet once to bind it to a particular place, then carry yourself and everyone around you back to that point in a flash simply by using it again'; 69 113 }; 70 114 }; 71 115 }; 72 116 emerald = { 73 117 name = 'Banishment'; 74 118 desc = 'Use this amulet once to bind it to a particular point in the world, then wield it against a foe to whisk them away immediately to your chosen prison'; 75 119 frame = { 76 120 iridium = { 77 121 name = 'Mass Banishment'; 78 122 desc = 'Use this amulet once to bind it to a particular point in the world, then use it again to seize up everyone surrounding you in the grip of a fearsome magic that will deport them all in the blink of an eye to whatever destination you have chosen'; 79 123 }; 80 124 }; 81 125 }; 82 - ruby = { 126 + ruby = minetest.get_modpath('beds') and { 83 127 name = 'Escape'; 84 128 desc = 'Immediately transport yourself out of a dangerous situation back to the last place you slept'; 129 + cast = function(ctx) 130 + -- if not beds.spawns then beds.read_spawns() end 131 + local subjects = {ctx.caster} 132 + for _,s in pairs(subjects) do 133 + local spp = beds.spawn[ctx.caster:get_player_name()] 134 + if spp then 135 + local oldpos = s:get_pos() 136 + minetest.sound_play('sorcery_splunch', {pos=oldpos}, true) 137 + sorcery.vfx.body_sparkle(nil,sorcery.lib.color(244,38,131),2,oldpos) 138 + s:set_pos(spp) 139 + minetest.sound_play('sorcery_splunch', {pos=spp}, true) 140 + sorcery.vfx.body_sparkle(nil,sorcery.lib.color(244,38,89),2,spp) 141 + end 142 + -- TODO decide what happens to the people who don't have 143 + -- respawn points already set 144 + end 145 + end; 85 146 frame = { 86 147 cobalt = { 87 148 name = 'Vengeful Exit'; 88 149 desc = 'Translocate away to the safety of your boudoir with a fearsome blast of dangerous radiance that will send bodies flying and deal heavy damage to those nearby'; 89 150 }; 90 151 iridium = { 91 152 name = 'Mass Escape'; ................................................................................ 121 182 minpower = 1; 122 183 rarity = 7; 123 184 amulets = { 124 185 amethyst = { 125 186 name = 'Hurling'; 126 187 desc = 'Wielding this amulet, a mere flick of your fingers will lift any target of your choice bodily into the air and press upon them with tremendous repulsive force, throwing them like a hapless ragdoll out of your path'; 127 188 }; 128 - diamond = { 189 + sapphire = { 190 + name = 'Flinging'; 191 + desc = 'Toss an enemy violently into the air, and allow the inevitable impact to do your dirty work for you'; 192 + }; 193 + emerald = { 129 194 name = 'Shockwave'; 195 + desc = 'Let loose a stream of concussive force that slams into everything in your path and sends them hurtling away from you'; 196 + }; 197 + luxite = { 198 + name = 'Repulsive Aura'; 199 + desc = 'For a period of time, anyone who approaches you will be violently thrust aside'; 200 + }; 201 + diamond = { 202 + name = 'Blastwave'; 130 203 desc = 'Unleash a tidal wave of force in every direction, blasting friends and foes alike away from you with enough violence to sprain and fracture bone'; 131 204 }; 132 205 }; 133 206 }; 134 207 obliterate = { 135 208 name = 'Obliterate'; 136 209 tone = {255,0,10}; ................................................................................ 141 214 name = 'Sapping'; 142 215 desc = 'Punch a hole in enemy fortifications big enough to slip through but small enough to avoid immediate attention'; 143 216 }; 144 217 ruby = { 145 218 name = 'Shattering'; 146 219 desc = 'Tear a violent wound in the earth with the destructive force of this amulet'; 147 220 }; 221 + emerald = { 222 + name = 'Detonate'; 223 + desc = 'Wielding this amulet, you can loose an extraordinarily powerful bolt of flame from your fingertips that will explode violently on impact, wreaking total havoc wherever it lands'; 224 + cast = function(ctx) 225 + local speed = 40 226 + local radius = math.random(math.floor(ctx.stats.power*0.5),math.ceil(ctx.stats.power)) 227 + local heading = ctx.heading 228 + heading.pos.y = heading.pos.y + heading.eyeheight*0.9 229 + local vel = vector.multiply(heading.yaw,speed) 230 + local bolt = minetest.add_entity(vector.add(heading.pos,vector.multiply(heading.yaw,2.5)),'sorcery:spell_projectile_flamebolt') 231 + bolt:set_rotation(heading.yaw) 232 + bolt:get_luaentity()._blastradius = radius 233 + bolt:set_velocity(vel) 234 + end; 235 + }; 236 + luxite = { 237 + name = 'Lethal Aura'; 238 + desc = 'For a time, anyone who approaches you, whether friend or foe, will suffer immediate retaliation as they are quickly sapped of their life force'; 239 + }; 148 240 diamond = { 149 241 name = 'Killing'; 242 + mingrade = 4; 150 243 desc = 'Wield this amulet against a foe to instantly snuff the life out of their mortal form, regardless of their physical protections.'; 151 244 cast = function(ctx) 152 245 if not (ctx.target and ctx.target.type == 'object') then return false end 153 246 local tgt = ctx.target.ref 154 247 if not minetest.is_player(obj) then return false end 155 248 local tgth = tgt:get_properties().eye_height 156 249 sorcery.vfx.bloodburst(vector.add(tgt:get_pos(),{x=0,y=tgth/2,z=0}),20) ................................................................................ 206 299 }; 207 300 diamond = { 208 301 name = 'Radiance'; 209 302 desc = 'Set the air around you alight with a mystic luminance, letting you see clearly a great distance in every direction for several minutes'; 210 303 frame = { 211 304 iridium = { 212 305 name = 'Sunshine'; 306 + mingrade = 5; 213 307 desc = 'Unleash the power of this amulet to seize ultimate control over the forces of nature and summon the Sun high into the nighttime sky'; 214 308 }; 215 309 }; 216 310 }; 217 311 }; 218 312 }; 219 313 dominate = { ................................................................................ 222 316 minpower = 4; 223 317 rarity = 40; 224 318 amulets = { 225 319 amethyst = { 226 320 name = 'Suffocation'; 227 321 desc = 'Wrap this spell tightly around your victim\'s throat, cutting off their oxygen until you release them.'; 228 322 }; 323 + emerald = { 324 + name = 'Caging'; 325 + desc = 'Trap your victim in an impenetrable field of force, leaving them with no way out but translocation or waiting for the field to release them'; 326 + }; 229 327 ruby = { 230 328 name = 'Exsanguination'; 231 - desc = 'Rip the life force out of another, leaving them on the brink of death, and use it to mend your own wounds and invigorate your own being'; 329 + desc = 'Rip the life force out of another, leaving them on the brink of death, and use it to mend your own wounds and invigorate your being'; 232 330 cast = function(ctx) 233 331 if not (ctx.target and ctx.target.type == 'object') then return false end 234 332 local tgt = ctx.target.ref 235 333 local takefac = math.min(99,50 + (ctx.stats.power * 5)) / 100 236 334 local dmg = tgt:get_hp() * takefac 237 335 print("!!! dmg calc",takefac,dmg,tgt:get_hp()) 238 336
Modified data/spells.lua from [151760f504] to [16c84d9b57].
179 179 uses = 32; 180 180 affinity = {'acacia','blazing'}; 181 181 leytype = 'praxic'; 182 182 desc = 'Conjure a gout of fire to scorch your foes with a flick of this wand'; 183 183 cast = function(ctx) 184 184 local speed = 30 -- TODO maybe amethyst tip increases speed? 185 185 local radius = math.random(math.max(1,math.floor((ctx.stats.power or 1) - 0.5)), math.ceil((ctx.stats.power or 1)+0.5)) 186 - print('!! radius',radius) 187 186 local heading = ctx.heading 188 187 heading.pos.y = heading.pos.y + heading.eyeheight*0.9 189 188 local vel = vector.multiply(heading.yaw,speed) 190 189 local bolt = minetest.add_entity(vector.add(heading.pos,vector.multiply(heading.yaw,2.5)),'sorcery:spell_projectile_flamebolt') 191 190 bolt:set_rotation(heading.yaw) 192 191 bolt:get_luaentity()._blastradius = radius 193 192 bolt:set_velocity(vel) ................................................................................ 491 490 cast = function(ctx) 492 491 local tgt = target_node(ctx, 'sorcery:enchanter') 493 492 if not tgt then return false end 494 493 495 494 local inv = minetest.get_meta(ctx.target.under):get_inventory() 496 495 for _,name in pairs{'foci','item'} do 497 496 for i=1,inv:get_size(name) do 497 + if inv:get_stack(name,i):is_empty() then goto skip end 498 498 local stack = 'sorcery:ash' 499 499 if ctx.base.gem == 'sapphire' then 500 500 stack = nil 501 501 end 502 502 inv:set_stack(name,i,ItemStack(stack)) 503 - end 503 + ::skip::end 504 504 end 505 505 506 506 enchantment_sparkle(ctx,sorcery.lib.color(255,12,0)) 507 507 enchantment_sparkle(ctx,sorcery.lib.color(85,18,35)) 508 508 enchantment_sparkle(ctx,sorcery.lib.color(0,0,0)) 509 509 end 510 510 };
Modified depends.txt from [01a845eb65] to [5b69774a87].
5 5 basic_materials 6 6 vessels 7 7 late 8 8 instant_ores 9 9 screwdriver 10 10 hopper? 11 11 unifieddyes? 12 +beds?
Modified gems.lua from [f5bc90eb64] to [d9755d7797].
61 61 if not sp or not sp.cast then return nil end 62 62 local stats = sorcery.amulet.stats(stack) 63 63 64 64 local ctx = { 65 65 caster = user; 66 66 target = target; 67 67 stats = stats; 68 - sound = "xdecor_enchanting"; --FIXME make own sounds 69 - sparkle = true; 70 68 amulet = stack; 71 69 meta = stack:get_meta(); -- avoid spell boilerplate 72 70 color = sorcery.lib.color(sp.tone); 71 + today = minetest.get_day_count(); 72 + heading = { 73 + pos = user:get_pos(); 74 + yaw = user:get_look_dir(); 75 + pitch = user:get_look_vertical(); 76 + angle = user:get_look_horizontal(); 77 + eyeheight = user:get_properties().eye_height; 78 + }; 79 + 80 + sound = "xdecor_enchanting"; --FIXME make own sounds 81 + sparkle = true; 73 82 } 74 83 print('casting') 75 84 local res = sp.cast(ctx) 76 85 77 86 if res == nil or res == true then 78 87 minetest.sound_play(ctx.sound, { 79 88 pos = user:get_pos();
Modified portal.lua from [e011f87b11] to [daf126a7a3].
297 297 local found = false 298 298 for _,u in pairs(dsp.users) do 299 299 if u.object:get_player_name() == name then 300 300 found = true 301 301 end 302 302 end 303 303 if not found then 304 + if user.sound then minetest.sound_fade(user.sound,1,0) end 304 305 portal_context.users[name] = nil 305 306 end 306 307 end 307 308 end 308 309 309 310 -- one user per pad only! 310 311 for _,n in pairs(dev.nodes) do ................................................................................ 311 312 for _,u in pairs(dsp.users) do 312 313 if u.slot == n then 313 314 local pname = u.object:get_player_name() 314 315 if not portal_context.users[pname] then 315 316 portal_context.users[pname] = { time = 0, portal = pos } end 316 317 local user = portal_context.users[pname] 317 318 if not vector.equals(pos,user.portal) then 319 + if user.sound then 320 + minetest.sound_fade(user.sound,1,0) 321 + user.sound = nil 322 + end 318 323 user.time = 0 319 324 user.portal = pos 320 325 end 321 326 local cap = sorcery.ley.netcaps(pos,delta) 322 327 local jc = (constants.portal_jump_cost_local*delta) 323 328 if not user.dest and cap.freepower >= jc then 324 329 user.dest = portal_pick_destination(dev,crc,partner) 325 330 sorcery.lib.node.preload(user.dest, u.object) 326 331 end 327 332 if not user.dest then goto skippad end 328 333 local fac = math.min(1,(user.time / constants.portal_jump_time)) 334 + if user.time == 0 then 335 + user.sound = minetest.sound_play('sorcery_windup', {pos=pos}) 336 + end 329 337 minetest.add_particlespawner { 330 338 time = 1, amount = 100 + (fac * 200); 331 339 minsize = 0.2 + fac*0.7, maxsize = 0.4 + fac*0.9; 332 340 minvel = {y = 0.2, x=0,z=0}, maxvel = {y = 0.5, x=0,z=0}; 333 341 minacc = {y = 0.0, x=0,z=0}, maxacc = {y = 0.3, x=0,z=0}; 334 342 minpos = vector.add(n.pad,{x = -0.5, y = 0.5, z = -0.5}); 335 343 maxpos = vector.add(n.pad,{x = 0.5, y = 0.5, z = 0.5}); ................................................................................ 362 370 aspect_w = 16, aspect_h = 16; 363 371 }; 364 372 } 365 373 end 366 374 -- hack to try and swat an unkillable fucking impossibug 367 375 if user.time > constants.portal_jump_time * 2 then 368 376 user.time = 0 377 + if user.sound then 378 + minetest.sound_stop(user.sound) 379 + user.sound = nil 380 + end 369 381 elseif user.time >= constants.portal_jump_time then 370 382 local dd = portal_disposition(portal_composition(user.dest)) 371 383 if #dd.freepads > 0 then 372 384 local destpad = dd.freepads[math.random(#dd.freepads)].pad 373 385 local rng = function(min,max) 374 386 return (math.random() * (max - min)) + min 375 387 end ................................................................................ 392 404 glow = 14; 393 405 animation = { 394 406 type = 'vertical_frames', length = life + 0.1; 395 407 aspect_w = 16, aspect_h = 16; 396 408 }; 397 409 } 398 410 end 411 + if user.sound then 412 + minetest.sound_fade(user.sound,1,0) 413 + user.sound = nil 414 + end 399 415 user.dest = nil 400 416 user.time = 0 417 + user.sound = nil 418 + minetest.sound_play('sorcery_zap',{pos=pos},true) 419 + minetest.sound_play('sorcery_zap',{pos=destpad},true) 401 420 portal_context.users[pname] = nil 402 421 u.object:set_pos(vector.add(destpad, {y=0.5,z=0,x=0})) 403 422 end 404 423 else 405 424 user.time = user.time + delta 406 425 end 407 426
Modified runeforge.lua from [e97e283f3c] to [c8e0c3ac03].
1 1 -- TODO make some kind of disposable "filter" tool that runeforges require 2 2 -- to generate runes and that wears down over time, to make amulets more 3 3 -- expensive than they currently are? the existing system is neat but 4 4 -- i think amulets are a little overpowered for something that just 5 5 -- passively consumes ley-current 6 6 7 7 local constants = { 8 - rune_mine_interval = 250; 8 + rune_mine_interval = 240; 9 9 -- how often a powered forge rolls for new runes 10 10 11 11 rune_cache_max = 4; 12 12 -- how many runes a runeforge can hold at a time 13 13 14 14 rune_grades = {'Fragile', 'Weak', 'Ordinary', 'Pristine', 'Sublime'}; 15 15 -- how many grades of rune quality/power there are ................................................................................ 23 23 great = {grade = 3; name = 'Great'; infusion = 'sorcery:powder_gold'}; 24 24 splendid = {grade = 4; name = 'Splendid'; infusion = 'sorcery:powder_electrum'}; 25 25 exalted = {grade = 5; name = 'Exalted'; infusion = 'sorcery:powder_levitanium'}; 26 26 supreme = {grade = 6; name = 'Supreme'; infusion = 'sorcery:essence_force'}; 27 27 }; 28 28 } 29 29 local calc_phial_props = function(phial) --> mine interval: float, time factor: float 30 - local g = phial:get_definition()._proto.grade 30 + local g = phial:get_definition()._proto.data.grade 31 31 local i = constants.rune_mine_interval 32 32 local fac = (g-1) / 5 33 33 return i - ((i*0.5) * fac), 0.5 * fac 34 34 end 35 35 sorcery.register.runes.foreach('sorcery:generate',{},function(name,rune) 36 36 local id = 'sorcery:rune_' .. name 37 37 rune.image = rune.image or string.format('sorcery_rune_%s.png',name) ................................................................................ 47 47 }; 48 48 _proto = { id = name, data = rune; }; 49 49 }) 50 50 end) 51 51 52 52 for name,p in pairs(constants.phial_kinds) do 53 53 local f = string.format 54 - local color = sorcery.lib.color(255,27,188) 54 + local color = sorcery.lib.color(204,38,235) 55 55 local fac = p.grade / 6 56 56 local id = f('phial_%s', name); 57 57 sorcery.register_potion_tbl { 58 58 name = id; 59 59 label = f('%s Phial',p.name); 60 - desc = "A powerful liquid consumed in the operation of a rune forge. Its quality determines how fast new runes can be constructed."; 60 + 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."; 61 61 color = color:brighten(1 + fac*0.5); 62 62 imgvariant = (fac >= 5) and 'sparkle' or 'dull'; 63 63 glow = 5+p.grade; 64 64 extra = { 65 65 groups = { sorcery_phial = p.grade }; 66 66 _proto = { id = name, data = p }; 67 67 }; 68 68 } 69 69 sorcery.register.infusions.link { 70 70 infuse = p.infusion; 71 71 into = 'sorcery:potion_subtle'; 72 - output = id; 72 + output = 'sorcery:'..id; 73 73 } 74 74 end 75 75 76 76 local register_rune_wrench = function(w) 77 77 local mp = sorcery.data.metals[w.metal].parts 78 78 minetest.register_tool(w.name, { 79 79 description = w.desc; ................................................................................ 89 89 }; 90 90 }) 91 91 minetest.register_craft { 92 92 output = w.name; 93 93 recipe = { 94 94 {'', mp.fragment,''}; 95 95 {'', mp.ingot, mp.fragment}; 96 - {'sorcery:vidrium_fragment','', ''}; 96 + {'sorcery:fragment_vidrium','', ''}; 97 97 }; 98 98 } 99 99 end 100 100 101 101 register_rune_wrench { 102 102 name = 'sorcery:rune_wrench', desc = 'Rune Wrench'; 103 103 img = 'sorcery_rune_wrench.png', metal = 'brass'; ................................................................................ 132 132 if rune then 133 133 local rp = rune:get_definition()._proto 134 134 local rg = rune:get_meta():get_int('rune_grade') 135 135 m:set_string('amulet_rune', rp.id) 136 136 m:set_int('amulet_rune_grade', rg) 137 137 local spell = sorcery.amulet.getspell(stack) 138 138 if not spell then return nil end 139 - 140 - local name = string.format('Amulet of %s %s', constants.amulet_grades[rg], spell.name) 139 + local name 140 + if spell.minrune then -- indicating quality makes less sense if it's restricted 141 + name = string.format('Amulet of %s', spell.name) 142 + else 143 + name = string.format('Amulet of %s %s', constants.amulet_grades[rg], spell.name) 144 + end 141 145 m:set_string('description', sorcery.lib.ui.tooltip { 142 146 title = name; 143 147 color = spell.tone; 144 148 desc = spell.desc; 145 149 }) 146 150 147 151 if spell.apply then spell.apply { ................................................................................ 196 200 local proto = stack:get_definition()._sorcery.amulet 197 201 if not m:contains('amulet_rune') then return nil end 198 202 local rune = m:get_string('amulet_rune') 199 203 local rg = m:get_string('amulet_rune_grade') 200 204 local rd = sorcery.data.runes[rune] 201 205 local spell = rd.amulets[proto.base] 202 206 if not spell then return nil end 203 - local title,desc,cast,apply,remove = spell.name, spell.desc, spell.cast, spell.apply, spell.remove -- FIXME in serious need of refactoring 207 + local title,desc,cast,apply,remove,mingrade = spell.name, spell.desc, spell.cast, spell.apply, spell.remove, spell.mingrade -- FIXME in serious need of refactoring 204 208 local base_spell = true 205 209 206 210 if proto.frame and spell.frame and spell.frame[proto.frame] then 207 211 local sp = spell.frame[proto.frame] 208 212 title = sp.name or title 209 213 desc = sp.desc or desc 210 214 cast = sp.desc or cast 211 215 apply = sp.apply or apply 212 216 remove = sp.remove or remove 217 + mingrade = sp.mingrade or remove 213 218 base_spell = false 214 219 end 215 220 216 221 return { 217 - rune = rune; 218 - grade = rg; 219 - spell = spell; 222 + rune = rune, grade = rg; 223 + spell = spell, mingrade = mingrade; 220 224 name = title, desc = desc; 221 225 cast = cast, apply = apply, remove = remove; 222 226 frame = proto.frame; 223 227 framestats = proto.frame and sorcery.data.metals[proto.frame].amulet; 224 228 tone = sorcery.lib.color(rd.tone); 225 229 base_spell = base_spell; 226 230 } ................................................................................ 233 237 local l = sorcery.ley.netcaps(pos,time or 1) 234 238 235 239 local pow_min = l.self.powerdraw >= l.self.minpower 236 240 local pow_max = l.self.powerdraw >= l.self.maxpower 237 241 local has_phial = function() return not i:is_empty('phial') end 238 242 239 243 if time and has_phial() and pow_min then -- roll for runes 240 - local rolls = math.floor(time/calc_phial_props(i:get_stack('phial',1))) 244 + local int, powerfac = calc_phial_props(i:get_stack('phial',1)) 245 + local rolls = math.floor(time/int) 241 246 local newrunes = {} 242 247 for _=1,rolls do 243 248 local choices = {} 244 249 for name,rune in pairs(sorcery.data.runes) do 245 - if rune.minpower*time <= l.self.powerdraw and math.random(rune.rarity) == 1 then 250 + print('considering',name) 251 + print('-- power',rune.minpower,(rune.minpower*powerfac)*time,'//',l.self.powerdraw,l.self.powerdraw/time,'free',l.freepower,'max',l.maxpower) 252 + if (rune.minpower*powerfac)*time <= l.self.powerdraw and math.random(rune.rarity) == 1 then 246 253 local n = ItemStack(rune.item) 247 254 choices[#choices + 1] = n 248 255 end 249 256 end 250 257 if #choices > 0 then newrunes[#newrunes + 1] = choices[math.random(#choices)] end 258 + print('rune choices:',dump(choices)) 259 + print('me',dump(l.self)) 251 260 end 252 261 253 262 for _,r in pairs(newrunes) do 254 263 if i:room_for_item('cache',r) and has_phial() then 255 264 local qual = math.random(#constants.rune_grades) 256 265 rune_set(r,{grade = qual}) 257 266 i:add_item('cache',r) ................................................................................ 442 451 allow_metadata_inventory_move = function(pos, fl,fi, tl,ti, count, user) 443 452 local inv = minetest.get_meta(pos):get_inventory() 444 453 local wrench if not inv:is_empty('wrench') then 445 454 wrench = inv:get_stack('wrench',1):get_definition()._proto 446 455 end 447 456 if fl == 'cache' then 448 457 if tl == 'cache' then return 1 end 449 - if tl == 'active' then 458 + if tl == 'active' and inv:is_empty('active') then 450 459 print(dump(wrench)) 451 460 if wrench and wrench.powers.imbue and not inv:is_empty('amulet') then 452 461 local amulet = inv:get_stack('amulet',1) 453 462 local rune = inv:get_stack(fl,fi) 454 - if sorcery.data.runes[rune:get_definition()._proto.id].amulets[amulet:get_definition()._sorcery.amulet.base] then 455 - return 1 463 + local runeid = rune:get_definition()._proto.id 464 + local runegrade = rune:get_meta():get_int('rune_grade') 465 + if sorcery.data.runes[runeid].amulets[amulet:get_definition()._sorcery.amulet.base] then 466 + local spell do -- haaaack 467 + local i=ItemStack(amulet:get_name()) 468 + local im = i:get_meta() 469 + im:set_string('amulet_rune',runeid) 470 + im:set_int('amulet_rune_grade',runegrade) 471 + spell = sorcery.amulet.getspell(i) 472 + end 473 + if not spell.mingrade or runegrade >= spell.mingrade then 474 + return 1 475 + end 456 476 end 457 477 end 458 478 end 459 479 end 460 480 if fl == 'active' then 461 481 if tl == 'cache' and wrench and (wrench.powers.extract or wrench.powers.purge) then return 1 end 462 482 end
Modified sorcery.md from [06f5d982e8] to [246ca8c1c8].
6 6 7 7 ## first-party 8 8 * **default** 9 9 * **stairs** for slabs, used in crafting recipes 10 10 * **screwdriver** for several crafting recipes 11 11 * **vessels** for potions, ink bottles, etc. 12 12 * **tnt** for the flamebolt spell impact effect 13 + * **beds** for the escape amulet *(optional)* 13 14 14 15 ## third-party 15 16 * **xdecor** for various tools and ingredients, especially honey and the hammer 16 17 * **basic_materials** for crafting ingredients 17 18 * **instant_ores** for ore generation. temporary, will be removed and replaced with home-grown mechanism soon 18 19 * **farming redo** for potion ingredients 19 20 * **late** for spell, potion, and gravitator effects
Added sounds/sorcery_splunch.ogg version [1bea3745a1].
cannot compute difference between binary files
Added sounds/sorcery_stutter.ogg version [ef5efc482f].
cannot compute difference between binary files
Added sounds/sorcery_windup.ogg version [060bf562bb].
cannot compute difference between binary files
Added sounds/sorcery_zap.ogg version [0c5f6f503c].
cannot compute difference between binary files
Modified wands.lua from [a021a4fd8f] to [b35b5eeee9].
37 37 wandprops = { sturdiness = 1.5 }; 38 38 }; 39 39 diamond = { 40 40 item = 'sorcery:shard_diamond'; 41 41 wandprops = { sturdiness = 1.7, reliability = 0.85 }; 42 42 }; 43 43 mese = { 44 - item = 'default:mese_fragment'; 44 + item = 'default:mese_crystal_fragment'; 45 45 wandprops = { generate = 2 }; 46 46 }; 47 47 cobalt = { 48 48 item = 'sorcery:powder_cobalt'; 49 49 wandprops = { power = 1.4 }; 50 50 }; 51 51 iridium = {