initial commit - cross reference with 5th port - obviously has compile errors
This commit is contained in:
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user