mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 16:13:19 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into BookClub
This commit is contained in:
@@ -66,6 +66,10 @@ Pipelines + Other Objects -> Pipe network
|
||||
/obj/machinery/atmospherics/update_icon()
|
||||
return null
|
||||
|
||||
/obj/machinery/atmospherics/proc/update_pipe_image()
|
||||
pipe_image = image(src, loc, layer = 20, dir = dir) //the 20 puts it above Byond's darkness (not its opacity view)
|
||||
pipe_image.plane = HUD_PLANE
|
||||
|
||||
/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
|
||||
if(!istype(icon_manager))
|
||||
if(!safety) //to prevent infinite loops
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
|
||||
overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
|
||||
|
||||
update_pipe_image()
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
|
||||
if(..())
|
||||
underlays.Cut()
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
scrubber_icon = "scrubberweld"
|
||||
|
||||
overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon)
|
||||
update_pipe_image()
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
|
||||
if(..())
|
||||
|
||||
@@ -255,10 +255,11 @@
|
||||
0, 0, 1, 0,\
|
||||
0, 0, 0, 1)
|
||||
|
||||
#define MATRIX_GREYSCALE list(0.3, 0.3, 0.3, 0,\
|
||||
0.3, 0.3, 0.3, 0,\
|
||||
0.3, 0.3, 0.3, 0,\
|
||||
0, 0, 0, 1)
|
||||
#define MATRIX_GREYSCALE list(0.33, 0.33, 0.33, 0,\
|
||||
0.33, 0.33, 0.33, 0,\
|
||||
0.33, 0.33, 0.33, 0,\
|
||||
0.00, 0.00, 0.00, 1,\
|
||||
0.00, 0.00, 0.00, 0)
|
||||
//Gun trigger guards
|
||||
#define TRIGGER_GUARD_ALLOW_ALL -1
|
||||
#define TRIGGER_GUARD_NONE 0
|
||||
|
||||
@@ -27,3 +27,10 @@
|
||||
#define DONATOR_PUBLIC 32768
|
||||
|
||||
#define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC|MEMBER_PUBLIC|DONATOR_PUBLIC)
|
||||
|
||||
// Playtime tracking system, see jobs_exp.dm
|
||||
#define EXP_TYPE_LIVING "Living"
|
||||
#define EXP_TYPE_CREW "Crew"
|
||||
#define EXP_TYPE_SPECIAL "Special"
|
||||
#define EXP_TYPE_GHOST "Ghost"
|
||||
#define EXP_TYPE_EXEMPT "Exempt"
|
||||
@@ -115,6 +115,7 @@
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
|
||||
return result
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,4 +33,4 @@ var/global/list/shuttle_caller_list = list() //list of all communication cons
|
||||
var/global/list/tracked_implants = list() //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented...
|
||||
var/global/list/pinpointer_list = list() //list of all pinpointers. Used to change stuff they are pointing to all at once.
|
||||
var/global/list/abductor_equipment = list() //list of all abductor equipment
|
||||
var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels
|
||||
var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels
|
||||
@@ -0,0 +1,157 @@
|
||||
var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
|
||||
/datum/controller/process/mob_hunt
|
||||
var/max_normal_spawns = 15 //change this to adjust the number of normal spawns that can exist at one time. trapped spawns (from traitors) don't count towards this
|
||||
var/list/normal_spawns = list()
|
||||
var/max_trap_spawns = 15 //change this to adjust the number of trap spawns that can exist at one time. traps spawned beyond this point clear the oldest traps
|
||||
var/list/trap_spawns = list()
|
||||
var/list/connected_clients = list()
|
||||
var/server_status = 1 //1 is online, 0 is offline
|
||||
var/reset_cooldown = 0 //number of controller cycles before the manual_reboot proc can be used again (ignored if server is offline so you can always boot back up)
|
||||
var/obj/machinery/computer/mob_battle_terminal/red_terminal
|
||||
var/obj/machinery/computer/mob_battle_terminal/blue_terminal
|
||||
var/battle_turn = null
|
||||
|
||||
/datum/controller/process/mob_hunt/setup()
|
||||
name = "Nano-Mob Hunter GO Server"
|
||||
start_delay = 20
|
||||
mob_hunt_server = src
|
||||
|
||||
/datum/controller/process/mob_hunt/doWork()
|
||||
if(reset_cooldown) //if reset_cooldown is set (we are on cooldown, duh), reduce the remaining cooldown every cycle
|
||||
reset_cooldown--
|
||||
if(!server_status)
|
||||
return
|
||||
client_mob_update()
|
||||
if(normal_spawns.len < max_normal_spawns)
|
||||
spawn_mob()
|
||||
|
||||
//leaving this here in case admins want to use it for a random mini-event or something
|
||||
/datum/controller/process/mob_hunt/proc/server_crash(recover_time = 3000)
|
||||
server_status = 0
|
||||
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
|
||||
client.disconnect("Server Crash")
|
||||
for(var/obj/effect/nanomob/N in trap_spawns)
|
||||
N.despawn()
|
||||
for(var/obj/effect/nanomob/N in normal_spawns)
|
||||
N.despawn()
|
||||
//just in case
|
||||
normal_spawns.Cut()
|
||||
trap_spawns.Cut()
|
||||
connected_clients.Cut()
|
||||
if(!isnum(recover_time))
|
||||
recover_time = 3000
|
||||
if(recover_time > 0) //when provided with a negative or zero valued recover_time argument, the server won't auto-restart but can be manually rebooted still
|
||||
//set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too)
|
||||
addtimer(src, "auto_recover", recover_time, TRUE)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/client_mob_update()
|
||||
var/list/ex_players = list()
|
||||
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
|
||||
var/mob/living/carbon/human/H = client.get_player()
|
||||
if(connected_clients[client])
|
||||
if(!H || H != connected_clients[client])
|
||||
ex_players |= connected_clients[client]
|
||||
connected_clients[client] = H
|
||||
if(ex_players.len) //to make sure we don't do this if we didn't lose any player since the last update
|
||||
for(var/obj/effect/nanomob/N in (normal_spawns + trap_spawns))
|
||||
N.conceal(ex_players)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/auto_recover()
|
||||
if(server_status != 0)
|
||||
return
|
||||
server_status = 1
|
||||
while(normal_spawns.len < max_normal_spawns) //repopulate the server's spawns completely if we auto-recover from crash
|
||||
spawn_mob()
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/manual_reboot()
|
||||
if(server_status && reset_cooldown)
|
||||
return 0
|
||||
for(var/obj/effect/nanomob/N in trap_spawns)
|
||||
N.despawn()
|
||||
for(var/obj/effect/nanomob/N in normal_spawns)
|
||||
N.despawn()
|
||||
server_status = 1
|
||||
reset_cooldown = 25 //25 controller cycle cooldown for manual restarts
|
||||
return 1
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/spawn_mob()
|
||||
var/list/nanomob_types = subtypesof(/datum/mob_hunt)
|
||||
var/datum/mob_hunt/mob_info = pick(nanomob_types)
|
||||
new mob_info()
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/register_spawn(datum/mob_hunt/mob_info)
|
||||
if(!mob_info)
|
||||
return 0
|
||||
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
|
||||
normal_spawns += new_mob
|
||||
new_mob.reveal()
|
||||
return 1
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info)
|
||||
if(!mob_info)
|
||||
return 0
|
||||
if(!mob_info.is_trap)
|
||||
return register_spawn(mob_info)
|
||||
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
|
||||
trap_spawns += new_mob
|
||||
new_mob.reveal()
|
||||
if(trap_spawns.len > max_trap_spawns)
|
||||
var/obj/effect/nanomob/old_trap = trap_spawns[1]
|
||||
old_trap.despawn()
|
||||
return 1
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/start_check()
|
||||
if(battle_turn) //somehow we got called mid-battle, so lets just stop now
|
||||
return
|
||||
if(red_terminal && red_terminal.ready && blue_terminal && blue_terminal.ready)
|
||||
battle_turn = pick("Red", "Blue")
|
||||
red_terminal.audible_message("Battle starting!", null, 5)
|
||||
blue_terminal.audible_message("Battle starting!", null, 5)
|
||||
if(battle_turn == "Red")
|
||||
red_terminal.audible_message("Red Player's Turn!", null, 5)
|
||||
else if(battle_turn == "Blue")
|
||||
blue_terminal.audible_message("Blue Player's Turn!", null, 5)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type)
|
||||
if(!team || !raw_damage)
|
||||
return
|
||||
var/obj/machinery/computer/mob_battle_terminal/target = null
|
||||
if(team == "Red")
|
||||
target = blue_terminal
|
||||
else if(team == "Blue")
|
||||
target = red_terminal
|
||||
else
|
||||
return
|
||||
target.receive_attack(raw_damage, attack_type)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/end_battle(loser, surrender = 0)
|
||||
var/obj/machinery/computer/mob_battle_terminal/winner_terminal = null
|
||||
var/obj/machinery/computer/mob_battle_terminal/loser_terminal = null
|
||||
if(loser == "Red")
|
||||
loser_terminal = red_terminal
|
||||
winner_terminal = blue_terminal
|
||||
else if (loser == "Blue")
|
||||
loser_terminal = blue_terminal
|
||||
winner_terminal = red_terminal
|
||||
battle_turn = null
|
||||
winner_terminal.ready = 0
|
||||
loser_terminal.ready = 0
|
||||
if(surrender) //surrender doesn't give exp, to avoid people just farming exp without actually doing a battle
|
||||
winner_terminal.audible_message("Your rival surrendered!", null, 2)
|
||||
else
|
||||
var/progress_message = winner_terminal.mob_info.gain_exp()
|
||||
winner_terminal.audible_message("[winner_terminal.team] Player wins!", null, 5)
|
||||
winner_terminal.audible_message(progress_message, null, 2)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/end_turn()
|
||||
red_terminal.updateUsrDialog()
|
||||
blue_terminal.updateUsrDialog()
|
||||
if(!battle_turn)
|
||||
return
|
||||
if(battle_turn == "Red")
|
||||
battle_turn = "Blue"
|
||||
blue_terminal.audible_message("Blue's turn.", null, 5)
|
||||
else if(battle_turn == "Blue")
|
||||
battle_turn = "Red"
|
||||
blue_terminal.audible_message("Red's turn.", null, 5)
|
||||
@@ -89,6 +89,8 @@
|
||||
var/overflow_server_url
|
||||
var/forbid_singulo_possession = 0
|
||||
|
||||
var/check_randomizer = 0
|
||||
|
||||
//game_options.txt configs
|
||||
|
||||
var/health_threshold_softcrit = 0
|
||||
@@ -127,6 +129,10 @@
|
||||
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
|
||||
var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database
|
||||
|
||||
var/use_exp_tracking = 0
|
||||
var/use_exp_restrictions = 0
|
||||
var/use_exp_restrictions_admin_bypass = 0
|
||||
|
||||
var/simultaneous_pm_warning_timeout = 100
|
||||
|
||||
var/assistant_maint = 0 //Do assistants get maint access?
|
||||
@@ -140,6 +146,7 @@
|
||||
var/main_irc = ""
|
||||
var/admin_irc = ""
|
||||
var/admin_notify_irc = ""
|
||||
var/cidrandomizer_irc = ""
|
||||
var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix
|
||||
|
||||
var/default_laws = 0 //Controls what laws the AI spawns with.
|
||||
@@ -240,6 +247,15 @@
|
||||
if("use_age_restriction_for_antags")
|
||||
config.use_age_restriction_for_antags = 1
|
||||
|
||||
if("use_exp_tracking")
|
||||
config.use_exp_tracking = 1
|
||||
|
||||
if("use_exp_restrictions")
|
||||
config.use_exp_restrictions = 1
|
||||
|
||||
if("use_exp_restrictions_admin_bypass")
|
||||
config.use_exp_restrictions_admin_bypass = 1
|
||||
|
||||
if("jobs_have_minimal_access")
|
||||
config.jobs_have_minimal_access = 1
|
||||
|
||||
@@ -405,6 +421,9 @@
|
||||
if("forbid_singulo_possession")
|
||||
forbid_singulo_possession = 1
|
||||
|
||||
if("check_randomizer")
|
||||
check_randomizer = 1
|
||||
|
||||
if("popup_admin_pm")
|
||||
config.popup_admin_pm = 1
|
||||
|
||||
@@ -472,6 +491,9 @@
|
||||
if("admin_notify_irc")
|
||||
config.admin_notify_irc = value
|
||||
|
||||
if("cidrandomizer_irc")
|
||||
config.cidrandomizer_irc = value
|
||||
|
||||
if("python_path")
|
||||
if(value)
|
||||
config.python_path = value
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
return
|
||||
|
||||
|
||||
/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote"))
|
||||
/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Mob Hunt Server"))
|
||||
set category = "Debug"
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
@@ -76,6 +76,9 @@
|
||||
if("Vote")
|
||||
debug_variables(vote)
|
||||
feedback_add_details("admin_verb","DVote")
|
||||
if("Mob Hunt Server")
|
||||
debug_variables(mob_hunt_server)
|
||||
feedback_add_details("admin_verb","DMobHuntServer")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
|
||||
return
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
access_heads, access_construction, access_sec_doors,
|
||||
access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_minisat, access_mechanic, access_mineral_storeroom)
|
||||
minimal_player_age = 21
|
||||
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
@@ -51,7 +52,6 @@
|
||||
minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_mineral_storeroom)
|
||||
alt_titles = list("Maintenance Technician","Engine Technician","Electrician")
|
||||
minimal_player_age = 7
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear)
|
||||
@@ -83,7 +83,6 @@
|
||||
minimal_access = list(access_eva, access_atmospherics, access_maint_tunnels, access_external_airlocks, access_emergency_storage, access_construction, access_mineral_storeroom)
|
||||
alt_titles = list("Atmospheric Technician")
|
||||
minimal_player_age = 7
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear)
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
//If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.)
|
||||
var/minimal_player_age = 0
|
||||
|
||||
var/exp_requirements = 0
|
||||
var/exp_type = ""
|
||||
|
||||
var/admin_only = 0
|
||||
var/spawn_ert = 0
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
|
||||
access_keycard_auth, access_sec_doors, access_psychiatrist, access_maint_tunnels, access_paramedic, access_mineral_storeroom)
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
@@ -109,7 +111,6 @@
|
||||
alt_titles = list("Pharmacist","Pharmacologist")
|
||||
minimal_player_age = 7
|
||||
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
switch(H.backbag)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
access_research, access_robotics, access_xenobiology, access_ai_upload,
|
||||
access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_minisat, access_maint_tunnels, access_mineral_storeroom)
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
// All science-y guys get bonuses for maxing out their tech.
|
||||
required_objectives=list(
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting,
|
||||
access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_pilot, access_weapons)
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
@@ -56,6 +58,8 @@
|
||||
access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue, access_weapons)
|
||||
minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_weapons)
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
@@ -98,6 +102,8 @@
|
||||
minimal_access = list(access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court, access_weapons)
|
||||
alt_titles = list("Forensic Technician")
|
||||
minimal_player_age = 14
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear)
|
||||
@@ -148,6 +154,8 @@
|
||||
access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons)
|
||||
minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_weapons)
|
||||
minimal_player_age = 14
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
supervisors = "your laws"
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 30
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
@@ -15,7 +17,7 @@
|
||||
|
||||
/datum/job/ai/is_position_available()
|
||||
return (empty_playable_ai_cores.len != 0)
|
||||
|
||||
|
||||
|
||||
/datum/job/cyborg
|
||||
title = "Cyborg"
|
||||
@@ -26,6 +28,8 @@
|
||||
supervisors = "your laws and the AI" //Nodrak
|
||||
selection_color = "#ddffdd"
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
alt_titles = list("Android", "Robot")
|
||||
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
|
||||
@@ -12,6 +12,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
|
||||
access = list() //See get_access()
|
||||
minimal_access = list() //See get_access()
|
||||
minimal_player_age = 30
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
equip(var/mob/living/carbon/human/H)
|
||||
if(!H) return 0
|
||||
H.equip_or_collect(new /obj/item/device/radio/headset/heads/captain/alt(H), slot_l_ear)
|
||||
@@ -56,6 +58,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
|
||||
idtype = /obj/item/weapon/card/id/silver
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 600
|
||||
exp_type = EXP_TYPE_CREW
|
||||
access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers,
|
||||
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
|
||||
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
|
||||
|
||||
@@ -123,6 +123,9 @@ var/global/datum/controller/occupations/job_master
|
||||
if(job.admin_only) // No admin positions either.
|
||||
continue
|
||||
|
||||
if(job.available_in_playtime(player.client))
|
||||
continue
|
||||
|
||||
if(jobban_isbanned(player, job.title))
|
||||
Debug("GRJ isbanned failed, Player: [player], Job: [job.title]")
|
||||
continue
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// Admin Verbs
|
||||
|
||||
/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are.
|
||||
set category = "Admin"
|
||||
set name = "Check Player Playtime"
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/msg = "<html><head><title>Playtime Report</title></head><body>Playtime:<BR><UL>"
|
||||
for(var/client/C in clients)
|
||||
msg += "<LI> - [key_name_admin(C)]: <A href='?_src_=holder;getplaytimewindow=[C.mob.UID()]'>" + C.get_exp_living() + "</a></LI>"
|
||||
msg += "</UL></BODY></HTML>"
|
||||
src << browse(msg, "window=Player_playtime_check")
|
||||
|
||||
|
||||
/datum/admins/proc/cmd_show_exp_panel(var/client/C)
|
||||
if(!C)
|
||||
to_chat(usr, "ERROR: Client not found.")
|
||||
return
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/body = "<html><head><title>Playtime for [C.key]</title></head><BODY><BR>Playtime:"
|
||||
body += C.get_exp_report()
|
||||
body += "</BODY></HTML>"
|
||||
usr << browse(body, "window=playerplaytime[C.ckey];size=550x615")
|
||||
|
||||
|
||||
// Procs
|
||||
|
||||
|
||||
/datum/job/proc/available_in_playtime(client/C)
|
||||
if(!C)
|
||||
return 0
|
||||
if(!exp_requirements || !exp_type)
|
||||
return 0
|
||||
if(!config.use_exp_restrictions)
|
||||
return 0
|
||||
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, C.mob))
|
||||
return 0
|
||||
var/list/play_records = params2list(C.prefs.exp)
|
||||
var/isexempt = text2num(play_records[EXP_TYPE_EXEMPT])
|
||||
if(isexempt)
|
||||
return 0
|
||||
var/my_exp = text2num(play_records[get_exp_req_type()])
|
||||
var/job_requirement = text2num(get_exp_req_amount())
|
||||
if(my_exp >= job_requirement)
|
||||
return 0
|
||||
else
|
||||
return (job_requirement - my_exp)
|
||||
|
||||
/datum/job/proc/get_exp_req_amount()
|
||||
return exp_requirements
|
||||
|
||||
/datum/job/proc/get_exp_req_type()
|
||||
return exp_type
|
||||
|
||||
/mob/proc/get_exp_report()
|
||||
if(client)
|
||||
return client.get_exp_report()
|
||||
else
|
||||
return "[src] has no client."
|
||||
|
||||
/client/proc/get_exp_report()
|
||||
if(!config.use_exp_tracking)
|
||||
return "Tracking is disabled in the server configuration file."
|
||||
var/list/play_records = params2list(prefs.exp)
|
||||
if(!play_records.len)
|
||||
return "[key] has no records."
|
||||
var/return_text = "<UL>"
|
||||
var/list/exp_data = list()
|
||||
for(var/category in exp_jobsmap)
|
||||
if(text2num(play_records[category]))
|
||||
exp_data[category] = text2num(play_records[category])
|
||||
else
|
||||
exp_data[category] = 0
|
||||
for(var/dep in exp_data)
|
||||
if(exp_data[dep] > 0)
|
||||
if(dep == EXP_TYPE_EXEMPT)
|
||||
return_text += "<LI>Exempt (all jobs auto-unlocked)</LI>"
|
||||
else if(exp_data[EXP_TYPE_LIVING] > 0)
|
||||
var/my_pc = num2text(round(exp_data[dep]/exp_data[EXP_TYPE_LIVING]*100))
|
||||
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] ([my_pc]%)</LI>"
|
||||
else
|
||||
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] </LI>"
|
||||
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, mob))
|
||||
return_text += "<LI>Admin (all jobs auto-unlocked)</LI>"
|
||||
return_text += "</UL>"
|
||||
var/list/jobs_locked = list()
|
||||
var/list/jobs_unlocked = list()
|
||||
for(var/datum/job/job in job_master.occupations)
|
||||
if(job.exp_requirements && job.exp_type)
|
||||
if(!job.available_in_playtime(mob.client))
|
||||
jobs_unlocked += job.title
|
||||
else
|
||||
var/xp_req = job.get_exp_req_amount()
|
||||
jobs_locked += "[job.title] [get_exp_format(text2num(play_records[job.get_exp_req_type()]))] / [get_exp_format(xp_req)] as [job.get_exp_req_type()])"
|
||||
if(jobs_unlocked.len)
|
||||
return_text += "<BR><BR>Jobs Unlocked:<UL><LI>"
|
||||
return_text += jobs_unlocked.Join("</LI><LI>")
|
||||
return_text += "</LI></UL>"
|
||||
if(jobs_locked.len)
|
||||
return_text += "<BR><BR>Jobs Not Unlocked:<UL><LI>"
|
||||
return_text += jobs_locked.Join("</LI><LI>")
|
||||
return_text += "</LI></UL>"
|
||||
return return_text
|
||||
|
||||
|
||||
/client/proc/get_exp_living()
|
||||
var/list/play_records = params2list(prefs.exp)
|
||||
var/exp_living = text2num(play_records[EXP_TYPE_LIVING])
|
||||
return get_exp_format(exp_living)
|
||||
|
||||
/proc/get_exp_format(var/expnum)
|
||||
if(expnum > 60)
|
||||
return num2text(round(expnum / 60)) + "h"
|
||||
else if(expnum > 0)
|
||||
return num2text(expnum) + "m"
|
||||
else
|
||||
return "0h"
|
||||
|
||||
/proc/update_exp(var/mins, var/ann = 0)
|
||||
if(!establish_db_connection())
|
||||
return -1
|
||||
spawn(0)
|
||||
for(var/client/L in clients)
|
||||
if(L.inactivity >= (10 MINUTES))
|
||||
continue
|
||||
spawn(0)
|
||||
L.update_exp_client(mins, ann)
|
||||
sleep(10)
|
||||
|
||||
/client/proc/update_exp_client(var/minutes, var/announce_changes = 0)
|
||||
if(!src ||!ckey)
|
||||
return
|
||||
var/DBQuery/exp_read = dbcon.NewQuery("SELECT exp FROM [format_table_name("player")] WHERE ckey='[ckey]'")
|
||||
if(!exp_read.Execute())
|
||||
var/err = exp_read.ErrorMsg()
|
||||
log_game("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
|
||||
message_admins("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
|
||||
return
|
||||
var/list/read_records = list()
|
||||
var/hasread = 0
|
||||
while(exp_read.NextRow())
|
||||
read_records = params2list(exp_read.item[1])
|
||||
hasread = 1
|
||||
if(!hasread)
|
||||
return
|
||||
var/list/play_records = list()
|
||||
for(var/rtype in exp_jobsmap)
|
||||
if(text2num(read_records[rtype]))
|
||||
play_records[rtype] = text2num(read_records[rtype])
|
||||
else
|
||||
play_records[rtype] = 0
|
||||
if(mob.stat == CONSCIOUS && mob.mind.assigned_role)
|
||||
play_records[EXP_TYPE_LIVING] += minutes
|
||||
if(announce_changes)
|
||||
to_chat(mob,"<span class='notice'>You got: [minutes] Living EXP!")
|
||||
for(var/category in exp_jobsmap)
|
||||
if(exp_jobsmap[category]["titles"])
|
||||
if(mob.mind.assigned_role in exp_jobsmap[category]["titles"])
|
||||
play_records[category] += minutes
|
||||
if(announce_changes)
|
||||
to_chat(mob,"<span class='notice'>You got: [minutes] [category] EXP!")
|
||||
if(mob.mind.special_role)
|
||||
play_records[EXP_TYPE_SPECIAL] += minutes
|
||||
if(announce_changes)
|
||||
to_chat(mob,"<span class='notice'>You got: [minutes] Special EXP!")
|
||||
else if(isobserver(mob))
|
||||
play_records[EXP_TYPE_GHOST] += minutes
|
||||
if(announce_changes)
|
||||
to_chat(mob,"<span class='notice'>You got: [minutes] Ghost EXP!")
|
||||
else
|
||||
return
|
||||
var/new_exp = list2params(play_records)
|
||||
prefs.exp = new_exp
|
||||
new_exp = sanitizeSQL(new_exp)
|
||||
var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET exp = '[new_exp]' WHERE ckey='[ckey]'")
|
||||
if(!update_query.Execute())
|
||||
var/err = update_query.ErrorMsg()
|
||||
log_game("SQL ERROR during exp_update_client write. Error : \[[err]\]\n")
|
||||
message_admins("SQL ERROR during exp_update_client write. Error : \[[err]\]\n")
|
||||
return
|
||||
|
||||
/hook/roundstart/proc/exptimer()
|
||||
if(!config.sql_enabled || !config.use_exp_tracking)
|
||||
return 1
|
||||
spawn(0)
|
||||
while(TRUE)
|
||||
sleep(5 MINUTES)
|
||||
update_exp(5,0)
|
||||
return 1
|
||||
@@ -183,3 +183,10 @@ var/list/whitelisted_positions = list(
|
||||
|
||||
return titles
|
||||
|
||||
var/global/list/exp_jobsmap = list(
|
||||
EXP_TYPE_LIVING = list(), // all living mobs
|
||||
EXP_TYPE_CREW = list(titles = command_positions | engineering_positions | medical_positions | science_positions | support_positions | supply_positions | security_positions | civilian_positions | list("AI","Cyborg") | whitelisted_positions), // crew positions
|
||||
EXP_TYPE_SPECIAL = list(), // antags, ERT, etc
|
||||
EXP_TYPE_GHOST = list(), // dead people, observers
|
||||
EXP_TYPE_EXEMPT = list() // special grandfather setting
|
||||
)
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["on"] = on ? 1 : 0
|
||||
data["gasPressure"] = round(air_contents.return_pressure())
|
||||
@@ -267,7 +267,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["on"] = on ? 1 : 0
|
||||
data["gasPressure"] = round(air_contents.return_pressure())
|
||||
|
||||
@@ -696,7 +696,7 @@
|
||||
data["danger"] = danger
|
||||
return data
|
||||
|
||||
/obj/machinery/alarm/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/alarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
var/list/href_list = state.href_list()
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ var/datum/canister_icons/canister_icon_container = new()
|
||||
var/list/LL = L[i]
|
||||
LL = LL.Copy() //make sure we don't edit the datum list
|
||||
LL.Add(list("active" = decals[LL["icon"]])) //"active" used by nanoUI
|
||||
possibledecals[i] = LL
|
||||
possibledecals.Add(LL)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/check_change()
|
||||
var/old_flag = update_flag
|
||||
@@ -181,6 +181,7 @@ update_flag
|
||||
if(src.destroyed)
|
||||
src.overlays = 0
|
||||
src.icon_state = text("[]-1", src.canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
|
||||
return
|
||||
|
||||
if(icon_state != src.canister_color["prim"])
|
||||
icon_state = src.canister_color["prim"]
|
||||
@@ -420,9 +421,9 @@ update_flag
|
||||
|
||||
data["hasHoldingTank"] = holding ? 1 : 0
|
||||
if(holding)
|
||||
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
|
||||
|
||||
return data
|
||||
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
|
||||
if(..())
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/portable_atmospherics/pump/ui_data(mob/user, datum/topic_state/state = physical_state)
|
||||
/obj/machinery/portable_atmospherics/pump/ui_data(mob/user, ui_key = "main", datum/topic_state/state = physical_state)
|
||||
var/data[0]
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0)
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/portable_atmospherics/scrubber/ui_data(mob/user, datum/topic_state/state = physical_state)
|
||||
/obj/machinery/portable_atmospherics/scrubber/ui_data(mob/user, ui_key = "main", datum/topic_state/state = physical_state)
|
||||
var/data[0]
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0)
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/operating/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/operating/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
var/mob/living/carbon/human/occupant = src.table.victim
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/obj/machinery/computer/security
|
||||
name = "security camera console"
|
||||
desc = "Used to access the various cameras networks on the station."
|
||||
|
||||
|
||||
icon_keyboard = "security_key"
|
||||
icon_screen = "cameras"
|
||||
light_color = LIGHT_COLOR_RED
|
||||
circuit = /obj/item/weapon/circuitboard/camera
|
||||
|
||||
|
||||
var/mapping = 0 // For the overview file (overview.dm), not used on this page
|
||||
|
||||
|
||||
var/list/network = list()
|
||||
var/list/available_networks = list()
|
||||
var/list/watchers = list() //who's using the console, associated with the camera they're on.
|
||||
@@ -16,7 +16,7 @@
|
||||
/obj/machinery/computer/security/New() // Lists existing networks and their required access. Format: available_networks[<name>] = list(<access>)
|
||||
generate_network_access()
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/computer/security/proc/generate_network_access()
|
||||
available_networks["SS13"] = list(access_hos,access_captain)
|
||||
available_networks["Telecomms"] = list(access_hos,access_captain)
|
||||
@@ -39,7 +39,7 @@
|
||||
available_networks["ERT"] = list(access_cent_specops_commander,access_cent_commander)
|
||||
available_networks["CentComm"] = list(access_cent_security,access_cent_commander)
|
||||
available_networks["Thunderdome"] = list(access_cent_thunder,access_cent_commander)
|
||||
|
||||
|
||||
/obj/machinery/computer/security/Destroy()
|
||||
if(watchers.len)
|
||||
for(var/mob/M in watchers)
|
||||
@@ -58,11 +58,11 @@
|
||||
user.unset_machine()
|
||||
return
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/computer/security/on_unset_machine(mob/user)
|
||||
watchers.Remove(user)
|
||||
user.reset_perspective(null)
|
||||
|
||||
|
||||
/obj/machinery/computer/security/attack_hand(mob/user)
|
||||
if(stat || ..())
|
||||
user.unset_machine()
|
||||
@@ -83,7 +83,7 @@
|
||||
attack_hand(user)
|
||||
else
|
||||
attack_hand(user)
|
||||
|
||||
|
||||
/obj/machinery.computer/security/proc/get_user_access(mob/user)
|
||||
var/list/access = list()
|
||||
if(ishuman(user))
|
||||
@@ -105,8 +105,8 @@
|
||||
ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
|
||||
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/security/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
|
||||
/obj/machinery/computer/security/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/list/cameras = list()
|
||||
@@ -126,7 +126,7 @@
|
||||
cameras.Swap(j, j + 1)
|
||||
|
||||
data["cameras"] = cameras
|
||||
|
||||
|
||||
var/list/access = get_user_access(user)
|
||||
if(emagged)
|
||||
access = get_all_accesses() // Assume captain level access when emagged
|
||||
@@ -149,8 +149,8 @@
|
||||
data["current"] = null
|
||||
if(watchers[user])
|
||||
var/obj/machinery/camera/watched = watchers[user]
|
||||
data["current"] = watched.nano_structure()
|
||||
|
||||
data["current"] = watched.nano_structure()
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/security/Topic(href, href_list)
|
||||
@@ -162,7 +162,7 @@
|
||||
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras
|
||||
if(!C)
|
||||
return 1
|
||||
|
||||
|
||||
switch_to_camera(usr, C)
|
||||
|
||||
else if(href_list["reset"])
|
||||
@@ -180,31 +180,31 @@
|
||||
else
|
||||
network += net
|
||||
break
|
||||
|
||||
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
// Check if camera is accessible when jumping
|
||||
/obj/machinery/computer/security/proc/can_access_camera(var/obj/machinery/camera/C, var/mob/M)
|
||||
if(CanUseTopic(M, default_state) != STATUS_INTERACTIVE || M.incapacitated() || M.blinded)
|
||||
return 0
|
||||
|
||||
|
||||
if(isrobot(M))
|
||||
var/list/viewing = viewers(src)
|
||||
if(!viewing.Find(M))
|
||||
return 0
|
||||
|
||||
|
||||
if(isAI(M))
|
||||
var/mob/living/silicon/ai/A = M
|
||||
if(!A.is_in_chassis())
|
||||
return 0
|
||||
|
||||
|
||||
if(!issilicon(M) && !Adjacent(M))
|
||||
return 0
|
||||
|
||||
|
||||
var/list/shared_networks = network & C.network
|
||||
if(!shared_networks.len || !C.can_use())
|
||||
return 0
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
// Switching to cameras
|
||||
@@ -212,7 +212,7 @@
|
||||
if(!can_access_camera(C, user))
|
||||
user.unset_machine()
|
||||
return 1
|
||||
|
||||
|
||||
if(isAI(user))
|
||||
var/mob/living/silicon/ai/A = user
|
||||
A.eyeobj.setLoc(get_turf(C))
|
||||
@@ -226,12 +226,12 @@
|
||||
/obj/machinery/computer/security/proc/jump_on_click(var/mob/user, var/A)
|
||||
if(user.machine != src)
|
||||
return
|
||||
|
||||
|
||||
var/obj/machinery/camera/jump_to
|
||||
|
||||
|
||||
if(istype(A, /obj/machinery/camera))
|
||||
jump_to = A
|
||||
|
||||
|
||||
else if(ismob(A))
|
||||
if(ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
@@ -239,11 +239,11 @@
|
||||
else if(isrobot(A))
|
||||
var/mob/living/silicon/robot/R = A
|
||||
jump_to = R.camera
|
||||
|
||||
|
||||
else if(isobj(A))
|
||||
var/obj/O = A
|
||||
jump_to = locate() in O
|
||||
|
||||
|
||||
else if(isturf(A))
|
||||
var/best_dist = INFINITY
|
||||
for(var/obj/machinery/camera/camera in get_area(A))
|
||||
@@ -255,10 +255,10 @@
|
||||
if(dist < best_dist)
|
||||
best_dist = dist
|
||||
jump_to = camera
|
||||
|
||||
|
||||
if(isnull(jump_to))
|
||||
return
|
||||
|
||||
|
||||
if(can_access_camera(jump_to, user))
|
||||
switch_to_camera(user, jump_to)
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ var/time_last_changed_position = 0
|
||||
ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 775, 700)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/card/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/card/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["src"] = UID()
|
||||
data["station_name"] = station_name()
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
ui = new(user, src, ui_key, "cloning_console.tmpl", "Cloning Console UI", 640, 520)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/cloning/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/cloning/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["menu"] = src.menu
|
||||
data["scanner"] = sanitize("[src.scanner]")
|
||||
|
||||
@@ -276,6 +276,18 @@
|
||||
src.emagged = 0
|
||||
setMenuState(usr,COMM_SCREEN_MAIN)
|
||||
|
||||
if("RestartNanoMob")
|
||||
if(mob_hunt_server)
|
||||
if(mob_hunt_server.manual_reboot())
|
||||
var/loading_msg = pick("Respawning spawns", "Reticulating splines", "Flipping hat",
|
||||
"Capturing all of them", "Fixing minor text issues", "Being the very best",
|
||||
"Nerfing this", "Not communicating with playerbase", "Coding a ripoff in a 2D spaceman game")
|
||||
to_chat(usr, "<span class='notice'>Restarting Nano-Mob Hunter GO! game server. [loading_msg]...</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Nano-Mob Hunter GO! game server reboot failed due to recent restart. Please wait before re-attempting.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.</span>")
|
||||
|
||||
if("AcceptDocking")
|
||||
to_chat(usr, "Docking request accepted!")
|
||||
trade_dock_timelimit = world.time + 1200
|
||||
@@ -322,7 +334,7 @@
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/communications/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/communications/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["is_ai"] = isAI(user)||isrobot(user)
|
||||
data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/podtracker/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/podtracker/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
var/list/pods[0]
|
||||
for(var/obj/item/device/spacepod_equipment/misc/tracker/TR in world)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/robotics/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/robotics/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
var/list/robots = get_cyborgs(user)
|
||||
if(robots.len)
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["isOperating"] = on
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data = list(
|
||||
@@ -83,7 +83,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data = list(
|
||||
@@ -146,7 +146,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data = list(
|
||||
|
||||
@@ -180,7 +180,7 @@ FIRE ALARM
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/firealarm/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/firealarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/area/A = get_area(src)
|
||||
|
||||
@@ -154,7 +154,7 @@ Class Procs:
|
||||
if(use_power && stat == 0)
|
||||
use_power(7500/severity)
|
||||
|
||||
new/obj/effect/overlay/temp/emp(src.loc)
|
||||
new/obj/effect/overlay/temp/emp(loc)
|
||||
..()
|
||||
|
||||
/obj/machinery/ex_act(severity)
|
||||
@@ -184,9 +184,9 @@ Class Procs:
|
||||
/obj/machinery/proc/auto_use_power()
|
||||
if(!powered(power_channel))
|
||||
return 0
|
||||
if(src.use_power == 1)
|
||||
if(use_power == 1)
|
||||
use_power(idle_power_usage,power_channel, 1)
|
||||
else if(src.use_power >= 2)
|
||||
else if(use_power >= 2)
|
||||
use_power(active_power_usage,power_channel, 1)
|
||||
return 1
|
||||
|
||||
@@ -229,7 +229,7 @@ Class Procs:
|
||||
if(!(href_list["set_tag"] in vars))
|
||||
to_chat(usr, "<span class='warning'>Something went wrong: Unable to find [href_list["set_tag"]] in vars!</span>")
|
||||
return 1
|
||||
var/current_tag = src.vars[href_list["set_tag"]]
|
||||
var/current_tag = vars[href_list["set_tag"]]
|
||||
var/newid = copytext(reject_bad_text(input(usr, "Specify the new value", src, current_tag) as null|text),1,MAX_MESSAGE_LEN)
|
||||
if(newid)
|
||||
vars[href_list["set_tag"]] = newid
|
||||
@@ -355,13 +355,13 @@ Class Procs:
|
||||
return 1
|
||||
|
||||
if(panel_open)
|
||||
src.add_fingerprint(user)
|
||||
add_fingerprint(user)
|
||||
return 0
|
||||
|
||||
if(!interact_offline && stat & (NOPOWER|BROKEN|MAINT))
|
||||
return 1
|
||||
|
||||
src.add_fingerprint(user)
|
||||
add_fingerprint(user)
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -379,8 +379,8 @@ Class Procs:
|
||||
|
||||
/obj/machinery/proc/default_deconstruction_crowbar(var/obj/item/weapon/crowbar/C, var/ignore_panel = 0)
|
||||
if(istype(C) && (panel_open || ignore_panel))
|
||||
playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
|
||||
var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(src.loc)
|
||||
playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
|
||||
var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(loc)
|
||||
M.state = 2
|
||||
M.icon_state = "box_1"
|
||||
for(var/obj/item/I in component_parts)
|
||||
@@ -393,7 +393,7 @@ Class Procs:
|
||||
|
||||
/obj/machinery/proc/default_deconstruction_screwdriver(var/mob/user, var/icon_state_open, var/icon_state_closed, var/obj/item/weapon/screwdriver/S)
|
||||
if(istype(S))
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
if(!panel_open)
|
||||
panel_open = 1
|
||||
icon_state = icon_state_open
|
||||
@@ -407,7 +407,7 @@ Class Procs:
|
||||
|
||||
/obj/machinery/proc/default_change_direction_wrench(var/mob/user, var/obj/item/weapon/wrench/W)
|
||||
if(panel_open && istype(W))
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
dir = turn(dir,-90)
|
||||
to_chat(user, "<span class='notice'>You rotate [src].</span>")
|
||||
return 1
|
||||
@@ -416,11 +416,14 @@ Class Procs:
|
||||
/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20)
|
||||
if(istype(W))
|
||||
to_chat(user, "<span class='notice'>Now [anchored ? "un" : ""]securing [name].</span>")
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
if(do_after(user, time, target = src))
|
||||
to_chat(user, "<span class='notice'>You've [anchored ? "un" : ""]secured [name].</span>")
|
||||
anchored = !anchored
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
if(istype(src, /obj/machinery))
|
||||
var/obj/machinery/M = src
|
||||
M.power_change() //Turn on or off the machine depending on the status of power in the new area.
|
||||
playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -506,7 +509,7 @@ Class Procs:
|
||||
if(check_access && !allowed(perp))
|
||||
threatcount += 4
|
||||
|
||||
if(auth_weapons && !src.allowed(perp))
|
||||
if(auth_weapons && !allowed(perp))
|
||||
if(istype(perp.l_hand, /obj/item/weapon/gun) || istype(perp.l_hand, /obj/item/weapon/melee))
|
||||
threatcount += 4
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
ui = new(user, src, ui_key, "poolcontroller.tmpl", "Pool Controller Interface", 520, 410)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/poolcontroller/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/poolcontroller/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["currentTemp"] = temperature
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/porta_turret/tag/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/porta_turret/tag/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["locked"] = locked
|
||||
|
||||
@@ -200,7 +200,7 @@ var/list/turret_icons
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/porta_turret/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/porta_turret/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["screen"] = screen
|
||||
|
||||
@@ -115,7 +115,7 @@ var/list/obj/machinery/requests_console/allConsoles = list()
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/requests_console/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/requests_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["department"] = department
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/slot_machine/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/slot_machine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["working"] = working
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
ui = new(user, src, ui_key, "teleporter_console.tmpl", "Teleporter Console UI", 400, 400)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/teleporter/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/teleporter/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["powerstation"] = power_station
|
||||
if(power_station)
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/turretid/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/turretid/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["locked"] = locked
|
||||
|
||||
@@ -416,7 +416,7 @@
|
||||
ui = new(user, src, ui_key, "vending_machine.tmpl", src.name, 440, 600)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/vending/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/vending/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/list/data = list()
|
||||
if(currently_vending)
|
||||
data["mode"] = 1
|
||||
@@ -834,11 +834,11 @@
|
||||
product_slogans = "Carts to go!"
|
||||
icon_state = "cart"
|
||||
icon_deny = "cart-deny"
|
||||
products = list(/obj/item/device/pda =10,/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/chemistry = 10,
|
||||
products = list(/obj/item/device/pda =10,/obj/item/weapon/cartridge/mob_hunt_game = 25,/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/chemistry = 10,
|
||||
/obj/item/weapon/cartridge/engineering = 10,/obj/item/weapon/cartridge/atmos = 10,/obj/item/weapon/cartridge/janitor = 10,
|
||||
/obj/item/weapon/cartridge/signal/toxins = 10,/obj/item/weapon/cartridge/signal = 10)
|
||||
contraband = list(/obj/item/weapon/cartridge/clown = 1,/obj/item/weapon/cartridge/mime = 1)
|
||||
prices = list(/obj/item/device/pda =300,/obj/item/weapon/cartridge/medical = 200,/obj/item/weapon/cartridge/chemistry = 150,/obj/item/weapon/cartridge/engineering = 100,
|
||||
prices = list(/obj/item/device/pda =300,/obj/item/weapon/cartridge/mob_hunt_game = 50,/obj/item/weapon/cartridge/medical = 200,/obj/item/weapon/cartridge/chemistry = 150,/obj/item/weapon/cartridge/engineering = 100,
|
||||
/obj/item/weapon/cartridge/atmos = 75,/obj/item/weapon/cartridge/janitor = 100,/obj/item/weapon/cartridge/signal/toxins = 150,
|
||||
/obj/item/weapon/cartridge/signal = 75)
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
if(!recharge_port)
|
||||
reconnect()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/mecha/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/mecha/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["screen"] = screen
|
||||
if(screen == 0)
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
ui.set_auto_update(1)
|
||||
|
||||
|
||||
/obj/item/device/aicard/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/device/aicard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
|
||||
var/mob/living/silicon/ai/AI = locate() in src
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/item/device/guitar/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, state)
|
||||
/obj/item/device/guitar/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/item/device/guitar/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
@@ -46,4 +46,4 @@
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(/obj/item/weapon/screwdriver, /obj/item/weapon/wirecutters)
|
||||
time = 80
|
||||
time = 80
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/device/radio/electropack/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/item/device/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["power"] = on
|
||||
|
||||
@@ -114,7 +114,7 @@ var/global/list/default_medbay_channels = list(
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/device/radio/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/item/device/radio/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["mic_status"] = broadcasting
|
||||
@@ -757,7 +757,7 @@ var/global/list/default_medbay_channels = list(
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/device/radio/borg/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/item/device/radio/borg/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["mic_status"] = broadcasting
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
// auto update every Master Controller tick
|
||||
//ui.set_auto_update(1)
|
||||
|
||||
/obj/item/device/transfer_valve/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/item/device/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["attachmentOne"] = tank_one ? tank_one.name : null
|
||||
|
||||
@@ -198,7 +198,7 @@ var/list/world_uplinks = list()
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/uplink/hidden/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/device/uplink/hidden/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
|
||||
data["welcome"] = welcome
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/item/device/violin/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, state)
|
||||
/obj/item/device/violin/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/item/device/violin/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
@@ -89,7 +89,7 @@ RCD
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/weapon/rcd/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/weapon/rcd/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
data["mode"] = mode
|
||||
data["door_type"] = door_type
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/weapon/tank/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/item/weapon/tank/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/using_internal
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/song/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/song/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["lines"] = lines
|
||||
@@ -296,8 +296,8 @@
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/structure/piano/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, state)
|
||||
/obj/structure/piano/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/structure/piano/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
@@ -120,10 +120,11 @@
|
||||
return 0
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter
|
||||
if(!B)
|
||||
blood_splatter(src,M.get_blood(M.vessel),1)
|
||||
B = locate(/obj/effect/decal/cleanable/blood) in contents
|
||||
B.add_blood_list(M)
|
||||
return 1 //we bloodied the floor
|
||||
B = blood_splatter(src,M.get_blood(M.vessel),1)
|
||||
if(B)
|
||||
B.add_blood_list(M)
|
||||
return 1 //we bloodied the floor
|
||||
return 0 // Clean floors club
|
||||
|
||||
// Only adds blood on the floor -- Skie
|
||||
/turf/simulated/add_blood_floor(mob/living/carbon/M as mob)
|
||||
|
||||
@@ -41,7 +41,8 @@ var/global/nologevent = 0
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
|
||||
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_living() + "</a>\]"
|
||||
|
||||
if(istype(M, /mob/new_player))
|
||||
body += " <B>Hasn't Entered Game</B> "
|
||||
|
||||
@@ -74,6 +74,7 @@ var/list/admin_verbs_admin = list(
|
||||
/client/proc/debug_variables,
|
||||
/client/proc/show_snpc_verbs,
|
||||
/client/proc/reset_all_tcs, /*resets all telecomms scripts*/
|
||||
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
|
||||
/client/proc/toggle_mentor_chat
|
||||
)
|
||||
var/list/admin_verbs_ban = list(
|
||||
|
||||
@@ -1996,6 +1996,15 @@
|
||||
|
||||
fax_panel(usr)
|
||||
|
||||
else if(href_list["getplaytimewindow"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/mob/M = locateUID(href_list["getplaytimewindow"])
|
||||
if(!M)
|
||||
to_chat(usr, "ERROR: Mob not found.")
|
||||
return
|
||||
cmd_show_exp_panel(M.client)
|
||||
|
||||
else if(href_list["jumpto"])
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal
|
||||
name = "Nano-Mob Hunter GO! Battle Terminal"
|
||||
desc = "Insert a mob card to partake in life-like Nano-Mob Battle Action!"
|
||||
icon_state = "mob_battle_empty"
|
||||
icon_screen = null
|
||||
icon_keyboard = null
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/obj/item/weapon/nanomob_card/card
|
||||
var/datum/mob_hunt/mob_info
|
||||
var/obj/effect/nanomob/battle/avatar
|
||||
var/ready = 0
|
||||
var/team = "Grey"
|
||||
var/avatar_x_offset = 4
|
||||
var/avatar_y_offset = 0
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/red
|
||||
pixel_y = 24
|
||||
dir = SOUTH
|
||||
team = "Red"
|
||||
avatar_y_offset = -1
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/blue
|
||||
pixel_y = -24
|
||||
dir = NORTH
|
||||
team = "Blue"
|
||||
avatar_y_offset = 1
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/red/initialize()
|
||||
..()
|
||||
check_connection()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/blue/initialize()
|
||||
..()
|
||||
check_connection()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/update_icon()
|
||||
if(card)
|
||||
icon_state = "mob_battle_loaded"
|
||||
else
|
||||
icon_state = "mob_battle_empty"
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/Destroy()
|
||||
eject_card(1)
|
||||
if(mob_hunt_server)
|
||||
if(mob_hunt_server.battle_turn)
|
||||
mob_hunt_server.battle_turn = null
|
||||
if(mob_hunt_server.red_terminal == src)
|
||||
mob_hunt_server.red_terminal = null
|
||||
if(mob_hunt_server.blue_terminal == src)
|
||||
mob_hunt_server.blue_terminal = null
|
||||
if(avatar)
|
||||
qdel(avatar)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/weapon/nanomob_card))
|
||||
insert_card(O, user)
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/insert_card(obj/item/weapon/nanomob_card/new_card, mob/user)
|
||||
if(!new_card)
|
||||
return
|
||||
if(card)
|
||||
to_chat(user, "<span class='warning'>The card slot is currently filled.</span>")
|
||||
return
|
||||
if(!new_card.mob_data)
|
||||
to_chat(user, "<span class='danger'>This is a blank mob card.</span>")
|
||||
return
|
||||
if(new_card.mob_data && !new_card.mob_data.cur_health)
|
||||
to_chat(user, "<span class='warning'>This mob is incapacitated! Heal it before attempting to use it in battle!</span>")
|
||||
return
|
||||
user.unEquip(new_card)
|
||||
new_card.forceMove(src)
|
||||
card = new_card
|
||||
mob_info = card.mob_data
|
||||
update_icon()
|
||||
update_avatar()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0)
|
||||
if(!override)
|
||||
if(ready && mob_hunt_server.battle_turn != team)
|
||||
audible_message("You can't recall on your rival's turn!", null, 2)
|
||||
return
|
||||
card.mob_data = mob_info
|
||||
mob_info = null
|
||||
card.forceMove(get_turf(src))
|
||||
card = null
|
||||
update_avatar()
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/update_avatar()
|
||||
//if we don't have avatars yet, spawn them
|
||||
if(!avatar)
|
||||
avatar = new(locate((x + avatar_x_offset), (y + avatar_y_offset), z))
|
||||
//update avatar info from card
|
||||
if(mob_info)
|
||||
avatar.mob_info = mob_info
|
||||
else
|
||||
avatar.mob_info = null
|
||||
//tell the avatar to update themself with the new info
|
||||
avatar.update_self()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attack_hand(mob/user)
|
||||
add_fingerprint(user)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/attack_ai(mob/user)
|
||||
to_chat(user, "<span class='warning'>You cannot interface with this portion of the simulation.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/interact(mob/user)
|
||||
check_connection()
|
||||
var/dat = ""
|
||||
dat += "<table border='1' style='width:75%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "[team] PLAYER"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
if(!card)
|
||||
dat += "<h1>No Nano-Mob card loaded.</h1>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(ready && mob_hunt_server.battle_turn) //offer the surrender option if they are in a battle (ready), but don't have a card loaded
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];surrender=1'>Surrender!</a></td>"
|
||||
dat += "</tr>"
|
||||
else
|
||||
dat += "<table>"
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "<h1>[mob_info.mob_name]</h1>"
|
||||
dat += "</td>"
|
||||
if(mob_info.nickname)
|
||||
dat += "<td rowspan='2'>"
|
||||
else
|
||||
dat += "<td>"
|
||||
var/img_src = "[mob_info.icon_state_normal].png"
|
||||
if(mob_info.is_shiny)
|
||||
dat += "[mob_info.icon_state_shiny].png"
|
||||
dat += "<img src='[img_src]'>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(mob_info.nickname)
|
||||
dat += "<tr>"
|
||||
dat += "<td>"
|
||||
dat += "<h2>[mob_info.nickname]</h2>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "<hr>"
|
||||
dat += "Health: [mob_info.cur_health] / [mob_info.max_health]<br>"
|
||||
dat += "<table border='1'>"
|
||||
dat += "<tr>"
|
||||
if(mob_info.cur_health)
|
||||
dat += "<td><a href='?src=[UID()];attack=1'>Attack!</a></td>"
|
||||
else
|
||||
dat += "<td>Incapacitated!</td>"
|
||||
dat += "<td><a href='?src=[UID()];eject=1'>Recall!</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "</td>"
|
||||
dat += "</tr>"
|
||||
if(!ready)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];ready=1'>Battle!</a></td>"
|
||||
dat += "</tr>"
|
||||
if(ready && !mob_hunt_server.battle_turn)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href='?src=[UID()];ready=2'>Cancel Battle!</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
var/datum/browser/popup = new(user, "mob_battle_terminal", "Nano-Mob Hunter GO! Battle Terminal", 575, 400)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["attack"])
|
||||
do_attack()
|
||||
|
||||
if(href_list["eject"])
|
||||
eject_card()
|
||||
|
||||
if(href_list["surrender"])
|
||||
surrender()
|
||||
|
||||
if(href_list["ready"])
|
||||
var/option = text2num(href_list["ready"])
|
||||
if(option == 1)
|
||||
start_battle()
|
||||
else if(option == 2)
|
||||
ready = 0
|
||||
audible_message("[team] Player cancels their battle challenge.", null, 5)
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/check_connection()
|
||||
if(team == "Red")
|
||||
if(mob_hunt_server && !mob_hunt_server.red_terminal)
|
||||
mob_hunt_server.red_terminal = src
|
||||
else if(team == "Blue")
|
||||
if(mob_hunt_server && !mob_hunt_server.blue_terminal)
|
||||
mob_hunt_server.blue_terminal = src
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/do_attack()
|
||||
if(!ready) //no attacking if you arent ready to fight (duh)
|
||||
return
|
||||
if(!mob_hunt_server || team != mob_hunt_server.battle_turn) //don't attack unless it is actually our turn
|
||||
return
|
||||
else
|
||||
var/message = "[mob_info.mob_name] attacks!"
|
||||
if(mob_info.nickname)
|
||||
message = "[mob_info.nickname] attacks!"
|
||||
audible_message(message, null, 5)
|
||||
mob_hunt_server.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type())
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/start_battle()
|
||||
if(ready) //don't do anything if we are still ready
|
||||
return
|
||||
if(!card) //don't do anything if there isn't a card inserted
|
||||
return
|
||||
ready = 1
|
||||
audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5)
|
||||
mob_hunt_server.start_check()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type)
|
||||
var/message = mob_info.take_damage(raw_damage, attack_type)
|
||||
avatar.audible_message(message, null, 5)
|
||||
if(!mob_info.cur_health)
|
||||
mob_hunt_server.end_battle(team)
|
||||
eject_card(1) //force the card out, they were defeated
|
||||
else
|
||||
mob_hunt_server.end_turn()
|
||||
|
||||
/obj/machinery/computer/mob_battle_terminal/proc/surrender()
|
||||
audible_message("[team] Player surrenders the battle!", null, 5)
|
||||
mob_hunt_server.end_battle(team, 1)
|
||||
|
||||
//////////////////////////////
|
||||
// Mob Healing Terminal //
|
||||
// (Pokemon Center) //
|
||||
//////////////////////////////
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal
|
||||
name = "Nano-Mob Hunter GO! Restoration Terminal"
|
||||
desc = "Swipe a mob card to instantly restore it to full health!"
|
||||
icon_state = "mob_battle_loaded"
|
||||
icon_screen = null
|
||||
icon_keyboard = null
|
||||
density = 0
|
||||
anchored = 1
|
||||
dir = EAST
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/weapon/nanomob_card))
|
||||
heal_card(O, user)
|
||||
|
||||
/obj/machinery/computer/mob_healer_terminal/proc/heal_card(obj/item/weapon/nanomob_card/patient, mob/user)
|
||||
if(!patient)
|
||||
return
|
||||
if(!patient.mob_data)
|
||||
to_chat(user, "<span class='danger'>This is a blank mob card.</span>")
|
||||
return
|
||||
if(patient.mob_data && patient.mob_data.cur_health == patient.mob_data.max_health)
|
||||
to_chat(user, "<span class='warning'>This mob is already at maximum health!</span>")
|
||||
return
|
||||
patient.mob_data.cur_health = patient.mob_data.max_health
|
||||
to_chat(user, "<span class='notify'>[patient.mob_data.nickname ? patient.mob_data.nickname : patient.mob_data.mob_name] has been restored to full health!</span>")
|
||||
@@ -0,0 +1,162 @@
|
||||
|
||||
/obj/effect/nanomob
|
||||
name = "Nano-Mob Avatar" //will be overridden by the mob datum name value when created
|
||||
desc = "A wild Nano-Mob appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
invisibility = 101
|
||||
alpha = 128
|
||||
anchored = 1 //just in case
|
||||
density = 0
|
||||
icon = 'icons/effects/mob_hunt.dmi'
|
||||
var/state_name
|
||||
var/datum/mob_hunt/mob_info = null
|
||||
var/list/clients_encountered = list() //tracks who has already interacted with us, so they can't attempt a second capture
|
||||
var/image/avatar
|
||||
|
||||
/obj/effect/nanomob/New(loc, datum/mob_hunt/new_info)
|
||||
..()
|
||||
if(!new_info)
|
||||
qdel(src)
|
||||
return
|
||||
mob_info = new_info
|
||||
update_self()
|
||||
forceMove(mob_info.spawn_point)
|
||||
if(!mob_info.is_trap)
|
||||
addtimer(src, "despawn", mob_info.lifetime)
|
||||
|
||||
/obj/effect/nanomob/proc/update_self()
|
||||
if(!mob_info)
|
||||
return
|
||||
name = mob_info.mob_name
|
||||
desc = "A wild [name] (level [mob_info.level]) appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
if(mob_info.is_shiny)
|
||||
state_name = mob_info.icon_state_shiny
|
||||
else
|
||||
state_name = mob_info.icon_state_normal
|
||||
avatar = image(icon, src, state_name)
|
||||
avatar.override = 1
|
||||
add_alt_appearance("nanomob_avatar", avatar)
|
||||
|
||||
/obj/effect/nanomob/attackby(obj/item/O, mob/user)
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P, -20) //attempting a melee capture reduces the mob's effective run_chance by 20% to balance the risk of triggering a trap mob
|
||||
return 1
|
||||
|
||||
/obj/effect/nanomob/hitby(obj/item/O)
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P) //attempting a ranged capture does not affect the mob's effective run_chance but does prevent you from being shocked by a trap mob
|
||||
return 1
|
||||
|
||||
/obj/effect/nanomob/proc/attempt_capture(obj/item/device/pda/P, catch_mod = 0) //negative catch_mods lower effective run chance,
|
||||
if(!P || !P.current_app || !istype(P.current_app, /datum/data/pda/app/mob_hunter_game) || !P.cartridge)
|
||||
return
|
||||
|
||||
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
|
||||
var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
|
||||
if(!client.connected) //must be connected to attempt captures
|
||||
P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
|
||||
return
|
||||
|
||||
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
|
||||
if(client.hacked) //hacked copies of the game (copies capable of setting traps) are protected from traps
|
||||
return
|
||||
if(iscarbon(P.loc))
|
||||
var/mob/living/carbon/C = P.loc
|
||||
//Strike them down with a lightning bolt to complete the illusion (copied from the surge reagent overdose, probably could make this a general-use proc in the future)
|
||||
playsound(get_turf(C), 'sound/effects/eleczap.ogg', 75, 1)
|
||||
var/icon/I=new('icons/obj/zap.dmi',"lightningend")
|
||||
I.Turn(-135)
|
||||
var/obj/effect/overlay/beam/B = new(get_turf(C))
|
||||
B.pixel_x = rand(-20, 0)
|
||||
B.pixel_y = rand(-20, 0)
|
||||
B.icon = I
|
||||
//then actually do the damage/stun
|
||||
C.electrocute_act(20, P, 1) //same damage as a revenant's overload ability, except subject to gloves/species shock resistance (for human mobs at least)
|
||||
return
|
||||
|
||||
if(client in clients_encountered) //we've already dealt with you, go away!
|
||||
return
|
||||
else //deal with the new hunter by either running away or getting caught
|
||||
clients_encountered += client
|
||||
var/message = "[bicon(P)] "
|
||||
var/effective_run_chance = mob_info.run_chance + total_catch_mod
|
||||
if((effective_run_chance > 0) && prob(effective_run_chance))
|
||||
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
|
||||
conceal(client)
|
||||
else
|
||||
if(client.register_capture(mob_info, 1))
|
||||
message += "Capture success! [P.owner ? P.owner : "This hunter"] captured [name]!"
|
||||
conceal(client)
|
||||
else
|
||||
message += "Capture error! Try again."
|
||||
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
|
||||
P.audible_message(message, null, 4)
|
||||
|
||||
/obj/effect/nanomob/proc/despawn()
|
||||
if(mob_hunt_server)
|
||||
if(mob_info.is_trap)
|
||||
mob_hunt_server.trap_spawns -= src
|
||||
else
|
||||
mob_hunt_server.normal_spawns -= src
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/nanomob/proc/reveal()
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/show_to = list()
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) || !mob_hunt_server.connected_clients[A])
|
||||
continue
|
||||
show_to |= mob_hunt_server.connected_clients[A]
|
||||
display_alt_appearance("nanomob_avatar", show_to)
|
||||
|
||||
/obj/effect/nanomob/proc/conceal(list/hide_from)
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/hiding_from = list()
|
||||
if(hide_from)
|
||||
hiding_from = hide_from
|
||||
else
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) && mob_hunt_server.connected_clients[A])
|
||||
hiding_from |= mob_hunt_server.connected_clients[A]
|
||||
hide_alt_appearance("nanomob_avatar", hiding_from)
|
||||
|
||||
// BATTLE MOB AVATARS
|
||||
|
||||
/obj/effect/nanomob/battle
|
||||
name = "Nano-Mob Battle Avatar"
|
||||
desc = "A new challenger approaches!"
|
||||
invisibility = 0
|
||||
icon_state = "placeholder"
|
||||
var/obj/machinery/computer/mob_battle_terminal/my_terminal
|
||||
|
||||
/obj/effect/nanomob/battle/New(loc, datum/mob_hunt/new_info)
|
||||
if(new_info)
|
||||
mob_info = new_info
|
||||
update_self()
|
||||
|
||||
/obj/effect/nanomob/battle/update_self()
|
||||
if(!mob_info)
|
||||
name = "Nano-Mob Battle Avatar"
|
||||
desc = "A new challenger approaches"
|
||||
icon_state = "placeholder"
|
||||
else
|
||||
name = mob_info.mob_name
|
||||
desc = "A tamed [name] (level [mob_info.level]) ready for battle!"
|
||||
if(mob_info.is_shiny)
|
||||
icon_state = mob_info.icon_state_shiny
|
||||
else
|
||||
icon_state = mob_info.icon_state_normal
|
||||
|
||||
/obj/effect/nanomob/battle/attempt_capture(obj/item/device/pda/P, catch_mod = 0)
|
||||
//you can't capture battle avatars, since they belong to someone already
|
||||
return
|
||||
|
||||
//battle avatars are always visible, so we can ignore reveal and conceal calls for them
|
||||
/obj/effect/nanomob/battle/reveal()
|
||||
return
|
||||
|
||||
/obj/effect/nanomob/battle/conceal()
|
||||
return
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
//Standard Cards
|
||||
/obj/item/weapon/nanomob_card
|
||||
name = "Nano-Mob Hunter Trading Card"
|
||||
desc = "A blank Nano-Mob Hunter Trading Card. Worthless!"
|
||||
icon = 'icons/obj/card.dmi'
|
||||
icon_state = "trade_card"
|
||||
force = 0
|
||||
throwforce = 1
|
||||
w_class = 1
|
||||
var/datum/mob_hunt/mob_data
|
||||
|
||||
/obj/item/weapon/nanomob_card/proc/update_info()
|
||||
if(!mob_data)
|
||||
return
|
||||
if(mob_data.is_shiny)
|
||||
name = "Holographic [mob_data.mob_name] Nano-Mob Hunter Card"
|
||||
desc = "WOW! A holographic trading card containing a level [mob_data.level] [mob_data.mob_name]!"
|
||||
icon_state = "trade_card_holo"
|
||||
else
|
||||
name = "[mob_data.mob_name] Nano-Mob Hunter Card"
|
||||
desc = "A trading card containing a level [mob_data.level] [mob_data.mob_name]!"
|
||||
|
||||
//Booster Pack Cards (random mob data)
|
||||
/obj/item/weapon/nanomob_card/booster
|
||||
name = "Nano-Mob Hunter Booster Pack Card"
|
||||
desc = "A random Nano-Mob Trading Card from a Booster Pack. Wonder what it is?"
|
||||
|
||||
/obj/item/weapon/nanomob_card/booster/New()
|
||||
var/datum/mob_hunt/mob_info = pick(subtypesof(/datum/mob_hunt))
|
||||
mob_data = new mob_info(0,null,1)
|
||||
update_info()
|
||||
|
||||
//Booster Packs (Box of booster pack cards)
|
||||
/obj/item/weapon/storage/box/nanomob_booster_pack
|
||||
name = "Nano-Mob Hunter Trading Card Booster Pack"
|
||||
desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!"
|
||||
can_hold = list("/obj/item/weapon/nanomob_card")
|
||||
|
||||
/obj/item/weapon/storage/box/nanomob_booster_pack/New()
|
||||
..()
|
||||
for(var/i in 1 to 6)
|
||||
new /obj/item/weapon/nanomob_card/booster(src)
|
||||
@@ -0,0 +1,501 @@
|
||||
|
||||
#define TYPE_FIRE /datum/mob_type/fire
|
||||
#define TYPE_WATER /datum/mob_type/water
|
||||
#define TYPE_GRASS /datum/mob_type/grass
|
||||
#define TYPE_ELECTRIC /datum/mob_type/electric
|
||||
#define TYPE_GROUND /datum/mob_type/ground
|
||||
#define TYPE_ROCK /datum/mob_type/rock
|
||||
#define TYPE_BUG /datum/mob_type/bug
|
||||
#define TYPE_POISON /datum/mob_type/poison
|
||||
#define TYPE_NORMAL /datum/mob_type/normal
|
||||
#define TYPE_FIGHTING /datum/mob_type/fighting
|
||||
#define TYPE_PSYCHIC /datum/mob_type/psychic
|
||||
#define TYPE_GHOST /datum/mob_type/ghost
|
||||
#define TYPE_ICE /datum/mob_type/ice
|
||||
#define TYPE_FLYING /datum/mob_type/flying
|
||||
#define TYPE_BLUESPACE /datum/mob_type/bluespace
|
||||
#define TYPE_DARK /datum/mob_type/dark
|
||||
#define TYPE_STEEL /datum/mob_type/steel
|
||||
|
||||
/datum/mob_hunt
|
||||
//GENERAL STATS AND VARIABLES
|
||||
var/mob_name = "Generic Mob" //the mob's original name (its species/type/whatever)
|
||||
var/nickname = "" //the mob's nickname (if given by the owner)
|
||||
var/run_chance = 0 //percent chance the mob will escape capture attempts (higher is obviously more likely to get away)
|
||||
|
||||
//COMBAT STATS AND VARIABLES
|
||||
var/level = 0 //actual level of this mob (don't set this, it gets overwritten in New())
|
||||
var/min_level = 1 //minimum level of this mob (used for randomizing the actual level)
|
||||
var/max_level = 1 //maximum level of this mob (used for randomizing the actual level)
|
||||
var/exp = 0 //number of battles the mob has won towards the next level (resets to 0 on level-up)
|
||||
var/exp_to_level = 3 //number of battles the mob must win to level up (in case we want to make some mobs harder or easier to level)
|
||||
//the types of the mob will be used for battles to determine damage resistance or weakness (mob_type_datums.dm)
|
||||
var/datum/mob_type/primary_type //Make sure you set this or the mob will be unable to deal damage and will take absurd damage in battles
|
||||
var/datum/mob_type/secondary_type //Don't set if not a dual-type mob so the mob will only calculate damage based on primary type
|
||||
var/base_attack = 5 //base damage dealt by the mob's attacks for battling (effectively damage dealt at level 0)
|
||||
var/base_health = 5 //base health of the mob for battling (effectively max health at level 0)
|
||||
var/attack_multiplier = 1 //how much additional damage per level the mob deals (level * attack_multiplier)
|
||||
var/health_multiplier = 1 //how much additional health per level the mob gets (level * health_multiplier) for calculating max health
|
||||
var/cur_health = 0
|
||||
var/max_health = 0
|
||||
|
||||
//SPAWN PREFERENCES AND VARIABLES
|
||||
//A note on mob spawn preferences: The mob types also have preferences, which are handled prior to per-mob preferences, so ultimately you use a combined set of preferences
|
||||
var/list/area_blacklist = list() //list of areas this mob can NOT spawn in (such as the bridge)
|
||||
var/list/turf_blacklist = list() //list of turfs this mob can NOT spawn on (such as wood floors)
|
||||
var/list/area_whitelist = list() //list of areas this mob is more likely to spawn in (can be used to reinclude subtypes of blacklisted areas)
|
||||
var/list/turf_whitelist = list() //list of turfs this mob is more likely to spawn on (can be used to reinclude subtypes of blacklisted turfs)
|
||||
var/turf/spawn_point //gets set and sent to the game server to spawn its avatar (generated in select_spawn or assigned via set_trap)
|
||||
var/lifetime = 6000 //number of deciseconds the mob will remain before despawning (REMEMBER: DECISECONDS! So 6000 is 600 seconds which is 10 minutes)
|
||||
var/is_shiny = 0 //if this gets set at spawn (super rare), the mob is considered "shiny" and will use the shiny icon_state and holographic cards
|
||||
|
||||
//the icon file for mob_hunt stuff is 'icons/effects/mob_hunt.dmi' so reference that for the following vars
|
||||
var/icon_state_normal = "placeholder" //the icon_state for this mob's normal version
|
||||
var/icon_state_shiny = "placeholder" //the icon_state for this mob's rare shiney version
|
||||
|
||||
var/is_trap = 0 //if this gets set, the mob is a booby-trap and will electrocute any players that dare attempt to catch it
|
||||
|
||||
/datum/mob_hunt/New(set_trap = 0, turf/trap_turf = null, no_register = 0)
|
||||
if(set_trap)
|
||||
level = max_level
|
||||
is_trap = 1
|
||||
spawn_point = trap_turf
|
||||
else
|
||||
level = rand(min_level, max_level)
|
||||
if(prob(1) && prob(1))
|
||||
is_shiny = 1
|
||||
max_health = base_health + (level * health_multiplier)
|
||||
cur_health = max_health
|
||||
if(primary_type)
|
||||
primary_type = new primary_type()
|
||||
if(secondary_type)
|
||||
secondary_type = new secondary_type()
|
||||
if(no_register) //for booster pack cards
|
||||
return
|
||||
if(mob_hunt_server)
|
||||
if(set_trap)
|
||||
if(mob_hunt_server.register_trap(src))
|
||||
return
|
||||
else if(select_spawn())
|
||||
if(mob_hunt_server.register_spawn(src))
|
||||
return
|
||||
qdel(src) //if you reach this, the datum is just pure clutter, so delete it
|
||||
|
||||
/datum/mob_hunt/proc/select_spawn()
|
||||
var/list/possible_areas = get_possible_areas()
|
||||
if(!possible_areas.len)
|
||||
log_admin("No possible areas to spawn [type] found. Possible code/mapping error?")
|
||||
return 0
|
||||
while(possible_areas.len)
|
||||
//randomly select an area from our possible_areas list to try spawning in, then remove it from possible_areas so it won't get picked over and over forever.
|
||||
var/area/spawn_area = locate(pickweight(possible_areas))
|
||||
possible_areas -= spawn_area
|
||||
if(!spawn_area)
|
||||
break
|
||||
//clear and generate a fresh list of turfs in the selected area, weighted based on white/black lists
|
||||
var/list/possible_turfs = get_possible_turfs(spawn_area)
|
||||
if(!possible_turfs.len) //If we don't have any possible turfs, this attempt was a failure. Try again.
|
||||
continue
|
||||
//if we got this far, we're spawning on this attempt, hooray!
|
||||
spawn_point = pickweight(possible_turfs)
|
||||
break
|
||||
if(!spawn_point)
|
||||
//if we get to this, we failed every attempt to find a suitable turf for EVERY area in our list of possible areas. DAMN.
|
||||
log_admin("No acceptable turfs to spawn [type] on could be located. Possible code/mapping error, or someone replaced/destroyed all the acceptable turf types?")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/mob_hunt/proc/get_possible_areas()
|
||||
var/list/possible_areas = list()
|
||||
//setup, sets all station areas (and subtypes) to weight 1
|
||||
for(var/A in the_station_areas)
|
||||
if(A == /area/holodeck) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well
|
||||
continue
|
||||
if(A in possible_areas)
|
||||
continue
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] = 1
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
for(var/A in primary_type.area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in primary_type.area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
for(var/A in secondary_type.area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in secondary_type.area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//mob preferences
|
||||
for(var/A in area_whitelist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] += 4
|
||||
for(var/A in area_blacklist)
|
||||
for(var/areapath in typesof(A))
|
||||
possible_areas[areapath] -= 2
|
||||
//removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
|
||||
var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
|
||||
for(var/A in bad_areas)
|
||||
possible_areas -= A
|
||||
//weight check, remove negative or zero weight areas from the list, then return the list.
|
||||
for(var/areapath in possible_areas)
|
||||
//remove any areas that shouldn't be on the station-level
|
||||
if(possible_areas[areapath] < 1)
|
||||
possible_areas -= areapath
|
||||
continue
|
||||
return possible_areas
|
||||
|
||||
/datum/mob_hunt/proc/get_possible_turfs(area/spawn_area)
|
||||
if(!spawn_area)
|
||||
return list()
|
||||
var/list/possible_turfs = list()
|
||||
//setup, sets all turfs in spawn_area to weight 1
|
||||
for(var/turf/T in spawn_area)
|
||||
if(!is_station_level(T.z)) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars
|
||||
continue
|
||||
possible_turfs[T] = 1
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
if(is_type_in_list(T, primary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, primary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
if(is_type_in_list(T, secondary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, secondary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//mob preferences
|
||||
if(is_type_in_list(T, turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//weight check, remove negative or zero weight turfs from the list, then return the list
|
||||
if(possible_turfs[T] < 1)
|
||||
possible_turfs -= T
|
||||
return possible_turfs
|
||||
|
||||
/datum/mob_hunt/proc/calc_def_multiplier(datum/mob_type/attack_type)
|
||||
if(!primary_type)
|
||||
return 99 //typeless mobs are weak to everything since they shouldn't exist
|
||||
if(!attack_type) //typeless attacks will return a multiplier of 1 in case we want to use this for calculating unmodified damage for some reason (UI maybe?)
|
||||
return 1
|
||||
|
||||
var/multiplier = 1
|
||||
if(attack_type in primary_type.immunity)
|
||||
return 0 //a single immunity negates all damage
|
||||
else if(attack_type in primary_type.resistance)
|
||||
multiplier *= 0.5
|
||||
else if(attack_type in primary_type.weakness)
|
||||
multiplier *= 2
|
||||
else
|
||||
multiplier *= 1
|
||||
|
||||
if(!secondary_type) //if we don't have a second type, we're done here
|
||||
return multiplier
|
||||
if(attack_type in secondary_type.immunity)
|
||||
return 0 //a single immunity negates all damage
|
||||
else if(attack_type in secondary_type.resistance)
|
||||
multiplier *= 0.5
|
||||
else if(attack_type in secondary_type.weakness)
|
||||
multiplier *= 2
|
||||
else
|
||||
multiplier *= 1
|
||||
return multiplier
|
||||
|
||||
/datum/mob_hunt/proc/take_damage(raw_damage, datum/mob_type/attack_type)
|
||||
var/message = ""
|
||||
var/multiplier = calc_def_multiplier(attack_type)
|
||||
var/total_damage = raw_damage * multiplier
|
||||
if(!cur_health) //it's already downed, quit hitting it
|
||||
return null
|
||||
if(!total_damage)
|
||||
message += "The attack is completely ineffective! "
|
||||
else
|
||||
cur_health = max(cur_health - total_damage, 0)
|
||||
switch(multiplier)
|
||||
if(0)
|
||||
message += "The attack is completely ineffective! "
|
||||
if(0.25)
|
||||
message += "It's barely effective... "
|
||||
if(0.5)
|
||||
message += "It's not very effective... "
|
||||
if(2)
|
||||
message += "It's super effective! "
|
||||
if(4)
|
||||
message += "It's ultra effective! "
|
||||
if(99)
|
||||
message += pick("REKT! ", "DUNKED! ", "DEFENSE BREAK! ", "WOMBO-COMBO'D!")
|
||||
if(!cur_health)
|
||||
message += "[nickname ? nickname : mob_name] is downed!"
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/get_raw_damage()
|
||||
return (level * attack_multiplier)
|
||||
|
||||
/datum/mob_hunt/proc/get_attack_type()
|
||||
var/datum/mob_type/attack_type = primary_type
|
||||
if(secondary_type && prob(40))
|
||||
attack_type = secondary_type
|
||||
return attack_type
|
||||
|
||||
/datum/mob_hunt/proc/gain_exp()
|
||||
exp++
|
||||
var/message = "[nickname ? nickname : mob_name] gained EXP! ([exp] / [exp_to_level] EXP)"
|
||||
if(exp >= exp_to_level)
|
||||
message = levelup()
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/levelup()
|
||||
var/message = ""
|
||||
level++
|
||||
exp = 0
|
||||
if(level > max_level) //This is where we would trigger an evolution, when those are added (need to add evolved forms first)
|
||||
level = max_level //for now though, we'll just cap them back at their max_level
|
||||
message += "[nickname ? nickname : mob_name] can't get any stronger right now!"
|
||||
else
|
||||
max_health = base_health + (level * health_multiplier)
|
||||
cur_health = max_health //full heal on level-up
|
||||
message += "[nickname ? nickname : mob_name] has reached level [level]!"
|
||||
return message
|
||||
|
||||
/datum/mob_hunt/proc/get_type1()
|
||||
if(!primary_type)
|
||||
return "Typeless"
|
||||
else
|
||||
return primary_type.name
|
||||
|
||||
/datum/mob_hunt/proc/get_type2()
|
||||
if(!secondary_type)
|
||||
return null
|
||||
else
|
||||
return secondary_type.name
|
||||
|
||||
|
||||
/datum/mob_hunt/nemabug
|
||||
mob_name = "Nemabug"
|
||||
run_chance = 50
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_BUG
|
||||
icon_state_normal = "nemabug"
|
||||
icon_state_shiny = "nemabug_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/stoutquill
|
||||
mob_name = "Stoutquill"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_ICE
|
||||
icon_state_normal = "stoutquill"
|
||||
icon_state_shiny = "stoutquill_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/spectra
|
||||
mob_name = "Spectra"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_POISON
|
||||
icon_state_normal = "spectra"
|
||||
icon_state_shiny = "spectra_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/dunny
|
||||
mob_name = "Dunny"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_FIRE
|
||||
icon_state_normal = "dunny"
|
||||
icon_state_shiny = "dunny_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/buffsel
|
||||
mob_name = "Buffsel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_ROCK
|
||||
icon_state_normal = "buffsel"
|
||||
icon_state_shiny = "buffsel_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/quarrel
|
||||
mob_name = "Quarrel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_NORMAL
|
||||
icon_state_normal = "quarrel"
|
||||
icon_state_shiny = "quarrel_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/vulerrt
|
||||
mob_name = "Vulerrt"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_DARK
|
||||
icon_state_normal = "vulerrt"
|
||||
icon_state_shiny = "vulerrt_shiny"
|
||||
turf_whitelist = list()
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/strudel
|
||||
mob_name = "Strudel"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_ELECTRIC
|
||||
icon_state_normal = "strudel"
|
||||
icon_state_shiny = "strudel_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/folstick
|
||||
mob_name = "Folstick"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_WATER
|
||||
icon_state_normal = "folstick"
|
||||
icon_state_shiny = "folstick_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/glimmerflare
|
||||
mob_name = "Glimmerflare"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_PSYCHIC
|
||||
icon_state_normal = "glimmerflare"
|
||||
icon_state_shiny = "glimmerflare_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/leecoon
|
||||
mob_name = "Leecoon"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_GRASS
|
||||
icon_state_normal = "leecoon"
|
||||
icon_state_shiny = "leecoon_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/halk
|
||||
mob_name = "Halk"
|
||||
run_chance = 35
|
||||
min_level = 1
|
||||
max_level = 10
|
||||
primary_type = TYPE_FLYING
|
||||
icon_state_normal = "halk"
|
||||
icon_state_shiny = "halk_shiny"
|
||||
lifetime = 6000
|
||||
|
||||
/datum/mob_hunt/gooby
|
||||
mob_name = "Gooby"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_ELECTRIC
|
||||
secondary_type = TYPE_BUG
|
||||
icon_state_normal = "gooby"
|
||||
icon_state_shiny = "gooby_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/pandoom
|
||||
mob_name = "Pandoom"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 15
|
||||
primary_type = TYPE_GHOST
|
||||
icon_state_normal = "pandoom"
|
||||
icon_state_shiny = "pandoom_shiny"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/relish
|
||||
mob_name = "Relish"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_GROUND
|
||||
icon_state_normal = "relish"
|
||||
icon_state_shiny = "relish_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/xofine
|
||||
mob_name = "Xofine"
|
||||
run_chance = 50
|
||||
min_level = 5
|
||||
max_level = 10
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_NORMAL
|
||||
icon_state_normal = "xofine"
|
||||
icon_state_shiny = "xofine_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/gitten
|
||||
mob_name = "Gitten"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_WATER
|
||||
secondary_type = TYPE_POISON
|
||||
icon_state_normal = "gitten"
|
||||
icon_state_shiny = "gitten_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/nai
|
||||
mob_name = "Nai"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_GRASS
|
||||
secondary_type = TYPE_NORMAL
|
||||
icon_state_normal = "nai"
|
||||
icon_state_shiny = "nai_shiny"
|
||||
lifetime = 3000
|
||||
|
||||
/datum/mob_hunt/pyroghast
|
||||
mob_name = "Pyroghast"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIRE
|
||||
secondary_type = TYPE_GHOST
|
||||
icon_state_normal = "pyroghast"
|
||||
icon_state_shiny = "pyroghast"
|
||||
lifetime = 4500
|
||||
|
||||
/datum/mob_hunt/starslam
|
||||
mob_name = "Starslam"
|
||||
run_chance = 65
|
||||
min_level = 5
|
||||
max_level = 20
|
||||
primary_type = TYPE_FIGHTING
|
||||
secondary_type = TYPE_ICE
|
||||
icon_state_normal = "starslam"
|
||||
icon_state_shiny = "starslam_shiny"
|
||||
lifetime = 2500
|
||||
|
||||
/datum/mob_hunt/pheron
|
||||
mob_name = "Pheron"
|
||||
run_chance = 85
|
||||
min_level = 10
|
||||
max_level = 20
|
||||
primary_type = TYPE_BLUESPACE
|
||||
icon_state_normal = "pheron"
|
||||
icon_state_shiny = "pheron_shiny"
|
||||
area_blacklist = list()
|
||||
turf_blacklist = list()
|
||||
area_whitelist = list()
|
||||
turf_whitelist = list()
|
||||
lifetime = 2000
|
||||
@@ -0,0 +1,256 @@
|
||||
|
||||
/datum/mob_type
|
||||
var/name = "Typeless"
|
||||
var/list/weakness = list()
|
||||
var/list/resistance = list()
|
||||
var/list/immunity = list()
|
||||
|
||||
//Type-based spawn preferences (to eliminate copy-pasting the same area and turf lists on each mob type)
|
||||
var/list/area_blacklist = list() //areas to be avoided
|
||||
var/list/area_whitelist = list() //areas to be more preferred
|
||||
var/list/turf_blacklist = list() //turf types to be avoided
|
||||
var/list/turf_whitelist = list() //turf types to be more preferred
|
||||
|
||||
//Type defines, to avoid spelling mistakes
|
||||
/datum/mob_type/fire
|
||||
name = "Fire"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_ROCK,
|
||||
TYPE_GROUND)
|
||||
resistance = list(TYPE_BUG,
|
||||
TYPE_FIRE,
|
||||
TYPE_GRASS,
|
||||
TYPE_ICE,
|
||||
TYPE_STEEL)
|
||||
area_blacklist = list(/area/crew_quarters/toilet,
|
||||
/area/crew_quarters/sleep_male/toilet_male,
|
||||
/area/crew_quarters/sleep_female/toilet_female,
|
||||
/area/crew_quarters/locker/locker_toilet,
|
||||
/area/toxins/server_coldroom)
|
||||
area_whitelist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
turf_blacklist = list(/turf/simulated/floor/beach/water)
|
||||
|
||||
/datum/mob_type/water
|
||||
name = "Water"
|
||||
weakness = list(TYPE_ELECTRIC,
|
||||
TYPE_GRASS)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_ICE,
|
||||
TYPE_STEEL,
|
||||
TYPE_WATER)
|
||||
area_blacklist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
area_whitelist = list(/area/crew_quarters/toilet,
|
||||
/area/crew_quarters/sleep_male/toilet_male,
|
||||
/area/crew_quarters/sleep_female/toilet_female,
|
||||
/area/crew_quarters/locker/locker_toilet)
|
||||
turf_whitelist = list(/turf/simulated/floor/beach/water)
|
||||
|
||||
/datum/mob_type/grass
|
||||
name = "Grass"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_BUG,
|
||||
TYPE_POISON,
|
||||
TYPE_ICE,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ELECTRIC,
|
||||
TYPE_GROUND)
|
||||
area_blacklist = list(/area/toxins)
|
||||
area_whitelist = list(/area/hydroponics,
|
||||
/area/hallway/secondary/construction)
|
||||
turf_whitelist = list(/turf/simulated/floor/grass)
|
||||
|
||||
/datum/mob_type/electric
|
||||
name = "Electric"
|
||||
weakness = list(TYPE_GROUND)
|
||||
resistance = list(TYPE_ELECTRIC,
|
||||
TYPE_FLYING,
|
||||
TYPE_STEEL)
|
||||
area_whitelist = list(/area/engine,
|
||||
/area/toxins/server,
|
||||
/area/maintenance,
|
||||
/area/turret_protected/ai,
|
||||
/area/turret_protected/ai_upload,
|
||||
/area/turret_protected/aisat_interior,
|
||||
/area/aisat,
|
||||
/area/assembly)
|
||||
turf_whitelist = list(/turf/simulated/floor/bluegrid)
|
||||
|
||||
/datum/mob_type/ground
|
||||
name = "Ground"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ICE)
|
||||
resistance = list(TYPE_ROCK,
|
||||
TYPE_POISON)
|
||||
immunity = list(TYPE_ELECTRIC)
|
||||
|
||||
/datum/mob_type/rock
|
||||
name = "Rock"
|
||||
weakness = list(TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING,
|
||||
TYPE_STEEL)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_FLYING,
|
||||
TYPE_POISON,
|
||||
TYPE_NORMAL)
|
||||
area_whitelist = list(/area/quartermaster,
|
||||
/area/maintenance/disposal)
|
||||
turf_whitelist = list(/turf/simulated/wall,
|
||||
/turf/simulated/floor/mineral)
|
||||
|
||||
/datum/mob_type/bug
|
||||
name = "Bug"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_ROCK,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING)
|
||||
area_blacklist = list(/area/toxins)
|
||||
area_whitelist = list(/area/hydroponics,
|
||||
/area/hallway/secondary/construction)
|
||||
turf_whitelist = list(/turf/simulated/floor/grass)
|
||||
|
||||
/datum/mob_type/poison
|
||||
name = "Poison"
|
||||
weakness = list(TYPE_GROUND,
|
||||
TYPE_PSYCHIC)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_BUG,
|
||||
TYPE_POISON,
|
||||
TYPE_FIGHTING)
|
||||
area_blacklist = list(/area/medical,
|
||||
/area/security/medbay,
|
||||
/area/janitor)
|
||||
area_whitelist = list(/area/medical/virology,
|
||||
/area/toxins,
|
||||
/area/medical/research,
|
||||
/area/medical/research_shuttle_dock,
|
||||
/area/crew_quarters/hor,
|
||||
/area/maintenance/asmaint2)
|
||||
|
||||
/datum/mob_type/normal
|
||||
name = "Normal"
|
||||
weakness = list(TYPE_FIGHTING)
|
||||
immunity = list(TYPE_GHOST)
|
||||
|
||||
/datum/mob_type/fighting
|
||||
name = "Fighting"
|
||||
weakness = list(TYPE_PSYCHIC,
|
||||
TYPE_FLYING)
|
||||
resistance = list(TYPE_ROCK,
|
||||
TYPE_BUG,
|
||||
TYPE_DARK)
|
||||
area_blacklist = list(/area/medical)
|
||||
area_whitelist = list(/area/crew_quarters/bar,
|
||||
/area/crew_quarters/fitness,
|
||||
/area/security)
|
||||
turf_whitelist = list(/turf/simulated/floor/wood)
|
||||
|
||||
/datum/mob_type/psychic
|
||||
name = "Psychic"
|
||||
weakness = list(TYPE_BUG,
|
||||
TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
resistance = list(TYPE_FIGHTING,
|
||||
TYPE_PSYCHIC)
|
||||
area_blacklist = list(/area/toxins,
|
||||
/area/medical/research,
|
||||
/area/medical/research_shuttle_dock,
|
||||
/area/crew_quarters/hor,
|
||||
/area/maintenance/asmaint2,
|
||||
/area/teleporter,
|
||||
/area/gateway)
|
||||
area_whitelist = list(/area/library,
|
||||
/area/chapel,
|
||||
/area/medical/psych)
|
||||
|
||||
/datum/mob_type/ghost
|
||||
name = "Ghost"
|
||||
weakness = list(TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
resistance = list(TYPE_BUG,
|
||||
TYPE_POISON)
|
||||
immunity = list(TYPE_NORMAL,
|
||||
TYPE_FIGHTING)
|
||||
area_whitelist = list(/area/medical/morgue,
|
||||
/area/chapel,
|
||||
/area/medical/genetics_cloning)
|
||||
|
||||
/datum/mob_type/ice
|
||||
name = "Ice"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_ROCK,
|
||||
TYPE_FIGHTING,
|
||||
TYPE_STEEL)
|
||||
resistance = list(TYPE_ICE)
|
||||
area_blacklist = list(/area/maintenance/turbine,
|
||||
/area/maintenance/incinerator,
|
||||
/area/crew_quarters/kitchen)
|
||||
area_whitelist = list(/area/toxins/server_coldroom)
|
||||
|
||||
/datum/mob_type/flying
|
||||
name = "Flying"
|
||||
weakness = list(TYPE_ELECTRIC,
|
||||
TYPE_ROCK,
|
||||
TYPE_ICE)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_BUG,
|
||||
TYPE_FIGHTING)
|
||||
immunity = list(TYPE_GROUND)
|
||||
area_blacklist = list(/area/maintenance)
|
||||
area_whitelist = list(/area/hallway,
|
||||
/area/escapepodbay,
|
||||
/area/engine/mechanic_workshop,
|
||||
/area/security/podbay)
|
||||
|
||||
/datum/mob_type/bluespace
|
||||
name = "Bluespace"
|
||||
weakness = list(TYPE_ICE,
|
||||
TYPE_BLUESPACE)
|
||||
resistance = list(TYPE_FIRE,
|
||||
TYPE_WATER,
|
||||
TYPE_GRASS,
|
||||
TYPE_ELECTRIC)
|
||||
|
||||
/datum/mob_type/dark
|
||||
name = "Dark"
|
||||
weakness = list(TYPE_BUG,
|
||||
TYPE_FIGHTING)
|
||||
resistance = list(TYPE_GHOST,
|
||||
TYPE_DARK)
|
||||
immunity = list(TYPE_PSYCHIC)
|
||||
area_blacklist = list(/area/solar,
|
||||
/area/maintenance/auxsolarport,
|
||||
/area/maintenance/starboardsolar,
|
||||
/area/maintenance/portsolar,
|
||||
/area/maintenance/auxsolarstarboard,
|
||||
/area/clownoffice)
|
||||
area_whitelist = list(/area/maintenance,
|
||||
/area/assembly/assembly_line,
|
||||
/area/mimeoffice)
|
||||
turf_blacklist = list(/turf/simulated/floor/light)
|
||||
|
||||
/datum/mob_type/steel
|
||||
name = "Steel"
|
||||
weakness = list(TYPE_FIRE,
|
||||
TYPE_GROUND,
|
||||
TYPE_FIGHTING)
|
||||
resistance = list(TYPE_GRASS,
|
||||
TYPE_ROCK,
|
||||
TYPE_BUG,
|
||||
TYPE_NORMAL,
|
||||
TYPE_PSYCHIC,
|
||||
TYPE_ICE,
|
||||
TYPE_FLYING,
|
||||
TYPE_BLUESPACE,
|
||||
TYPE_STEEL)
|
||||
immunity = list(TYPE_POISON)
|
||||
@@ -190,6 +190,12 @@ var/global/datum/prizes/global_prizes = new
|
||||
typepath = /obj/item/weapon/spellbook/oneuse/fake_gib
|
||||
cost = 100
|
||||
|
||||
/datum/prize_item/nanomob_booster
|
||||
name = "Nano-Mob Hunter Trading Card Booster Pack"
|
||||
desc = "Contains 6 random Nano-Mob Hunter Trading Cards. May contain a holographic card!"
|
||||
typepath = /obj/item/weapon/storage/box/nanomob_booster_pack
|
||||
cost = 100
|
||||
|
||||
/datum/prize_item/capgun
|
||||
name = "Capgun Revolver"
|
||||
desc = "Do you feel lucky... punk?"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/artillerycontrol/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/artillerycontrol/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/time_to_wait = round(reload_cooldown - ((world.time / 10) - last_fire), 1)
|
||||
|
||||
@@ -9,14 +9,14 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
unacidable = 1
|
||||
var/active = 0
|
||||
|
||||
/obj/machinery/gateway/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
update_density_from_dir()
|
||||
|
||||
/obj/machinery/gateway/New()
|
||||
if(!the_gateway)
|
||||
the_gateway = src
|
||||
spawn(25)
|
||||
update_icon()
|
||||
if(dir == 2)
|
||||
density = 0
|
||||
/obj/machinery/gateway/proc/update_density_from_dir()
|
||||
if(dir == 2)
|
||||
density = 0
|
||||
|
||||
|
||||
/obj/machinery/gateway/update_icon()
|
||||
@@ -40,13 +40,18 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
var/obj/machinery/gateway/centeraway/awaygate = null
|
||||
|
||||
/obj/machinery/gateway/centerstation/New()
|
||||
..()
|
||||
if(!the_gateway)
|
||||
the_gateway = src
|
||||
spawn(25)
|
||||
update_icon()
|
||||
wait = world.time + config.gateway_delay //+ thirty minutes default
|
||||
awaygate = locate(/obj/machinery/gateway/centeraway) in world
|
||||
|
||||
/obj/machinery/gateway/centerstation/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
wait = world.time + config.gateway_delay //+ thirty minutes default
|
||||
awaygate = locate(/obj/machinery/gateway/centeraway) in world
|
||||
|
||||
/obj/machinery/gateway/centerstation/update_density_from_dir()
|
||||
return
|
||||
|
||||
/obj/machinery/gateway/centerstation/Destroy()
|
||||
if(the_gateway == src)
|
||||
@@ -61,7 +66,7 @@ var/obj/machinery/gateway/centerstation/the_gateway = null
|
||||
|
||||
|
||||
|
||||
obj/machinery/gateway/centerstation/process()
|
||||
/obj/machinery/gateway/centerstation/process()
|
||||
if(stat & (NOPOWER))
|
||||
if(active) toggleoff()
|
||||
return
|
||||
@@ -165,12 +170,15 @@ obj/machinery/gateway/centerstation/process()
|
||||
var/obj/machinery/gateway/centeraway/stationgate = null
|
||||
|
||||
|
||||
/obj/machinery/gateway/centeraway/New()
|
||||
spawn(25)
|
||||
update_icon()
|
||||
stationgate = locate(/obj/machinery/gateway/centerstation) in world
|
||||
/obj/machinery/gateway/centeraway/initialize()
|
||||
..()
|
||||
update_icon()
|
||||
stationgate = locate(/obj/machinery/gateway/centerstation) in world
|
||||
|
||||
|
||||
/obj/machinery/gateway/centeraway/update_density_from_dir()
|
||||
return
|
||||
|
||||
/obj/machinery/gateway/centeraway/update_icon()
|
||||
if(active)
|
||||
icon_state = "oncenter"
|
||||
|
||||
@@ -261,6 +261,8 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
send_asset_list(client, uncommon)
|
||||
send_asset_list(client, common)
|
||||
|
||||
|
||||
//Pill sprites for UIs
|
||||
/datum/asset/chem_master
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
@@ -274,4 +276,21 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
|
||||
//Mob Hunt sprites for UIs
|
||||
/datum/asset/mob_hunt
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/mob_hunt/register()
|
||||
for(var/state in icon_states('icons/effects/mob_hunt.dmi'))
|
||||
if(state == "Placeholder")
|
||||
continue
|
||||
assets["[state].png"] = icon('icons/effects/mob_hunt.dmi', state)
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/mob_hunt/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
@@ -111,49 +111,49 @@
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Barber",5)
|
||||
DB_job_unlock("Barber",5)
|
||||
return
|
||||
if("2")
|
||||
if(karma <5)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Brig Physician",5)
|
||||
DB_job_unlock("Brig Physician",5)
|
||||
return
|
||||
if("3")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Nanotrasen Representative",30)
|
||||
DB_job_unlock("Nanotrasen Representative",30)
|
||||
return
|
||||
if("5")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Blueshield",30)
|
||||
DB_job_unlock("Blueshield",30)
|
||||
return
|
||||
if("6")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Mechanic",30)
|
||||
DB_job_unlock("Mechanic",30)
|
||||
return
|
||||
if("7")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Magistrate",45)
|
||||
DB_job_unlock("Magistrate",45)
|
||||
return
|
||||
if("9")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_job_unlock("Security Pod Pilot",30)
|
||||
DB_job_unlock("Security Pod Pilot",30)
|
||||
return
|
||||
if(href_list["KarmaBuy2"])
|
||||
var/karma=verify_karma()
|
||||
@@ -163,55 +163,55 @@
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Machine",15)
|
||||
DB_species_unlock("Machine",15)
|
||||
return
|
||||
if("2")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Kidan",30)
|
||||
DB_species_unlock("Kidan",30)
|
||||
return
|
||||
if("3")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Grey",30)
|
||||
DB_species_unlock("Grey",30)
|
||||
return
|
||||
if("4")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Vox",45)
|
||||
DB_species_unlock("Vox",45)
|
||||
return
|
||||
if("5")
|
||||
if(karma <45)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Slime People",45)
|
||||
DB_species_unlock("Slime People",45)
|
||||
return
|
||||
if("6")
|
||||
if(karma <100)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Plasmaman",100)
|
||||
DB_species_unlock("Plasmaman",100)
|
||||
return
|
||||
if("7")
|
||||
if(karma <30)
|
||||
to_chat(usr, "You do not have enough karma!")
|
||||
return
|
||||
else
|
||||
src.DB_species_unlock("Drask",30)
|
||||
DB_species_unlock("Drask",30)
|
||||
return
|
||||
if(href_list["KarmaRefund"])
|
||||
var/type = href_list["KarmaRefundType"]
|
||||
var/job = href_list["KarmaRefund"]
|
||||
var/cost = href_list["KarmaRefundCost"]
|
||||
src.karmarefund(type,job,cost)
|
||||
karmarefund(type,job,cost)
|
||||
return
|
||||
|
||||
switch(href_list["_src_"])
|
||||
@@ -273,6 +273,7 @@
|
||||
//CONNECT//
|
||||
///////////
|
||||
/client/New(TopicData)
|
||||
var/tdata = TopicData //save this for later use
|
||||
chatOutput = new /datum/chatOutput(src) // Right off the bat.
|
||||
TopicData = null //Prevent calls to client.Topic from connect
|
||||
|
||||
@@ -290,8 +291,8 @@
|
||||
|
||||
// Change the way they should download resources.
|
||||
if(config.resource_urls)
|
||||
src.preload_rsc = pick(config.resource_urls)
|
||||
else src.preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
|
||||
preload_rsc = pick(config.resource_urls)
|
||||
else preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
|
||||
|
||||
to_chat(src, "\red If the title screen is black, resources are still downloading. Please be patient until the title screen appears.")
|
||||
|
||||
@@ -340,7 +341,7 @@
|
||||
winset(src, null, "command=\".configure graphics-hwmode off\"")
|
||||
winset(src, null, "command=\".configure graphics-hwmode on\"")
|
||||
|
||||
log_client_to_db()
|
||||
log_client_to_db(tdata)
|
||||
|
||||
if(ckey in clientmessages)
|
||||
for(var/message in clientmessages[ckey])
|
||||
@@ -399,7 +400,7 @@
|
||||
donator_level = text2num(query_donor_select.item[2])
|
||||
break
|
||||
|
||||
/client/proc/log_client_to_db()
|
||||
/client/proc/log_client_to_db(connectiontopic)
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
@@ -430,6 +431,14 @@
|
||||
if(ckey != query_cid.item[1])
|
||||
related_accounts_cid.Add("[query_cid.item[1]]")
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(holder)
|
||||
admin_rank = holder.rank
|
||||
// Admins don't get slammed by this, I guess
|
||||
else
|
||||
if(check_randomizer(connectiontopic))
|
||||
return
|
||||
|
||||
//Log all the alts
|
||||
if(related_accounts_cid.len)
|
||||
log_access("Alts: [key_name(src)]:[jointext(related_accounts_cid, " - ")]")
|
||||
@@ -446,10 +455,6 @@
|
||||
if(!isnum(sql_id))
|
||||
return
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(src.holder)
|
||||
admin_rank = src.holder.rank
|
||||
|
||||
var/sql_ip = sanitizeSQL(address)
|
||||
var/sql_computerid = sanitizeSQL(computer_id)
|
||||
var/sql_admin_rank = sanitizeSQL(admin_rank)
|
||||
@@ -469,11 +474,128 @@
|
||||
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');")
|
||||
query_accesslog.Execute()
|
||||
|
||||
|
||||
#undef TOPIC_SPAM_DELAY
|
||||
#undef UPLOAD_LIMIT
|
||||
#undef MIN_CLIENT_VERSION
|
||||
|
||||
// Returns true if a randomizer is being used
|
||||
/client/proc/check_randomizer(topic)
|
||||
. = FALSE
|
||||
if(connection != "seeker") //Invalid connection type.
|
||||
return null
|
||||
topic = params2list(topic)
|
||||
if(!config.check_randomizer)
|
||||
return
|
||||
// Stash o' ckeys
|
||||
var/static/cidcheck = list()
|
||||
var/static/tokens = list()
|
||||
// Ckeys that failed the test, stored to send acceptance messages only for atoners
|
||||
var/static/cidcheck_failedckeys = list()
|
||||
var/static/cidcheck_spoofckeys = list()
|
||||
|
||||
var/oldcid = cidcheck[ckey]
|
||||
|
||||
if(!oldcid)
|
||||
var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
|
||||
query_cidcheck.Execute()
|
||||
|
||||
var/lastcid = computer_id
|
||||
if(query_cidcheck.NextRow())
|
||||
lastcid = query_cidcheck.item[1]
|
||||
|
||||
if(computer_id != lastcid)
|
||||
// Their current CID does not match what the DB says - OFF WITH THEIR HEAD
|
||||
cidcheck[ckey] = computer_id
|
||||
|
||||
// Disable the reconnect button to force a CID change
|
||||
winset(src, "reconnectbutton", "is-disable=true")
|
||||
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
sleep(10) // Since browse is non-instant, and kinda async
|
||||
|
||||
to_chat(src, "<pre class=\"system system\">you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point</pre>")
|
||||
del(src)
|
||||
return TRUE
|
||||
else
|
||||
if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
|
||||
if (!cidcheck_spoofckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] appears to have attempted to spoof a cid randomizer check.</span>")
|
||||
cidcheck_spoofckeys[ckey] = TRUE
|
||||
cidcheck[ckey] = computer_id
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
|
||||
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.
|
||||
del(src)
|
||||
return TRUE
|
||||
// We DO have their cached CID handy - compare it, now
|
||||
if(oldcid != computer_id)
|
||||
// Change detected, they are randomizing
|
||||
cidcheck -= ckey // To allow them to try again after removing CID randomization
|
||||
|
||||
to_chat(src, "<span class='userdanger'>Connection Error:</span>")
|
||||
to_chat(src, "<span class='danger'>Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your BYOND installation and try again.</span>")
|
||||
|
||||
if(!cidcheck_failedckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] has been detected as using a CID randomizer. Connection rejected.</span>")
|
||||
send2irc(config.cidrandomizer_irc, "[key_name(src)] has been detected as using a CID randomizer. Connection rejected.")
|
||||
cidcheck_failedckeys[ckey] = TRUE
|
||||
note_randomizer_user()
|
||||
|
||||
log_access("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])")
|
||||
|
||||
del(src)
|
||||
return TRUE
|
||||
else
|
||||
// don't shoot, I'm innocent
|
||||
if(cidcheck_failedckeys[ckey])
|
||||
// Atonement
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer</span>")
|
||||
send2irc(config.cidrandomizer_irc, "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
|
||||
cidcheck_failedckeys -= ckey
|
||||
if (cidcheck_spoofckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it <i>appears</i> they aren't spoofing one this time</span>")
|
||||
cidcheck_spoofckeys -= ckey
|
||||
cidcheck -= ckey
|
||||
|
||||
/client/proc/note_randomizer_user()
|
||||
var/const/adminckey = "CID-Error"
|
||||
|
||||
// Check for notes in the last day - only 1 note per 24 hours
|
||||
var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n")
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
return
|
||||
|
||||
// Only add a note if their most recent note isn't from the randomizer blocker, either
|
||||
query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1")
|
||||
if(!query_get_notes.Execute())
|
||||
var/err = query_get_notes.ErrorMsg()
|
||||
log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n")
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
if(query_get_notes.item[1] == adminckey)
|
||||
return
|
||||
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0)
|
||||
|
||||
/client/proc/cid_check_reconnect()
|
||||
var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
|
||||
. = token
|
||||
log_access("Failed Login: [key] [computer_id] [address] - CID randomizer check")
|
||||
var/url = winget(src, null, "url")
|
||||
//special javascript to make them reconnect under a new window.
|
||||
src << browse("<a id='link' href='byond://[url]?token=[token]'>\
|
||||
byond://[url]?token=[token]\
|
||||
</a>\
|
||||
<script type='text/javascript'>\
|
||||
document.getElementById(\"link\").click();\
|
||||
window.location=\"byond://winset?command=.quit\"\
|
||||
</script>",
|
||||
"border=0;titlebar=0;size=1x1")
|
||||
to_chat(src, "<a href='byond://[url]?token=[token]'>You will be automatically taken to the game, if not, click here to be taken manually</a>. Except you can't, since the chat window doesn't exist yet.")
|
||||
|
||||
//checks if a client is afk
|
||||
//3000 frames = 5 minutes
|
||||
/client/proc/is_afk(duration=3000)
|
||||
|
||||
@@ -74,3 +74,8 @@
|
||||
/datum/gear/skullbandana
|
||||
display_name = "bandana, skull"
|
||||
path = /obj/item/clothing/mask/bandana/skull
|
||||
|
||||
/datum/gear/mob_hunt_game
|
||||
display_name = "Nano-Mob Hunter GO! Cartridge"
|
||||
path = /obj/item/weapon/cartridge/mob_hunt_game
|
||||
cost = 2
|
||||
|
||||
@@ -82,6 +82,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
|
||||
//game-preferences
|
||||
var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
|
||||
var/exp
|
||||
var/ooccolor = "#b82e00"
|
||||
var/be_special = list() //Special role selection
|
||||
var/UI_style = "Midnight"
|
||||
@@ -593,6 +594,10 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
if(jobban_isbanned(user, rank))
|
||||
HTML += "<del>[rank]</del></td><td><b> \[BANNED]</b></td></tr>"
|
||||
continue
|
||||
var/available_in_playtime = job.available_in_playtime(user.client)
|
||||
if(available_in_playtime)
|
||||
HTML += "<del>[rank]</del></td><td> \[ " + get_exp_format(available_in_playtime) + " as " + job.get_exp_req_type() + "</td></tr>"
|
||||
continue
|
||||
if(!job.player_old_enough(user.client))
|
||||
var/available_in_days = job.available_in_days(user.client)
|
||||
HTML += "<del>[rank]</del></td><td> \[IN [(available_in_days)] DAYS]</td></tr>"
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
volume,
|
||||
nanoui_fancy,
|
||||
show_ghostitem_attack,
|
||||
lastchangelog
|
||||
lastchangelog,
|
||||
exp
|
||||
FROM [format_table_name("player")]
|
||||
WHERE ckey='[C.ckey]'"}
|
||||
)
|
||||
@@ -40,6 +41,7 @@
|
||||
nanoui_fancy = text2num(query.item[11])
|
||||
show_ghostitem_attack = text2num(query.item[12])
|
||||
lastchangelog = query.item[13]
|
||||
exp = query.item[14]
|
||||
|
||||
//Sanitize
|
||||
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
|
||||
@@ -54,6 +56,7 @@
|
||||
nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy))
|
||||
show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack))
|
||||
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
|
||||
exp = sanitize_text(exp, initial(exp))
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/save_preferences(client/C)
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
var/invis_override = 0
|
||||
|
||||
var/emagged = 0
|
||||
var/color_view = null//overrides client.color while worn
|
||||
var/list/color_view = null//overrides client.color while worn
|
||||
var/prescription = 0
|
||||
var/prescription_upgradable = 0
|
||||
strip_delay = 20 // but seperated to allow items to protect but not impair vision, like space helmets
|
||||
|
||||
@@ -243,26 +243,35 @@
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/proc/toggle_noir()
|
||||
var/list/difference = difflist(usr.client.color, color_view)
|
||||
|
||||
if(!noir_mode)
|
||||
if(color_view && usr.client && !usr.client.color)
|
||||
if(color_view && usr.client && (!usr.client.color || difference))
|
||||
animate(usr.client, color = color_view, time = 10)
|
||||
noir_mode = 1
|
||||
else
|
||||
if(usr.client && usr.client.color)
|
||||
animate(usr.client, color = null, time = 10)
|
||||
if(usr.client && usr.client.color && !difference)
|
||||
animate(usr.client, color = initial(usr.client.color), time = 10)
|
||||
noir_mode = 0
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/equipped(mob/user, slot)
|
||||
var/list/difference = difflist(user.client.color, color_view)
|
||||
|
||||
if(slot == slot_glasses)
|
||||
if(noir_mode)
|
||||
if(color_view && user.client && !user.client.color)
|
||||
if(color_view && user.client && (!user.client.color || difference.len))
|
||||
animate(user.client, color = color_view, time = 10)
|
||||
else
|
||||
if(user.client && user.client.color && !difference.len)
|
||||
animate(user.client, color = initial(user.client.color), time = 10)
|
||||
..(user, slot)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/noir/dropped(mob/living/carbon/human/user)
|
||||
var/list/difference = difflist(user.client.color, color_view)
|
||||
|
||||
if(istype(user) && user.glasses == src)
|
||||
if(user.client && user.client.color)
|
||||
animate(user.client, color = null, time = 10)
|
||||
if(user.client && user.client.color && !difference.len)
|
||||
animate(user.client, color = initial(user.client.color), time = 10)
|
||||
..(user)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/yeah
|
||||
|
||||
@@ -514,7 +514,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/item/weapon/rig/ui_data(mob/user, datum/topic_state/state = inventory_state)
|
||||
/obj/item/weapon/rig/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
|
||||
var/data[0]
|
||||
|
||||
data["primarysystem"] = null
|
||||
|
||||
@@ -313,6 +313,11 @@
|
||||
icon_state = "eyepro"
|
||||
item_state = "eyepro"
|
||||
|
||||
/obj/item/clothing/glasses/hud/security/sunglasses/fluff/voxxyhud //LP Spartan: Kaskreyarawkta
|
||||
name = "VoxxyHUD"
|
||||
desc = "A worn down visor from a vox raider's gear, crudely ripped from its helmet and linked into the security systems of the station. The word 'Kask' is scratched into the side."
|
||||
icon_state = "hud-spartan"
|
||||
|
||||
//////////// Hats ////////////
|
||||
/obj/item/clothing/head/fluff/heather_winceworth // Regens: Heather Winceworth
|
||||
name= "Heather's rose"
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/account_database/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/computer/account_database/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["src"] = UID()
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
ui = new(user, src, ui_key, "smartfridge.tmpl", name, 400, 500)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/smartfridge/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/smartfridge/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["contents"] = null
|
||||
|
||||
@@ -634,14 +634,20 @@
|
||||
chems[rid] = gene_chem.Copy()
|
||||
continue
|
||||
|
||||
// Normally a length 2 list - but sometimes, it's length 1 - poisonberries, etc.
|
||||
// This means the reagent does not scale with potency.
|
||||
// Index 1 is the base value, index 2 is the potency per u of reagent
|
||||
var/list/rgnt_list = chems[rid]
|
||||
rgnt_list.len = max(gene_chem.len, rgnt_list.len)
|
||||
|
||||
for(var/i=1;i<=gene_chem.len;i++)
|
||||
|
||||
if(isnull(gene_chem[i])) gene_chem[i] = 0
|
||||
|
||||
if(chems[rid][i])
|
||||
chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2))
|
||||
if(rgnt_list[i])
|
||||
rgnt_list[i] = max(1,round((gene_chem[i] + rgnt_list[i])/2))
|
||||
else
|
||||
chems[rid][i] = gene_chem[i]
|
||||
rgnt_list[i] = gene_chem[i]
|
||||
|
||||
var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"]
|
||||
if(islist(new_gasses))
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/botany/extractor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/botany/extractor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/list/geneMasks[0]
|
||||
@@ -318,7 +318,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/botany/editor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/obj/machinery/botany/editor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
data["activity"] = active
|
||||
|
||||
@@ -428,6 +428,19 @@
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/terrorspider
|
||||
name = "Spider Hivemind"
|
||||
desc = "Terror spiders have a limited ability to commune over a psychic hivemind, similar to xenomorphs."
|
||||
speech_verb = "chitters"
|
||||
ask_verb = "chitters"
|
||||
exclaim_verb = "chitters"
|
||||
colour = "terrorspider"
|
||||
key = "ts"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/ling
|
||||
name = "Changeling"
|
||||
desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance."
|
||||
@@ -559,7 +572,7 @@
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
drone_only = 1
|
||||
follow = 1
|
||||
|
||||
|
||||
/datum/language/drone
|
||||
name = "Drone"
|
||||
desc = "An encrypted stream of data converted to speech patterns."
|
||||
|
||||
@@ -454,8 +454,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
|
||||
totalMembers |= pipeline.other_atmosmch
|
||||
for(var/obj/machinery/atmospherics/A in totalMembers)
|
||||
if(!A.pipe_image)
|
||||
A.pipe_image = image(A, A.loc, layer = 20, dir = A.dir) //the 20 puts it above Byond's darkness (not its opacity view)
|
||||
A.pipe_image.plane = HUD_PLANE
|
||||
A.update_pipe_image()
|
||||
pipes_shown += A.pipe_image
|
||||
client.images += A.pipe_image
|
||||
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
|
||||
aiRestorePowerRoutine = 0
|
||||
clear_fullscreen("blind")
|
||||
update_sight()
|
||||
else if(aiRestorePowerRoutine == 3)
|
||||
to_chat(src, "Alert cancelled. Power has been restored.")
|
||||
aiRestorePowerRoutine = 0
|
||||
clear_fullscreen("blind")
|
||||
update_sight()
|
||||
|
||||
|
||||
else
|
||||
|
||||
@@ -114,8 +114,6 @@
|
||||
C.toff = 1
|
||||
..()
|
||||
|
||||
/mob/living/silicon/pai/Login()
|
||||
..()
|
||||
|
||||
// this function shows the information about being silenced as a pAI in the Status panel
|
||||
/mob/living/silicon/pai/proc/show_silenced()
|
||||
|
||||
@@ -41,7 +41,12 @@ var/global/list/default_pai_software = list()
|
||||
if(ui_key != "main")
|
||||
var/datum/pai_software/S = software[ui_key]
|
||||
if(S && !S.toggle)
|
||||
S.on_ui_interact(src, ui, force_open)
|
||||
ui = nanomanager.try_update_ui(user, src, S.id, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, S.id, S.template_file, S.ui_title, S.ui_width, S.ui_height, state = state)
|
||||
ui.open()
|
||||
if(S.autoupdate)
|
||||
ui.set_auto_update(1)
|
||||
else
|
||||
if(ui)
|
||||
ui.set_status(STATUS_CLOSE, 0)
|
||||
@@ -53,9 +58,15 @@ var/global/list/default_pai_software = list()
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/mob/living/silicon/pai/ui_data(mob/user, datum/topic_state/state = self_state)
|
||||
/mob/living/silicon/pai/ui_data(mob/user, ui_key = "main", datum/topic_state/state = self_state)
|
||||
var/data[0]
|
||||
|
||||
if(ui_key != "main")
|
||||
var/datum/pai_software/S = software[ui_key]
|
||||
if(S && !S.toggle)
|
||||
return S.on_ui_data(user, state)
|
||||
log_runtime(EXCEPTION("Unrecognized/invalid pAI UI state '[ui_key]'"), src)
|
||||
return
|
||||
// Software we have bought
|
||||
var/bought_software[0]
|
||||
// Software we have not bought
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -285,6 +285,7 @@
|
||||
|
||||
if(player.mob && player.mob.mind)
|
||||
player.mob.mind.transfer_to(src)
|
||||
player.mob.mind.assigned_role = "Drone"
|
||||
|
||||
lawupdate = 0
|
||||
to_chat(src, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>.")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
#define SPINNING_WEB 1
|
||||
#define LAYING_EGGS 2
|
||||
#define MOVING_TO_TARGET 3
|
||||
#define SPINNING_COCOON 4
|
||||
|
||||
#define TS_TIER_1 1
|
||||
#define TS_TIER_2 2
|
||||
#define TS_TIER_3 3
|
||||
#define TS_TIER_4 4
|
||||
#define TS_TIER_5 5
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
|
||||
/datum/action/innate/terrorspider/web
|
||||
name = "Web"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "stickyweb1"
|
||||
|
||||
/datum/action/innate/terrorspider/web/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.Web()
|
||||
|
||||
/datum/action/innate/terrorspider/wrap
|
||||
name = "Wrap"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "cocoon_large1"
|
||||
|
||||
/datum/action/innate/terrorspider/wrap/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.FindWrapTarget()
|
||||
user.DoWrap()
|
||||
|
||||
|
||||
// ---------- WEB
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web()
|
||||
visible_message("<span class='notice'>[src] begins to secrete a sticky substance.</span>")
|
||||
if(do_after(src, 40, target = loc))
|
||||
var/obj/effect/spider/terrorweb/T = locate() in get_turf(src)
|
||||
if(T)
|
||||
to_chat(src, "<span class='danger'>There is already a web here.</span>")
|
||||
else
|
||||
new /obj/effect/spider/terrorweb(loc)
|
||||
|
||||
/obj/effect/spider/terrorweb
|
||||
name = "terror web"
|
||||
desc = "it's stringy and sticky"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
anchored = 1 // prevents people dragging it
|
||||
density = 0 // prevents it blocking all movement
|
||||
health = 20 // two welders, or one laser shot (15 for the normal spider webs)
|
||||
icon_state = "stickyweb1"
|
||||
|
||||
|
||||
/obj/effect/spider/terrorweb/New()
|
||||
..()
|
||||
if(prob(50))
|
||||
icon_state = "stickyweb2"
|
||||
|
||||
|
||||
/obj/effect/spider/terrorweb/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
return 1
|
||||
if(isliving(mover))
|
||||
if(prob(80))
|
||||
to_chat(mover, "<span class='danger'>You get stuck in [src] for a moment.</span>")
|
||||
var/mob/living/M = mover
|
||||
M.Stun(4) // 8 seconds.
|
||||
M.Weaken(4) // 8 seconds.
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
return prob(20)
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------- WRAP
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget()
|
||||
if(!cocoon_target)
|
||||
var/list/choices = list()
|
||||
for(var/mob/living/L in oview(1,src))
|
||||
if(Adjacent(L))
|
||||
if(L.stat == DEAD)
|
||||
choices += L
|
||||
for(var/obj/O in oview(1,src))
|
||||
if(Adjacent(O) && !O.anchored)
|
||||
if(!istype(O, /obj/effect/spider/terrorweb) && !istype(O, /obj/effect/spider/cocoon))
|
||||
choices += O
|
||||
if(choices.len)
|
||||
cocoon_target = input(src,"What do you wish to cocoon?") in null|choices
|
||||
else
|
||||
to_chat(src, "<span class='danger'>There is nothing nearby you can wrap.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoWrap()
|
||||
if(cocoon_target && busy != SPINNING_COCOON)
|
||||
busy = SPINNING_COCOON
|
||||
visible_message("<span class='notice'>[src] begins to secrete a sticky substance around [cocoon_target].</span>")
|
||||
stop_automated_movement = 1
|
||||
walk(src,0)
|
||||
if(do_after(src, 40, target = cocoon_target.loc))
|
||||
if(busy == SPINNING_COCOON)
|
||||
if(cocoon_target && isturf(cocoon_target.loc) && get_dist(src,cocoon_target) <= 1)
|
||||
var/obj/effect/spider/cocoon/C = new(cocoon_target.loc)
|
||||
var/large_cocoon = 0
|
||||
C.pixel_x = cocoon_target.pixel_x
|
||||
C.pixel_y = cocoon_target.pixel_y
|
||||
for(var/obj/O in C.loc)
|
||||
if(istype(O, /obj/item))
|
||||
O.loc = C
|
||||
else if(istype(O, /obj/machinery) || istype(O, /obj/structure))
|
||||
O.loc = C
|
||||
large_cocoon = 1
|
||||
for(var/mob/living/L in C.loc)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
continue
|
||||
if(iscarbon(L))
|
||||
regen_points += regen_points_per_kill
|
||||
fed++
|
||||
large_cocoon = 1
|
||||
last_cocoon_object = 0
|
||||
L.loc = C
|
||||
C.pixel_x = L.pixel_x
|
||||
C.pixel_y = L.pixel_y
|
||||
visible_message("<span class='danger'>[src] sticks a proboscis into [L] and sucks a viscous substance out.</span>")
|
||||
break
|
||||
if(large_cocoon)
|
||||
C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
|
||||
cocoon_target = null
|
||||
busy = 0
|
||||
stop_automated_movement = 0
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T2 BLACK TERROR ------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: assassin, poisoner, DoT expert
|
||||
// -------------: AI: attacks to inject its venom, then retreats. Will inject its enemies multiple times then hang back to ensure they die.
|
||||
// -------------: SPECIAL: venom that does more damage the more of it is in you
|
||||
// -------------: TO FIGHT IT: if bitten once, retreat, get charcoal/etc treatment, and come back with a gun.
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/black
|
||||
name = "Black Terror spider"
|
||||
desc = "An ominous-looking spider, black as the darkest night, and with merciless eyes and a blood-red hourglass pattern on its back."
|
||||
spider_role_summary = "Hit-and-run attacker with extremely venomous bite."
|
||||
|
||||
icon_state = "terror_widow"
|
||||
icon_living = "terror_widow"
|
||||
icon_dead = "terror_widow_dead"
|
||||
maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but its bite will kill you!
|
||||
health = 120
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 10
|
||||
move_to_delay = 5
|
||||
stat_attack = 1 // ensures they will target people in crit, too!
|
||||
spider_tier = TS_TIER_2
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/black/spider_specialattack(mob/living/carbon/human/L, poisonable)
|
||||
if(!poisonable)
|
||||
return ..()
|
||||
if(L.reagents.has_reagent("terror_black_toxin", 50))
|
||||
return ..()
|
||||
var/inject_target = pick("chest", "head")
|
||||
if(L.stunned || L.can_inject(null, 0, inject_target, 0))
|
||||
L.reagents.add_reagent("terror_black_toxin", 15) // inject our special poison
|
||||
visible_message("<span class='danger'>[src] buries its long fangs deep into the [inject_target] of [target]!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] bites [target], but cannot inject venom into their [inject_target]!</span>")
|
||||
L.attack_animal(src)
|
||||
@@ -0,0 +1,33 @@
|
||||
// Terror Spider, Black, Deadly Venom
|
||||
|
||||
/datum/reagent/terror_black_toxin
|
||||
name = "Black Widow venom"
|
||||
id = "terror_black_toxin"
|
||||
description = "An incredibly toxic venom injected by the Black Widow spider."
|
||||
color = "#CF3600"
|
||||
metabolization_rate = 0.1
|
||||
|
||||
/datum/reagent/terror_black_toxin/on_mob_life(mob/living/M)
|
||||
if(volume < 15)
|
||||
// bitten once, die slowly. Easy to survive a single bite - just go to medbay.
|
||||
// total damage: 2/tick, human health 150 until crit, = 75 ticks, = 150 seconds = 2.5 minutes to get to medbay.
|
||||
M.adjustToxLoss(2) // same damage/tick as tabun cycle 0 to 60
|
||||
else if(volume < 30)
|
||||
// bitten twice, die more quickly, muscle cramps make movement difficult. Call medics immediately.
|
||||
// total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death
|
||||
M.adjustToxLoss(4)
|
||||
M.Confused(3)
|
||||
M.EyeBlurry(3)
|
||||
else if(volume < 45)
|
||||
// bitten thrice, die very quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you.
|
||||
// total damage: 8, human health 150 until crit, = 18.75 ticks, = 37s until death
|
||||
M.adjustToxLoss(8) // a bit worse than coiine
|
||||
M.Confused(6)
|
||||
M.EyeBlurry(6)
|
||||
else
|
||||
// bitten 4 or more times, whole body goes into shock/death
|
||||
// total damage: 12, human health 150 until crit, = 12.5 ticks, = 25s until death
|
||||
M.adjustToxLoss(12)
|
||||
M.EyeBlurry(6)
|
||||
M.Paralyse(5)
|
||||
..()
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Topic(href, href_list)
|
||||
if(href_list["activate"])
|
||||
var/mob/dead/observer/ghost = usr
|
||||
if(istype(ghost))
|
||||
humanize_spider(ghost)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/attack_ghost(mob/user)
|
||||
humanize_spider(user)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/humanize_spider(mob/user)
|
||||
if(key)//Someone is in it
|
||||
return
|
||||
var/error_on_humanize = ""
|
||||
var/humanize_prompt = "Take direct control of [src]?"
|
||||
humanize_prompt += "Role: [spider_role_summary]"
|
||||
if(user.ckey in ts_ckey_blacklist)
|
||||
error_on_humanize = "You are not able to control any terror spider this round."
|
||||
else if(!ai_playercontrol_allowingeneral)
|
||||
error_on_humanize = "Terror spiders cannot currently be player-controlled."
|
||||
else if(spider_awaymission)
|
||||
error_on_humanize = "Terror spiders that are part of an away mission cannot be controlled by ghosts."
|
||||
else if(!ai_playercontrol_allowtype)
|
||||
error_on_humanize = "This specific type of terror spider is not player-controllable."
|
||||
else if(stat == DEAD)
|
||||
error_on_humanize = "Dead spiders are not player-controllable."
|
||||
if(jobban_isbanned(user, "Syndicate") || jobban_isbanned(user, "alien"))
|
||||
to_chat(user,"You are jobbanned from role of syndicate and/or alien lifeform.")
|
||||
return
|
||||
if(error_on_humanize == "")
|
||||
var/spider_ask = alert(humanize_prompt, "Join as Terror Spider?", "Yes", "No")
|
||||
if(spider_ask == "No" || !src || qdeleted(src))
|
||||
return
|
||||
else
|
||||
to_chat(user, "Cannot inhabit spider: [error_on_humanize]")
|
||||
return
|
||||
if(key)
|
||||
to_chat(user, "<span class='notice'>Someone else already took this spider.</span>")
|
||||
return
|
||||
key = user.key
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
G.show_message("<i>A ghost has taken control of <b>[src]</b>. ([ghost_follow_link(src, ghost=G)]).</i>")
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T1 GRAY TERROR -------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: fast, weak terror spider
|
||||
// -------------: SPECIAL: silences targets
|
||||
// -------------: TO FIGHT IT: shoot it!
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/gray
|
||||
name = "Gray Terror spider"
|
||||
desc = "An ominous-looking gray spider, it seems jittery."
|
||||
spider_role_summary = "Fast-moving but weak spider."
|
||||
icon_state = "terror_gray"
|
||||
icon_living = "terror_gray"
|
||||
icon_dead = "terror_gray_dead"
|
||||
maxHealth = 120 // same health as hunter spider, aka, pretty weak.. but silences its targets
|
||||
health = 120
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 20
|
||||
ventcrawler = 1
|
||||
move_to_delay = 5 // normal speed
|
||||
stat_attack = 1 // ensures they will target people in crit, too!
|
||||
environment_smash = 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_specialattack(mob/living/carbon/human/L, poisonable)
|
||||
if(!poisonable)
|
||||
..()
|
||||
return
|
||||
if(L.silent >= 10)
|
||||
L.attack_animal(src)
|
||||
else
|
||||
var/inject_target = pick("chest","head")
|
||||
if(L.stunned || L.can_inject(null,0,inject_target,0))
|
||||
L.Silence(20) // instead of having a venom that only lasts seconds, we just add the silence directly.
|
||||
visible_message("<span class='danger'>[src] buries grey fangs deep into the [inject_target] of [target]!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] bites [target], but cannot inject venom into their [inject_target]!</span>")
|
||||
L.attack_animal(src)
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T3 PRINCE OF TERROR --------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: boss
|
||||
// -------------: AI: no special ai
|
||||
// -------------: SPECIAL: massive health
|
||||
// -------------: TO FIGHT IT: a squad of at least 4 people with laser rifles.
|
||||
// -------------: SPRITES FROM: Travelling Merchant, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=2766
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince
|
||||
name = "Prince of Terror spider"
|
||||
desc = "An enormous, terrifying spider. It looks like it is judging everything it sees. Its hide seems armored, and it bears the scars of many battles."
|
||||
spider_role_summary = "Boss-level terror spider. Lightning bruiser. Capable of taking on a squad by itself."
|
||||
icon_state = "terror_allblack"
|
||||
icon_living = "terror_allblack"
|
||||
icon_dead = "terror_allblack_dead"
|
||||
maxHealth = 400 // 20 laser shots.
|
||||
health = 400
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 25
|
||||
move_to_delay = 5
|
||||
ventcrawler = 1
|
||||
loot = list(/obj/item/clothing/accessory/medal)
|
||||
spider_tier = TS_TIER_3
|
||||
spider_opens_doors = 2
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince/spider_specialattack(mob/living/carbon/human/L)
|
||||
if(prob(15))
|
||||
visible_message("<span class='danger'>[src] rams into [L], knocking them to the floor!</span>")
|
||||
L.Weaken(5)
|
||||
L.Stun(5)
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T1 RED TERROR --------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: generic attack spider
|
||||
// -------------: AI: uses very powerful fangs to wreck people in melee
|
||||
// -------------: SPECIAL: the more you hurt it, the harder it bites you
|
||||
// -------------: TO FIGHT IT: shoot it from range. Kite it.
|
||||
// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/red
|
||||
name = "Red Terror spider"
|
||||
desc = "An ominous-looking red spider, it has eight beady red eyes, and nasty, big, pointy fangs! It looks like it has a vicious streak a mile wide."
|
||||
|
||||
spider_role_summary = "High health, high damage, very slow, melee juggernaut"
|
||||
|
||||
icon_state = "terror_red"
|
||||
icon_living = "terror_red"
|
||||
icon_dead = "terror_red_dead"
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
move_to_delay = 20
|
||||
spider_opens_doors = 2
|
||||
var/enrage = 0
|
||||
var/melee_damage_lower_rage0 = 15
|
||||
var/melee_damage_upper_rage0 = 20
|
||||
var/melee_damage_lower_rage1 = 15
|
||||
var/melee_damage_upper_rage1 = 35
|
||||
var/melee_damage_lower_rage2 = 35
|
||||
var/melee_damage_upper_rage2 = 40
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/red/AttackingTarget()
|
||||
if(enrage == 0)
|
||||
if(health < maxHealth)
|
||||
enrage = 1
|
||||
visible_message("<span class='danger'>[src] growls, flexing its fangs!</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage1
|
||||
melee_damage_upper = melee_damage_upper_rage1
|
||||
else if(enrage == 1)
|
||||
if(health == maxHealth)
|
||||
enrage = 0
|
||||
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage0
|
||||
melee_damage_upper = melee_damage_upper_rage0
|
||||
else if(health < (maxHealth/2))
|
||||
enrage = 2
|
||||
visible_message("<span class='danger'>[src] growls, spreading its fangs wide!</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage2
|
||||
melee_damage_upper = melee_damage_upper_rage2
|
||||
else if(enrage == 2)
|
||||
if(health > (maxHealth/2))
|
||||
enrage = 1
|
||||
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage0
|
||||
melee_damage_upper = melee_damage_upper_rage0
|
||||
..()
|
||||
@@ -0,0 +1,329 @@
|
||||
|
||||
var/global/list/ts_ckey_blacklist = list()
|
||||
var/global/ts_count_dead = 0
|
||||
var/global/ts_count_alive_awaymission = 0
|
||||
var/global/ts_count_alive_station = 0
|
||||
var/global/ts_death_last = 0
|
||||
var/global/ts_death_window = 9000 // 15 minutes
|
||||
var/global/list/ts_spiderlist = list()
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: DEFAULTS ---------------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// Because: http://tvtropes.org/pmwiki/pmwiki.php/Main/SpidersAreScary
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider
|
||||
// Name / Description
|
||||
name = "terror spider"
|
||||
desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug."
|
||||
|
||||
// Icons
|
||||
icon = 'icons/mob/terrorspider.dmi'
|
||||
icon_state = "terror_red"
|
||||
icon_living = "terror_red"
|
||||
icon_dead = "terror_red_dead"
|
||||
|
||||
// Health
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
// Melee attacks
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
poison_type = "" // we do not use that silly system.
|
||||
|
||||
// Movement
|
||||
move_to_delay = 6
|
||||
turns_per_move = 5
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
// Ventcrawling
|
||||
ventcrawler = 1 // allows player ventcrawling
|
||||
|
||||
// Speech
|
||||
speak_chance = 0 // quiet but deadly
|
||||
speak_emote = list("hisses")
|
||||
emote_hear = list("hisses")
|
||||
|
||||
// Languages are handled in terror_spider/New()
|
||||
|
||||
// Interaction keywords
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
|
||||
// regeneration settings - overridable by child classes
|
||||
var/regen_points = 0 // number of regen points they have by default
|
||||
var/regen_points_max = 100 // max number of points they can accumulate
|
||||
var/regen_points_per_tick = 1 // gain one regen point per tick
|
||||
var/regen_points_per_kill = 90 // gain extra regen points if you kill something
|
||||
var/regen_points_per_hp = 3 // every X regen points = 1 health point you can regen
|
||||
// desired: 20hp/minute unmolested, 40hp/min on food boost, assuming one tick every 2 seconds
|
||||
// 90/kill means bonus 30hp/kill regenerated over the next 1-2 minutes
|
||||
|
||||
// Vision
|
||||
idle_vision_range = 10
|
||||
aggro_vision_range = 10
|
||||
see_in_dark = 10
|
||||
nightvision = 1
|
||||
vision_type = new /datum/vision_override/nightvision/thermals/ling_augmented_eyesight
|
||||
see_invisible = 5
|
||||
|
||||
// player control by ghosts
|
||||
var/ai_playercontrol_allowingeneral = 1 // if 0, no spiders are player controllable. Default set in code, can be changed by queens.
|
||||
var/ai_playercontrol_allowtype = 1 // if 0, this specific class of spider is not player-controllable. Default set in code for each class, cannot be changed.
|
||||
|
||||
var/spider_opens_doors = 1 // all spiders can open firedoors (they have no security). 1 = can open depowered doors. 2 = can open powered doors
|
||||
faction = list("terrorspiders")
|
||||
var/spider_awaymission = 0 // if 1, limits certain behavior in away missions
|
||||
var/spider_role_summary = "UNDEFINED"
|
||||
var/spider_placed = 0
|
||||
|
||||
// AI variables designed for use in procs
|
||||
var/atom/cocoon_target // for queen and nurse
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/entry_vent // nearby vent they are going to try to get to, and enter
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/exit_vent // remote vent they intend to come out of
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/nest_vent // home vent, usually used by queens
|
||||
var/fed = 0
|
||||
var/travelling_in_vent = 0
|
||||
var/busy = 0 // leave this alone!
|
||||
var/spider_tier = TS_TIER_1 // 1 for red,gray,green. 2 for purple,black,white, 3 for prince, mother. 4 for queen, 5 for empress.
|
||||
var/hasdied = 0
|
||||
var/attackstep = 0
|
||||
var/attackcycles = 0
|
||||
var/mylocation = null
|
||||
var/chasecycles = 0
|
||||
var/last_cocoon_object = 0 // leave this, changed by procs.
|
||||
var/killcount = 0
|
||||
|
||||
// Breathing, Pressure & Fire
|
||||
// - No breathing / cannot be suffocated (spiders can hold their breath, look it up)
|
||||
// - No pressure damage either - they have effectively exoskeletons
|
||||
// - HOWEVER they can be burned to death!
|
||||
// - Normal SPACE spiders should probably be immune to SPACE too, but meh, we try to leave the base spiders alone.
|
||||
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
|
||||
heat_damage_per_tick = 5 //amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
|
||||
// DEBUG OPTIONS & COMMANDS
|
||||
var/spider_debug = 0
|
||||
|
||||
var/datum/action/innate/terrorspider/web/web_action
|
||||
var/datum/action/innate/terrorspider/wrap/wrap_action
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: SHARED ATTACK CODE -----------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget()
|
||||
if(istype(target, /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = target
|
||||
if(T.spider_tier > spider_tier)
|
||||
visible_message("<span class='notice'>[src] bows in respect for the terrifying presence of [target].</span>")
|
||||
else if(T.spider_tier == spider_tier)
|
||||
visible_message("<span class='notice'>[src] nuzzles [target].</span>")
|
||||
else if(T.spider_tier < spider_tier && spider_tier >= 4)
|
||||
visible_message("<span class='notice'>[src] gives [target] a stern look.</span>")
|
||||
else
|
||||
visible_message("<span class='notice'>[src] harmlessly nuzzles [target].</span>")
|
||||
T.CheckFaction()
|
||||
CheckFaction()
|
||||
else if(istype(target, /obj/effect/spider/cocoon))
|
||||
to_chat(src, "Destroying our own cocoons would not help us.")
|
||||
else if(istype(target, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = target
|
||||
if(F.density)
|
||||
if(F.blocked)
|
||||
to_chat(src, "The fire door is welded shut.")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] pries open the firedoor!</span>")
|
||||
F.open()
|
||||
else
|
||||
to_chat(src, "Closing fire doors does not help.")
|
||||
else if(istype(target, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = target
|
||||
if(A.density)
|
||||
try_open_airlock(A)
|
||||
else if(isliving(target))
|
||||
var/mob/living/G = target
|
||||
if(issilicon(G))
|
||||
G.attack_animal(src)
|
||||
return
|
||||
else if(G.reagents && (iscarbon(G)))
|
||||
var/can_poison = 1
|
||||
if(ishuman(G))
|
||||
var/mob/living/carbon/human/H = G
|
||||
if(!(H.species.reagent_tag & PROCESS_ORG) || (H.species.flags & NO_POISON))
|
||||
can_poison = 0
|
||||
spider_specialattack(G,can_poison)
|
||||
else
|
||||
G.attack_animal(src)
|
||||
else
|
||||
target.attack_animal(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, var/poisonable)
|
||||
L.attack_animal(src)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: PROC OVERRIDES ---------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user)
|
||||
..()
|
||||
var/list/msgs = list()
|
||||
if(stat == DEAD)
|
||||
msgs += "<span class='notice'>It appears to be dead.</span>\n"
|
||||
else
|
||||
if(key)
|
||||
msgs += "<span class='warning'>Its eyes regard you with a curious intelligence.</span>"
|
||||
if(health > (maxHealth*0.95))
|
||||
msgs += "<span class='notice'>It is in excellent health.</span>"
|
||||
else if(health > (maxHealth*0.75))
|
||||
msgs += "<span class='notice'>It has a few injuries.</span>"
|
||||
else if(health > (maxHealth*0.55))
|
||||
msgs += "<span class='warning'>It has many injuries.</span>"
|
||||
else if(health > (maxHealth*0.25))
|
||||
msgs += "<span class='warning'>It is barely clinging on to life!</span>"
|
||||
else if(health < maxHealth && regen_points > regen_points_per_kill)
|
||||
msgs += "<span class='notice'>It appears to be regenerating quickly.</span>"
|
||||
if(killcount >= 1)
|
||||
msgs += "<span class='warning'>It has blood dribbling from its mouth.</span>"
|
||||
to_chat(usr,msgs.Join("<BR>"))
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/New()
|
||||
..()
|
||||
ts_spiderlist += src
|
||||
add_language("Spider Hivemind")
|
||||
add_language("Galactic Common")
|
||||
default_language = all_languages["Spider Hivemind"]
|
||||
|
||||
web_action = new()
|
||||
web_action.Grant(src)
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
|
||||
name += " ([rand(1, 1000)])"
|
||||
msg_terrorspiders("[src] has grown in [get_area(src)].")
|
||||
if(is_away_level(z))
|
||||
spider_awaymission = 1
|
||||
ts_count_alive_awaymission++
|
||||
else
|
||||
ts_count_alive_station++
|
||||
// after 30 seconds, assuming nobody took control of it yet, offer it to ghosts.
|
||||
addtimer(src, "CheckFaction", 150)
|
||||
addtimer(src, "announcetoghosts", 300)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts()
|
||||
if(spider_awaymission)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(ckey)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay)
|
||||
else if(ai_playercontrol_allowingeneral && ai_playercontrol_allowtype)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "<a href=?src=[UID()];activate=1>(Click to control)</a>", source = src, alert_overlay = alert_overlay, attack_not_jump = 1)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Destroy()
|
||||
ts_spiderlist -= src
|
||||
handle_dying()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Life()
|
||||
..()
|
||||
if(stat == DEAD)
|
||||
if(prob(2))
|
||||
// 2% chance every cycle to decompose
|
||||
visible_message("<span class='notice'>\The dead body of the [src] decomposes!</span>")
|
||||
gib()
|
||||
else
|
||||
if(regen_points < regen_points_max)
|
||||
regen_points += regen_points_per_tick
|
||||
if((bruteloss > 0) || (fireloss > 0))
|
||||
if(regen_points > regen_points_per_hp)
|
||||
if(bruteloss > 0)
|
||||
adjustBruteLoss(-1)
|
||||
regen_points -= regen_points_per_hp
|
||||
else if(fireloss > 0)
|
||||
adjustFireLoss(-1)
|
||||
regen_points -= regen_points_per_hp
|
||||
if(prob(5))
|
||||
CheckFaction()
|
||||
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/handle_dying()
|
||||
if(!hasdied)
|
||||
hasdied = 1
|
||||
ts_count_dead++
|
||||
ts_death_last = world.time
|
||||
if(spider_awaymission)
|
||||
ts_count_alive_awaymission--
|
||||
else
|
||||
ts_count_alive_station--
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/death(gibbed)
|
||||
if(!gibbed)
|
||||
msg_terrorspiders("[src] has died in [get_area(src)].")
|
||||
handle_dying()
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_special_action()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Bump(atom/A)
|
||||
if(istype(A, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/L = A
|
||||
if(L.density)
|
||||
try_open_airlock(L)
|
||||
if(istype(A, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = A
|
||||
if(F.density && !F.blocked)
|
||||
F.open()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext)
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in ts_spiderlist)
|
||||
if(T.stat != DEAD)
|
||||
to_chat(T, "<span class='terrorspider'>TerrorSense: [msgtext]</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction()
|
||||
if(faction.len != 1 || (!("terrorspiders" in faction)) || master_commander != null)
|
||||
visible_message("<span class='danger'>[src] writhes in pain!</span>")
|
||||
log_runtime(EXCEPTION("Terror spider created with incorrect faction list at: [atom_loc_line(src)]"))
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D)
|
||||
if(D.operating)
|
||||
return
|
||||
if(!D.density)
|
||||
to_chat(src, "<span class='warning'>Closing doors does not help us.</span>")
|
||||
else if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded shut.</span>")
|
||||
else if(D.locked)
|
||||
to_chat(src, "<span class='warning'>The door is bolted shut.</span>")
|
||||
else if(D.allowed(src))
|
||||
D.open(1)
|
||||
else if(D.arePowerSystemsOn() && (spider_opens_doors != 2))
|
||||
to_chat(src, "<span class='warning'>The door's motors resist your efforts to force it.</span>")
|
||||
else if(!spider_opens_doors)
|
||||
to_chat(src, "<span class='warning'>Your type of spider is not strong enough to force open doors.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] pries open the door!</span>")
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
D.open(1)
|
||||
@@ -244,8 +244,10 @@
|
||||
if(!job.is_position_available()) return 0
|
||||
if(jobban_isbanned(src,rank)) return 0
|
||||
if(!is_job_whitelisted(src, rank)) return 0
|
||||
if(!job.player_old_enough(src.client)) return 0
|
||||
if(!job.player_old_enough(client)) return 0
|
||||
if(job.admin_only && !(check_rights(R_EVENT, 0))) return 0
|
||||
if(job.available_in_playtime(client))
|
||||
return 0
|
||||
|
||||
if(config.assistantlimit)
|
||||
if(job.title == "Civilian")
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/nano_module/alarm_monitor/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
|
||||
var/categories[0]
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
ui.set_auto_update(1)
|
||||
ui_ref = ui
|
||||
|
||||
/datum/nano_module/atmos_control/ui_data(mob/user, datum/topic_state/state = default_state)
|
||||
/datum/nano_module/atmos_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
|
||||
var/data[0]
|
||||
data["alarms"] = air_alarm_repository.air_alarm_data(monitored_alarms)
|
||||
return data
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user