123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- local function get_midfeld_spawn(realm)
- local tries = 0
- ::try_again::
- tries = tries + 1
- local pos = {
- x = math.random(realm.gate_minp.x, realm.gate_maxp.x),
- y = math.random(realm.gate_minp.y, realm.gate_maxp.y),
- z = math.random(realm.gate_minp.z, realm.gate_maxp.z),
- }
- -- Need to load the area otherwise 'find_node_near' will usually fail.
- minetest.load_area(
- vector.add(pos, {x=-16, y=-16, z=-16}),
- vector.add(pos, {x=16, y=16, z=16}))
- pos = minetest.find_node_near(pos, 16, "air", true)
- if pos and minetest.get_node(vector.add(pos, {x=0, y=1, z=0})).name == "air" then
- local minp = realm.minp
- local maxp = realm.maxp
- if pos.x >= minp.x and pos.x <= maxp.x and
- pos.y >= minp.y and pos.y <= maxp.y and
- pos.z >= minp.z and pos.z <= maxp.z then
- return pos
- end
- end
- if tries < 10 then
- goto try_again
- end
- return realm.realm_origin
- end
- function obsidian_gateway.get_midfeld_spawn()
- local realm = rc.get_realm_data("midfeld")
- return get_midfeld_spawn(realm)
- end
- function obsidian_gateway.on_flamestaff_use(item, user, pt)
- if pt.type ~= "node" then
- return
- end
- if not user:is_player() then
- return
- end
- local pname = user:get_player_name()
- ambiance.sound_play("fire_flint_and_steel", pt.above, 0.7, 10)
- -- Punched node must be one of these.
- do
- local nn = minetest.get_node(pt.under).name
- if nn ~= "default:obsidian" and
- nn ~= "griefer:grieferstone" and
- nn ~= "cavestuff:dark_obsidian" and
- nn ~= "cavestuff:glow_obsidian" then
- return
- end
- end
- local pos = pt.under
- local success, origin, airpoints, northsouth, ns_key, playerorigin =
- obsidian_gateway.find_gate(pos)
- if not success then
- return
- end
- -- Using the staff on an uninitialized gate does nothing.
- do
- local meta = minetest.get_meta(origin)
- local target = meta:get_string("obsidian_gateway_destination_" .. ns_key)
- local dest = minetest.string_to_pos(target)
- if not dest then
- return
- end
- end
- -- Add/update sound beacon.
- ambiance.spawn_sound_beacon("soundbeacon:gate", origin, 20, 1)
- ambiance.replay_nearby_sound_beacons(origin, 6)
- if sheriff.is_cheater(pname) then
- if sheriff.punish_probability(pname) then
- sheriff.punish_player(pname)
- return
- end
- end
- local do_effect = false
- do
- local meta = item:get_meta()
- if meta:get_string("gate1") == "" then
- -- Punch first gate.
- meta:set_string("gate1", minetest.pos_to_string(playerorigin))
- meta:set_string("description", "Flame Staff (Partially Linked)")
- meta:set_string("owner", pname)
- do_effect = true
- elseif meta:get_string("gate2") == "" then
- -- Punch second gate.
- if meta:get_string("owner") ~= pname then
- return
- end
- meta:set_string("gate2", minetest.pos_to_string(playerorigin))
- local info = "\n" ..
- rc.pos_to_namestr(minetest.string_to_pos(meta:get_string("gate1"))) .. "\n" ..
- rc.pos_to_namestr(minetest.string_to_pos(meta:get_string("gate2")))
- meta:set_string("description", "Flame Staff (Linked)" .. info)
- item:set_wear(1)
- do_effect = true
- end
- end
- if do_effect then
- local p = pt.above
- minetest.sound_play("default_item_smoke", {
- pos = pos,
- max_hear_distance = 8,
- }, true)
- minetest.add_particlespawner({
- amount = 3,
- time = 0.1,
- minpos = {x = p.x - 0.1, y = p.y + 0.1, z = p.z - 0.1 },
- maxpos = {x = p.x + 0.1, y = p.y + 0.2, z = p.z + 0.1 },
- minvel = {x = 0, y = 2.5, z = 0},
- maxvel = {x = 0, y = 2.5, z = 0},
- minacc = {x = -0.15, y = -0.02, z = -0.15},
- maxacc = {x = 0.15, y = -0.01, z = 0.15},
- minexptime = 4,
- maxexptime = 6,
- minsize = 5,
- maxsize = 5,
- collisiondetection = true,
- texture = "default_item_smoke.png"
- })
- end
- -- Success, but do not continue to the teleport logic.
- if do_effect then
- return item
- end
- -- If user is not staff owner, do nothing. But if staff doesn't yet have an
- -- owner (old staff), then set owner to first user.
- do
- local meta = item:get_meta()
- local owner = meta:get_string("owner")
- if owner == "" then
- owner = pname
- meta:set_string("owner", pname)
- -- Meta changes do not take effect until we return the itemstack.
- end
- if owner ~= pname then
- return
- end
- end
- -- Player must be standing in the gate.
- do
- local posunder = utility.node_under_pos(user:get_pos())
- local namunder = minetest.get_node(posunder).name
- if namunder ~= "default:obsidian" and
- namunder ~= "griefer:grieferstone" and
- namunder ~= "cavestuff:dark_obsidian" and
- namunder ~= "cavestuff:glow_obsidian" then
- return
- end
- end
- do
- local meta = item:get_meta()
- local spos1 = meta:get_string("gate1")
- local spos2 = meta:get_string("gate2")
- if spos1 == "" or spos2 == "" then
- return
- end
- local tar1 = minetest.string_to_pos(spos1)
- local tar2 = minetest.string_to_pos(spos2)
- if not tar1 or not tar2 then
- return
- end
- -- If the linked targets are the same, nothing happens.
- if vector.equals(tar1, tar2) then
- return
- end
- -- If either target is in a realm which disallows incoming gates ...
- do
- local d1 = rc.get_realm_data(rc.current_realm_at_pos(tar1)) or {}
- local d2 = rc.get_realm_data(rc.current_realm_at_pos(tar2)) or {}
- if d1.disabled or d2.disabled then
- return
- end
- end
- -- If player activates gate #2 first, then pretend we didn't notice and just
- -- swap the datums.
- if vector.equals(playerorigin, tar2) then
- local tmp
- tmp = tar1
- tar1 = tar2
- tar2 = tmp
- meta:set_string("gate1", spos2)
- meta:set_string("gate2", spos1)
- tmp = spos1
- spos1 = spos2
- spos2 = tmp
- -- Meta changes do not take effect until we return the itemstack.
- end
- -- Don't allow player to teleport into Void, we cannot have chunks generated
- -- there!
- if not rc.is_valid_realm_pos(tar1) then
- return
- end
- if not rc.is_valid_realm_pos(tar2) then
- return
- end
- -- Just in case someone managed to link a flamestaff to the Outback gate.
- if rc.current_realm_at_pos(tar1) == "abyss" or rc.current_realm_at_pos(tar2) == "abyss" then
- return
- end
- -- Player has activated gate #1.
- -- Send them to the MIDFELD!
- if vector.equals(playerorigin, tar1) then
- local realmdata = rc.get_realm_data("midfeld")
- assert(realmdata)
- local hidden_spawn = get_midfeld_spawn(realmdata)
- preload_tp.execute({
- player_name = pname,
- target_position = hidden_spawn,
- emerge_radius = 8,
- particle_effects = true,
- spinup_time = 2,
- pre_teleport_callback = function()
- -- Need better sound someday.
- --coresounds.play_death_sound(user, pname)
- end,
- post_teleport_callback = function()
- portal_sickness.on_use_portal(pname)
- end,
- teleport_sound = "nether_portal_usual",
- send_blocks = true,
- })
- -- The metadata will have been updated if we swapped datums.
- ambiance.sound_play("fire_flint_and_steel", pos, 0.7, 20)
- item:add_wear_by_uses(20)
- return item
- end
- -- Player has activated a gate in Midfeld. Send then back.
- -- Also destroy the flame staff.
- if rc.current_realm_at_pos(origin) == "midfeld" then
- preload_tp.execute({
- player_name = pname,
- target_position = tar2,
- emerge_radius = 16,
- particle_effects = true,
- spinup_time = 2,
- pre_teleport_callback = function()
- obsidian_gateway.regenerate_liquid(tar2, nil)
- end,
- post_teleport_callback = function()
- -- Only check for portal sickness ONCE!
- -- Already checked on first gate use.
- --portal_sickness.on_use_portal(pname)
- end,
- teleport_sound = "nether_portal_usual",
- send_blocks = true,
- })
- ambiance.sound_play("fire_flint_and_steel", pos, 0.7, 20)
- item:add_wear_by_uses(20)
- return item
- end
- -- Implicit is this: if player uses a linked flamestaff on a third-party
- -- gate located NOT in MIDFELD, then nothing shall happen. Stuff happens
- -- only if player uses flamestaff on gate #1, #2, or any gate in MIDFELD.
- end
- end
|