diff --git a/code/modules/research/designs_vr.dm b/code/modules/research/designs_vr.dm index b2776ec826..dee8eebc77 100644 --- a/code/modules/research/designs_vr.dm +++ b/code/modules/research/designs_vr.dm @@ -37,6 +37,15 @@ build_path = /obj/item/clothing/glasses/omnihud sort_string = "GAAFB" +/datum/design/item/translocator + name = "personal translocator" + id = "translocator" + req_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_ILLEGAL = 7) + materials = list(DEFAULT_WALL_MATERIAL = 4000, "glass" = 2000, "uranium" = 4000, "diamond" = 2000) + build_path = /obj/item/device/perfect_tele + sort_string = "HABAF" + + // Resleeving Circuitboards /datum/design/circuit/comm_server diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm index 623062a67f..313d5c9581 100644 --- a/code/modules/vore/fluffstuff/custom_items_vr.dm +++ b/code/modules/vore/fluffstuff/custom_items_vr.dm @@ -595,3 +595,254 @@ obj/item/weapon/material/hatchet/tacknife/combatknife/fluff/katarina/handle_shie user.verbs |= /mob/living/carbon/human/proc/shapeshifter_select_gender else return + +//The perfect adminboos device? +/obj/item/device/perfect_tele + name = "personal translocator" + desc = "Seems absurd, doesn't it? Yet, here we are. Generally considered dangerous contraband unless the user has permission from Central Command." + icon = 'icons/obj/device_alt.dmi' + icon_state = "hand_tele" + w_class = ITEMSIZE_SMALL + + var/list/beacons = list() + var/ready = 1 + var/beacons_left = 3 + var/obj/item/device/perfect_tele_beacon/destination + var/datum/effect/effect/system/spark_spread/spk + var/list/warned_users = list() + var/list/logged_events = list() + +/obj/item/device/perfect_tele/New() + ..() + flags |= NOBLUDGEON + spk = new(src) + spk.set_up(5, 0, src) + spk.attach(src) + +/obj/item/device/perfect_tele/Destroy() + beacons.Cut() + qdel(spk) + ..() + +/obj/item/device/perfect_tele/update_icon() + if(ready) + icon_state = "[initial(icon_state)]" + else + icon_state = "[initial(icon_state)]_w" + + ..() + +/obj/item/device/perfect_tele/attack_self(mob/user) + if(!(user.ckey in warned_users)) + warned_users |= user.ckey + alert(user,"This device can be easily used to break ERP preferences due to the nature of teleporting \ + and tele-vore. Make sure you carefully examine someone's OOC prefs before teleporting them if you are \ + going to use this device for ERP purposes. This device records all warnings given and teleport events for \ + admin review in case of pref-breaking, so just don't do it.","OOC WARNING") + + var/choice = alert(user,"What do you want to do?","[src]","Create Beacon","Cancel","Target Beacon") + switch(choice) + if("Create Beacon") + if(beacons_left <= 0) + user << "\The [src] can't support any more beacons!" + return + + var/new_name = html_encode(input(user,"New beacon's name (2-20 char):","[src]") as text|null) + + if(length(new_name) > 20 || length(new_name) < 2) + alert("Entered name length invalid (must be longer than 2, no more than than 20).","Error") + return + if(new_name in beacons) + alert("No duplicate names, please. '[new_name]' exists already.","Error") + return + + var/obj/item/device/perfect_tele_beacon/nb = new(get_turf(src)) + nb.tele_name = new_name + nb.tele_hand = src + nb.creator = user.ckey + beacons[new_name] = nb + beacons_left-- + if(isliving(user)) + var/mob/living/L = user + L.put_in_any_hand_if_possible(nb) + + if("Target Beacon") + if(!beacons.len) + user << "\The [src] doesn't have any beacons!" + else + var/target = input("Which beacon do you target?","[src]") in beacons|null + if(target && (target in beacons)) + destination = beacons[target] + user << "Destination set to '[target]'." + else + return + +/obj/item/device/perfect_tele/attackby(obj/W, mob/user) + if(istype(W,/obj/item/device/perfect_tele_beacon)) + var/obj/item/device/perfect_tele_beacon/tb = W + if(tb.tele_name in beacons) + user << "You re-insert \the [tb] into \the [src]." + beacons -= tb.tele_name + user.unEquip(tb) + qdel(tb) + beacons_left++ + else + user << "\The [tb] doesn't belong to \the [src]." + return + else + ..() + +/obj/item/device/perfect_tele/afterattack(mob/living/target, mob/living/user, proximity) + //No, you can't teleport people from over there. + if(!proximity) + return + + //Only mob/living need apply. + if(!istype(user) || !istype(target)) + return + + //No, you can't teleport buckled people. + if(target.buckled) + user << "The target appears to be attached to something..." + return + + //No, you can't teleport if it's not ready yet. + if(!ready) + user << "\The [src] is still recharging!" + return + + //No, you can't teleport if there's no destination. + if(!destination) + user << "\The [src] doesn't have a current valid destination set!" + return + + //No, you can't port to or from away missions. Stupidly complicated check. + var/turf/uT = get_turf(user) + var/turf/dT = get_turf(destination) + if(!uT || !dT) + return + + if( (uT.z != dT.z) && ( (uT.z > max_default_z_level() ) || (dT.z > max_default_z_level()) ) ) + user << "\The [src] can't teleport you that far!" + return + + //Bzzt. + ready = 0 + + //Destination beacon vore checking + var/datum/belly/target_belly + var/atom/real_dest = get_turf(destination) + + //Destination beacon is held/eaten + if(isliving(destination.loc) && (user != destination.loc)) //We should definitely get televored + var/mob/living/L = destination.loc + + //Is the beacon IN a belly? + target_belly = check_belly(destination) + + //No? Well do they have vore organs at all? + if(!target_belly && L.vore_organs.len) + + //If they do, use their picked one. + if(L.vore_selected) + target_belly = L.vore_organs[L.vore_selected] + else + //Else just use the first one. + var/I = L.vore_organs[1] //We're just going to use 1 + target_belly = L.vore_organs[I] + + //Televore fluff stuff + if(target_belly) + real_dest = destination.loc + target_belly.internal_contents |= target + playsound(target_belly.owner, target_belly.vore_sound, 100, 1) + user << "\The [src] teleports you right into [target_belly.owner]'s [target_belly.name]!" + target_belly.owner << "Your [target_belly.name] suddenly has a new occupant!" + + //Phase-out effect + phase_out(target,get_turf(target)) + + //Move them + target.forceMove(real_dest) + + //Phase-in effect + phase_in(target,get_turf(target)) + + //And any friends! + for(var/obj/item/weapon/grab/G in target.contents) + if(G.affecting && (G.state >= GRAB_AGGRESSIVE)) + + //Phase-out effect for grabbed person + phase_out(G.affecting,get_turf(G.affecting)) + + //Move them, and televore if necessary + G.affecting.forceMove(real_dest) + if(target_belly) + target_belly.internal_contents |= G.affecting + G.affecting << "\The [src] teleports you right into [target_belly.owner]'s [target_belly.name]!" + + //Phase-in effect for grabbed person + phase_in(G.affecting,get_turf(G.affecting)) + + update_icon() + spawn(30 SECONDS) + if(src) //If we still exist, anyway. + ready = 1 + update_icon() + + logged_events["[world.time]"] = "[user] teleported [target] to [real_dest] [target_belly ? "(Belly: [target_belly.name])" : null]" + +/obj/item/device/perfect_tele/proc/phase_out(var/mob/M,var/turf/T) + + if(!M || !T) + return + + spk.set_up(5, 0, M) + spk.attach(M) + playsound(T, "sparks", 50, 1) + anim(T,M,'icons/mob/mob.dmi',,"phaseout",,M.dir) + +/obj/item/device/perfect_tele/proc/phase_in(var/mob/M,var/turf/T) + + if(!M || !T) + return + + spk.start() + playsound(T, 'sound/effects/phasein.ogg', 25, 1) + playsound(T, 'sound/effects/sparks2.ogg', 50, 1) + anim(T,M,'icons/mob/mob.dmi',,"phasein",,M.dir) + spk.set_up(5, 0, src) + spk.attach(src) + +/obj/item/device/perfect_tele_beacon + name = "translocator beacon" + desc = "That's unusual." + icon = 'icons/obj/device_alt.dmi' + icon_state = "motion2" + w_class = ITEMSIZE_TINY + + var/tele_name + var/obj/item/device/perfect_tele/tele_hand + var/creator + var/warned_users = list() + +/obj/item/device/perfect_tele_beacon/New() + ..() + flags |= NOBLUDGEON + +/obj/item/device/perfect_tele_beacon/Destroy() + tele_name = null + tele_hand = null + ..() + +/obj/item/device/perfect_tele_beacon/attack_hand(mob/user) + if((user.ckey != creator) && !(user.ckey in warned_users)) + warned_users |= user.ckey + var/choice = alert(user,"This device is a translocator beacon. Having it on your person may mean that anyone \ + who teleports to this beacon gets teleported into your selected vore-belly. If you are prey-only \ + or don't wish to potentially have a random person teleported into you, it's suggested that you \ + not carry this around.","OOC WARNING","Take It","Leave It") + if(choice == "Leave It") + return + + ..() diff --git a/icons/obj/device_alt.dmi b/icons/obj/device_alt.dmi new file mode 100644 index 0000000000..a6ab695e74 Binary files /dev/null and b/icons/obj/device_alt.dmi differ