initial commit - cross reference with 5th port - obviously has compile errors

This commit is contained in:
LetterJay
2016-07-03 02:17:19 -05:00
commit 35a1723e98
4355 changed files with 2221257 additions and 0 deletions
@@ -0,0 +1,67 @@
#define ARTILLERY_RELOAD_TIME 60
#define EXPLOSION_SIZE 3
/obj/machinery/artillerycontrol
var/reload = ARTILLERY_RELOAD_TIME
var/explosionsize = EXPLOSION_SIZE
name = "bluespace artillery control"
icon_state = "control_boxp1"
icon = 'icons/obj/machines/particle_accelerator.dmi'
density = 1
anchored = 1
/obj/machinery/artillerycontrol/process()
if(src.reload<ARTILLERY_RELOAD_TIME)
src.reload++
/obj/structure/artilleryplaceholder
name = "artillery"
icon = 'icons/obj/machines/artillery.dmi'
anchored = 1
density = 1
/obj/structure/artilleryplaceholder/decorative
density = 0
/obj/machinery/artillerycontrol/attack_hand(mob/user)
user.set_machine(src)
var/dat = "<B>Bluespace Artillery Control:</B><BR>"
dat += "Locked on<BR>"
dat += "<B>Charge progress: [reload]/[ARTILLERY_RELOAD_TIME]:</B><BR>"
dat += "<A href='byond://?src=\ref[src];fire=1'>Open Fire</A><BR>"
dat += "Deployment of weapon authorized by <br>Nanotrasen Naval Command<br><br>Remember, friendly fire is grounds for termination of your contract and life.<HR>"
user << browse(dat, "window=scroll")
onclose(user, "scroll")
return
/obj/machinery/artillerycontrol/Topic(href, href_list)
if(..())
return
var/A
A = input("Area to jump bombard", "Open Fire", A) in teleportlocs
var/area/thearea = teleportlocs[A]
if (usr.stat || usr.restrained()) return
if(src.reload < ARTILLERY_RELOAD_TIME) return
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
priority_announce("Bluespace artillery fire detected. Brace for impact.")
message_admins("[key_name_admin(usr)] has launched an artillery strike.")
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
L+=T
var/loc = pick(L)
explosion(loc,explosionsize,explosionsize*2,explosionsize*4)
reload = 0
/*/mob/proc/openfire()
var/A
A = input("Area to jump bombard", "Open Fire", A) in teleportlocs
var/area/thearea = teleportlocs[A]
priority_announce("Bluespace artillery fire detected. Brace for impact.")
spawn(30)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
L+=T
var/loc = pick(L)
explosion(loc,2,5,11)*/
@@ -0,0 +1,516 @@
#define WHITE_TEAM "white"
#define RED_TEAM "red"
#define BLUE_TEAM "blue"
#define FLAG_RETURN_TIME 200 // 20 seconds
#define INSTAGIB_RESPAWN 50 //5 seconds
#define DEFAULT_RESPAWN 150 //15 seconds
/obj/item/weapon/twohanded/required/ctf
name = "banner"
icon = 'icons/obj/items.dmi'
icon_state = "banner"
item_state = "banner"
desc = "A banner with Nanotrasen's logo on it."
slowdown = 2
throw_speed = 0
throw_range = 1
force = 200
armour_penetration = 1000
anchored = TRUE
flags = HANDSLOW
var/team = WHITE_TEAM
var/reset_cooldown = 0
var/obj/effect/ctf/flag_reset/reset
var/reset_path = /obj/effect/ctf/flag_reset
/obj/item/weapon/twohanded/required/ctf/New()
if(!reset)
reset = new reset_path(get_turf(src))
/obj/item/weapon/twohanded/required/ctf/Destroy()
if(reset)
qdel(reset)
reset = null
. = ..()
/obj/item/weapon/twohanded/required/ctf/initialize()
if(!reset)
reset = new reset_path(get_turf(src))
/obj/item/weapon/twohanded/required/ctf/process()
if(world.time > reset_cooldown)
forceMove(get_turf(src.reset))
for(var/mob/M in player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='userdanger'>\The [src] has been returned \
to base!</span>"
STOP_PROCESSING(SSobj, src)
/obj/item/weapon/twohanded/required/ctf/attack_hand(mob/living/user)
if(!user)
return
if(team in user.faction)
user << "You can't move your own flag!"
return
if(loc == user)
if(!user.unEquip(src))
return
anchored = FALSE
pickup(user)
if(!user.put_in_active_hand(src))
dropped(user)
return
for(var/mob/M in player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='userdanger'>\The [src] has been taken!</span>"
STOP_PROCESSING(SSobj, src)
/obj/item/weapon/twohanded/required/ctf/dropped(mob/user)
..()
reset_cooldown = world.time + 200 //20 seconds
START_PROCESSING(SSobj, src)
for(var/mob/M in player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='userdanger'>\The [src] has been dropped!</span>"
anchored = TRUE
/obj/item/weapon/twohanded/required/ctf/red
name = "red flag"
icon_state = "banner-red"
item_state = "banner-red"
desc = "A red banner used to play capture the flag."
team = RED_TEAM
reset_path = /obj/effect/ctf/flag_reset/red
/obj/item/weapon/twohanded/required/ctf/blue
name = "blue flag"
icon_state = "banner-blue"
item_state = "banner-blue"
desc = "A blue banner used to play capture the flag."
team = BLUE_TEAM
reset_path = /obj/effect/ctf/flag_reset/blue
/obj/effect/ctf/flag_reset
name = "banner landmark"
icon = 'icons/obj/items.dmi'
icon_state = "banner"
desc = "This is where a banner with Nanotrasen's logo on it would go."
layer = LOW_ITEM_LAYER
/obj/effect/ctf/flag_reset/red
name = "red flag landmark"
icon_state = "banner-red"
desc = "This is where a red banner used to play capture the flag \
would go."
/obj/effect/ctf/flag_reset/blue
name = "blue flag landmark"
icon_state = "banner-blue"
desc = "This is where a blue banner used to play capture the flag \
would go."
/obj/machinery/capture_the_flag
name = "CTF Controller"
desc = "Used for running friendly games of capture the flag."
icon = 'icons/obj/device.dmi'
icon_state = "syndbeacon"
anchored = 1
var/team = WHITE_TEAM
//Capture the Flag scoring
var/points = 0
var/points_to_win = 3
var/respawn_cooldown = DEFAULT_RESPAWN
//Capture Point/King of the Hill scoring
var/control_points = 0
var/control_points_to_win = 180
var/list/team_members = list()
var/ctf_enabled = FALSE
var/ctf_gear = /datum/outfit/ctf
var/instagib_gear = /datum/outfit/ctf/instagib
var/list/dead_barricades = list()
var/static/ctf_object_typecache
var/static/arena_cleared = FALSE
/obj/machinery/capture_the_flag/New()
..()
if(!ctf_object_typecache)
ctf_object_typecache = typecacheof(list(
/turf,
/mob,
/area,
/obj/machinery,
/obj/structure,
/obj/effect/ctf,
/obj/item/weapon/twohanded/required/ctf
))
poi_list |= src
/obj/machinery/capture_the_flag/Destroy()
poi_list.Remove(src)
..()
/obj/machinery/capture_the_flag/red
name = "Red CTF Controller"
icon_state = "syndbeacon"
team = RED_TEAM
ctf_gear = /datum/outfit/ctf/red
instagib_gear = /datum/outfit/ctf/red/instagib
/obj/machinery/capture_the_flag/blue
name = "Blue CTF Controller"
icon_state = "bluebeacon"
team = BLUE_TEAM
ctf_gear = /datum/outfit/ctf/blue
instagib_gear = /datum/outfit/ctf/blue/instagib
/obj/machinery/capture_the_flag/attack_ghost(mob/user)
if(ctf_enabled == FALSE)
return
if(ticker.current_state != GAME_STATE_PLAYING)
return
if(user.ckey in team_members)
if(user.mind.current && user.mind.current.timeofdeath + respawn_cooldown > world.time)
user << "It must be more than [respawn_cooldown/10] seconds from your last death to respawn!"
return
var/client/new_team_member = user.client
dust_old(user)
spawn_team_member(new_team_member)
return
for(var/obj/machinery/capture_the_flag/CTF in machines)
if(CTF == src || CTF.ctf_enabled == FALSE)
continue
if(user.ckey in CTF.team_members)
user << "No switching teams while the round is going!"
return
if(CTF.team_members.len < src.team_members.len)
user << "[src.team] has more team members than [CTF.team]. Try joining [CTF.team] to even things up."
return
team_members |= user.ckey
var/client/new_team_member = user.client
dust_old(user)
spawn_team_member(new_team_member)
/obj/machinery/capture_the_flag/proc/dust_old(mob/user)
if(user.mind && user.mind.current && user.mind.current.z == src.z)
new /obj/item/ammo_box/magazine/recharge/ctf (get_turf(user.mind.current))
new /obj/item/ammo_box/magazine/recharge/ctf (get_turf(user.mind.current))
user.mind.current.dust()
/obj/machinery/capture_the_flag/proc/spawn_team_member(client/new_team_member)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(get_turf(src))
new_team_member.prefs.copy_to(M)
M.key = new_team_member.key
M.faction += team
M.equipOutfit(ctf_gear)
/obj/machinery/capture_the_flag/Topic(href, href_list)
if(href_list["join"])
var/mob/dead/observer/ghost = usr
if(istype(ghost))
attack_ghost(ghost)
/obj/machinery/capture_the_flag/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/twohanded/required/ctf))
var/obj/item/weapon/twohanded/required/ctf/flag = I
if(flag.team != src.team)
user.unEquip(flag)
flag.loc = get_turf(flag.reset)
points++
for(var/mob/M in player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='userdanger'>[user.real_name] has captured \the [flag], scoring a point for [team] team! They now have [points]/[points_to_win] points!</span>"
if(points >= points_to_win)
victory()
/obj/machinery/capture_the_flag/proc/victory()
for(var/mob/M in mob_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='narsie'>[team] team wins!</span>"
M << "<span class='userdanger'>The game has been reset! Teams have been cleared. The machines will be active again in 30 seconds.</span>"
for(var/obj/item/weapon/twohanded/required/ctf/W in M)
M.unEquip(W)
M.dust()
for(var/obj/machinery/control_point/control in machines)
control.icon_state = "dominator"
control.controlling = null
for(var/obj/machinery/capture_the_flag/CTF in machines)
if(CTF.ctf_enabled == TRUE)
CTF.points = 0
CTF.control_points = 0
CTF.ctf_enabled = FALSE
CTF.team_members = list()
CTF.arena_cleared = FALSE
addtimer(CTF, "start_ctf", 300)
/obj/machinery/capture_the_flag/proc/toggle_ctf()
if(!ctf_enabled)
start_ctf()
. = TRUE
else
stop_ctf()
. = FALSE
/obj/machinery/capture_the_flag/proc/start_ctf()
ctf_enabled = TRUE
for(var/obj/effect/ctf/dead_barricade/ded in dead_barricades)
ded.respawn()
dead_barricades.Cut()
notify_ghosts("[name] has been activated!", enter_link="<a href=?src=\ref[src];join=1>(Click to join the [team] team!)</a> or click on the controller directly!", source = src, action=NOTIFY_ATTACK)
if(!arena_cleared)
clear_the_arena()
arena_cleared = TRUE
/obj/machinery/capture_the_flag/proc/clear_the_arena()
var/area/A = get_area(src)
for(var/atm in A)
if(!is_type_in_typecache(atm, ctf_object_typecache))
qdel(atm)
/obj/machinery/capture_the_flag/proc/stop_ctf()
ctf_enabled = FALSE
var/area/A = get_area(src)
for(var/i in mob_list)
var/mob/M = i
if((get_area(A) == A) && (M.ckey in team_members))
M.dust()
team_members.Cut()
/obj/machinery/capture_the_flag/proc/instagib_mode()
for(var/obj/machinery/capture_the_flag/CTF in machines)
if(CTF.ctf_enabled == TRUE)
CTF.ctf_gear = CTF.instagib_gear
CTF.respawn_cooldown = INSTAGIB_RESPAWN
/obj/machinery/capture_the_flag/proc/normal_mode()
for(var/obj/machinery/capture_the_flag/CTF in machines)
if(CTF.ctf_enabled == TRUE)
CTF.ctf_gear = initial(ctf_gear)
CTF.respawn_cooldown = DEFAULT_RESPAWN
/obj/item/weapon/gun/projectile/automatic/pistol/deagle/CTF
desc = "This looks like it could really hurt in melee."
force = 75
/obj/item/weapon/gun/projectile/automatic/laser/ctf
mag_type = /obj/item/ammo_box/magazine/recharge/ctf
desc = "This looks like it could really hurt in melee."
force = 50
/obj/item/ammo_box/magazine/recharge/ctf
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf
/obj/item/ammo_casing/caseless/laser/ctf
projectile_type = /obj/item/projectile/beam/ctf
/obj/item/projectile/beam/ctf
damage = 150
/obj/item/weapon/gun/projectile/automatic/laser/ctf/red
mag_type = /obj/item/ammo_box/magazine/recharge/ctf/red
/obj/item/ammo_box/magazine/recharge/ctf/red
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/red
/obj/item/ammo_casing/caseless/laser/ctf/red
projectile_type = /obj/item/projectile/beam/ctf/red
/obj/item/projectile/beam/ctf/red
icon_state = "laser"
/obj/item/weapon/gun/projectile/automatic/laser/ctf/blue
mag_type = /obj/item/ammo_box/magazine/recharge/ctf/blue
/obj/item/ammo_box/magazine/recharge/ctf/blue
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf/blue
/obj/item/ammo_casing/caseless/laser/ctf/blue
projectile_type = /obj/item/projectile/beam/ctf/blue
/obj/item/projectile/beam/ctf/blue
icon_state = "bluelaser"
/datum/outfit/ctf
name = "CTF"
/obj/item/device/radio/headset
uniform = /obj/item/clothing/under/syndicate
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
id = /obj/item/weapon/card/id/syndicate
belt = /obj/item/weapon/gun/projectile/automatic/pistol/deagle/CTF
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_hand = /obj/item/weapon/gun/projectile/automatic/laser/ctf
/datum/outfit/ctf/instagib
r_hand = /obj/item/weapon/gun/energy/laser/instakill
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/red
ears = /obj/item/device/radio/headset/syndicate/alt
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf/red
r_hand = /obj/item/weapon/gun/projectile/automatic/laser/ctf/red
/datum/outfit/ctf/red/instagib
r_hand = /obj/item/weapon/gun/energy/laser/instakill/red
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/blue
ears = /obj/item/device/radio/headset/headset_cent/commander
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf/blue
r_hand = /obj/item/weapon/gun/projectile/automatic/laser/ctf/blue
/datum/outfit/ctf/blue/instagib
r_hand = /obj/item/weapon/gun/energy/laser/instakill/blue
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H)
var/obj/item/device/radio/R = H.ears
R.set_frequency(SYND_FREQ)
R.freqlock = 1
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H)
var/obj/item/device/radio/R = H.ears
R.set_frequency(CENTCOM_FREQ)
R.freqlock = 1
/obj/structure/divine/trap/ctf
name = "Spawn protection"
desc = "Stay outta the enemy spawn!"
icon_state = "trap"
health = INFINITY
maxhealth = INFINITY
var/team = WHITE_TEAM
constructable = FALSE
time_between_triggers = 1
alpha = 255
/obj/structure/divine/trap/examine(mob/user)
return
/obj/structure/divine/trap/ctf/trap_effect(mob/living/L)
if(!(src.team in L.faction))
L << "<span class='danger'><B>Stay out of the enemy spawn!</B></span>"
L.dust()
/obj/structure/divine/trap/ctf/red
team = RED_TEAM
icon_state = "trap-fire"
/obj/structure/divine/trap/ctf/blue
team = BLUE_TEAM
icon_state = "trap-frost"
/obj/structure/barricade/security/ctf
name = "barrier"
desc = "A barrier. Provides cover in fire fights."
/obj/structure/barricade/security/ctf/make_debris()
new /obj/effect/ctf/dead_barricade(get_turf(src))
/obj/effect/ctf
density = FALSE
anchored = TRUE
invisibility = INVISIBILITY_OBSERVER
alpha = 100
/obj/effect/ctf/dead_barricade
icon = 'icons/obj/objects.dmi'
icon_state = "barrier0"
/obj/effect/ctf/dead_barricade/New()
for(var/obj/machinery/capture_the_flag/CTF in machines)
CTF.dead_barricades += src
/obj/effect/ctf/dead_barricade/proc/respawn()
if(!qdeleted(src))
new /obj/structure/barricade/security/ctf(get_turf(src))
qdel(src)
//Areas
/area/ctf
name = "Capture the Flag"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
/area/ctf/control_room
name = "Control Room A"
/area/ctf/control_room2
name = "Control Room B"
/area/ctf/central
name = "Central"
/area/ctf/main_hall
name = "Main Hall A"
/area/ctf/main_hall2
name = "Main Hall B"
/area/ctf/corridor
name = "Corridor A"
/area/ctf/corridor2
name = "Corridor B"
/area/ctf/flag_room
name = "Flag Room A"
/area/ctf/flag_room2
name = "Flag Room B"
//Control Point
/obj/machinery/control_point
name = "control point"
desc = "You should capture this."
icon = 'icons/obj/machines/dominator.dmi'
icon_state = "dominator"
anchored = 1
var/obj/machinery/capture_the_flag/controlling
var/team = "none"
var/point_rate = 1
/obj/machinery/control_point/process()
if(controlling)
controlling.control_points += point_rate
if(controlling.control_points >= controlling.control_points_to_win)
controlling.victory()
/obj/machinery/control_point/attackby(mob/user, params)
capture(user)
/obj/machinery/control_point/attack_hand(mob/user)
capture(user)
/obj/machinery/control_point/proc/capture(mob/user)
if(do_after(user, 30, target = src))
for(var/obj/machinery/capture_the_flag/CTF in machines)
if(CTF.ctf_enabled && (user.ckey in CTF.team_members))
controlling = CTF
icon_state = "dominator-[CTF.team]"
for(var/mob/M in player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
M << "<span class='userdanger'>[user.real_name] has captured \the [src], claiming it for [CTF.team]! Go take it back!</span>"
break
+522
View File
@@ -0,0 +1,522 @@
//If someone can do this in a neater way, be my guest-Kor
//To do: Allow corpses to appear mangled, bloody, etc. Allow customizing the bodies appearance (they're all bald and white right now).
/obj/effect/mob_spawn
name = "Unknown"
var/mob_type = null
var/mob_name = ""
var/mob_gender = null
var/death = TRUE //Kill the mob
var/roundstart = TRUE //fires on initialize
var/instant = FALSE //fires on New
var/flavour_text = "The mapper forgot to set this!"
var/faction = null
var/permanent = FALSE //If true, the spawner will not disappear upon running out of uses.
var/random = FALSE //Don't set a name or gender, just go random
var/objectives = null
var/uses = 1 //how many times can we spawn from it. set to -1 for infinite.
var/brute_damage = 0
var/oxy_damage = 0
density = 1
anchored = 1
/obj/effect/mob_spawn/attack_ghost(mob/user)
if(ticker.current_state != GAME_STATE_PLAYING || !loc)
return
if(!uses)
user << "<span class='warning'>This spawner is out of charges!</span>"
return
var/ghost_role = alert("Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No")
if(ghost_role == "No" || !loc)
return
log_game("[user.ckey] became [mob_name]")
create(ckey = user.ckey)
/obj/effect/mob_spawn/spawn_atom_to_world()
//We no longer need to spawn mobs, deregister ourself
SSobj.atom_spawners -= src
if(roundstart)
create()
else
poi_list |= src
/obj/effect/mob_spawn/New()
..()
if(roundstart)
//Add to the atom spawners register for roundstart atom spawning
SSobj.atom_spawners += src
if(instant)
create()
else
poi_list |= src
/obj/effect/mob_spawn/Destroy()
poi_list.Remove(src)
. = ..()
/obj/effect/mob_spawn/proc/special(mob/M)
return
/obj/effect/mob_spawn/proc/equip(mob/M)
return
/obj/effect/mob_spawn/proc/create(ckey)
var/mob/living/M = new mob_type(get_turf(src)) //living mobs only
if(!random)
M.real_name = mob_name ? mob_name : M.name
if(!mob_gender)
mob_gender = pick(MALE, FEMALE)
M.gender = mob_gender
if(faction)
M.faction = list(faction)
if(death)
M.death(1) //Kills the new mob
M.adjustOxyLoss(oxy_damage)
M.adjustBruteLoss(brute_damage)
equip(M)
if(ckey)
M.ckey = ckey
M << "[flavour_text]"
var/datum/mind/MM = M.mind
if(objectives)
for(var/objective in objectives)
MM.objectives += new/datum/objective(objective)
special(M)
MM.name = M.real_name
if(uses > 0)
uses--
if(!permanent && !uses)
qdel(src)
// Base version - place these on maps/templates.
/obj/effect/mob_spawn/human
mob_type = /mob/living/carbon/human
//Human specific stuff.
var/mob_species = null //Set to make them a mutant race such as lizard or skeleton. Uses the datum typepath instead of the ID.
var/uniform = null //Set this to an object path to have the slot filled with said object on the corpse.
var/r_hand = null
var/l_hand = null
var/suit = null
var/shoes = null
var/gloves = null
var/radio = null
var/glasses = null
var/mask = null
var/helmet = null
var/belt = null
var/pocket1 = null
var/pocket2 = null
var/back = null
var/has_id = 0 //Just set to 1 if you want them to have an ID
var/id_job = null // Needs to be in quotes, such as "Clown" or "Chef." This just determines what the ID reads as, not their access
var/id_access = null //This is for access. See access.dm for which jobs give what access. Again, put in quotes. Use "Captain" if you want it to be all access.
var/id_icon = null //For setting it to be a gold, silver, centcom etc ID
var/husk = null
var/outfit_type = null // Will start with this if exists then apply specific slots
var/list/implants = list()
/obj/effect/mob_spawn/human/equip(mob/living/carbon/human/H)
if(mob_species)
H.set_species(mob_species)
if(husk)
H.Drain()
if(outfit_type)
H.equipOutfit(outfit_type)
if(uniform)
H.equip_to_slot_or_del(new uniform(H), slot_w_uniform)
if(suit)
H.equip_to_slot_or_del(new suit(H), slot_wear_suit)
if(shoes)
H.equip_to_slot_or_del(new shoes(H), slot_shoes)
if(gloves)
H.equip_to_slot_or_del(new gloves(H), slot_gloves)
if(radio)
H.equip_to_slot_or_del(new radio(H), slot_ears)
if(glasses)
H.equip_to_slot_or_del(new glasses(H), slot_glasses)
if(mask)
H.equip_to_slot_or_del(new mask(H), slot_wear_mask)
if(helmet)
H.equip_to_slot_or_del(new helmet(H), slot_head)
if(belt)
H.equip_to_slot_or_del(new belt(H), slot_belt)
if(pocket1)
H.equip_to_slot_or_del(new pocket1(H), slot_r_store)
if(pocket2)
H.equip_to_slot_or_del(new pocket2(H), slot_l_store)
if(back)
H.equip_to_slot_or_del(new back(H), slot_back)
if(l_hand)
H.equip_to_slot_or_del(new l_hand(H), slot_l_hand)
if(r_hand)
H.equip_to_slot_or_del(new r_hand(H), slot_r_hand)
if(has_id)
var/obj/item/weapon/card/id/W = new(H)
if(id_icon)
W.icon_state = id_icon
if(id_access)
var/datum/job/jobdatum
for(var/jobtype in typesof(/datum/job))
var/datum/job/J = new jobtype
if(J.title == id_access)
jobdatum = J
break
if(jobdatum)
W.access = jobdatum.get_access()
else
W.access = list()
if(id_job)
W.assignment = id_job
W.registered_name = H.real_name
W.update_label()
H.equip_to_slot_or_del(W, slot_wear_id)
for(var/I in implants)
var/obj/item/weapon/implant/X = new I
X.implant(H)
//Instant version - use when spawning corpses during runtime
/obj/effect/mob_spawn/human/corpse
roundstart = FALSE
instant = TRUE
/obj/effect/mob_spawn/human/corpse/damaged
brute_damage = 1000
/obj/effect/mob_spawn/human/alive
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
death = FALSE
roundstart = FALSE //you could use these for alive fake humans on roundstart but this is more common scenario
//Non-human spawners
/obj/effect/mob_spawn/AICorpse/create() //Creates a corrupted AI
var/A = locate(/mob/living/silicon/ai) in loc
if(A)
return
var/L = new /datum/ai_laws/default/asimov
var/B = new /obj/item/device/mmi
var/mob/living/silicon/ai/M = new(src.loc, L, B, 1) //spawn new AI at landmark as var M
M.name = src.name
M.real_name = src.name
M.aiPDA.toff = 1 //turns the AI's PDA messenger off, stopping it showing up on player PDAs
M.death() //call the AI's death proc
qdel(src)
/obj/effect/mob_spawn/slime
mob_type = /mob/living/simple_animal/slime
var/mobcolour = "grey"
icon = 'icons/mob/slimes.dmi'
icon_state = "grey baby slime" //sets the icon in the map editor
/obj/effect/mob_spawn/slime/equip(mob/living/simple_animal/slime/S)
S.colour = mobcolour
/obj/effect/mob_spawn/human/facehugger/create() //Creates a squashed facehugger
var/obj/item/clothing/mask/facehugger/O = new(src.loc) //variable O is a new facehugger at the location of the landmark
O.name = src.name
O.Die() //call the facehugger's death proc
qdel(src)
/obj/effect/mob_spawn/mouse
name = "sleeper"
mob_type = /mob/living/simple_animal/mouse
death = FALSE
roundstart = FALSE
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
/obj/effect/mob_spawn/cow
name = "sleeper"
mob_type = /mob/living/simple_animal/cow
death = FALSE
roundstart = FALSE
mob_gender = FEMALE
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
// I'll work on making a list of corpses people request for maps, or that I think will be commonly used. Syndicate operatives for example.
/obj/effect/mob_spawn/human/syndicatesoldier
name = "Syndicate Operative"
uniform = /obj/item/clothing/under/syndicate
suit = /obj/item/clothing/suit/armor/vest
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
radio = /obj/item/device/radio/headset
mask = /obj/item/clothing/mask/gas
helmet = /obj/item/clothing/head/helmet/swat
back = /obj/item/weapon/storage/backpack
has_id = 1
id_job = "Operative"
id_access = "Syndicate"
/obj/effect/mob_spawn/human/syndicatecommando
name = "Syndicate Commando"
uniform = /obj/item/clothing/under/syndicate
suit = /obj/item/clothing/suit/space/hardsuit/syndi
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
radio = /obj/item/device/radio/headset
mask = /obj/item/clothing/mask/gas/syndicate
helmet = /obj/item/clothing/head/helmet/space/hardsuit/syndi
back = /obj/item/weapon/tank/jetpack/oxygen
pocket1 = /obj/item/weapon/tank/internals/emergency_oxygen
has_id = 1
id_job = "Operative"
id_access = "Syndicate"
///////////Civilians//////////////////////
/obj/effect/mob_spawn/human/cook
name = "Cook"
uniform = /obj/item/clothing/under/rank/chef
suit = /obj/item/clothing/suit/apron/chef
shoes = /obj/item/clothing/shoes/sneakers/black
helmet = /obj/item/clothing/head/chefhat
back = /obj/item/weapon/storage/backpack
radio = /obj/item/device/radio/headset
has_id = 1
id_job = "Cook"
id_access = "Cook"
/obj/effect/mob_spawn/human/doctor
name = "Doctor"
radio = /obj/item/device/radio/headset/headset_med
uniform = /obj/item/clothing/under/rank/medical
suit = /obj/item/clothing/suit/toggle/labcoat
back = /obj/item/weapon/storage/backpack/medic
pocket1 = /obj/item/device/flashlight/pen
shoes = /obj/item/clothing/shoes/sneakers/black
has_id = 1
id_job = "Medical Doctor"
id_access = "Medical Doctor"
/obj/effect/mob_spawn/human/doctor/alive
death = FALSE
roundstart = FALSE
random = TRUE
radio = null
back = null
name = "sleeper"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "You are a space doctor!"
/obj/effect/mob_spawn/human/engineer
name = "Engineer"
radio = /obj/item/device/radio/headset/headset_eng
uniform = /obj/item/clothing/under/rank/engineer
back = /obj/item/weapon/storage/backpack/industrial
shoes = /obj/item/clothing/shoes/sneakers/orange
belt = /obj/item/weapon/storage/belt/utility/full
gloves = /obj/item/clothing/gloves/color/yellow
helmet = /obj/item/clothing/head/hardhat
has_id = 1
id_job = "Station Engineer"
id_access = "Station Engineer"
/obj/effect/mob_spawn/human/engineer/rig
suit = /obj/item/clothing/suit/space/hardsuit/engine
mask = /obj/item/clothing/mask/breath
/obj/effect/mob_spawn/human/clown
name = "Clown"
uniform = /obj/item/clothing/under/rank/clown
shoes = /obj/item/clothing/shoes/clown_shoes
radio = /obj/item/device/radio/headset
mask = /obj/item/clothing/mask/gas/clown_hat
pocket1 = /obj/item/weapon/bikehorn
back = /obj/item/weapon/storage/backpack/clown
has_id = 1
id_job = "Clown"
id_access = "Clown"
/obj/effect/mob_spawn/human/scientist
name = "Scientist"
radio = /obj/item/device/radio/headset/headset_sci
uniform = /obj/item/clothing/under/rank/scientist
suit = /obj/item/clothing/suit/toggle/labcoat/science
back = /obj/item/weapon/storage/backpack
shoes = /obj/item/clothing/shoes/sneakers/white
has_id = 1
id_job = "Scientist"
id_access = "Scientist"
/obj/effect/mob_spawn/human/miner
radio = /obj/item/device/radio/headset/headset_cargo/mining
uniform = /obj/item/clothing/under/rank/miner
gloves = /obj/item/clothing/gloves/color/black
back = /obj/item/weapon/storage/backpack/industrial
shoes = /obj/item/clothing/shoes/sneakers/black
has_id = 1
id_job = "Shaft Miner"
id_access = "Shaft Miner"
/obj/effect/mob_spawn/human/miner/rig
suit = /obj/item/clothing/suit/space/hardsuit/mining
mask = /obj/item/clothing/mask/breath
/obj/effect/mob_spawn/human/miner/explorer
uniform = /obj/item/clothing/under/rank/miner/lavaland
back = /obj/item/weapon/storage/backpack/explorer
shoes = /obj/item/clothing/shoes/workboots/mining
suit = /obj/item/clothing/suit/hooded/explorer
mask = /obj/item/clothing/mask/gas/explorer
belt = /obj/item/weapon/gun/energy/kinetic_accelerator
/obj/effect/mob_spawn/human/plasmaman
mob_species = /datum/species/plasmaman
helmet = /obj/item/clothing/head/helmet/space/plasmaman
uniform = /obj/item/clothing/under/plasmaman
back = /obj/item/weapon/tank/internals/plasmaman/full
mask = /obj/item/clothing/mask/breath
/obj/effect/mob_spawn/human/bartender
name = "Space Bartender"
uniform = /obj/item/clothing/under/rank/bartender
back = /obj/item/weapon/storage/backpack
shoes = /obj/item/clothing/shoes/sneakers/black
suit = /obj/item/clothing/suit/armor/vest
glasses = /obj/item/clothing/glasses/sunglasses/reagent
has_id = 1
id_job = "Bartender"
id_access = "Bartender"
/obj/effect/mob_spawn/human/bartender/alive
death = FALSE
roundstart = FALSE
random = TRUE
name = "bartender sleeper"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "You are a space bartender!"
/obj/effect/mob_spawn/human/beach
glasses = /obj/item/clothing/glasses/sunglasses
uniform = /obj/item/clothing/under/shorts/red
pocket1 = /obj/item/weapon/storage/wallet/random
/obj/effect/mob_spawn/human/beach/alive
death = FALSE
roundstart = FALSE
random = TRUE
mob_name = "Beach Bum"
name = "beach bum sleeper"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "You are a beach bum!"
/////////////////Officers+Nanotrasen Security//////////////////////
/obj/effect/mob_spawn/human/bridgeofficer
name = "Bridge Officer"
radio = /obj/item/device/radio/headset/heads/hop
uniform = /obj/item/clothing/under/rank/centcom_officer
suit = /obj/item/clothing/suit/armor/bulletproof
shoes = /obj/item/clothing/shoes/sneakers/black
glasses = /obj/item/clothing/glasses/sunglasses
has_id = 1
id_job = "Bridge Officer"
id_access = "Captain"
/obj/effect/mob_spawn/human/commander
name = "Commander"
uniform = /obj/item/clothing/under/rank/centcom_commander
suit = /obj/item/clothing/suit/armor/bulletproof
radio = /obj/item/device/radio/headset/heads/captain
glasses = /obj/item/clothing/glasses/eyepatch
mask = /obj/item/clothing/mask/cigarette/cigar/cohiba
helmet = /obj/item/clothing/head/centhat
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat/swat
pocket1 = /obj/item/weapon/lighter
has_id = 1
id_job = "Commander"
id_access = "Captain"
/obj/effect/mob_spawn/human/nanotrasensoldier
name = "Nanotrasen Private Security Officer"
uniform = /obj/item/clothing/under/rank/security
suit = /obj/item/clothing/suit/armor/vest
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
mask = /obj/item/clothing/mask/gas/sechailer/swat
helmet = /obj/item/clothing/head/helmet/swat/nanotrasen
back = /obj/item/weapon/storage/backpack/security
has_id = 1
id_job = "Private Security Force"
id_access = "Security Officer"
/obj/effect/mob_spawn/human/commander/alive
death = FALSE
roundstart = FALSE
mob_name = "Nanotrasen Commander"
name = "sleeper"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "You are a Nanotrasen Commander!"
/////////////////Spooky Undead//////////////////////
/obj/effect/mob_spawn/human/skeleton
name = "skeletal remains"
mob_name = "skeleton"
mob_species = /datum/species/skeleton
mob_gender = NEUTER
/obj/effect/mob_spawn/human/skeleton/alive
death = FALSE
roundstart = FALSE
icon = 'icons/effects/blood.dmi'
icon_state = "remains"
flavour_text = "By unknown powers, your skeletal remains have been reanimated! Walk this mortal plain and terrorize all living adventurers who dare cross your path."
/obj/effect/mob_spawn/human/zombie
name = "rotting corpse"
mob_name = "zombie"
mob_species = /datum/species/zombie
/obj/effect/mob_spawn/human/zombie/alive
death = FALSE
roundstart = FALSE
icon = 'icons/effects/blood.dmi'
icon_state = "remains"
flavour_text = "By unknown powers, your rotting remains have been resurrected! Walk this mortal plain and terrorize all living adventurers who dare cross your path."
/obj/effect/mob_spawn/human/abductor
name = "abductor"
mob_name = "alien"
mob_species = /datum/species/abductor
uniform = /obj/item/clothing/under/color/grey
shoes = /obj/item/clothing/shoes/combat
//For ghost bar.
/obj/effect/mob_spawn/human/alive/space_bar_patron
name = "Bar cryogenics"
mob_name = "Bar patron"
random = TRUE
permanent = TRUE
uses = -1
uniform = /obj/item/clothing/under/rank/bartender
back = /obj/item/weapon/storage/backpack
shoes = /obj/item/clothing/shoes/sneakers/black
suit = /obj/item/clothing/suit/armor/vest
glasses = /obj/item/clothing/glasses/sunglasses/reagent
/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user)
var/despawn = alert("Return to cryosleep? (Warning, Your mob will be deleted!)",,"Yes","No")
if(despawn == "No" || !loc || !Adjacent(user))
return
user.visible_message("<span class='notice'>[user.name] climbs back into cryosleep...</span>")
qdel(user)
+44
View File
@@ -0,0 +1,44 @@
//Exile implants will allow you to use the station gate, but not return home.
//This will allow security to exile badguys/for badguys to exile their kill targets
/obj/item/weapon/implant/exile
name = "exile implant"
desc = "Prevents you from returning from away missions"
origin_tech = "materials=2;biotech=3;magnets=2;bluespace=3"
activated = 0
/obj/item/weapon/implant/exile/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Nanotrasen Employee Exile Implant<BR>
<b>Implant Details:</b> The onboard gateway system has been modified to reject entry by individuals containing this implant<BR>"}
return dat
/obj/item/weapon/implanter/exile
name = "implanter (exile)"
/obj/item/weapon/implanter/exile/New()
imp = new /obj/item/weapon/implant/exile( src )
..()
/obj/item/weapon/implantcase/exile
name = "implant case - 'Exile'"
desc = "A glass case containing an exile implant."
/obj/item/weapon/implantcase/exile/New()
imp = new /obj/item/weapon/implant/exile(src)
..()
/obj/structure/closet/secure_closet/exile
name = "exile implants"
req_access = list(access_hos)
/obj/structure/closet/secure_closet/exile/New()
..()
new /obj/item/weapon/implanter/exile(src)
new /obj/item/weapon/implantcase/exile(src)
new /obj/item/weapon/implantcase/exile(src)
new /obj/item/weapon/implantcase/exile(src)
new /obj/item/weapon/implantcase/exile(src)
new /obj/item/weapon/implantcase/exile(src)
+276
View File
@@ -0,0 +1,276 @@
var/obj/machinery/gateway/centerstation/the_gateway = null
/obj/machinery/gateway
name = "gateway"
desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
icon = 'icons/obj/machines/gateway.dmi'
icon_state = "off"
density = 1
anchored = 1
unacidable = 1
var/active = 0
/obj/machinery/gateway/centerstation/New()
..()
if(!the_gateway)
the_gateway = src
/obj/machinery/gateway/centerstation/Destroy()
if(the_gateway == src)
the_gateway = null
return ..()
/obj/machinery/gateway/initialize()
update_icon()
switch(dir)
if(SOUTH,SOUTHEAST,SOUTHWEST)
density = 0
/obj/machinery/gateway/update_icon()
if(active)
icon_state = "on"
return
icon_state = "off"
//prevents shuttles attempting to rotate this since it messes up sprites
/obj/machinery/gateway/shuttleRotate()
return
//this is da important part wot makes things go
/obj/machinery/gateway/centerstation
density = 1
icon_state = "offcenter"
use_power = 1
//warping vars
var/list/linked = list()
var/ready = 0 //have we got all the parts for a gateway?
var/wait = 0 //this just grabs world.time at world start
var/obj/machinery/gateway/centeraway/awaygate = null
/obj/machinery/gateway/centerstation/initialize()
update_icon()
wait = world.time + config.gateway_delay //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
/obj/machinery/gateway/centerstation/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centerstation/process()
if(stat & (NOPOWER))
if(active) toggleoff()
return
if(active)
use_power(5000)
/obj/machinery/gateway/centerstation/proc/detect()
linked = list() //clear the list
var/turf/T = loc
for(var/i in alldirs)
T = get_step(loc, i)
var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
if(G)
linked.Add(G)
continue
//this is only done if we fail to find a part
ready = 0
toggleoff()
break
if(linked.len == 8)
ready = 1
/obj/machinery/gateway/centerstation/proc/toggleon(mob/user)
if(!ready)
return
if(linked.len != 8)
return
if(!powered())
return
if(!awaygate)
user << "<span class='notice'>Error: No destination found.</span>"
return
if(world.time < wait)
user << "<span class='notice'>Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.</span>"
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
/obj/machinery/gateway/centerstation/proc/toggleoff()
for(var/obj/machinery/gateway/G in linked)
G.active = 0
G.update_icon()
active = 0
update_icon()
/obj/machinery/gateway/centerstation/attack_hand(mob/user)
if(!ready)
detect()
return
if(!active)
toggleon(user)
return
toggleoff()
//okay, here's the good teleporting stuff
/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
if(!ready)
return
if(!active)
return
if(!awaygate || qdeleted(awaygate))
return
if(awaygate.calibrated)
AM.forceMove(get_step(awaygate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
return
else
var/obj/effect/landmark/dest = pick(awaydestinations)
if(dest)
AM.forceMove(get_turf(dest))
AM.setDir(SOUTH)
use_power(5000)
return
/obj/machinery/gateway/centerstation/attackby(obj/item/device/W, mob/user, params)
if(istype(W,/obj/item/device/multitool))
user << "\black The gate is already calibrated, there is no work for you to do here."
return
/////////////////////////////////////Away////////////////////////
/obj/machinery/gateway/centeraway
density = 1
icon_state = "offcenter"
use_power = 0
var/calibrated = 1
var/list/linked = list() //a list of the connected gateway chunks
var/ready = 0
var/obj/machinery/gateway/centeraway/stationgate = null
/obj/machinery/gateway/centeraway/initialize()
update_icon()
stationgate = locate(/obj/machinery/gateway/centerstation)
/obj/machinery/gateway/centeraway/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/obj/machinery/gateway/centeraway/proc/detect()
linked = list() //clear the list
var/turf/T = loc
for(var/i in alldirs)
T = get_step(loc, i)
var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
if(G)
linked.Add(G)
continue
//this is only done if we fail to find a part
ready = 0
toggleoff()
break
if(linked.len == 8)
ready = 1
/obj/machinery/gateway/centeraway/proc/toggleon(mob/user)
if(!ready)
return
if(linked.len != 8)
return
if(!stationgate)
user << "<span class='notice'>Error: No destination found.</span>"
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
/obj/machinery/gateway/centeraway/proc/toggleoff()
for(var/obj/machinery/gateway/G in linked)
G.active = 0
G.update_icon()
active = 0
update_icon()
/obj/machinery/gateway/centeraway/attack_hand(mob/user)
if(!ready)
detect()
return
if(!active)
toggleon(user)
return
toggleoff()
/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
if(!ready)
return
if(!active)
return
if(!stationgate || qdeleted(stationgate))
return
if(istype(AM, /mob/living/carbon))
for(var/obj/item/weapon/implant/exile/E in AM)//Checking that there is an exile implant in the contents
if(E.imp_in == AM)//Checking that it's actually implanted vs just in their pocket
AM << "\black The station gate has detected your exile implant and is blocking your entry."
return
AM.forceMove(get_step(stationgate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
if(istype(W,/obj/item/device/multitool))
if(calibrated)
user << "\black The gate is already calibrated, there is no work for you to do here."
return
else
user << "<span class='boldnotice'>Recalibration successful!</span>: \black This gate's systems have been fine tuned. Travel to this gate will now be on target."
calibrated = 1
return
@@ -0,0 +1,75 @@
var/global/dmm_suite/maploader = new
dmm_suite{
/*
dmm_suite version 1.0
Released January 30th, 2011.
defines the object /dmm_suite
- Provides the proc load_map()
- Loads the specified map file onto the specified z-level.
- provides the proc write_map()
- Returns a text string of the map in dmm format
ready for output to a file.
- provides the proc save_map()
- Returns a .dmm file if map is saved
- Returns FALSE if map fails to save
The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.
------------------------
To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
- A turf representing one corner of a three dimensional grid (Required).
- Another turf representing the other corner of the same grid (Required).
- Any, or a combination, of several bit flags (Optional, see documentation).
The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.
------------------------
To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
- A .dmm file to load (Required).
- A number representing the z-level on which to start loading the map (Optional).
The /dmm_suite will load the map file starting on the specified z-level. If no
z-level was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.
Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.
*/
verb/load_map(var/dmm_file as file, var/x_offset as num, var/y_offset as num, var/z_offset as num, var/cropMap as num, var/measureOnly as num){
// dmm_file: A .dmm file to load (Required).
// z_offset: A number representing the z-level on which to start loading the map (Optional).
// cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional).
// measureOnly: When true, no changes will be made to the world (Optional).
}
verb/write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){
// t1: A turf representing one corner of a three dimensional grid (Required).
// t2: Another turf representing the other corner of the same grid (Required).
// flags: Any, or a combination, of several bit flags (Optional, see documentation).
}
// save_map is included as a legacy proc. Use write_map instead.
verb/save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){
// t1: A turf representing one corner of a three dimensional grid (Required).
// t2: Another turf representing the other corner of the same grid (Required).
// map_name: A valid name for the map to be saved, such as "castle" (Required).
// flags: Any, or a combination, of several bit flags (Optional, see documentation).
}
}
@@ -0,0 +1,402 @@
///////////////////////////////////////////////////////////////
//SS13 Optimized Map loader
//////////////////////////////////////////////////////////////
//global datum that will preload variables on atoms instanciation
var/global/use_preloader = FALSE
var/global/dmm_suite/preloader/_preloader = new
/dmm_suite
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
// /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g
var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
// /^[\s\n]+|[\s\n]+$/
var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
var/static/list/modelCache = list()
/**
* Construct the model map and control the loading process
*
* WORKING :
*
* 1) Makes an associative mapping of model_keys with model
* e.g aa = /turf/unsimulated/wall{icon_state = "rock"}
* 2) Read the map line by line, parsing the result (using parse_grid)
*
*/
/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num)
var/tfile = dmm_file//the map file we're creating
if(isfile(tfile))
tfile = file2text(tfile)
if(!x_offset)
x_offset = 1
if(!y_offset)
y_offset = 1
if(!z_offset)
z_offset = world.maxz + 1
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
var/list/grid_models = list()
var/key_len = 0
dmmRegex.next = 1
while(dmmRegex.Find(tfile, dmmRegex.next))
// "aa" = (/type{vars=blah})
if(dmmRegex.group[1]) // Model
var/key = dmmRegex.group[1]
if(grid_models[key]) // Duplicate model keys are ignored in DMMs
continue
if(key_len != length(key))
if(!key_len)
key_len = length(key)
else
throw EXCEPTION("Inconsistant key length in DMM")
if(!measureOnly)
grid_models[key] = dmmRegex.group[2]
// (1,1,1) = {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
else if(dmmRegex.group[3]) // Coords
if(!key_len)
throw EXCEPTION("Coords before model definition in DMM")
var/xcrdStart = text2num(dmmRegex.group[3]) + x_offset - 1
//position of the currently processed square
var/xcrd
var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1
var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1
if(zcrd > world.maxz)
if(cropMap)
continue
else
world.maxz = zcrd //create a new z_level if needed
bounds[MAP_MINX] = min(bounds[MAP_MINX], xcrdStart)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd)
var/list/gridLines = splittext(dmmRegex.group[6], "\n")
var/leadingBlanks = 0
while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "")
if(leadingBlanks > 1)
gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines.
if(!gridLines.len) // Skip it if only blank lines exist.
continue
if(gridLines.len && gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
bounds[MAP_MINY] = min(bounds[MAP_MINY], ycrd)
ycrd += gridLines.len - 1 // Start at the top and work down
if(!cropMap && ycrd > world.maxy)
if(!measureOnly)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], ycrd)
else
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], min(ycrd, world.maxy))
var/maxx = xcrdStart
if(measureOnly)
for(var/line in gridLines)
maxx = max(maxx, xcrdStart + length(line) / key_len - 1)
else
for(var/line in gridLines)
if(ycrd <= world.maxy && ycrd >= 1)
xcrd = xcrdStart
for(var/tpos = 1 to length(line) - key_len + 1 step key_len)
if(xcrd > world.maxx)
if(cropMap)
break
else
world.maxx = xcrd
if(xcrd >= 1)
var/model_key = copytext(line, tpos, tpos + key_len)
if(!grid_models[model_key])
throw EXCEPTION("Undefined model key in DMM.")
parse_grid(grid_models[model_key], xcrd, ycrd, zcrd)
CHECK_TICK
maxx = max(maxx, xcrd)
++xcrd
--ycrd
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx)
CHECK_TICK
if(bounds[1] == 1.#INF) // Shouldn't need to check every item
return null
else
if(!measureOnly)
for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/turf/T = t
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(TRUE)
return bounds
/**
* Fill a given tile with its area/turf/objects/mobs
* Variable model is one full map line (e.g /turf/unsimulated/wall{icon_state = "rock"},/area/mine/explored)
*
* WORKING :
*
* 1) Read the model string, member by member (delimiter is ',')
*
* 2) Get the path of the atom and store it into a list
*
* 3) a) Check if the member has variables (text within '{' and '}')
*
* 3) b) Construct an associative list with found variables, if any (the atom index in members is the same as its variables in members_attributes)
*
* 4) Instanciates the atom with its variables
*
*/
/dmm_suite/proc/parse_grid(model as text,xcrd as num,ycrd as num,zcrd as num)
/*Method parse_grid()
- Accepts a text string containing a comma separated list of type paths of the
same construction as those contained in a .dmm file, and instantiates them.
*/
var/list/members //will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/explored)
var/list/members_attributes //will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/cached = modelCache[model]
var/index
if(cached)
members = cached[1]
members_attributes = cached[2]
else
/////////////////////////////////////////////////////////
//Constructing members and corresponding variables lists
////////////////////////////////////////////////////////
members = list()
members_attributes = list()
index = 1
var/old_position = 1
var/dpos
do
//finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/explored)
dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") //find next delimiter (comma here) that's not within {...}
var/full_def = trim_text(copytext(model, old_position, dpos)) //full definition, e.g : /obj/foo/bar{variables=derp}
var/variables_start = findtext(full_def, "{")
var/atom_def = text2path(trim_text(copytext(full_def, 1, variables_start))) //path definition, e.g /obj/foo/bar
old_position = dpos + 1
if(!atom_def) // Skip the item if the path does not exist. Fix your crap, mappers!
continue
members.Add(atom_def)
//transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
var/list/fields = list()
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
fields = readlist(full_def, ";")
//then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
CHECK_TICK
while(dpos != 0)
modelCache[model] = list(members, members_attributes)
////////////////
//Instanciation
////////////////
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
//first instance the /area and remove it from the members list
index = members.len
if(members[index] != /area/template_noop)
var/atom/instance
_preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
instance = locate(members[index])
var/turf/crds = locate(xcrd,ycrd,zcrd)
if(crds)
instance.contents.Add(crds)
if(use_preloader && instance)
_preloader.load(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
var/first_turf_index = 1
while(!ispath(members[first_turf_index],/turf)) //find first /turf object in members
first_turf_index++
//instanciate the first /turf
var/turf/T
if(members[first_turf_index] != /turf/template_noop)
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],xcrd,ycrd,zcrd)
if(T)
//if others /turf are presents, simulates the underlays piling effect
index = first_turf_index + 1
while(index <= members.len - 1) // Last item is an /area
var/underlay = T.appearance
T = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
T.underlays += underlay
index++
//finally instance all remainings objects/mobs
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)
CHECK_TICK
////////////////
//Helpers procs
////////////////
//Instance an atom at (x,y,z) and gives it the variables in attributes
/dmm_suite/proc/instance_atom(path,list/attributes, x, y, z)
var/atom/instance
_preloader.setup(attributes, path)
var/turf/T = locate(x,y,z)
if(T)
if(ispath(path, /turf))
T.ChangeTurf(path, TRUE)
instance = T
else
instance = new path (T)//first preloader pass
if(use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
_preloader.load(instance)
return instance
//text trimming (both directions) helper proc
//optionally removes quotes before and after the text (for variable name)
/dmm_suite/proc/trim_text(what as text,trim_quotes=0)
if(trim_quotes)
return trimQuotesRegex.Replace(what, "")
else
return trimRegex.Replace(what, "")
//find the position of the next delimiter,skipping whatever is comprised between opening_escape and closing_escape
//returns 0 if reached the last delimiter
/dmm_suite/proc/find_next_delimiter_position(text as text,initial_position as num, delimiter=",",opening_escape=quote,closing_escape=quote)
var/position = initial_position
var/next_delimiter = findtext(text,delimiter,position,0)
var/next_opening = findtext(text,opening_escape,position,0)
while((next_opening != 0) && (next_opening < next_delimiter))
position = findtext(text,closing_escape,next_opening + 1,0)+1
next_delimiter = findtext(text,delimiter,position,0)
next_opening = findtext(text,opening_escape,position,0)
return next_delimiter
//build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
//return the filled list
/dmm_suite/proc/readlist(text as text, delimiter=",")
var/list/to_return = list()
var/position
var/old_position = 1
do
//find next delimiter that is not within "..."
position = find_next_delimiter_position(text,old_position,delimiter)
//check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7))
var/equal_position = findtext(text,"=",old_position, position)
var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)),1)//the name of the variable, must trim quotes to build a BYOND compliant associatives list
old_position = position + 1
if(equal_position)//associative var, so do the association
var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable
//Check for string
if(findtext(trim_right,quote,1,2))
trim_right = copytext(trim_right,2,findtext(trim_right,quote,3,0))
//Check for number
else if(isnum(text2num(trim_right)))
trim_right = text2num(trim_right)
//Check for null
else if(trim_right == "null")
trim_right = null
//Check for list
else if(copytext(trim_right,1,5) == "list")
trim_right = readlist(copytext(trim_right,6,length(trim_right)))
//Check for file
else if(copytext(trim_right,1,2) == "'")
trim_right = file(copytext(trim_right,2,length(trim_right)))
//Check for path
else if(ispath(text2path(trim_right)))
trim_right = text2path(trim_right)
to_return[trim_left] = trim_right
else//simple var
to_return[trim_left] = null
while(position != 0)
return to_return
//atom creation method that preloads variables at creation
/atom/New()
if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
_preloader.load(src)
. = ..()
/dmm_suite/Destroy()
..()
return QDEL_HINT_HARDDEL_NOW
//////////////////
//Preloader datum
//////////////////
/dmm_suite/preloader
parent_type = /datum
var/list/attributes
var/target_path
/dmm_suite/preloader/proc/setup(list/the_attributes, path)
if(the_attributes.len)
use_preloader = TRUE
attributes = the_attributes
target_path = path
/dmm_suite/preloader/proc/load(atom/what)
for(var/attribute in attributes)
var/value = attributes[attribute]
if(islist(value))
value = deepCopyList(value)
what.vars[attribute] = value
use_preloader = FALSE
/area/template_noop
name = "Area Passthrough"
/turf/template_noop
name = "Turf Passthrough"
@@ -0,0 +1,679 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/*
SwapMaps library by Lummox JR
developed for digitalBYOND
http://www.digitalbyond.org
Version 2.1
The purpose of this library is to make it easy for authors to swap maps
in and out of their game using savefiles. Swapped-out maps can be
transferred between worlds for an MMORPG, sent to the client, etc.
This is facilitated by the use of a special datum and a global list.
Uses of swapmaps:
- Temporary battle arenas
- House interiors
- Individual custom player houses
- Virtually unlimited terrain
- Sharing maps between servers running different instances of the same
game
- Loading and saving pieces of maps for reusable room templates
*/
/*
User Interface:
VARS:
swapmaps_iconcache
An associative list of icon files with names, like
'player.dmi' = "player"
swapmaps_mode
This must be set at runtime, like in world/New().
SWAPMAPS_SAV 0 (default)
Uses .sav files for raw /savefile output.
SWAPMAPS_TEXT 1
Uses .txt files via ExportText() and ImportText(). These maps
are easily editable and appear to take up less space in the
current version of BYOND.
PROCS:
SwapMaps_Find(id)
Find a map by its id
SwapMaps_Load(id)
Load a map by its id
SwapMaps_Save(id)
Save a map by its id (calls swapmap.Save())
SwapMaps_Unload(id)
Save and unload a map by its id (calls swapmap.Unload())
SwapMaps_Save_All()
Save all maps
SwapMaps_DeleteFile(id)
Delete a map file
SwapMaps_CreateFromTemplate(id)
Create a new map by loading another map to use as a template.
This map has id==src and will not be saved. To make it savable,
change id with swapmap.SetID(newid).
SwapMaps_LoadChunk(id,turf/locorner)
Load a swapmap as a "chunk", at a specific place. A new datum is
created but it's not added to the list of maps to save or unload.
The new datum can be safely deleted without affecting the turfs
it loaded. The purpose of this is to load a map file onto part of
another swapmap or an existing part of the world.
locorner is the corner turf with the lowest x,y,z values.
SwapMaps_SaveChunk(id,turf/corner1,turf/corner2)
Save a piece of the world as a "chunk". A new datum is created
for the chunk, but it can be deleted without destroying any turfs.
The chunk file can be reloaded as a swapmap all its own, or loaded
via SwapMaps_LoadChunk() to become part of another map.
SwapMaps_GetSize(id)
Return a list corresponding to the x,y,z sizes of a map file,
without loading the map.
Returns null if the map is not found.
SwapMaps_AddIconToCache(name,icon)
Cache an icon file by name for space-saving storage
swapmap.New(id,x,y,z)
Create a new map; specify id, width (x), height (y), and
depth (z)
Default size is world.maxx,world.maxy,1
swapmap.New(id,turf1,turf2)
Create a new map; specify id and 2 corners
This becomes a /swapmap for one of the compiled-in maps, for
easy saving.
swapmap.New()
Create a new map datum, but does not allocate space or assign an
ID (used for loading).
swapmap.Del()
Deletes a map but does not save
swapmap.Save()
Saves to map_[id].sav
Maps with id==src are not saved.
swapmap.Unload()
Saves the map and then deletes it
Maps with id==src are not saved.
swapmap.SetID(id)
Change the map's id and make changes to the lookup list
swapmap.AllTurfs(z)
Returns a block of turfs encompassing the entire map, or on just
one z-level
z is in world coordinates; it is optional
swapmap.Contains(turf/T)
Returns nonzero if T is inside the map's boundaries.
Also works for objs and mobs, but the proc is not area-safe.
swapmap.InUse()
Returns nonzero if a mob with a key is within the map's
boundaries.
swapmap.LoCorner(z=z1)
Returns locate(x1,y1,z), where z=z1 if none is specified.
swapmap.HiCorner(z=z2)
Returns locate(x2,y2,z), where z=z2 if none is specified.
swapmap.BuildFilledRectangle(turf/corner1,turf/corner2,item)
Builds a filled rectangle of item from one corner turf to the
other, on multiple z-levels if necessary. The corners may be
specified in any order.
item is a type path like /turf/closed/wall or /obj/barrel{full=1}.
swapmap.BuildRectangle(turf/corner1,turf/corner2,item)
Builds an unfilled rectangle of item from one corner turf to
the other, on multiple z-levels if necessary.
swapmap.BuildInTurfs(list/turfs,item)
Builds item on all of the turfs listed. The list need not
contain only turfs, or even only atoms.
*/
swapmap
var/id // a string identifying this map uniquely
var/x1 // minimum x,y,z coords
var/y1
var/z1
var/x2 // maximum x,y,z coords (also used as width,height,depth until positioned)
var/y2
var/z2
var/tmp/locked // don't move anyone to this map; it's saving or loading
var/tmp/mode // save as text-mode
var/ischunk // tells the load routine to load to the specified location
New(_id,x,y,z)
if(isnull(_id)) return
id=_id
mode=swapmaps_mode
if(isturf(x) && isturf(y))
/*
Special format: Defines a map as an existing set of turfs;
this is useful for saving a compiled map in swapmap format.
Because this is a compiled-in map, its turfs are not deleted
when the datum is deleted.
*/
x1=min(x:x,y:x);x2=max(x:x,y:x)
y1=min(x:y,y:y);y2=max(x:y,y:y)
z1=min(x:z,y:z);z2=max(x:z,y:z)
InitializeSwapMaps()
if(z2>swapmaps_compiled_maxz ||\
y2>swapmaps_compiled_maxy ||\
x2>swapmaps_compiled_maxx)
qdel(src)
return
x2=x?(x):world.maxx
y2=y?(y):world.maxy
z2=z?(z):1
AllocateSwapMap()
Destroy()
// a temporary datum for a chunk can be deleted outright
// for others, some cleanup is necessary
if(!ischunk)
swapmaps_loaded-=src
swapmaps_byname-=id
if(z2>swapmaps_compiled_maxz ||\
y2>swapmaps_compiled_maxy ||\
x2>swapmaps_compiled_maxx)
var/list/areas=new
for(var/atom/A in block(locate(x1,y1,z1),locate(x2,y2,z2)))
for(var/obj/O in A) qdel(O)
for(var/mob/M in A)
if(!M.key) qdel(M)
else M.loc=null
areas[A.loc]=null
qdel(A)
// delete areas that belong only to this map
for(var/area/a in areas)
if(a && !a.contents.len) qdel(a)
if(x2>=world.maxx || y2>=world.maxy || z2>=world.maxz) CutXYZ()
qdel(areas)
..()
return QDEL_HINT_HARDDEL_NOW
/*
Savefile format:
map
id
x // size, not coords
y
z
areas // list of areas, not including default
[each z; 1 to depth]
[each y; 1 to height]
[each x; 1 to width]
type // of turf
AREA // if non-default; saved as a number (index into areas list)
vars // all other changed vars
*/
Write(savefile/S)
var/x
var/y
var/z
var/n
var/list/areas
var/area/defarea=locate(world.area)
if(!defarea) defarea=new world.area
areas=list()
for(var/turf/T in block(locate(x1,y1,z1),locate(x2,y2,z2)))
areas[T.loc]=null
for(n in areas) // quickly eliminate associations for smaller storage
areas-=n
areas+=n
areas-=defarea
InitializeSwapMaps()
locked=1
S["id"] << id
S["z"] << z2-z1+1
S["y"] << y2-y1+1
S["x"] << x2-x1+1
S["areas"] << areas
for(n in 1 to areas.len) areas[areas[n]]=n
var/oldcd=S.cd
for(z in z1 to z2)
S.cd="[z-z1+1]"
for(y in y1 to y2)
S.cd="[y-y1+1]"
for(x in x1 to x2)
S.cd="[x-x1+1]"
var/turf/T=locate(x,y,z)
S["type"] << T.type
if(T.loc!=defarea) S["AREA"] << areas[T.loc]
T.Write(S)
S.cd=".."
S.cd=".."
sleep()
S.cd=oldcd
locked=0
qdel(areas)
Read(savefile/S,_id,turf/locorner)
var/x
var/y
var/z
var/n
var/list/areas
var/area/defarea=locate(world.area)
id=_id
if(locorner)
ischunk=1
x1=locorner.x
y1=locorner.y
z1=locorner.z
if(!defarea) defarea=new world.area
if(!_id)
S["id"] >> id
else
var/dummy
S["id"] >> dummy
S["z"] >> z2 // these are depth,
S["y"] >> y2 // height,
S["x"] >> x2 // width
S["areas"] >> areas
locked=1
AllocateSwapMap() // adjust x1,y1,z1 - x2,y2,z2 coords
var/oldcd=S.cd
for(z in z1 to z2)
S.cd="[z-z1+1]"
for(y in y1 to y2)
S.cd="[y-y1+1]"
for(x in x1 to x2)
S.cd="[x-x1+1]"
var/tp
S["type"]>>tp
var/turf/T=locate(x,y,z)
T.loc.contents-=T
T=new tp(locate(x,y,z))
if("AREA" in S.dir)
S["AREA"]>>n
var/area/A=areas[n]
A.contents+=T
else defarea.contents+=T
// clear the turf
for(var/obj/O in T) qdel(O)
for(var/mob/M in T)
if(!M.key) qdel(M)
else M.loc=null
// finish the read
T.Read(S)
S.cd=".."
S.cd=".."
sleep()
S.cd=oldcd
locked=0
qdel(areas)
/*
Find an empty block on the world map in which to load this map.
If no space is found, increase world.maxz as necessary. (If the
map is greater in x,y size than the current world, expand
world.maxx and world.maxy too.)
Ignore certain operations if loading a map as a chunk. Use the
x1,y1,z1 position for it, and *don't* count it as a loaded map.
*/
proc/AllocateSwapMap()
InitializeSwapMaps()
world.maxx=max(x2,world.maxx) // stretch x/y if necessary
world.maxy=max(y2,world.maxy)
if(!ischunk)
if(world.maxz<=swapmaps_compiled_maxz)
z1=swapmaps_compiled_maxz+1
x1=1;y1=1
else
var/list/l=ConsiderRegion(1,1,world.maxx,world.maxy,swapmaps_compiled_maxz+1)
x1=l[1]
y1=l[2]
z1=l[3]
qdel(l)
x2+=x1-1
y2+=y1-1
z2+=z1-1
world.maxz=max(z2,world.maxz) // stretch z if necessary
if(!ischunk)
swapmaps_loaded[src]=null
swapmaps_byname[id]=src
proc/ConsiderRegion(X1,Y1,X2,Y2,Z1,Z2)
while(1)
var/nextz=0
var/swapmap/M
for(M in swapmaps_loaded)
if(M.z2<Z1 || (Z2 && M.z1>Z2) || M.z1>=Z1+z2 ||\
M.x1>X2 || M.x2<X1 || M.x1>=X1+x2 ||\
M.y1>Y2 || M.y2<Y1 || M.y1>=Y1+y2) continue
// look for sub-regions with a defined ceiling
var/nz2=Z2?(Z2):Z1+z2-1+M.z2-M.z1
if(M.x1>=X1+x2)
.=ConsiderRegion(X1,Y1,M.x1-1,Y2,Z1,nz2)
if(.) return
else if(M.x2<=X2-x2)
.=ConsiderRegion(M.x2+1,Y1,X2,Y2,Z1,nz2)
if(.) return
if(M.y1>=Y1+y2)
.=ConsiderRegion(X1,Y1,X2,M.y1-1,Z1,nz2)
if(.) return
else if(M.y2<=Y2-y2)
.=ConsiderRegion(X1,M.y2+1,X2,Y2,Z1,nz2)
if(.) return
nextz=nextz?min(nextz,M.z2+1):(M.z2+1)
if(!M)
/* If nextz is not 0, then at some point there was an overlap that
could not be resolved by using an area to the side */
if(nextz) Z1=nextz
if(!nextz || (Z2 && Z2-Z1+1<z2))
return (!Z2 || Z2-Z1+1>=z2)?list(X1,Y1,Z1):null
X1=1;X2=world.maxx
Y1=1;Y2=world.maxy
proc/CutXYZ()
var/mx=swapmaps_compiled_maxx
var/my=swapmaps_compiled_maxy
var/mz=swapmaps_compiled_maxz
for(var/swapmap/M in swapmaps_loaded) // may not include src
mx=max(mx,M.x2)
my=max(my,M.y2)
mz=max(mz,M.z2)
world.maxx=mx
world.maxy=my
world.maxz=mz
// save and delete
proc/Unload()
Save()
qdel(src)
proc/Save()
if(id==src) return 0
var/savefile/S=mode?(new):new("map_[id].sav")
S << src
while(locked) sleep(1)
if(mode)
fdel("map_[id].txt")
S.ExportText("/","map_[id].txt")
return 1
// this will not delete existing savefiles for this map
proc/SetID(newid)
swapmaps_byname-=id
id=newid
swapmaps_byname[id]=src
proc/AllTurfs(z)
if(isnum(z) && (z<z1 || z>z2)) return null
return block(LoCorner(z),HiCorner(z))
// this could be safely called for an obj or mob as well, but
// probably not an area
proc/Contains(turf/T)
return (T && T.x>=x1 && T.x<=x2\
&& T.y>=y1 && T.y<=y2\
&& T.z>=z1 && T.z<=z2)
proc/InUse()
for(var/turf/T in AllTurfs())
for(var/mob/M in T) if(M.key) return 1
proc/LoCorner(z=z1)
return locate(x1,y1,z)
proc/HiCorner(z=z2)
return locate(x2,y2,z)
/*
Build procs: Take 2 turfs as corners, plus an item type.
An item may be like:
/turf/closed/wall
/obj/fence{icon_state="iron"}
*/
proc/BuildFilledRectangle(turf/T1,turf/T2,item)
if(!Contains(T1) || !Contains(T2)) return
var/turf/T=T1
// pick new corners in a block()-friendly form
T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z))
T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z))
for(T in block(T1,T2)) new item(T)
proc/BuildRectangle(turf/T1,turf/T2,item)
if(!Contains(T1) || !Contains(T2)) return
var/turf/T=T1
// pick new corners in a block()-friendly form
T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z))
T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z))
if(T2.x-T1.x<2 || T2.y-T1.y<2) BuildFilledRectangle(T1,T2,item)
else
//for(T in block(T1,T2)-block(locate(T1.x+1,T1.y+1,T1.z),locate(T2.x-1,T2.y-1,T2.z)))
for(T in block(T1,locate(T2.x,T1.y,T2.z))) new item(T)
for(T in block(locate(T1.x,T2.y,T1.z),T2)) new item(T)
for(T in block(locate(T1.x,T1.y+1,T1.z),locate(T1.x,T2.y-1,T2.z))) new item(T)
for(T in block(locate(T2.x,T1.y+1,T1.z),locate(T2.x,T2.y-1,T2.z))) new item(T)
/*
Supplementary build proc: Takes a list of turfs, plus an item
type. Actually the list doesn't have to be just turfs.
*/
proc/BuildInTurfs(list/turfs,item)
for(var/T in turfs) new item(T)
atom
Write(savefile/S)
for(var/V in vars-"x"-"y"-"z"-"contents"-"icon"-"overlays"-"underlays")
if(issaved(vars[V]))
if(vars[V]!=initial(vars[V])) S[V]<<vars[V]
else S.dir.Remove(V)
if(icon!=initial(icon))
if(swapmaps_iconcache && swapmaps_iconcache[icon])
S["icon"]<<swapmaps_iconcache[icon]
else S["icon"]<<icon
// do not save mobs with keys; do save other mobs
var/mob/M
for(M in src) if(M.key) break
if(overlays.len) S["overlays"]<<overlays
if(underlays.len) S["underlays"]<<underlays
if(contents.len && !isarea(src))
var/list/l=contents
if(M)
l=l.Copy()
for(M in src) if(M.key) l-=M
if(l.len) S["contents"]<<l
if(l!=contents) qdel(l)
Read(savefile/S)
var/list/l
if(contents.len) l=contents
..()
// if the icon was a text string, it would not have loaded properly
// replace it from the cache list
if(!icon && ("icon" in S.dir))
var/ic
S["icon"]>>ic
if(istext(ic)) icon=swapmaps_iconcache[ic]
if(l && contents!=l)
contents+=l
qdel(l)
// set this up (at runtime) as follows:
// list(\
// 'player.dmi'="player",\
// 'monster.dmi'="monster",\
// ...
// 'item.dmi'="item")
var/list/swapmaps_iconcache
// preferred mode; sav or text
var/const/SWAPMAPS_SAV=0
var/const/SWAPMAPS_TEXT=1
var/swapmaps_mode=SWAPMAPS_SAV
var/swapmaps_compiled_maxx
var/swapmaps_compiled_maxy
var/swapmaps_compiled_maxz
var/swapmaps_initialized
var/swapmaps_loaded
var/swapmaps_byname
proc/InitializeSwapMaps()
if(swapmaps_initialized) return
swapmaps_initialized=1
swapmaps_compiled_maxx=world.maxx
swapmaps_compiled_maxy=world.maxy
swapmaps_compiled_maxz=world.maxz
swapmaps_loaded=list()
swapmaps_byname=list()
if(swapmaps_iconcache)
for(var/V in swapmaps_iconcache)
// reverse-associate everything
// so you can look up an icon file by name or vice-versa
swapmaps_iconcache[swapmaps_iconcache[V]]=V
proc/SwapMaps_AddIconToCache(name,icon)
if(!swapmaps_iconcache) swapmaps_iconcache=list()
swapmaps_iconcache[name]=icon
swapmaps_iconcache[icon]=name
proc/SwapMaps_Find(id)
InitializeSwapMaps()
return swapmaps_byname[id]
proc/SwapMaps_Load(id)
InitializeSwapMaps()
var/swapmap/M=swapmaps_byname[id]
if(!M)
var/savefile/S
var/text=0
if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt"))
text=1
else if(fexists("map_[id].sav"))
S=new("map_[id].sav")
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt"))
text=1
else return // no file found
if(text)
S=new
S.ImportText("/",file("map_[id].txt"))
S >> M
while(M.locked) sleep(1)
M.mode=text
return M
proc/SwapMaps_Save(id)
InitializeSwapMaps()
var/swapmap/M=swapmaps_byname[id]
if(M) M.Save()
return M
proc/SwapMaps_Save_All()
InitializeSwapMaps()
for(var/swapmap/M in swapmaps_loaded)
if(M) M.Save()
proc/SwapMaps_Unload(id)
InitializeSwapMaps()
var/swapmap/M=swapmaps_byname[id]
if(!M) return // return silently from an error
M.Unload()
return 1
proc/SwapMaps_DeleteFile(id)
fdel("map_[id].sav")
fdel("map_[id].txt")
proc/SwapMaps_CreateFromTemplate(template_id)
var/swapmap/M=new
var/savefile/S
var/text=0
if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[template_id].txt"))
text=1
else if(fexists("map_[template_id].sav"))
S=new("map_[template_id].sav")
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[template_id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found."
return
if(text)
S=new
S.ImportText("/",file("map_[template_id].txt"))
/*
This hacky workaround is needed because S >> M will create a brand new
M to fill with data. There's no way to control the Read() process
properly otherwise. The //.0 path should always match the map, however.
*/
S.cd="//.0"
M.Read(S,M)
M.mode=text
while(M.locked) sleep(1)
return M
proc/SwapMaps_LoadChunk(chunk_id,turf/locorner)
var/swapmap/M=new
var/savefile/S
var/text=0
if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[chunk_id].txt"))
text=1
else if(fexists("map_[chunk_id].sav"))
S=new("map_[chunk_id].sav")
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[chunk_id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found."
return
if(text)
S=new
S.ImportText("/",file("map_[chunk_id].txt"))
/*
This hacky workaround is needed because S >> M will create a brand new
M to fill with data. There's no way to control the Read() process
properly otherwise. The //.0 path should always match the map, however.
*/
S.cd="//.0"
M.Read(S,M,locorner)
while(M.locked) sleep(1)
qdel(M)
return 1
proc/SwapMaps_SaveChunk(chunk_id,turf/corner1,turf/corner2)
if(!corner1 || !corner2)
world.log << "SwapMaps error in SwapMaps_SaveChunk():"
if(!corner1) world.log << " corner1 turf is null"
if(!corner2) world.log << " corner2 turf is null"
return
var/swapmap/M=new
M.id=chunk_id
M.ischunk=1 // this is a chunk
M.x1=min(corner1.x,corner2.x)
M.y1=min(corner1.y,corner2.y)
M.z1=min(corner1.z,corner2.z)
M.x2=max(corner1.x,corner2.x)
M.y2=max(corner1.y,corner2.y)
M.z2=max(corner1.z,corner2.z)
M.mode=swapmaps_mode
M.Save()
while(M.locked) sleep(1)
qdel(M)
return 1
proc/SwapMaps_GetSize(id)
var/savefile/S
var/text=0
if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt"))
text=1
else if(fexists("map_[id].sav"))
S=new("map_[id].sav")
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_GetSize(): map_[id] file not found."
return
if(text)
S=new
S.ImportText("/",file("map_[id].txt"))
/*
The //.0 path should always be the map. There's no other way to
read this data.
*/
S.cd="//.0"
var/x
var/y
var/z
S["x"] >> x
S["y"] >> y
S["z"] >> z
return list(x,y,z)
@@ -0,0 +1,174 @@
#define DMM_IGNORE_AREAS 1
#define DMM_IGNORE_TURFS 2
#define DMM_IGNORE_OBJS 4
#define DMM_IGNORE_NPCS 8
#define DMM_IGNORE_PLAYERS 16
#define DMM_IGNORE_MOBS 24
dmm_suite{
var{
quote = "\""
list/letter_digits = list(
"a","b","c","d","e",
"f","g","h","i","j",
"k","l","m","n","o",
"p","q","r","s","t",
"u","v","w","x","y",
"z",
"A","B","C","D","E",
"F","G","H","I","J",
"K","L","M","N","O",
"P","Q","R","S","T",
"U","V","W","X","Y",
"Z"
)
}
save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){
//Check for illegal characters in file name... in a cheap way.
if(!((ckeyEx(map_name)==map_name) && ckeyEx(map_name))){
CRASH("Invalid text supplied to proc save_map, invalid characters or empty string.")
}
//Check for valid turfs.
if(!isturf(t1) || !isturf(t2)){
CRASH("Invalid arguments supplied to proc save_map, arguments were not turfs.")
}
var/file_text = write_map(t1,t2,flags)
if(fexists("[map_name].dmm")){
fdel("[map_name].dmm")
}
var/saved_map = file("[map_name].dmm")
saved_map << file_text
return saved_map
}
write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){
//Check for valid turfs.
if(!isturf(t1) || !isturf(t2)){
CRASH("Invalid arguments supplied to proc write_map, arguments were not turfs.")
}
var/turf/nw = locate(min(t1.x,t2.x),max(t1.y,t2.y),min(t1.z,t2.z))
var/turf/se = locate(max(t1.x,t2.x),min(t1.y,t2.y),max(t1.z,t2.z))
var/list/templates[0]
var/template_buffer = {""}
var/dmm_text = {""}
for(var/pos_z in nw.z to se.z){
for(var/pos_y in nw.y to se.y){
for(var/pos_x in nw.x to se.x){
var/turf/test_turf = locate(pos_x,pos_y,pos_z)
var/test_template = make_template(test_turf, flags)
var/template_number = templates.Find(test_template)
if(!template_number){
templates.Add(test_template)
template_number = templates.len
}
template_buffer += "[template_number],"
}
template_buffer += ";"
}
template_buffer += "."
}
var/key_length = round/*floor*/(log(letter_digits.len,templates.len-1)+1)
var/list/keys[templates.len]
for(var/key_pos in 1 to templates.len){
keys[key_pos] = get_model_key(key_pos,key_length)
dmm_text += {""[keys[key_pos]]" = ([templates[key_pos]])\n"}
}
var/z_level = 0
for(var/z_pos=1;TRUE;z_pos=findtext(template_buffer,".",z_pos)+1){
if(z_pos>=length(template_buffer)){break}
if(z_level){dmm_text+={"\n"}}
dmm_text += {"\n(1,1,[++z_level]) = {"\n"}
var/z_block = copytext(template_buffer,z_pos,findtext(template_buffer,".",z_pos))
for(var/y_pos=1;TRUE;y_pos=findtext(z_block,";",y_pos)+1){
if(y_pos>=length(z_block)){break}
var/y_block = copytext(z_block,y_pos,findtext(z_block,";",y_pos))
for(var/x_pos=1;TRUE;x_pos=findtext(y_block,",",x_pos)+1){
if(x_pos>=length(y_block)){break}
var/x_block = copytext(y_block,x_pos,findtext(y_block,",",x_pos))
var/key_number = text2num(x_block)
var/temp_key = keys[key_number]
dmm_text += temp_key
sleep(-1)
}
dmm_text += {"\n"}
sleep(-1)
}
dmm_text += {"\"}"}
sleep(-1)
}
return dmm_text
}
proc{
make_template(var/turf/model as turf, var/flags as num){
var/template = ""
var/obj_template = ""
var/mob_template = ""
var/turf_template = ""
if(!(flags & DMM_IGNORE_TURFS)){
turf_template = "[model.type][check_attributes(model)],"
} else{ turf_template = "[world.turf],"}
var/area_template = ""
if(!(flags & DMM_IGNORE_OBJS)){
for(var/obj/O in model.contents){
obj_template += "[O.type][check_attributes(O)],"
}
}
for(var/mob/M in model.contents){
if(M.client){
if(!(flags & DMM_IGNORE_PLAYERS)){
mob_template += "[M.type][check_attributes(M)],"
}
}
else{
if(!(flags & DMM_IGNORE_NPCS)){
mob_template += "[M.type][check_attributes(M)],"
}
}
}
if(!(flags & DMM_IGNORE_AREAS)){
var/area/m_area = model.loc
area_template = "[m_area.type][check_attributes(m_area)]"
} else{ area_template = "[world.area]"}
template = "[obj_template][mob_template][turf_template][area_template]"
return template
}
check_attributes(var/atom/A){
var/attributes_text = {"{"}
for(var/V in A.vars){
sleep(-1)
if((!issaved(A.vars[V])) || (A.vars[V]==initial(A.vars[V]))){continue}
if(istext(A.vars[V])){
attributes_text += {"[V] = "[A.vars[V]]""}
}
else if(isnum(A.vars[V])||ispath(A.vars[V])){
attributes_text += {"[V] = [A.vars[V]]"}
}
else if(isicon(A.vars[V])||isfile(A.vars[V])){
attributes_text += {"[V] = '[A.vars[V]]'"}
}
else{
continue
}
if(attributes_text != {"{"}){
attributes_text+={"; "}
}
}
if(attributes_text=={"{"}){
return
}
if(copytext(attributes_text, length(attributes_text)-1, 0) == {"; "}){
attributes_text = copytext(attributes_text, 1, length(attributes_text)-1)
}
attributes_text += {"}"}
return attributes_text
}
get_model_key(var/which as num, var/key_length as num){
var/key = ""
var/working_digit = which-1
for(var/digit_pos in key_length to 1 step -1){
var/place_value = round/*floor*/(working_digit/(letter_digits.len**(digit_pos-1)))
working_digit-=place_value*(letter_digits.len**(digit_pos-1))
key = "[key][letter_digits[place_value+1]]"
}
return key
}
}
}
@@ -0,0 +1,348 @@
//Academy Areas
/area/awaymission/academy
name = "Academy Asteroids"
icon_state = "away"
/area/awaymission/academy/headmaster
name = "Academy Fore Block"
icon_state = "away1"
/area/awaymission/academy/classrooms
name = "Academy Classroom Block"
icon_state = "away2"
/area/awaymission/academy/academyaft
name = "Academy Ship Aft Block"
icon_state = "away3"
/area/awaymission/academy/academygate
name = "Academy Gateway"
icon_state = "away4"
/area/awaymission/academy/academycellar
name = "Academy Cellar"
icon_state = "away4"
/area/awaymission/academy/academyengine
name = "Academy Engine"
icon_state = "away4"
//Academy Items
/obj/singularity/academy
dissipate = 0
move_self = 0
grav_pull = 1
/obj/singularity/academy/admin_investigate_setup()
return
/obj/singularity/academy/process()
eat()
if(prob(1))
mezzer()
/obj/item/clothing/glasses/meson/truesight
name = "The Lens of Truesight"
desc = "I can see forever!"
icon_state = "monocle"
item_state = "headset"
/obj/structure/academy_wizard_spawner
name = "Academy Defensive System"
desc = "Made by Abjuration Inc"
icon = 'icons/obj/cult.dmi'
icon_state = "forge"
anchored = 1
var/health = 200
var/mob/living/current_wizard = null
var/next_check = 0
var/cooldown = 600
var/faction = "wizard"
var/broken = 0
var/braindead_check = 0
/obj/structure/academy_wizard_spawner/New()
START_PROCESSING(SSobj, src)
/obj/structure/academy_wizard_spawner/process()
if(next_check < world.time)
if(!current_wizard)
for(var/mob/living/L in player_list)
if(L.z == src.z && L.stat != DEAD && !(faction in L.faction))
summon_wizard()
break
else
if(current_wizard.stat == DEAD)
current_wizard = null
summon_wizard()
if(!current_wizard.client)
if(!braindead_check)
braindead_check = 1
else
braindead_check = 0
give_control()
next_check = world.time + cooldown
/obj/structure/academy_wizard_spawner/proc/give_control()
if(!current_wizard)
return
spawn(0)
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as Wizard Academy Defender?", "wizard", null, ROLE_WIZARD)
var/mob/dead/observer/chosen = null
if(candidates.len)
chosen = pick(candidates)
message_admins("[key_name_admin(chosen)] was spawned as Wizard Academy Defender")
current_wizard.ghostize() // on the off chance braindead defender gets back in
current_wizard.key = chosen.key
/obj/structure/academy_wizard_spawner/proc/summon_wizard()
var/turf/T = src.loc
var/mob/living/carbon/human/wizbody = new(T)
wizbody.equipOutfit(/datum/outfit/wizard/academy)
var/obj/item/weapon/implant/exile/Implant = new/obj/item/weapon/implant/exile(wizbody)
Implant.implant(wizbody)
wizbody.faction |= "wizard"
wizbody.real_name = "Academy Teacher"
wizbody.name = "Academy Teacher"
var/datum/mind/wizmind = new /datum/mind()
wizmind.name = "Wizard Defender"
wizmind.special_role = "Academy Defender"
var/datum/objective/O = new("Protect Wizard Academy from the intruders")
wizmind.objectives += O
wizmind.transfer_to(wizbody)
ticker.mode.wizards |= wizmind
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
wizmind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball)
current_wizard = wizbody
give_control()
/obj/structure/academy_wizard_spawner/proc/update_status()
if(health<0)
visible_message("<span class='warning'>[src] breaks down!</span>")
icon_state = "forge_off"
STOP_PROCESSING(SSobj, src)
broken = 1
/obj/structure/academy_wizard_spawner/attackby(obj/item/weapon/W, mob/living/user, params)
add_fingerprint(user)
user.changeNext_move(CLICK_CD_MELEE)
if(!broken)
health -= W.force
update_status()
..()
/obj/structure/academy_wizard_spawner/bullet_act(obj/item/projectile/Proj)
if(!broken)
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
health -= Proj.damage
update_status()
..()
return
/datum/outfit/wizard/academy
name = "Academy Wizard"
r_pocket = null
r_hand = null
suit = /obj/item/clothing/suit/wizrobe/red
head = /obj/item/clothing/head/wizard/red
backpack_contents = list(/obj/item/weapon/storage/box/survival = 1)
/obj/item/weapon/dice/d20/fate
name = "Die of Fate"
desc = "A die with twenty sides. You can feel unearthly energies radiating from it. Using this might be VERY risky."
icon_state = "d20"
sides = 20
var/reusable = 1
var/used = 0
var/rigged = -1
/obj/item/weapon/dice/d20/fate/one_use
reusable = 0
/obj/item/weapon/dice/d20/fate/diceroll(mob/user)
..()
if(!used)
if(!ishuman(user) || !user.mind || (user.mind in ticker.mode.wizards))
user << "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans!</span>"
return
if(rigged > 0)
effect(user,rigged)
else
effect(user,result)
/obj/item/weapon/dice/d20/fate/equipped(mob/user, slot)
if(!ishuman(user) || !user.mind || (user.mind in ticker.mode.wizards))
user << "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>"
user.drop_item()
/obj/item/weapon/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
if(!reusable)
used = 1
visible_message("<span class='userdanger'>The die flare briefly.</span>")
switch(roll)
if(1)
//Dust
user.dust()
if(2)
//Death
user.death()
if(3)
//Swarm of creatures
for(var/direction in alldirs)
var/turf/T = get_turf(src)
new /mob/living/simple_animal/hostile/creature(get_step(T,direction))
if(4)
//Destroy Equipment
for (var/obj/item/I in user)
if (istype(I, /obj/item/weapon/implant))
continue
qdel(I)
if(5)
//Monkeying
user.monkeyize()
if(6)
//Cut speed
var/datum/species/S = user.dna.species
S.speedmod += 1
if(7)
//Throw
user.Stun(3)
user.adjustBruteLoss(50)
var/throw_dir = pick(cardinal)
var/atom/throw_target = get_edge_target_turf(user, throw_dir)
user.throw_at(throw_target, 200, 4)
if(8)
//Fueltank Explosion
explosion(src.loc,-1,0,2, flame_range = 2)
if(9)
//Cold
var/datum/disease/D = new /datum/disease/cold
user.ForceContractDisease(D)
if(10)
//Nothing
visible_message("<span class='notice'>[src] roll perfectly.</span>")
if(11)
//Cookie
var/obj/item/weapon/reagent_containers/food/snacks/cookie/C = new(get_turf(src))
C.name = "Cookie of Fate"
if(12)
//Healing
user.revive(full_heal = 1, admin_revive = 1)
if(13)
//Mad Dosh
var/turf/Start = get_turf(src)
for(var/direction in alldirs)
var/turf/T = get_step(Start,direction)
if(rand(0,1))
new /obj/item/stack/spacecash/c1000(T)
else
var/obj/item/weapon/storage/bag/money/M = new(T)
for(var/i in 1 to rand(5,50))
new /obj/item/weapon/coin/gold(M)
if(14)
//Free Gun
new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(src))
if(15)
//Random One-use spellbook
new /obj/item/weapon/spellbook/oneuse/random(get_turf(src))
if(16)
//Servant & Servant Summon
var/mob/living/carbon/human/H = new(get_turf(src))
H.equipOutfit(/datum/outfit/butler)
var/datum/mind/servant_mind = new /datum/mind()
var/datum/objective/O = new("Serve [user.real_name].")
servant_mind.objectives += O
servant_mind.transfer_to(H)
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [user.real_name] Servant?", "wizard")
var/mob/dead/observer/chosen = null
if(candidates.len)
chosen = pick(candidates)
message_admins("[key_name_admin(chosen)] was spawned as Dice Servant")
H.key = chosen.key
var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
S.target_mob = H
user.mind.AddSpell(S)
if(17)
//Tator Kit
new /obj/item/weapon/storage/box/syndicate/(get_turf(src))
if(18)
//Captain ID
new /obj/item/weapon/card/id/captains_spare(get_turf(src))
if(19)
//Instrinct Resistance
user << "<span class='notice'>You feel robust.</span>"
var/datum/species/S = user.dna.species
S.brutemod *= 0.5
S.burnmod *= 0.5
S.coldmod *= 0.5
if(20)
//Free wizard!
user.mind.make_Wizard()
/datum/outfit/butler
name = "Butler"
uniform = /obj/item/clothing/under/suit_jacket/really_black
shoes = /obj/item/clothing/shoes/laceup
head = /obj/item/clothing/head/bowler
glasses = /obj/item/clothing/glasses/monocle
gloves = /obj/item/clothing/gloves/color/white
/obj/effect/proc_holder/spell/targeted/summonmob
name = "Summon Servant"
desc = "This spell can be used to call your servant, whenever you need it."
charge_max = 100
clothes_req = 0
invocation = "JE VES"
invocation_type = "whisper"
range = -1
level_max = 0 //cannot be improved
cooldown_min = 100
include_user = 1
var/mob/living/target_mob
action_icon_state = "summons"
/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets,mob/user = usr)
if(!target_mob)
return
var/turf/Start = get_turf(user)
for(var/direction in alldirs)
var/turf/T = get_step(Start,direction)
if(!T.density)
target_mob.Move(T)
/obj/structure/ladder/unbreakable/rune
name = "Teleportation Rune"
desc = "Could lead anywhere."
icon = 'icons/obj/rune.dmi'
icon_state = "1"
color = rgb(0,0,255)
/obj/structure/ladder/unbreakable/rune/update_icon()
return
/obj/structure/ladder/unbreakable/rune/show_fluff_message(up,mob/user)
user.visible_message("[user] activates \the [src].","<span class='notice'>You activate \the [src].</span>")
/obj/structure/ladder/can_use(mob/user)
if(user.mind in ticker.mode.wizards)
return 0
return 1
@@ -0,0 +1,133 @@
/*Cabin areas*/
/area/awaymission/snowforest
name = "Snow Forest"
icon_state = "away"
requires_power = 0
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/cabin
name = "Cabin"
icon_state = "away2"
requires_power = 1
luminosity = 0
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/snowforest/lumbermill
name = "Lumbermill"
icon_state = "away3"
/*Cabin code*/
/obj/structure/fireplace
name = "fireplace"
desc = "warm and toasty"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "fireplace-active"
density = 0
var/active = 1
/obj/structure/fireplace/initialize()
..()
toggleFireplace()
/obj/structure/fireplace/attack_hand(mob/living/user)
if(active)
active = 0
toggleFireplace()
else
..()
/obj/structure/fireplace/attackby(obj/item/W,mob/living/user,params)
if(!active)
if(W.is_hot())
active = 1
toggleFireplace()
else
return ..()
else
W.fire_act()
/obj/structure/fireplace/proc/toggleFireplace()
if(active)
SetLuminosity(8)
icon_state = "fireplace-active"
else
SetLuminosity(0)
icon_state = "fireplace"
/obj/structure/fireplace/extinguish()
if(active)
active = 0
toggleFireplace()
/obj/structure/fireplace/fire_act()
if(!active)
active = 1
toggleFireplace()
/obj/machinery/recycler/lumbermill
name = "lumbermill saw"
desc = "Faster then the cartoons!"
emagged = 2 //Always gibs people
item_recycle_sound = 'sound/weapons/chainsawhit.ogg'
/obj/machinery/recycler/lumbermill/recycle_item(obj/item/weapon/grown/log/L)
if(!istype(L))
return
else
var/potency = L.seed.potency
..()
new L.plank_type(src.loc, 1 + round(potency / 25))
/mob/living/simple_animal/chicken/rabbit/normal
icon_state = "b_rabbit"
icon_living = "b_rabbit"
icon_dead = "b_rabbit_dead"
icon_prefix = "b_rabbit"
minbodytemp = 0
eggsleft = 0
egg_type = null
speak = list()
/*Cabin's forest*/
/datum/mapGenerator/snowy
modules = list(/datum/mapGeneratorModule/snow/pineTrees, \
/datum/mapGeneratorModule/snow/deadTrees, \
/datum/mapGeneratorModule/snow/randBushes, \
/datum/mapGeneratorModule/snow/randIceRocks, \
/datum/mapGeneratorModule/snow/bunnies)
/datum/mapGeneratorModule/snow/checkPlaceAtom(turf/T)
if(istype(T,/turf/open/floor/plating/asteroid/snow))
return ..(T)
return 0
/datum/mapGeneratorModule/snow/pineTrees
spawnableAtoms = list(/obj/structure/flora/tree/pine = 30)
/datum/mapGeneratorModule/snow/deadTrees
spawnableAtoms = list(/obj/structure/flora/tree/dead = 10)
/datum/mapGeneratorModule/snow/randBushes
spawnableAtoms = list()
/datum/mapGeneratorModule/snow/randBushes/New()
..()
spawnableAtoms = typesof(/obj/structure/flora/ausbushes)
for(var/i in spawnableAtoms)
spawnableAtoms[i] = 1
/datum/mapGeneratorModule/snow/bunnies
//spawnableAtoms = list(/mob/living/simple_animal/chicken/rabbit/normal = 0.1)
spawnableAtoms = list(/mob/living/simple_animal/chicken/rabbit = 0.5)
/datum/mapGeneratorModule/snow/randIceRocks
spawnableAtoms = list(/obj/structure/flora/rock/icy = 5, /obj/structure/flora/rock/pile/icy = 5)
/obj/effect/landmark/mapGenerator/snowy
mapGeneratorType = /datum/mapGenerator/snowy
@@ -0,0 +1,22 @@
//Packer Ship Areas
/area/awaymission/BMPship
name = "BMP Asteroids"
icon_state = "away"
luminosity = 0
/area/awaymission/BMPship/Aft
name = "Aft Block"
icon_state = "away1"
requires_power = 1
/area/awaymission/BMPship/Midship
name = "Midship Block"
icon_state = "away2"
requires_power = 1
/area/awaymission/BMPship/Fore
name = "Fore Block"
icon_state = "away3"
requires_power = 1
@@ -0,0 +1,63 @@
//centcomAway areas
/area/awaymission/centcomAway
name = "XCC-P5831"
icon_state = "away"
requires_power = 0
/area/awaymission/centcomAway/general
name = "XCC-P5831"
music = "music/ambigen3.ogg"
/area/awaymission/centcomAway/maint
name = "XCC-P5831 Maintenance"
icon_state = "away1"
music = "music/ambisin1.ogg"
/area/awaymission/centcomAway/thunderdome
name = "XCC-P5831 Thunderdome"
icon_state = "away2"
music = "music/ambisin2.ogg"
/area/awaymission/centcomAway/cafe
name = "XCC-P5831 Kitchen Arena"
icon_state = "away3"
music = "music/ambisin3.ogg"
/area/awaymission/centcomAway/courtroom
name = "XCC-P5831 Courtroom"
icon_state = "away4"
music = "music/ambisin4.ogg"
/area/awaymission/centcomAway/hangar
name = "XCC-P5831 Hangars"
icon_state = "away4"
music = "music/ambigen5.ogg"
//centcomAway items
/obj/item/weapon/paper/pamphlet/ccaInfo
name = "Visitor Info Pamphlet"
info = "<b> XCC-P5831 Visitor Information </b><br>\
Greetings, visitor, to XCC-P5831! As you may know, this outpost was once \
used as Nanotrasen's CENTRAL COMMAND STATION, organizing and coordinating company \
projects across the vastness of space. <br>\
Since the completion of the much more efficient CC-A5831 on March 8, 2553, XCC-P5831 no longer \
acts as NT's base of operations but still plays a very important role its corporate affairs; \
serving as a supply and repair depot, as well as being host to its most important legal proceedings\
and the thrilling pay-per-view broadcasts of <i>PLASTEEL CHEF</i> and <i>THUNDERDOME LIVE</i>.<br> \
We hope you enjoy your stay!"
/obj/item/weapon/paper/ccaMemo
name = "Memo to XCC-P5831 QM"
info = "<b>From: XCC-P5831 Management Office</b><br>\
<b>To: Rolf Ingram, XCC-P5831 Quartermaster</b><br>\
Hey, Rolf, once you pack that gateway into the ferry hangar, <i>make absolutely sure</i> \
to deactivate it! As you may know, SS13 has recently got its network up and running, \
which means that until we get this gate shipped off to the next colonization staging \
area, they'll be able to hop straight in here if its hooked up on our end.<br>\
Obviously, that's something I'd very much rather avoid. Our forensics and medical \
teams never did figure out what happened that last time... and I can't wrap my head \
around it myself. Why would a shuttle full of evacuees all snap and beat each other \
to death the moment they reached safety?<br>\
- D. Cereza"
@@ -0,0 +1,35 @@
//Challenge Areas
/area/awaymission/challenge/start
name = "Where Am I?"
icon_state = "away"
/area/awaymission/challenge/main
name = "Danger Room"
icon_state = "away1"
requires_power = 0
/area/awaymission/challenge/end
name = "Administration"
icon_state = "away2"
requires_power = 0
/obj/machinery/power/emitter/energycannon
name = "Energy Cannon"
desc = "A heavy duty industrial laser"
icon = 'icons/obj/singularity.dmi'
icon_state = "emitter"
anchored = 1
density = 1
use_power = 0
idle_power_usage = 0
active_power_usage = 0
active = 1
locked = 1
state = 2
/obj/machinery/power/emitter/energycannon/RefreshParts()
return
@@ -0,0 +1,64 @@
//Research Base Areas//--
/area/awaymission/research
name = "Research Outpost"
icon_state = "away"
luminosity = 0
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/research/interior
name = "Research Inside"
requires_power = 1
icon_state = "away2"
/area/awaymission/research/interior/cryo
name = "Research Cryostasis Room"
icon_state = "medbay"
/area/awaymission/research/interior/clonestorage
name = "Research Clone Storage"
icon_state = "cloning"
/area/awaymission/research/interior/genetics
name = "Research Genetics Research"
icon_state = "genetics"
/area/awaymission/research/interior/engineering
name = "Research Engineering"
icon_state = "engine"
/area/awaymission/research/interior/security
name = "Research Security"
icon_state = "security"
/area/awaymission/research/interior/secure
name = "Research Secure Vault"
/area/awaymission/research/interior/maint
name = "Research Maintenance"
icon_state = "maintcentral"
/area/awaymission/research/interior/dorm
name = "Research Dorms"
icon_state = "Sleep"
/area/awaymission/research/interior/escapepods
name = "Research Escape Wing"
icon_state = "exit"
/area/awaymission/research/interior/gateway
name = "Research Gateway"
icon_state = "start"
/area/awaymission/research/interior/bathroom
name = "Research Bathrooms"
icon_state = "restrooms"
/area/awaymission/research/interior/medbay
name = "Research Medbay"
icon_state = "medbay"
/area/awaymission/research/exterior
name = "Research Exterior"
icon_state = "unknown"
@@ -0,0 +1,279 @@
//Snow Valley Areas//--
/area/awaymission/snowdin
name = "Snowdin Tundra Plains"
icon_state = "away"
requires_power = 0
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/snowdin/post
name = "Snowdin Outpost"
requires_power = 1
/area/awaymission/snowdin/igloo
name = "Snowdin Igloos"
icon_state = "away2"
/area/awaymission/snowdin/cave
name = "Snowdin Caves"
icon_state = "away2"
luminosity = 0
/area/awaymission/snowdin/base
name = "Snowdin Main Base"
icon_state = "away3"
requires_power = 1
/area/awaymission/snowdin/dungeon1
name = "Snowdin Depths"
icon_state = "away2"
luminosity = 0
/area/awaymission/snowdin/sekret
name = "Snowdin Operations"
icon_state = "away3"
requires_power = 1
//notes for lore or treasure hints wow//--
/obj/item/weapon/paper/crumpled/snowdin/snowdingatewaynotice
name = "scribbled note"
info = {"The gateway has been inactive for months, engineers think its due to the recent drop in tempature fucking with the
circuitry or something. Without a constant supply of resources from central command, our stock is getting awfully low. Some of the security members have taken to
using the sparse rifle ammo left to hunting some of the wildlife to try and keep our food supply from emptying. God forbid if the heating goes out, I don't want to
die as a fucking popsicle down here."}
/obj/item/weapon/paper/crumpled/snowdin/misc1
name = "Mission Prologe"
info = {"Holy shit, what a rush! Those Nanotrasen bastards didn't even know what hit 'em! All five of us dropped in right on the captain, didn't even have time to yell! We were in and out with that disk in mere minutes!
Crew didn't even know what was happening till the delta alert went down and by then were were already gone. We got a case to drink on the way home to celebrate, fuckin' job well done!"}
/obj/item/weapon/paper/crumpled/snowdin/keys
name = "scribbled note"
info = {"As a notice for anyone looking to borrow an ATV, some asshat lost the key set for all the vehicles. Nobody has yet to actually come forward about the potential where-abouts, either due to embarrassment or fear of
reprecussions. I hope they enjoy walking through that shit snow during the next shipment because I sure as hell ain't."}
/obj/item/weapon/paper/snowdin/snowdinlog
name = "Activity Log"
info = {"<b><center>ACTIVITY LOG</b></center><br><br><b>June 3rd</b><br>We've moved to the main base in the valley finally, apparently establishing a listening system on a planet
that never stops fucking snowing is a great idea. There's a few outposts further south we'll be supplying from the main gateway. The summer months are enough already, I can only imagine how bad it'll be during winter.<br><br><b>August 23rd</b><br>
The colder months are finally hitting, some of the machinery seems to be having trouble starting up sometimes. Central sent some portable heaters to help keep the airlocks from
freezing shut along with a couple storage crates with supplies. Nothing on the radio so far, what the hell do they even expect to hear down here, anyway?<br><br><b>September 15th</b>
<br>Another supply shipment through the gateway, they've sent some heavier sets of clothes for the coming winter months. Central said they might encounter issues with shipments
during December to Feburary, so we should try to be frugal with the next shipment.<br><br><b>November 20th</b><br>Final shipment from central for the next few months. Going outside
for more than 10-15 minutes without losing feeling in your fingers is difficult. We've finally gotten a signal on the radio, its mostly some weird static though. One of the researchers is trying to decypher it.
<br><br><b>December 10th</b><br>Signal has gotten much stronger, it almost seems like its coming from under us according to what the researcher managed to decypher. We're waiting from the go from central before investigating.<br><br>
<i>The rest of the paper seems to be a mixture of scribles and smudged ink.</i> "}
/obj/item/weapon/paper/snowdin/snowdinlog2
name = "Activity Log"
info = {"<b><center>ACTIVITY LOG</b></center><br><br><b>June 14th</b><br>Movement to the second post is finally done. We're located on the most-southern area of the valley with a similar objective as the northen post.
Theres two mid-way stops on the eastern and western sides of the valley so movement inbetween bases isn't horrible. Not too big of a fan of relying on the northen base for
equal supply distribution, though.<br><br><b>August 27h</b><br>First shipment arrived finally, about 4 days after the gateway shipped. Insulation on these buildings is awful, thank god for the spare heaters at least.<br><br>
<b>September 20th</b><br>Another shipment arrival, standard shit. Our radios have been picking up a weird signal during the nights recently, we've sent the transcripts over to the northen
base to be decyphered. Probably some drunk russians or something equally stupid.<br><br><b>November 24th</b><br>We've lost communications with the northern base after recieving the last
shipment of supplies. The snow has really kicked up recently, shits almost like a constant blizzard right now. Maybe it'll drop down soon so we can get a word in.<br><br>
<i>The rest of the paper seems to be a mixture of scribles and smudged ink.</i> "}
obj/item/weapon/paper/snowdin/secnotice
name = "Security Notice"
info = {"You have been assigned a postion on a listening outpost. Here you'll be watching over a several crewmembers assigned to watching signals of the general area.
As not much is expected in terms of issues, we've only assigned one guard per outpost. Crewmembers are expected to keep to their regulated work schedules and may be
disciplined properly if found slacking. Food hording is heavily discouraged as all outposts will be sharing from the same shipment every 2-3 months. Hording of supplies
should be punished severely as to prevent future incidients. Mutiny and/or rioting should be reported to central and dealt with swiftly. You're here to secure and protect
Nanotrasen assets, not be a police officer. Do what you must, but make sure its not messy."}
obj/item/weapon/paper/snowdin/syndienotice
name = "Assignment Notice"
info = {"You've been assigned as an agent to listen in on Nanotrasen activities from passing ships and nearby stations. The outpost you've been assigned to is under lays of solid
ice and we've supplied you with a scrambler to help avoid Nanotrasen discovery, as they've recently built a listening post of their own aboveground. Get aquainted with your new
crewmates, because you're gonna be here for awhile. Enjoy the free syndicakes."}
obj/item/weapon/paper/crumpled/snowdin/syndielava
name = "scribbled note"
info = {"Some cracks in the ice nearby have exposed some sort of hidden magma stream under all this shit ice. I don't know whats worse at this point honestly; freezing to death or
burning alive."}
obj/item/weapon/paper/crumpled/snowdin/lootstructures
name = "scribbled note"
info = {"From what we've seen so far, theres a ton of iced over ruins down here in the caves. We sent a few men out to check things out and they never came back, so we decided to
border up majority of the ruins. We've heard some weird shit coming out of these caves and I'm not gonna find out the hard way myself."}
obj/item/weapon/paper/crumpled/snowdin/shovel
name = "shoveling duties"
info = {"Snow piles up bad here all-year round, even worse during the winter months. Keeping a constant rotation of shoveling that shit out of the way of the airlocks and keeping the paths decently clear
is a good step towards not getting stuck walking through knee-deep snow."}
//lootspawners//--
/obj/effect/spawner/lootdrop/snowdin
name = "why are you using this dummy"
lootdoubles = 0
lootcount = 1
loot = list(/obj/item/weapon/bikehorn = 100)
/obj/effect/spawner/lootdrop/snowdin/dungeonlite
name = "dungeon lite"
loot = list(/obj/item/weapon/melee/classic_baton = 11,
/obj/item/weapon/melee/classic_baton/telescopic = 12,
/obj/item/weapon/spellbook/oneuse/smoke = 10,
/obj/item/weapon/spellbook/oneuse/blind = 10,
/obj/item/weapon/storage/firstaid/regular = 45,
/obj/item/weapon/storage/firstaid/toxin = 35,
/obj/item/weapon/storage/firstaid/brute = 27,
/obj/item/weapon/storage/firstaid/fire = 27,
/obj/item/weapon/storage/toolbox/syndicate = 12,
/obj/item/weapon/grenade/plastic/c4 = 7,
/obj/item/weapon/grenade/clusterbuster/smoke = 15,
/obj/item/clothing/under/chameleon = 13,
/obj/item/clothing/shoes/chameleon = 10,
/obj/item/borg/upgrade/ddrill = 3,
/obj/item/borg/upgrade/soh = 3)
/obj/effect/spawner/lootdrop/snowdin/dungeonmid
name = "dungeon mid"
loot = list(/obj/item/weapon/defibrillator/compact = 6,
/obj/item/weapon/storage/firstaid/tactical = 35,
/obj/item/weapon/shield/energy = 6,
/obj/item/weapon/shield/riot/tele = 12,
/obj/item/weapon/dnainjector/lasereyesmut = 7,
/obj/item/weapon/gun/magic/wand/fireball/inert = 3,
/obj/item/weapon/pneumatic_cannon = 15,
/obj/item/weapon/melee/energy/sword = 7,
/obj/item/weapon/spellbook/oneuse/knock = 15,
/obj/item/weapon/spellbook/oneuse/summonitem = 20,
/obj/item/weapon/spellbook/oneuse/forcewall = 17,
/obj/item/weapon/storage/backpack/holding = 12,
/obj/item/weapon/grenade/spawnergrenade/manhacks = 6,
/obj/item/weapon/grenade/spawnergrenade/spesscarp = 7,
/obj/item/weapon/grenade/clusterbuster/inferno = 3,
/obj/item/stack/sheet/mineral/diamond{amount = 15} = 10,
/obj/item/stack/sheet/mineral/uranium{amount = 15} = 10,
/obj/item/stack/sheet/mineral/plasma{amount = 15} = 10,
/obj/item/stack/sheet/mineral/gold{amount = 15} = 10,
/obj/item/weapon/spellbook/oneuse/barnyard = 4,
/obj/item/weapon/pickaxe/drill/diamonddrill = 6,
/obj/item/borg/upgrade/vtec = 7,
/obj/item/borg/upgrade/disablercooler = 7)
/obj/effect/spawner/lootdrop/snowdin/dungeonheavy
name = "dungeon heavy"
loot = list(/obj/item/weapon/twohanded/singularityhammer = 25,
/obj/item/weapon/twohanded/mjollnir = 10,
/obj/item/weapon/twohanded/fireaxe = 25,
/obj/item/organ/brain/alien = 17,
/obj/item/weapon/twohanded/dualsaber = 15,
/obj/item/organ/heart/demon = 7,
/obj/item/weapon/gun/projectile/automatic/c20r/unrestricted = 16,
/obj/item/weapon/gun/magic/wand/resurrection/inert = 15,
/obj/item/weapon/gun/magic/wand/resurrection = 10,
/obj/item/device/radio/uplink/old = 2,
/obj/item/weapon/spellbook/oneuse/charge = 12,
/obj/item/weapon/grenade/clusterbuster/spawner_manhacks = 15,
/obj/item/weapon/spellbook/oneuse/fireball = 10,
/obj/item/weapon/pickaxe/drill/jackhammer = 30,
/obj/item/borg/upgrade/syndicate = 13,
/obj/item/borg/upgrade/selfrepair = 17)
/obj/effect/spawner/lootdrop/snowdin/dungeonmisc
name = "dungeon misc"
lootdoubles = 2
lootcount = 1
loot = list(/obj/item/stack/sheet/mineral/snow{amount = 25} = 10,
/obj/item/toy/snowball = 15,
/obj/item/weapon/shovel = 10,
/obj/item/weapon/twohanded/spear = 8,
)
//special items//--
/obj/item/clothing/under/syndicate/coldres
name = "insulated tactical turtleneck"
desc = "A non-descript and slightly suspicious looking turtleneck with digital camouflage cargo pants. The interior has been padded with special insulation for both warmth and protection"
armor = list(melee = 20, bullet = 10, laser = 0,energy = 5, bomb = 0, bio = 0, rad = 0)
cold_protection = CHEST|GROIN|ARMS|LEGS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
/obj/item/clothing/shoes/combat/coldres
name = "insulated combat boots"
desc = "High speed, low drag combat boots, now with an added layer of insulation."
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
/obj/item/weapon/gun/magic/wand/fireball/inert
name = "weakened wand of fireball"
desc = "This wand shoots scorching balls of fire that explode into destructive flames. The years of the cold have weakened the magic inside the wand."
max_charges = 4
/obj/item/weapon/gun/magic/wand/resurrection/inert
name = "weakened wand of healing"
desc = "This wand uses healing magics to heal and revive. The years of the cold have weakened the magic inside the wand."
max_charges = 5
/obj/item/device/radio/uplink/old
name = "dusty radio"
desc = "A dusty looking radio."
/obj/item/device/radio/uplink/old/New()
..()
hidden_uplink.name = "dusty radio"
hidden_uplink.telecrystals = 10
obj/effect/mob_spawn/human/syndicatesoldier/coldres
name = "Syndicate Snow Operative"
uniform = /obj/item/clothing/under/syndicate/coldres
shoes = /obj/item/clothing/shoes/combat/coldres
radio = /obj/item/device/radio/headset/syndicate/alt
pocket1 = /obj/item/weapon/gun/projectile/automatic/pistol
pocket2 = /obj/item/weapon/card/id/syndicate
has_id = 0
obj/effect/mob_spawn/human/syndicatesoldier/coldres/alive
name = "sleeper"
mob_name = "Syndicate Snow Operative"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "sleeper"
roundstart = FALSE
death = FALSE
implants = list(/obj/item/weapon/implant/exile)
faction = "syndicate"
flavour_text = {"You are a syndicate operative recently awoken from cyrostatis in an underground outpost. Monitor Nanotrasen communications and record infomation. All intruders should be
disposed of swirfly to assure no gathered infomation is stolen or lost. Try not to wander too far from the outpost as the caves can be a deadly place even for a trained operative such as yourself."}
obj/effect/mob_spawn/human/syndicatesoldier/coldres/alive/female
mob_gender = FEMALE
//mobs//--
/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
name = "giant ice spider"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = 1500
color = rgb(114,228,250)
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/ice
name = "giant ice spider"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = 1500
color = rgb(114,228,250)
/mob/living/simple_animal/hostile/poison/giant_spider/hunter/ice
name = "giant ice spider"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = 1500
color = rgb(114,228,250)
//objs//--
/obj/structure/flora/rock/icy
name = "icy rock"
color = rgb(114,228,250)
/obj/structure/flora/rock/pile/icy
name = "icey rocks"
color = rgb(114,228,250)
@@ -0,0 +1,33 @@
//Spacebattle Areas
/area/awaymission/spacebattle
name = "Space Battle"
icon_state = "away"
requires_power = 0
/area/awaymission/spacebattle/cruiser
name = "Nanotrasen Cruiser"
/area/awaymission/spacebattle/syndicate1
name = "Syndicate Assault Ship 1"
/area/awaymission/spacebattle/syndicate2
name = "Syndicate Assault Ship 2"
/area/awaymission/spacebattle/syndicate3
name = "Syndicate Assault Ship 3"
/area/awaymission/spacebattle/syndicate4
name = "Syndicate War Sphere 1"
/area/awaymission/spacebattle/syndicate5
name = "Syndicate War Sphere 2"
/area/awaymission/spacebattle/syndicate6
name = "Syndicate War Sphere 3"
/area/awaymission/spacebattle/syndicate7
name = "Syndicate Fighter"
/area/awaymission/spacebattle/secret
name = "Hidden Chamber"
@@ -0,0 +1,197 @@
/* Station-Collision(sc) away mission map specific stuff
*
* Notes:
* Feel free to use parts of this map, or even all of it for your own project. Just include me in the credits :)
*
* Some of this code unnecessary, but the intent is to add a little bit of everything to serve as examples
* for anyone who wants to make their own stuff.
*
* Contains:
* Areas
* Landmarks
* Guns
* Safe code hints
* Captain's safe
* Modified Nar-Sie
*/
/*
* Areas
*/
//Gateroom gets its own APC specifically for the gate
/area/awaymission/gateroom
//Library, medbay, storage room
/area/awaymission/southblock
//Arrivals, security, hydroponics, shuttles (since they dont move, they dont need specific areas)
/area/awaymission/arrivalblock
//Crew quarters, cafeteria, chapel
/area/awaymission/midblock
//engineering, bridge (not really north but it doesnt really need its own APC)
/area/awaymission/northblock
//That massive research room
/area/awaymission/research
//Syndicate shuttle
/area/awaymission/syndishuttle
/*
* Landmarks - Instead of spawning a new object type, I'll spawn the bible using a landmark!
*/
/obj/effect/landmark/sc_bible_spawner
name = "Safecode hint spawner"
/obj/effect/landmark/sc_bible_spawner/New()
var/obj/item/weapon/storage/book/bible/B = new /obj/item/weapon/storage/book/bible/booze(src.loc)
B.name = "The Holy book of the Geometer"
B.deity_name = "Narsie"
B.icon_state = "melted"
B.item_state = "melted"
new /obj/item/weapon/paper/sc_safehint_paper_bible(B)
new /obj/item/weapon/pen(B)
qdel(src)
/*
* Guns - I'm making these specifically so that I dont spawn a pile of fully loaded weapons on the map.
*/
//Captain's retro laser - Fires practice laser shots instead.
obj/item/weapon/gun/energy/laser/retro/sc_retro
name ="retro laser"
icon_state = "retro"
desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces."
// projectile_type = "/obj/item/projectile/practice"
clumsy_check = 0 //No sense in having a harmless gun blow up in the clowns face
//Syndicate sub-machine guns.
/obj/item/weapon/gun/projectile/automatic/c20r/sc_c20r
/obj/item/weapon/gun/projectile/automatic/c20r/sc_c20r/New()
..()
for(var/ammo in magazine.stored_ammo)
if(prob(95)) //95% chance
magazine.stored_ammo -= ammo
//Barman's shotgun
/obj/item/weapon/gun/projectile/shotgun/sc_pump
/obj/item/weapon/gun/projectile/shotgun/sc_pump/New()
..()
for(var/ammo in magazine.stored_ammo)
if(prob(95)) //95% chance
magazine.stored_ammo -= ammo
//Lasers
/obj/item/weapon/gun/energy/laser/practice/sc_laser
name = "Old laser"
desc = "A once potent weapon, years of dust have collected in the chamber and lens of this weapon, weakening the beam significantly."
clumsy_check = 0
/*
* Safe code hints
*/
//These vars hold the code itself, they'll be generated at round-start
var/sc_safecode1 = "[rand(0,9)]"
var/sc_safecode2 = "[rand(0,9)]"
var/sc_safecode3 = "[rand(0,9)]"
var/sc_safecode4 = "[rand(0,9)]"
var/sc_safecode5 = "[rand(0,9)]"
//Pieces of paper actually containing the hints
/obj/item/weapon/paper/sc_safehint_paper_prison
name = "smudged paper"
/obj/item/weapon/paper/sc_safehint_paper_prison/New()
info = "<i>The ink is smudged, you can only make out a couple numbers:</i> '[sc_safecode1]**[sc_safecode4]*'"
/obj/item/weapon/paper/sc_safehint_paper_hydro
name = "shredded paper"
/obj/item/weapon/paper/sc_safehint_paper_hydro/New()
info = "<i>Although the paper is shredded, you can clearly see the number:</i> '[sc_safecode2]'"
/obj/item/weapon/paper/sc_safehint_paper_caf
name = "blood-soaked paper"
//This does not have to be in New() because it is a constant. There are no variables in it i.e. [sc_safcode]
info = "<font color=red><i>This paper is soaked in blood, it is impossible to read any text.</i></font>"
/obj/item/weapon/paper/sc_safehint_paper_bible
name = "hidden paper"
/obj/item/weapon/paper/sc_safehint_paper_bible/New()
info = {"<i>It would appear that the pen hidden with the paper had leaked ink over the paper.
However you can make out the last three digits:</i>'[sc_safecode3][sc_safecode4][sc_safecode5]'
"}
/obj/item/weapon/paper/sc_safehint_paper_shuttle
info = {"<b>Target:</b> Research-station Epsilon<br>
<b>Objective:</b> Prototype weaponry. The captain likely keeps them locked in her safe.<br>
<br>
Our on-board spy has learned the code and has hidden away a few copies of the code around the station. Unfortunatly he has been captured by security
Your objective is to split up, locate any of the papers containing the captain's safe code, open the safe and
secure anything found inside. If possible, recover the imprisioned syndicate operative and receive the code from him.<br>
<br>
<u>As always, eliminate anyone who gets in the way.</u><br>
<br>
Your assigned ship is designed specifically for penetrating the hull of another station or ship with minimal damage to operatives.
It is completely fly-by-wire meaning you have just have to enjoy the ride and when the red light comes on... find something to hold onto!
"}
/*
* Captain's safe
*/
/obj/item/weapon/storage/secure/safe/sc_ssafe
name = "Captain's secure safe"
/obj/item/weapon/storage/secure/safe/sc_ssafe/New()
..()
l_code = "[sc_safecode1][sc_safecode2][sc_safecode3][sc_safecode4][sc_safecode5]"
l_set = 1
new /obj/item/weapon/gun/energy/mindflayer(src)
new /obj/item/device/soulstone(src)
new /obj/item/clothing/suit/space/hardsuit/cult(src)
//new /obj/item/weapon/teleportation_scroll(src)
new /obj/item/weapon/ore/diamond(src)
/*
* Modified Nar-Sie
*/
/obj/singularity/narsie/sc_Narsie
desc = "Your body becomes weak and your feel your mind slipping away as you try to comprehend what you know can't be possible."
move_self = 0 //Contianed narsie does not move!
grav_pull = 0 //Contained narsie does not pull stuff in!
var/uneatable = list(/turf/open/space, /obj/effect/overlay, /mob/living/simple_animal/hostile/construct)
//Override this to prevent no adminlog runtimes and admin warnings about a singularity without containment
/obj/singularity/narsie/sc_Narsie/admin_investigate_setup()
return
/obj/singularity/narsie/sc_Narsie/process()
eat()
if(prob(25))
mezzer()
/obj/singularity/narsie/sc_Narsie/consume(atom/A)
if(is_type_in_list(A, uneatable))
return 0
if (istype(A,/mob/living))
var/mob/living/L = A
L.gib()
else if(istype(A,/obj/))
var/obj/O = A
O.ex_act(1)
if(O) qdel(O)
else if(isturf(A))
var/turf/T = A
if(T.intact)
for(var/obj/O in T.contents)
if(O.level != 1)
continue
if(O.invisibility == INVISIBILITY_MAXIMUM)
src.consume(O)
T.ChangeTurf(/turf/open/space)
return
/obj/singularity/narsie/sc_Narsie/ex_act()
return
@@ -0,0 +1,163 @@
/* Code for the Wild West map by Brotemis
* Contains:
* Wish Granter
* Meat Grinder
*/
//Wild West Areas
/area/awaymission/wwmines
name = "Wild West Mines"
icon_state = "away1"
luminosity = 1
requires_power = 0
/area/awaymission/wwgov
name = "Wild West Mansion"
icon_state = "away2"
luminosity = 1
requires_power = 0
/area/awaymission/wwrefine
name = "Wild West Refinery"
icon_state = "away3"
luminosity = 1
requires_power = 0
/area/awaymission/wwvault
name = "Wild West Vault"
icon_state = "away3"
luminosity = 0
/area/awaymission/wwvaultdoors
name = "Wild West Vault Doors" // this is to keep the vault area being entirely lit because of requires_power
icon_state = "away2"
requires_power = 0
luminosity = 0
/*
* Wish Granter
*/
/obj/machinery/wish_granter_dark
name = "Wish Granter"
desc = "You're not so sure about this, anymore..."
icon = 'icons/obj/device.dmi'
icon_state = "syndbeacon"
anchored = 1
density = 1
use_power = 0
var/chargesa = 1
var/insistinga = 0
/obj/machinery/wish_granter_dark/attack_hand(mob/living/carbon/human/user)
usr.set_machine(src)
if(chargesa <= 0)
user << "The Wish Granter lies silent."
return
else if(!istype(user, /mob/living/carbon/human))
user << "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's."
return
else if(is_special_character(user))
user << "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away."
else if (!insistinga)
user << "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?"
insistinga++
else
chargesa--
insistinga = 0
var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","Immortality","To Kill","Peace")
switch(wish)
if("Power")
user << "<B>Your wish is granted, but at a terrible cost...</B>"
user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart."
user.dna.add_mutation(LASEREYES)
user.dna.add_mutation(COLDRES)
user.dna.add_mutation(XRAY)
user.set_species(/datum/species/shadow)
if("Wealth")
user << "<B>Your wish is granted, but at a terrible cost...</B>"
user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart."
new /obj/structure/closet/syndicate/resources/everything(loc)
user.set_species(/datum/species/shadow)
if("Immortality")
user << "<B>Your wish is granted, but at a terrible cost...</B>"
user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart."
user.verbs += /mob/living/carbon/proc/immortality
user.set_species(/datum/species/shadow)
if("To Kill")
user << "<B>Your wish is granted, but at a terrible cost...</B>"
user << "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart."
ticker.mode.traitors += user.mind
user.mind.special_role = "traitor"
var/datum/objective/hijack/hijack = new
hijack.owner = user.mind
user.mind.objectives += hijack
user << "<B>Your inhibitions are swept away, the bonds of loyalty broken, you are free to murder as you please!</B>"
var/obj_count = 1
for(var/datum/objective/OBJ in user.mind.objectives)
user << "<B>Objective #[obj_count]</B>: [OBJ.explanation_text]"
obj_count++
user.set_species(/datum/species/shadow)
if("Peace")
user << "<B>Whatever alien sentience that the Wish Granter possesses is satisfied with your wish. There is a distant wailing as the last of the Faithless begin to die, then silence.</B>"
user << "You feel as if you just narrowly avoided a terrible fate..."
for(var/mob/living/simple_animal/hostile/faithless/F in mob_list)
F.death()
///////////////Meatgrinder//////////////
/obj/effect/meatgrinder
name = "Meat Grinder"
desc = "What is that thing?"
density = 1
anchored = 1
icon = 'icons/mob/blob.dmi'
icon_state = "blobpod"
var/triggered = 0
/obj/effect/meatgrinder/Crossed(AM as mob|obj)
Bumped(AM)
/obj/effect/meatgrinder/Bumped(mob/M as mob|obj)
if(triggered)
return
if(istype(M, /mob/living/carbon/human) && M.stat != DEAD && M.ckey)
for(var/mob/O in viewers(world.view, src.loc))
visible_message("<span class='warning'>[M] triggered the [src]!</span>")
triggered = 1
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
s.start()
explosion(M, 1, 0, 0, 0)
qdel(src)
/////For the Wishgranter///////////
/mob/living/carbon/proc/immortality() //Mob proc so people cant just clone themselves to get rid of the shadowperson race. No hiding your wickedness.
set category = "Immortality"
set name = "Resurrection"
var/mob/living/carbon/C = usr
if(!C.stat)
C << "<span class='notice'>You're not dead yet!</span>"
return
C << "<span class='notice'>Death is not your end!</span>"
spawn(rand(80,120))
C.revive(full_heal = 1, admin_revive = 1)
C << "<span class='notice'>You have regenerated.</span>"
C.visible_message("<span class='warning'>[usr] appears to wake from the dead, having healed all wounds.</span>")
C.update_canmove()
return 1
+37
View File
@@ -0,0 +1,37 @@
/obj/item/weapon/paper/pamphlet
name = "pamphlet"
icon_state = "pamphlet"
info = "<b>Welcome to the Nanotrasen Gateway project...</b><br>\
Congratulations! If you're reading this, you and your superiors have decided that you're \
ready to commit to a life spent colonising the rolling hills of far away worlds. You \
must be ready for a lifetime of adventure, a little bit of hard work, and an award \
winning dental plan- but that's not all the Nanotrasen Gateway project has to offer.<br>\
<br>Because we care about you, we feel it is only fair to make sure you know the risks \
before you commit to joining the Nanotrasen Gateway project. All away destinations have \
been fully scanned by a Nanotrasen expeditionary team, and are certified to be 100% safe. \
We've even left a case of space beer along with the basic materials you'll need to expand \
Nanotrasen's operational area and start your new life.<br><br>\
<b>Gateway Operation Basics</b><br>\
All Nanotrasen approved Gateways operate on the same basic principals. They operate off \
area equipment power as you would expect, and without this supply, it cannot safely function, \
causinng it to reject all attempts at operation.<br><br>\
Once it is correctly setup, and once it has enough power to operate, the Gateway will begin \
searching for an output location. The amount of time this takes is variable, but the Gateway \
interface will give you an estimate accurate to the minute. Power loss will not interrupt the \
searching process. Influenza will not interrupt the searching process. Temporal anomalies \
may cause the estimate to be inaccurate, but will not interrupt the searching process.<br><br> \
<b>Life On The Other Side</b><br>\
Once you have traversed the Gateway, you may experience some disorientation. Do not panic. \
This is a normal side effect of travelling vast distances in a short period of time. You should \
survey the immediate area, and attempt to locate your complimentary case of space beer. Our \
expeditionary teams have ensured the complete safety of all away locations, but in a small \
number of cases, the Gateway they have established may not be immediately obvious. \
Do not panic if you cannot locate the return Gateway. Begin colonisation of the destination. \
<br><br><b>A New World</b><br>\
As a participant in the Nanotrasen Gateway Project, you will be on the frontiers of space. \
Though complete safety is assured, participants are advised to prepare for inhospitable \
environs."
//we don't want the silly text overlay!
/obj/item/weapon/paper/pamphlet/update_icon()
return
+49
View File
@@ -0,0 +1,49 @@
/*An alternative to exit gateways, signposts send you back to somewhere safe onstation with their semiotic magic.*/
/obj/structure/signpost
icon = 'icons/obj/stationobjs.dmi'
icon_state = "signpost"
anchored = 1
density = 1
var/question = "Travel back?"
var/zlevels = list(ZLEVEL_STATION)
/obj/structure/signpost/New()
. = ..()
SetLuminosity(2)
/obj/structure/signpost/attackby(obj/item/weapon/W, mob/user, params)
return attack_hand(user)
/obj/structure/signpost/attack_hand(mob/user)
switch(alert(question,name,"Yes","No"))
if("Yes")
var/turf/T = find_safe_turf(zlevels=zlevels)
if(T)
var/area/A = get_area(T)
user.forceMove(T)
user << "<span class='notice'>You blink and find yourself \
in [A.name].</span>"
else
user << "Nothing happens. You feel that this is a bad sign."
if("No")
return
/obj/structure/signpost/salvation
name = "\proper salvation"
desc = "In the darkest times, we will find our way home."
/obj/structure/signpost/exit
name = "exit"
desc = "Make sure to bring all your belongings with you when you \
exit the area."
question = "Leave? You might never come back."
/obj/structure/signpost/exit/New()
. = ..()
zlevels = list()
for(var/i in 1 to world.maxz)
zlevels += i
zlevels -= ZLEVEL_CENTCOM // no easy victory, even with meme signposts
// also, could you think of the horror if they ended up in a holodeck
// template or something
+137
View File
@@ -0,0 +1,137 @@
// How much "space" we give the edge of the map
var/global/list/potentialRandomZlevels = generateMapList(filename = "config/awaymissionconfig.txt")
/proc/createRandomZlevel()
if(awaydestinations.len) //crude, but it saves another var!
return
if(potentialRandomZlevels && potentialRandomZlevels.len)
world << "<span class='boldannounce'>Loading away mission...</span>"
var/map = pick(potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
maploader.load_map(file)
smooth_zlevel(world.maxz)
world.log << "away mission loaded: [map]"
map_transition_config.Add(AWAY_MISSION_LIST)
for(var/obj/effect/landmark/L in landmarks_list)
if (L.name != "awaystart")
continue
awaydestinations.Add(L)
world << "<span class='boldannounce'>Away mission loaded.</span>"
SortAreas() //To add recently loaded areas
/proc/generateMapList(filename)
var/list/potentialMaps = list()
var/list/Lines = file2list(filename)
if(!Lines.len)
return
for (var/t in Lines)
if (!t)
continue
t = trim(t)
if (length(t) == 0)
continue
else if (copytext(t, 1, 2) == "#")
continue
var/pos = findtext(t, " ")
var/name = null
if (pos)
name = lowertext(copytext(t, 1, pos))
else
name = lowertext(t)
if (!name)
continue
potentialMaps.Add(t)
return potentialMaps
/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = /area/space, list/potentialRuins = space_ruins_templates)
if(!z_levels || !z_levels.len)
z_levels = list(1)
var/overall_sanity = 100
var/ruins = potentialRuins.Copy()
while(budget > 0 && overall_sanity > 0)
// Pick a ruin
var/datum/map_template/ruin/ruin = ruins[pick(ruins)]
// Can we afford it
if(ruin.cost > budget)
overall_sanity--
continue
// If so, try to place it
var/sanity = 100
// And if we can't fit it anywhere, give up, try again
while(sanity > 0)
sanity--
var/width_border = TRANSITIONEDGE + round(ruin.width / 2)
var/height_border = TRANSITIONEDGE + round(ruin.height / 2)
var/z_level = pick(z_levels)
var/turf/T = locate(rand(width_border, world.maxx - width_border), rand(height_border, world.maxy - height_border), z_level)
var/valid = TRUE
for(var/turf/check in ruin.get_affected_turfs(T,1))
var/area/new_area = get_area(check)
if(!(istype(new_area, whitelist)))
valid = FALSE
break
if(!valid)
continue
world.log << "Ruin \"[ruin.name]\" placed at ([T.x], [T.y], [T.z])"
var/obj/effect/ruin_loader/R = new /obj/effect/ruin_loader(T)
R.Load(ruins,ruin)
budget -= ruin.cost
if(!ruin.allow_duplicates)
ruins -= ruin.name
break
if(!overall_sanity)
world.log << "Ruin loader gave up with [budget] left to spend."
/obj/effect/ruin_loader
name = "random ruin"
icon = 'icons/obj/weapons.dmi'
icon_state = "syndballoon"
invisibility = 0
/obj/effect/ruin_loader/proc/Load(list/potentialRuins = space_ruins_templates, datum/map_template/template = null)
var/list/possible_ruins = list()
for(var/A in potentialRuins)
var/datum/map_template/T = potentialRuins[A]
if(!T.loaded)
possible_ruins += T
if(!template && possible_ruins.len)
template = safepick(possible_ruins)
if(!template)
return FALSE
var/turf/central_turf = get_turf(src)
for(var/i in template.get_affected_turfs(central_turf, 1))
var/turf/T = i
for(var/mob/living/simple_animal/monster in T)
qdel(monster)
template.load(central_turf,centered = TRUE)
template.loaded++
var/datum/map_template/ruin = template
if(istype(ruin))
new /obj/effect/landmark/ruin(central_turf, ruin)
qdel(src)
return TRUE