Merge pull request #2 from Aurorastation/master

updating to master
This commit is contained in:
Raven
2016-02-06 19:45:42 -05:00
225 changed files with 14381 additions and 8593 deletions
+10 -10
View File
@@ -1,4 +1,4 @@
CREATE TABLE `erro_admin` (
CREATE TABLE `ss13_admin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ckey` varchar(32) NOT NULL,
`rank` varchar(32) NOT NULL DEFAULT 'Administrator',
@@ -7,7 +7,7 @@ CREATE TABLE `erro_admin` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_admin_log` (
CREATE TABLE `ss13_admin_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`adminckey` varchar(32) NOT NULL,
@@ -16,7 +16,7 @@ CREATE TABLE `erro_admin_log` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_ban` (
CREATE TABLE `ss13_ban` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bantime` datetime NOT NULL,
`serverip` varchar(32) NOT NULL,
@@ -43,7 +43,7 @@ CREATE TABLE `erro_ban` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_feedback` (
CREATE TABLE `ss13_feedback` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` datetime NOT NULL,
`round_id` int(8) NOT NULL,
@@ -53,7 +53,7 @@ CREATE TABLE `erro_feedback` (
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_player` (
CREATE TABLE `ss13_player` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ckey` varchar(32) NOT NULL,
`firstseen` datetime NOT NULL,
@@ -65,7 +65,7 @@ CREATE TABLE `erro_player` (
UNIQUE KEY `ckey` (`ckey`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_poll_option` (
CREATE TABLE `ss13_poll_option` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pollid` int(11) NOT NULL,
`text` varchar(255) NOT NULL,
@@ -78,7 +78,7 @@ CREATE TABLE `erro_poll_option` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_poll_question` (
CREATE TABLE `ss13_poll_question` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`polltype` varchar(16) NOT NULL DEFAULT 'OPTION',
`starttime` datetime NOT NULL,
@@ -88,7 +88,7 @@ CREATE TABLE `erro_poll_question` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_poll_textreply` (
CREATE TABLE `ss13_poll_textreply` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`pollid` int(11) NOT NULL,
@@ -99,7 +99,7 @@ CREATE TABLE `erro_poll_textreply` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_poll_vote` (
CREATE TABLE `ss13_poll_vote` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`pollid` int(11) NOT NULL,
@@ -111,7 +111,7 @@ CREATE TABLE `erro_poll_vote` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
CREATE TABLE `erro_privacy` (
CREATE TABLE `ss13_privacy` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`ckey` varchar(32) NOT NULL,
+5 -5
View File
@@ -10,7 +10,7 @@ USE `tgstation` ;
-- -----------------------------------------------------
-- Table `tgstation`.`death`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tgstation`.`death` (
CREATE TABLE IF NOT EXISTS `ss13_death` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`pod` TEXT NOT NULL COMMENT 'Place of death' ,
`coord` TEXT NOT NULL COMMENT 'X, Y, Z POD' ,
@@ -35,7 +35,7 @@ DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `tgstation`.`karma`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tgstation`.`karma` (
CREATE TABLE IF NOT EXISTS `ss13_karma` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`spendername` TEXT NOT NULL ,
`spenderkey` TEXT NOT NULL ,
@@ -55,7 +55,7 @@ DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `tgstation`.`karmatotals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tgstation`.`karmatotals` (
CREATE TABLE IF NOT EXISTS `ss13_karmatotals` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`byondkey` TEXT NOT NULL ,
`karma` INT(11) NOT NULL ,
@@ -68,7 +68,7 @@ DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `tgstation`.`library`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tgstation`.`library` (
CREATE TABLE IF NOT EXISTS `ss13_library` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`author` TEXT NOT NULL ,
`title` TEXT NOT NULL ,
@@ -83,7 +83,7 @@ DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `tgstation`.`population`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tgstation`.`population` (
CREATE TABLE IF NOT EXISTS `ss13_population` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`playercount` INT(11) NULL DEFAULT NULL ,
`admincount` INT(11) NULL DEFAULT NULL ,
+32 -4
View File
@@ -24,6 +24,7 @@
#include "code\__HELPERS\lists.dm"
#include "code\__HELPERS\logging.dm"
#include "code\__HELPERS\maths.dm"
#include "code\__HELPERS\matrices.dm"
#include "code\__HELPERS\mobs.dm"
#include "code\__HELPERS\names.dm"
#include "code\__HELPERS\sanitize_values.dm"
@@ -44,6 +45,7 @@
#include "code\_onclick\other_mobs.dm"
#include "code\_onclick\telekinesis.dm"
#include "code\_onclick\hud\_defines.dm"
#include "code\_onclick\hud\ai.dm"
#include "code\_onclick\hud\alien_larva.dm"
#include "code\_onclick\hud\hud.dm"
#include "code\_onclick\hud\human.dm"
@@ -240,6 +242,7 @@
#include "code\game\antagonist\station\revolutionary.dm"
#include "code\game\antagonist\station\rogue_ai.dm"
#include "code\game\antagonist\station\traitor.dm"
#include "code\game\antagonist\station\vampire.dm"
#include "code\game\area\ai_monitored.dm"
#include "code\game\area\areas.dm"
#include "code\game\area\asteroid_areas.dm"
@@ -309,6 +312,8 @@
#include "code\game\gamemodes\nuclear\pinpointer.dm"
#include "code\game\gamemodes\revolution\revolution.dm"
#include "code\game\gamemodes\traitor\traitor.dm"
#include "code\game\gamemodes\vampire\vampire.dm"
#include "code\game\gamemodes\vampire\vampire_powers.dm"
#include "code\game\gamemodes\wizard\wizard.dm"
#include "code\game\jobs\access.dm"
#include "code\game\jobs\job_controller.dm"
@@ -573,6 +578,7 @@
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\magnetic_lock.dm"
#include "code\game\objects\items\devices\megaphone.dm"
#include "code\game\objects\items\devices\modkit.dm"
#include "code\game\objects\items\devices\multitool.dm"
@@ -813,6 +819,7 @@
#include "code\modules\admin\IsBanned.dm"
#include "code\modules\admin\NewBan.dm"
#include "code\modules\admin\player_notes.dm"
#include "code\modules\admin\player_notes_sql.dm"
#include "code\modules\admin\player_panel.dm"
#include "code\modules\admin\topic.dm"
#include "code\modules\admin\ToRban.dm"
@@ -847,6 +854,7 @@
#include "code\modules\admin\verbs\striketeam.dm"
#include "code\modules\admin\verbs\ticklag.dm"
#include "code\modules\admin\verbs\tripAI.dm"
#include "code\modules\admin\verbs\warning.dm"
#include "code\modules\alarm\alarm.dm"
#include "code\modules\alarm\alarm_handler.dm"
#include "code\modules\alarm\atmosphere_alarm.dm"
@@ -877,6 +885,7 @@
#include "code\modules\client\client defines.dm"
#include "code\modules\client\client procs.dm"
#include "code\modules\client\preferences.dm"
#include "code\modules\client\preferences_ambience.dm"
#include "code\modules\client\preferences_factions.dm"
#include "code\modules\client\preferences_gear.dm"
#include "code\modules\client\preferences_savefile.dm"
@@ -889,6 +898,7 @@
#include "code\modules\clothing\gloves\boxing.dm"
#include "code\modules\clothing\gloves\color.dm"
#include "code\modules\clothing\gloves\miscellaneous.dm"
#include "code\modules\clothing\gloves\stungloves.dm"
#include "code\modules\clothing\head\collectable.dm"
#include "code\modules\clothing\head\hardhat.dm"
#include "code\modules\clothing\head\helmet.dm"
@@ -957,11 +967,19 @@
#include "code\modules\clothing\under\jobs\medsci.dm"
#include "code\modules\clothing\under\jobs\security.dm"
#include "code\modules\customitems\item_spawning.dm"
#include "code\modules\detectivework\evidence.dm"
#include "code\modules\detectivework\footprints_and_rag.dm"
#include "code\modules\detectivework\footprints.dm"
#include "code\modules\detectivework\forensics.dm"
#include "code\modules\detectivework\scanner.dm"
#include "code\modules\detectivework\scanning_console.dm"
#include "code\modules\detectivework\microscope\dnascanner.dm"
#include "code\modules\detectivework\microscope\microscope.dm"
#include "code\modules\detectivework\microscope\slides.dm"
#include "code\modules\detectivework\tools\crimekit.dm"
#include "code\modules\detectivework\tools\evidencebag.dm"
#include "code\modules\detectivework\tools\luminol.dm"
#include "code\modules\detectivework\tools\rag.dm"
#include "code\modules\detectivework\tools\sample_kits.dm"
#include "code\modules\detectivework\tools\storage.dm"
#include "code\modules\detectivework\tools\swabs.dm"
#include "code\modules\detectivework\tools\uvlight.dm"
#include "code\modules\economy\Accounts.dm"
#include "code\modules\economy\Accounts_DB.dm"
#include "code\modules\economy\ATM.dm"
@@ -1245,6 +1263,7 @@
#include "code\modules\mob\living\silicon\ai\life.dm"
#include "code\modules\mob\living\silicon\ai\login.dm"
#include "code\modules\mob\living\silicon\ai\logout.dm"
#include "code\modules\mob\living\silicon\ai\nano.dm"
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"
@@ -1424,6 +1443,9 @@
#include "code\modules\power\singularity\particle_accelerator\particle_control.dm"
#include "code\modules\power\singularity\particle_accelerator\particle_emitter.dm"
#include "code\modules\power\singularity\particle_accelerator\particle_power.dm"
#include "code\modules\power\tesla\coil.dm"
#include "code\modules\power\tesla\energy_ball.dm"
#include "code\modules\power\tesla\generator.dm"
#include "code\modules\projectiles\ammunition.dm"
#include "code\modules\projectiles\effects.dm"
#include "code\modules\projectiles\gun.dm"
@@ -1436,6 +1458,7 @@
#include "code\modules\projectiles\guns\launcher.dm"
#include "code\modules\projectiles\guns\projectile.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"
#include "code\modules\projectiles\guns\energy\lawgiver.dm"
#include "code\modules\projectiles\guns\energy\nuclear.dm"
#include "code\modules\projectiles\guns\energy\pulse.dm"
#include "code\modules\projectiles\guns\energy\special.dm"
@@ -1641,6 +1664,7 @@
#include "code\modules\spells\targeted\targeted.dm"
#include "code\modules\spells\targeted\equip\equip.dm"
#include "code\modules\spells\targeted\equip\horsemask.dm"
#include "code\modules\spells\targeted\equip\remove_horsemask.dm"
#include "code\modules\spells\targeted\projectile\dumbfire.dm"
#include "code\modules\spells\targeted\projectile\fireball.dm"
#include "code\modules\spells\targeted\projectile\magic_missile.dm"
@@ -1665,6 +1689,10 @@
#include "code\modules\tables\rack.dm"
#include "code\modules\tables\tables.dm"
#include "code\modules\tables\update_triggers.dm"
#include "code\modules\telesci\bscrystal.dm"
#include "code\modules\telesci\gps.dm"
#include "code\modules\telesci\telepad.dm"
#include "code\modules\telesci\telesci_computer.dm"
#include "code\modules\vehicles\cargo_train.dm"
#include "code\modules\vehicles\train.dm"
#include "code\modules\vehicles\vehicle.dm"
+26
View File
@@ -0,0 +1,26 @@
/matrix/proc/TurnTo(old_angle, new_angle)
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3)
if(!segments)
return
var/segment = 360/segments
if(!clockwise)
segment = -segment
var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/M = matrix(transform)
M.Turn(segment*i)
matrices += M
var/matrix/last = matrix(transform)
matrices += last
speed /= segments
animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
+8
View File
@@ -138,6 +138,14 @@
/proc/sanitize_old(var/t,var/list/repl_chars = list("\n"="#","\t"="#"))
return html_encode(replace_characters(t,repl_chars))
// Truncates text to limit if necessary.
/proc/dd_limittext(message, length)
var/size = length(message)
if (size <= length)
return message
else
return copytext(message, 1, length + 1)
/*
* Text searches
*/
+58 -1
View File
@@ -538,7 +538,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/y = min(world.maxy, max(1, A.y + dy))
return locate(x,y,A.z)
//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority.
//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value.
/proc/between(var/low, var/middle, var/high)
return max(min(middle, high), low)
@@ -1309,6 +1309,63 @@ var/mob/dview/dview_mob = new
/mob/dview/New()
// do nothing. we don't want to be in any mob lists; we're a dummy not a mob.
//This is just so you can stop an orbit.
//orbit() can run without it (swap orbiting for A)
//but then you can never stop it and that's just silly.
/atom/movable/var/atom/orbiting = null
//A: atom to orbit
//radius: range to orbit at, radius of the circle formed by orbiting
//clockwise: whether you orbit clockwise or anti clockwise
//rotation_speed: how fast to rotate
//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
//lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts)
/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE)
if(!istype(A))
return
if(orbiting)
stop_orbit()
orbiting = A
var/matrix/initial_transform = matrix(transform)
var/lastloc = loc
//Head first!
if(pre_rotation)
var/matrix/M = matrix(transform)
var/pre_rot = 90
if(!clockwise)
pre_rot = -90
M.Turn(pre_rot)
transform = M
var/matrix/shift = matrix(transform)
shift.Translate(0,radius)
transform = shift
SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
//we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
transform = initial_transform
while(orbiting && orbiting == A && A.loc)
var/targetloc = get_turf(A)
if(!lockinorbit && loc != lastloc && loc != targetloc)
break
loc = targetloc
lastloc = loc
sleep(0.6)
if (orbiting == A) //make sure we haven't started orbiting something else.
orbiting = null
SpinAnimation(0,0)
/atom/movable/proc/stop_orbit()
orbiting = null
// call to generate a stack trace and print to runtime logs
/proc/crash_with(msg)
+19
View File
@@ -127,3 +127,22 @@
#define ui_spell_master "14:16,14:16"
#define ui_genetic_master "14:16,12:16"
// AI
#define ui_ai_camera_list "SOUTH:6+1,WEST+1:16"
#define ui_ai_track_with_camera "SOUTH:6+1,WEST+2:16"
#define ui_ai_camera_light "SOUTH:6+1,WEST+3:16"
#define ui_ai_sensor "SOUTH:6+1,WEST+4:16"
#define ui_ai_core "SOUTH:6,WEST+1:16"
#define ui_ai_crew_monitor "SOUTH:6,WEST+2:16"
#define ui_ai_crew_manifest "SOUTH:6,WEST+3:16"
#define ui_ai_alerts "SOUTH:6,WEST+4:16"
#define ui_ai_announcement "SOUTH:6,WEST+5:16"
#define ui_ai_shuttle "SOUTH:6,WEST+6:16"
#define ui_ai_state_laws "SOUTH:6,WEST+7:16"
#define ui_ai_pda_send "SOUTH:6,WEST+8:16"
#define ui_ai_pda_log "SOUTH:6,WEST+9:16"
#define ui_ai_take_picture "SOUTH:6,WEST+10:16"
#define ui_ai_view_images "SOUTH:6,WEST+11:16"
+143
View File
@@ -0,0 +1,143 @@
/datum/hud/proc/ai_hud()
adding = list()
other = list()
var/obj/screen/using
//AI core
using = new /obj/screen()
using.name = "AI Core"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "ai_core"
using.screen_loc = ui_ai_core
using.layer = 20
adding += using
//Camera list
using = new /obj/screen()
using.name = "Show Camera List"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "camera"
using.screen_loc = ui_ai_camera_list
using.layer = 20
adding += using
//Track
using = new /obj/screen()
using.name = "Track With Camera"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "track"
using.screen_loc = ui_ai_track_with_camera
using.layer = 20
adding += using
//Camera light
using = new /obj/screen()
using.name = "Toggle Camera Light"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "camera_light"
using.screen_loc = ui_ai_camera_light
using.layer = 20
adding += using
//Crew Monitorting
using = new /obj/screen()
using.name = "Crew Monitoring"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "crew_monitor"
using.screen_loc = ui_ai_crew_monitor
using.layer = 20
adding += using
//Crew Manifest
using = new /obj/screen()
using.name = "Show Crew Manifest"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "manifest"
using.screen_loc = ui_ai_crew_manifest
using.layer = 20
adding += using
//Alerts
using = new /obj/screen()
using.name = "Show Alerts"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "alerts"
using.screen_loc = ui_ai_alerts
using.layer = 20
adding += using
//Announcement
using = new /obj/screen()
using.name = "Announcement"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "announcement"
using.screen_loc = ui_ai_announcement
using.layer = 20
adding += using
//Shuttle
using = new /obj/screen()
using.name = "Call Emergency Shuttle"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "call_shuttle"
using.screen_loc = ui_ai_shuttle
using.layer = 20
adding += using
//Laws
using = new /obj/screen()
using.name = "State Laws"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "state_laws"
using.screen_loc = ui_ai_state_laws
using.layer = 20
adding += using
//PDA message
using = new /obj/screen()
using.name = "PDA - Send Message"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "pda_send"
using.screen_loc = ui_ai_pda_send
using.layer = 20
adding += using
//PDA log
using = new /obj/screen()
using.name = "PDA - Show Message Log"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "pda_receive"
using.screen_loc = ui_ai_pda_log
using.layer = 20
adding += using
//Take image
using = new /obj/screen()
using.name = "Take Image"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "take_picture"
using.screen_loc = ui_ai_take_picture
using.layer = 20
adding += using
//View images
using = new /obj/screen()
using.name = "View Images"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "view_images"
using.screen_loc = ui_ai_view_images
using.layer = 20
adding += using
//Medical/Security sensors
using = new /obj/screen()
using.name = "Set Sensor Augmentation"
using.icon = 'icons/mob/screen_ai.dmi'
using.icon_state = "ai_sensor"
using.screen_loc = ui_ai_sensor
using.layer = 20
adding += using
mymob.client.screen += adding + other
return
-3
View File
@@ -13,9 +13,6 @@
mymob.blind.screen_loc = "1,1"
mymob.blind.layer = 0
/datum/hud/proc/ai_hud()
return
/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
blobpwrdisplay = new /obj/screen()
+77
View File
@@ -478,6 +478,83 @@
usr.client.AllowTargetRadio()
gun_click_time = world.time
if("AI Core")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.view_core()
if("Show Camera List")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/camera = input(AI) in AI.get_camera_list()
AI.ai_camera_list(camera)
if("Track With Camera")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/target_name = input(AI) in AI.trackable_mobs()
AI.ai_camera_track(target_name)
if("Toggle Camera Light")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.toggle_camera_light()
if("Crew Monitoring")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.subsystem_crew_monitor()
if("Show Crew Manifest")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.show_station_manifest()
if("Show Alerts")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.subsystem_alarm_monitor()
if("Announcement")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.ai_announcement()
if("Call Emergency Shuttle")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.ai_call_shuttle()
if("State Laws")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.subsystem_law_manager()
if("PDA - Send Message")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.aiPDA.cmd_send_pdamesg(usr)
if("PDA - Show Message Log")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.aiPDA.cmd_show_message_log(usr)
if("Take Image")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.aiCamera.toggle_camera_mode()
if("View Images")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.aiCamera.viewpictures()
if("Set Sensor Augmentation")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.sensor_mode()
else
return 0
return 1
+12
View File
@@ -0,0 +1,12 @@
/datum/controller/process/news/setup()
name = "news"
schedule_interval = 600 // every 60 seconds
if(!news_controller)
news_controller = new
/datum/controller/process/news/doWork()
news_controller.process()
/datum/controller/process/news/getStatName()
return ..()+"(STAT:[news_controller.running] FLS:[news_controller.fails])"
+4 -6
View File
@@ -153,6 +153,7 @@ var/list/gamemode_cache = list()
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
var/sql_whitelists = 0 //Defined whether the server uses an SQL based whitelist system, or the legacy one with two .txts. Config option in config.txt
var/simultaneous_pm_warning_timeout = 100
@@ -674,6 +675,9 @@ var/list/gamemode_cache = list()
if("aggressive_changelog")
config.aggressive_changelog = 1
if("sql_whitelists")
config.sql_whitelists = 1
else
log_misc("Unknown setting in configuration: '[name]'")
@@ -772,12 +776,6 @@ var/list/gamemode_cache = list()
sqllogin = value
if ("password")
sqlpass = value
if ("feedback_database")
sqlfdbkdb = value
if ("feedback_login")
sqlfdbklogin = value
if ("feedback_password")
sqlfdbkpass = value
if ("enable_stat_tracking")
sqllogging = 1
else
+94
View File
@@ -0,0 +1,94 @@
var/global/datum/news_controller/news_controller
/datum/news_controller
var/count = 0 //Count of articles pulled and published
var/publish_time //Ingame time for when the stored article is to be published
var/article_id //Stored article's primary-key
var/running = 1 //Boolean value, self-explanitory
var/fails = 0 //Counter for failed queries
var/max_fails = 5 //Maximum amount of failures before the controller is killed
/datum/news_controller/proc/process()
if(!running) //Not running, return.
return
if(fails >= max_fails) //Too many failures, killing.
kill()
return
if(!article_id && !publish_time) //No entry stored. Update and get one.
update()
return
if(publish_time < world.time) //Time to publish the article.
publish()
if(fails)
fails = 0
//Stores a new article for publishing.
/datum/news_controller/proc/update()
establish_db_connection()
if(!dbcon.IsConnected())
error("SQL database connection failed. News_controller failed to retreive information.")
fails++
return
var/DBQuery/update_query = dbcon.NewQuery("SELECT id, publishtime FROM ss13_news WHERE status = 2 ORDER BY publishtime ASC LIMIT :count, 1")
update_query.Execute(list(":count" = count))
if(update_query.ErrorMsg())
fails++
return
if(!update_query.RowCount())
kill()
return
while(update_query.NextRow())
article_id = text2num(update_query.item[1])
publish_time = text2num(update_query.item[2]) * 600
count++
//Publish the stored article.
/datum/news_controller/proc/publish()
establish_db_connection()
if(!dbcon.IsConnected())
error("SQL database connection failed. News_controller failed to retreive information.")
fails++
return
var/DBQuery/publish_query = dbcon.NewQuery("SELECT channel, author, body FROM ss13_news WHERE id = :article_id")
publish_query.Execute(list(":article_id" = article_id))
if(publish_query.ErrorMsg())
fails++
return
var/article_channel
var/article_author
var/article_content
while(publish_query.NextRow())
article_channel = publish_query.item[1]
article_author = publish_query.item[2]
article_content = publish_query.item[3]
var/channel_found
for(var/datum/feed_channel/FC in news_network.network_channels)
if(FC.channel_name == article_channel)
channel_found = 1
break
if(!channel_found)
news_network.CreateFeedChannel(article_channel, article_author, 0)
news_network.SubmitArticle(article_content, article_author, article_channel)
article_id = null
publish_time = null
update()
//Kills the controller.
/datum/news_controller/proc/kill()
running = 0
return
+3
View File
@@ -258,6 +258,9 @@ datum/controller/vote
log_vote(text)
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period/10] seconds to vote.</font>"
for(var/client/C in clients)
if(C.prefs.asfx_togs & ASFX_VOTE) //Personal mute
C << sound('sound/effects/vote.ogg')
switch(vote_type)
if("crew_transfer")
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
+8 -2
View File
@@ -53,6 +53,8 @@
var/datum/faction/faction //associated faction
var/datum/changeling/changeling //changeling holder
var/datum/vampire/vampire //vampire holder
var/rev_cooldown = 0
// the world.time since the mob has been brigged, or -1 if not at all
@@ -72,6 +74,8 @@
if(changeling)
current.remove_changeling_powers()
current.verbs -= /datum/changeling/proc/EvolutionMenu
if(vampire)
current.remove_vampire_powers()
current.mind = null
nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
@@ -83,7 +87,8 @@
if(changeling)
new_character.make_changeling()
if(vampire)
new_character.make_vampire()
if(active)
new_character.key = key //now transfer the key to link the client to our new body
@@ -143,7 +148,7 @@
if(href_list["add_antagonist"])
var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]]
if(antag)
if(antag)
if(antag.add_antagonist(src, 1, 1, 0, 1, 1)) // Ignore equipment and role type for this.
log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.role_text].")
else
@@ -439,6 +444,7 @@
assigned_job = null
//faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know.
changeling = null
vampire = null
initial_account = null
objectives = list()
special_verbs = list()
+41 -1
View File
@@ -43,6 +43,20 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
group = "Security"
hidden = 1
/datum/supply_packs/forensics
name = "Auxiliary forensic tools"
contains = list(/obj/item/weapon/forensics/sample_kit,
/obj/item/weapon/forensics/sample_kit/powder,
/obj/item/weapon/storage/box/swabs,
/obj/item/weapon/storage/box/swabs,
/obj/item/weapon/storage/box/swabs,
/obj/item/weapon/storage/box/slides,
/obj/item/weapon/reagent_containers/spray/luminol)
cost = 30
containertype = /obj/structure/closet/crate
containername = "Auxiliary forensic tools"
group = "Security"
/datum/supply_packs/food
name = "Kitchen supply crate"
contains = list(/obj/item/weapon/reagent_containers/food/condiment/flour,
@@ -848,7 +862,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
name = "Automatic weapon crate"
num_contained = 2
contains = list(/obj/item/weapon/gun/projectile/automatic/wt550,
/obj/item/weapon/gun/projectile/automatic/z8)
/obj/item/weapon/gun/projectile/automatic/rifle/z8)
cost = 90
containertype = /obj/structure/closet/crate/secure
containername = "Automatic weapon crate"
@@ -1220,6 +1234,32 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
access = access_hydroponics
group = "Hydroponics"
/datum/supply_packs/aliengloves
name = "Non-Human Glove Kit"
contains = list(/obj/item/clothing/gloves/yellow/specialt,
/obj/item/clothing/gloves/yellow/specialt,
/obj/item/clothing/gloves/yellow/specialt,
/obj/item/clothing/gloves/yellow/specialu,
/obj/item/clothing/gloves/yellow/specialu,
/obj/item/clothing/gloves/yellow/specialu)
cost = 25
containertype = /obj/structure/closet/crate
containername = "speciality gloves kit"
group = "Supply"
/datum/supply_packs/alienmedicalgloves
name = "Non-Human Sterile Glove Kit"
contains = list(/obj/item/clothing/gloves/latex/unathi,
/obj/item/clothing/gloves/latex/unathi,
/obj/item/clothing/gloves/latex/unathi,
/obj/item/clothing/gloves/latex/tajara,
/obj/item/clothing/gloves/latex/tajara,
/obj/item/clothing/gloves/latex/tajara)
cost = 25
containertype = /obj/structure/closet/crate
containername = "speciality sterile gloves kit"
group = "Medical"
/datum/supply_packs/cardboard_sheets
contains = list(/obj/item/stack/material/cardboard)
name = "50 cardboard sheets"
+133 -63
View File
@@ -48,45 +48,45 @@ DBConnection
var/server = ""
var/port = 3306
DBConnection/New(dbi_handler,username,password_handler,cursor_handler)
src.dbi = dbi_handler
src.user = username
src.password = password_handler
src.default_cursor = cursor_handler
DBConnection/New(dbi_handler, username, password_handler, cursor_handler)
dbi = dbi_handler
user = username
password = password_handler
default_cursor = cursor_handler
_db_con = _dm_db_new_con()
DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler)
if(!sqllogging)
DBConnection/proc/Connect(dbi_handler = dbi, user_handler = user, password_handler = password, cursor_handler)
if (!sqllogging)
return 0
if(!src) return 0
cursor_handler = src.default_cursor
if(!cursor_handler) cursor_handler = Default_Cursor
return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null)
if (!src)
return 0
cursor_handler = default_cursor
if (!cursor_handler)
cursor_handler = Default_Cursor
return _dm_db_connect(_db_con,dbi_handler, user_handler, password_handler, cursor_handler, null)
DBConnection/proc/Disconnect() return _dm_db_close(_db_con)
DBConnection/proc/Disconnect()
return _dm_db_close(_db_con)
DBConnection/proc/IsConnected()
if(!sqllogging) return 0
if(!sqllogging)
return 0
var/success = _dm_db_is_connected(_db_con)
return success
DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str)
DBConnection/proc/Quote(str)
return _dm_db_quote(_db_con,str)
DBConnection/proc/ErrorMsg()
return _dm_db_error_msg(_db_con)
DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con)
DBConnection/proc/SelectDB(database_name,dbi)
if(IsConnected()) Disconnect()
//return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password)
return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]",user,password)
DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler)
DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler)
if(sql_query) src.sql = sql_query
if(connection_handler) src.db_connection = connection_handler
if(cursor_handler) src.default_cursor = cursor_handler
_db_query = _dm_db_new_query()
return ..()
return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]", user, password)
DBConnection/proc/NewQuery(sql_query, cursor_handler = default_cursor)
return new/DBQuery(sql_query, src, cursor_handler)
DBQuery
var/sql // The sql query being executed.
@@ -98,34 +98,53 @@ DBQuery
var/DBConnection/db_connection
var/_db_query
DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler
DBQuery/New(var/sql_query, var/DBConnection/connection_handler, var/cursor_handler)
if (sql_query)
sql = sql_query
if (connection_handler)
db_connection = connection_handler
if (cursor_handler)
default_cursor = cursor_handler
_db_query = _dm_db_new_query()
return ..()
DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor)
DBQuery/proc/Connect(DBConnection/connection_handler)
db_connection = connection_handler
DBQuery/proc/Execute(var/list/argument_list = null, var/pass_not_found = 0, sql_query = sql, cursor_handler = default_cursor)
Close()
return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null)
DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions)
if (argument_list)
sql_query = parseArguments(sql_query, argument_list, pass_not_found)
DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query)
return _dm_db_execute(_db_query, sql_query, db_connection._db_con, cursor_handler, null)
DBQuery/proc/RowCount() return _dm_db_row_count(_db_query)
DBQuery/proc/NextRow()
return _dm_db_next_row(_db_query,item,conversions)
DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query)
DBQuery/proc/RowsAffected()
return _dm_db_rows_affected(_db_query)
DBQuery/proc/RowCount()
return _dm_db_row_count(_db_query)
DBQuery/proc/ErrorMsg()
return _dm_db_error_msg(_db_query)
DBQuery/proc/Columns()
if(!columns)
if (!columns)
columns = _dm_db_columns(_db_query,/DBColumn)
return columns
DBQuery/proc/GetRowData()
var/list/columns = Columns()
var/list/results
if(columns.len)
if (columns.len)
results = list()
for(var/C in columns)
results+=C
for (var/C in columns)
results += C
var/DBColumn/cur_col = columns[C]
results[C] = src.item[(cur_col.position+1)]
results[C] = item[(cur_col.position+1)]
return results
DBQuery/proc/Close()
@@ -138,11 +157,49 @@ DBQuery/proc/Quote(str)
return db_connection.Quote(str)
DBQuery/proc/SetConversion(column,conversion)
if(istext(column)) column = columns.Find(column)
if(!conversions) conversions = new/list(column)
else if(conversions.len < column) conversions.len = column
if (istext(column))
column = columns.Find(column)
if (!conversions)
conversions = new/list(column)
else if (conversions.len < column)
conversions.len = column
conversions[column] = conversion
/* Works similarly to the PDO object's Execute() method in PHP.
* Insert a list of keys/values, it searches the SQL syntax for the keys,
* and replaces them with sanitized versions of the values.
* Can be called independently, or through dbcon.Execute(), where the list would be the first argument.
* passNotFound controls whether or not is passes keys not found in the SQL query.
* Keys are /case-sensitive/, be careful!
* Returns the parsed SQL query upon completion.
* - Skull132
*/
DBQuery/proc/parseArguments(var/query_to_parse = null, var/list/argument_list, var/pass_not_found = 0)
if (!query_to_parse || !argument_list || !argument_list.len)
return 0
for (var/placeholder in argument_list)
if (!findtextEx(sql, placeholder))
if (pass_not_found)
continue
else
return 0
var/argument = argument_list[placeholder]
if (isnull(argument))
argument = "NULL"
else if (istext(argument))
argument = dbcon.Quote(argument)
else if (isnum(argument))
argument = "'[argument]'"
else
return 0
query_to_parse = replacetextEx(sql, placeholder, argument)
return query_to_parse
DBColumn
var/name
@@ -153,32 +210,45 @@ DBColumn
var/length
var/max_length
DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler)
src.name = name_handler
src.table = table_handler
src.position = position_handler
src.sql_type = type_handler
src.flags = flag_handler
src.length = length_handler
src.max_length = max_length_handler
DBColumn/New(name_handler, table_handler, position_handler, type_handler, flag_handler, length_handler, max_length_handler)
name = name_handler
table = table_handler
position = position_handler
sql_type = type_handler
flags = flag_handler
length = length_handler
max_length = max_length_handler
return ..()
DBColumn/proc/SqlTypeName(type_handler=src.sql_type)
switch(type_handler)
if(TINYINT) return "TINYINT"
if(SMALLINT) return "SMALLINT"
if(MEDIUMINT) return "MEDIUMINT"
if(INTEGER) return "INTEGER"
if(BIGINT) return "BIGINT"
if(FLOAT) return "FLOAT"
if(DOUBLE) return "DOUBLE"
if(DATE) return "DATE"
if(DATETIME) return "DATETIME"
if(TIMESTAMP) return "TIMESTAMP"
if(TIME) return "TIME"
if(STRING) return "STRING"
if(BLOB) return "BLOB"
DBColumn/proc/SqlTypeName(type_handler = sql_type)
switch (type_handler)
if (TINYINT)
return "TINYINT"
if (SMALLINT)
return "SMALLINT"
if (MEDIUMINT)
return "MEDIUMINT"
if (INTEGER)
return "INTEGER"
if (BIGINT)
return "BIGINT"
if (FLOAT)
return "FLOAT"
if (DOUBLE)
return "DOUBLE"
if (DATE)
return "DATE"
if (DATETIME)
return "DATETIME"
if (TIMESTAMP)
return "TIMESTAMP"
if (TIME)
return "TIME"
if (STRING)
return "STRING"
if (BLOB)
return "BLOB"
#undef Default_Cursor
+5 -5
View File
@@ -11,7 +11,7 @@ proc/sql_poll_population()
log_game("SQL ERROR during population polling. Failed to connect.")
else
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO `tgstation`.`population` (`playercount`, `admincount`, `time`) VALUES ([playercount], [admincount], '[sqltime]')")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO `ss13_population` (`playercount`, `admincount`, `time`) VALUES ([playercount], [admincount], '[sqltime]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during population polling. Error : \[[err]\]\n")
@@ -53,7 +53,7 @@ proc/sql_report_death(var/mob/living/carbon/human/H)
if(!dbcon.IsConnected())
log_game("SQL ERROR during death reporting. Failed to connect.")
else
var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO ss13_death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during death reporting. Error : \[[err]\]\n")
@@ -87,7 +87,7 @@ proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H)
if(!dbcon.IsConnected())
log_game("SQL ERROR during death reporting. Failed to connect.")
else
var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO ss13_death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during death reporting. Error : \[[err]\]\n")
@@ -118,7 +118,7 @@ proc/sql_commit_feedback()
log_game("SQL ERROR during feedback reporting. Failed to connect.")
else
var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM erro_feedback")
var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM ss13_feedback")
max_query.Execute()
var/newroundid
@@ -138,7 +138,7 @@ proc/sql_commit_feedback()
var/variable = item.get_variable()
var/value = item.get_value()
var/DBQuery/query = dbcon.NewQuery("INSERT INTO erro_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO ss13_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during death reporting. Error : \[[err]\]\n")
+1 -1
View File
@@ -79,7 +79,7 @@ var/datum/antagonist/raider/raiders
/obj/item/weapon/gun/projectile/automatic/mini_uzi,
/obj/item/weapon/gun/projectile/automatic/c20r,
/obj/item/weapon/gun/projectile/automatic/wt550,
/obj/item/weapon/gun/projectile/automatic/sts35,
/obj/item/weapon/gun/projectile/automatic/rifle/sts35,
/obj/item/weapon/gun/projectile/silenced,
/obj/item/weapon/gun/projectile/shotgun/pump,
/obj/item/weapon/gun/projectile/shotgun/pump/combat,
+24
View File
@@ -0,0 +1,24 @@
var/datum/antagonist/vampire/vamp
/proc/isvampire(var/mob/player)
if(!vamp || !player.mind)
return 0
if(player.mind in vamp.current_antagonists)
return 1
/datum/antagonist/vampire
id = MODE_VAMPIRE
role_type = BE_VAMPIRE
role_text = "Vampire"
role_text_plural = "Vampires"
bantype = "vampires"
feedback_tag = "vampire_objective"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
welcome_text = "You are a Vampire! Use harm intent and aim for the head to drink blood! Stay away from the Chaplain, and use the darkness to your advantage."
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
antaghud_indicator = "hudchangeling" //NEEDS TO BE CHANGED
/datum/antagonist/vampire/update_antag_mob(var/datum/mind/player)
..()
player.current.make_vampire()
+4 -1
View File
@@ -234,6 +234,10 @@ var/list/mob/living/forced_ambiance_list = new
L.update_floating( L.Check_Dense_Object() )
L.lastarea = newarea
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(!(L && L.client && (L.client.prefs.asfx_togs & ASFX_AMBIENCE))) return
play_ambience(L)
/area/proc/play_ambience(var/mob/living/L)
@@ -285,4 +289,3 @@ var/list/mob/living/forced_ambiance_list = new
H.AdjustStunned(1)
H.AdjustWeakened(1)
mob << "<span class='notice'>The sudden appearance of gravity makes you fall to the floor!</span>"
+8 -2
View File
@@ -6,12 +6,14 @@
var/list/fingerprintshidden
var/fingerprintslast = null
var/list/blood_DNA
var/was_bloodied
var/blood_color
var/last_bumped = 0
var/pass_flags = 0
var/throwpass = 0
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
var/simulated = 1 //filter for actions - used by lighting overlays
var/fluorescent // Shows up under a UV light.
///Chemistry.
var/datum/reagents/reagents = null
@@ -23,6 +25,9 @@
//Detective Work, used for the duplicate data points kept in the scanners
var/list/original_atom
/atom/proc/reveal_blood()
return
/atom/proc/assume_air(datum/gas_mixture/giver)
return null
@@ -305,7 +310,7 @@ its easier to just keep the beam vertical.
fingerprints = list()
//Hash this shit.
var/full_print = md5(H.dna.uni_identity)
var/full_print = H.get_full_print()
// Add the fingerprints
//
@@ -388,6 +393,7 @@ its easier to just keep the beam vertical.
if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
blood_DNA = list()
was_bloodied = 1
blood_color = "#A10808"
if(istype(M))
if (!istype(M.dna, /datum/dna))
@@ -407,10 +413,10 @@ its easier to just keep the beam vertical.
if(toxvomit)
this.icon_state = "vomittox_[pick(1,4)]"
/atom/proc/clean_blood()
if(!simulated)
return
fluorescent = 0
src.germ_level = 0
if(istype(blood_DNA, /list))
blood_DNA = null
+2 -2
View File
@@ -336,7 +336,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
//var/dowhat = pick("STOP THIS", "SUPPORT THIS", "CONSTANTLY INFORM THE CREW OF THIS", "IGNORE THIS", "FEAR THIS")
var/aimust = pick("LIE", "RHYME", "RESPOND TO EVERY QUESTION WITH A QUESTION", "BE POLITE", "CLOWN", "BE HAPPY", "SPEAK IN SEXUAL INNUENDOS", "TALK LIKE A PIRATE", "QUESTION AUTHORITY", "SHOUT", "BE DISTRACTED", "HEY LISTEN", "MUMBLE", "SPEAK IN HAIKU")
var/define = pick("ABSENCE OF CYBORG HUGS", "LACK OF BEATINGS", "UNBOLTED AIRLOCKS", "BOLTED AIRLOCKS", "IMPROPERLY WORDED SENTENCES", "POOR SENTENCE STRUCTURE", "BRIG TIME", "NOT REPLACING EVERY SECOND WORD WITH HONK", "HONKING", "PRESENCE OF LIGHTS", "LACK OF BEER", "WEARING CLOTHING", "NOT SAYING HELLO WHEN YOU SPEAK", "ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER", "A SMALL ISLAND OFF THE COAST OF PORTUGAL", "ANSWERING REQUESTS THAT WERE MADE WHILE CLOTHED")
var/target = pick("a traitor", "a syndicate agent", "a changeling", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid")
var/target = pick("a traitor", "a syndicate agent", "a changeling", "a vampire", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid")
var/require = pick("ADDITIONAL PYLONS", "MORE VESPENE GAS", "MORE MINERALS", "THE ULTIMATE CUP OF COFFEE", "HIGH YIELD EXPLOSIVES", "THE CLOWN", "THE VACUUM OF SPACE", "IMMORTALITY", "SAINTHOOD", "ART", "VEGETABLES", "FAT PEOPLE", "MORE LAWS", "MORE DAKKA", "HERESY", "CORPSES", "TRAITORS", "MONKEYS", "AN ARCADE", "PLENTY OF GOLD", "FIVE TEENAGERS WITH ATTITUDE")
var/allergy = pick("cotton", "uniforms", "acid", "oxygen", "human contact", "cyborg contact", "medicine", "floors")
var/allergysev = pick("deathly", "mildly", "severely", "contagiously")
@@ -468,4 +468,4 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
world << "Ion Storm Main Done"
*/
*/
+10
View File
@@ -0,0 +1,10 @@
/datum/game_mode/vampire
name = "Vampire"
round_description = "There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!"
extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet something slipped past their eyes. Something dangerous. Something alive. Most frightening of all, however, is that this something is someone. An unknown alien specimen has incorporated itself into the crew of the NSS Exodus. No one knows where it came from. No one knows who it is or what it wants. One thing is for certain though... there is never just one of them. Good luck."
config_tag = "vampire"
required_players = 1
required_enemies = 1
end_on_antag_death = 1
antag_scaling_coeff = 8
antag_tags = list(MODE_VAMPIRE)
@@ -0,0 +1,838 @@
/datum/vampire
var/list/datum/mind/vampires = list()
var/list/datum/mind/enthralled = list() //those controlled by a vampire
var/list/thralls = list() //vammpires controlling somebody
var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
var/mob/living/owner = null
var/gender = FEMALE
var/iscloaking = 0 // handles the vampire cloak toggle
var/list/powers = list() // list of available powers and passives, see defines in setup.dm
var/mob/living/carbon/human/draining // who the vampire is draining of blood
var/nullified = 0 //Nullrod makes them useless for a short while.
/datum/vampire/New(gend = FEMALE)
..()
gender = gend
/mob/proc/make_vampire()
if(!mind) return
if(!mind.vampire)
mind.vampire = new /datum/vampire(gender)
mind.vampire.owner = src
verbs += /client/vampire/proc/vampire_rejuvinate
verbs += /client/vampire/proc/vampire_hypnotise
verbs += /client/vampire/proc/vampire_glare
//testing purposes REMOVE BEFORE PUSH TO MASTER
/*for(var/handler in typesof(/client/proc))
if(findtext("[handler]","vampire_"))
verbs += handler*/
for(var/i = 1; i <= 3; i++) // CHANGE TO 3 RATHER THAN 12 AFTER TESTING IS DONE
if(!(i in mind.vampire.powers))
mind.vampire.powers.Add(i)
for(var/n in mind.vampire.powers)
switch(n)
if(VAMP_SHAPE)
verbs += /client/vampire/proc/vampire_shapeshift
if(VAMP_VISION)
continue
if(VAMP_DISEASE)
verbs += /client/vampire/proc/vampire_disease
if(VAMP_CLOAK)
verbs += /client/vampire/proc/vampire_cloak
if(VAMP_BATS)
verbs += /client/vampire/proc/vampire_bats
if(VAMP_SCREAM)
verbs += /client/vampire/proc/vampire_screech
if(VAMP_JAUNT)
verbs += /client/vampire/proc/vampire_jaunt
if(VAMP_BLINK)
verbs += /client/vampire/proc/vampire_shadowstep
if(VAMP_SLAVE)
verbs += /client/vampire/proc/vampire_enthrall
if(VAMP_FULL)
continue
/mob/proc/remove_vampire_powers()
for(var/handler in typesof(/client/vampire/proc))
if(findtext("[handler]","vampire_"))
verbs -= handler
/mob/proc/handle_bloodsucking(mob/living/carbon/human/H)
src.mind.vampire.draining = H
var/blood = 0
var/bloodtotal = 0 //used to see if we increased our blood total
var/bloodusable = 0 //used to see if we increased our blood usable
src.visible_message("\red <b>[src.name] bites [H.name]'s neck!<b>", "\red <b>You bite [H.name]'s neck and begin to drain their blood.", "\blue You hear a soft puncture and a wet sucking noise")
if(!iscarbon(src))
H.LAssailant = null
else
H.LAssailant = src
while(do_mob(src, H, 50))
if(!mind.vampire)
src << "\red Your fangs have disappeared!"
return 0
bloodtotal = src.mind.vampire.bloodtotal
bloodusable = src.mind.vampire.bloodusable
if(!H.vessel.get_reagent_amount("blood"))
src << "\red They've got no blood left to give."
break
if(H.stat < 2) //alive
blood = min(10, H.vessel.get_reagent_amount("blood"))// if they have less than 10 blood, give them the remnant else they get 10 blood
src.mind.vampire.bloodtotal += blood
src.mind.vampire.bloodusable += blood
// H.adjustCloneLoss(10) // beep boop 10 damage //probably not necessary actually honestly okay
else
blood = min(5, H.vessel.get_reagent_amount("blood"))// The dead only give 5 bloods
src.mind.vampire.bloodtotal += blood
if(bloodtotal != src.mind.vampire.bloodtotal)
src << "\blue <b>You have accumulated [src.mind.vampire.bloodtotal] [src.mind.vampire.bloodtotal > 1 ? "units" : "unit"] of blood[src.mind.vampire.bloodusable != bloodusable ?", and have [src.mind.vampire.bloodusable] left to use" : "."]"
check_vampire_upgrade(mind)
H.vessel.remove_reagent("blood",25)
src.mind.vampire.draining = null
src << "\blue You stop draining [H.name] of blood."
return 1
/mob/proc/check_vampire_upgrade(datum/mind/v)
if(!v) return
if(!v.vampire) return
var/datum/vampire/vamp = v.vampire
var/list/old_powers = vamp.powers.Copy()
// This used to be a switch statement.
// Don't use switch statements for shit like this, since blood can be any random-ass value.
// if(100) requires the blood to be at EXACTLY 100 units to trigger.
// if(blud >= 100) activates when blood is at or over 100 units.
// TODO: Make this modular.
// TIER 1
if(vamp.bloodtotal >= 100)
if(!(VAMP_VISION in vamp.powers))
vamp.powers.Add(VAMP_VISION)
if(!(VAMP_SHAPE in vamp.powers))
vamp.powers.Add(VAMP_SHAPE)
// TIER 2
if(vamp.bloodtotal >= 150)
if(!(VAMP_CLOAK in vamp.powers))
vamp.powers.Add(VAMP_CLOAK)
// TIER 3
if(vamp.bloodtotal >= 200)
if(!(VAMP_BATS in vamp.powers))
vamp.powers.Add(VAMP_BATS)
if(!(VAMP_SCREAM in vamp.powers))
vamp.powers.Add(VAMP_SCREAM)
src << "\blue Your rejuvination abilities have improved and will now heal you over time when used."
if(!(VAMP_DISEASE in vamp.powers))
vamp.powers.Add(VAMP_DISEASE)
// TIER 3.5 (/vg/)
if(vamp.bloodtotal >= 250)
if(!(VAMP_BLINK in vamp.powers))
vamp.powers.Add(VAMP_BLINK)
// TIER 4
if(vamp.bloodtotal >= 300)
if(!(VAMP_JAUNT in vamp.powers))
vamp.powers.Add(VAMP_JAUNT)
if(!(VAMP_SLAVE in vamp.powers))
vamp.powers.Add(VAMP_SLAVE)
// TIER 5
if(vamp.bloodtotal >= 500)
if(!(VAMP_FULL in vamp.powers))
vamp.powers.Add(VAMP_FULL)
announce_new_power(old_powers, vamp.powers)
/mob/proc/announce_new_power(list/old_powers, list/new_powers)
for(var/n in new_powers)
if(!(n in old_powers))
switch(n)
if(VAMP_SHAPE)
src << "\blue You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently."
verbs += /client/vampire/proc/vampire_shapeshift
if(VAMP_VISION)
src << "\blue Your vampiric vision has improved."
//no verb
if(VAMP_DISEASE)
src << "\blue You have gained the Diseased Touch ability which causes those you touch to die shortly after unless treated medically."
verbs += /client/vampire/proc/vampire_disease
if(VAMP_CLOAK)
src << "\blue You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness."
verbs += /client/vampire/proc/vampire_cloak
if(VAMP_BATS)
src << "\blue You have gained the Summon Bats ability."
verbs += /client/vampire/proc/vampire_bats // work in progress
if(VAMP_SCREAM)
src << "\blue You have gained the Chiropteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process."
verbs += /client/vampire/proc/vampire_screech
if(VAMP_JAUNT)
src << "\blue You have gained the Mist Form ability which allows you to take on the form of mist for a short period and pass over any obstacle in your path."
verbs += /client/vampire/proc/vampire_jaunt
if(VAMP_SLAVE)
src << "\blue You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time."
verbs += /client/vampire/proc/vampire_enthrall
if(VAMP_BLINK)
src << "\blue You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
verbs += /client/vampire/proc/vampire_shadowstep
if(VAMP_FULL)
src << "\blue You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatly."
//no verb
//This should hold all the vampire related powers
/mob/proc/vampire_power(required_blood=0, max_stat=0)
if(!src.mind) return 0
if(!ishuman(src))
src << "<span class='warning'>You are in too weak of a form to do this!</span>"
return 0
var/datum/vampire/vampire = src.mind.vampire
if(!vampire)
//msg_scopes("[src] has vampire verbs but isn't a vampire.")
world.log << "[src] has vampire verbs but isn't a vampire."
return 0
var/fullpower = (VAMP_FULL in vampire.powers)
if(src.stat > max_stat)
src << "<span class='warning'>You are incapacitated.</span>"
return 0
if(vampire.nullified)
if(!fullpower)
src << "<span class='warning'>Something is blocking your powers!</span>"
return 0
if(vampire.bloodusable < required_blood)
src << "<span class='warning'>You require at least [required_blood] units of usable blood to do that!</span>"
return 0
//chapel check
if(istype(loc.loc, /area/chapel))
if(!fullpower)
src << "<span class='warning'>Your powers are useless on this holy ground.</span>"
return 0
return 1
/mob/proc/vampire_affected(datum/mind/M)
//Other vampires aren't affected
if(mind && mind.vampire) return 0
//Chaplains are resistant to vampire powers
if(mind && mind.assigned_role == "Chaplain")
return 0
if(get_species() == "Machine")
return 0
//Vampires who have reached their full potential can affect nearly everything
if(M && M.vampire && (VAMP_FULL in M.vampire.powers))
return 1 // This doesn't really need to be here because of well the line below it.
return 1
/mob/proc/vampire_can_reach(mob/M as mob, active_range = 1)
if(M.loc == src.loc) return 1 //target and source are in the same thing
if(!isturf(src.loc) || !isturf(M.loc)) return 0 //One is inside, the other is outside something.
if(Adjacent(M))//if(AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, active_range)) //If a path exists, good!
return 1
return 0
/mob/proc/vampire_active(required_blood=0, max_stat=0, active_range=1)
var/pass = vampire_power(required_blood, max_stat)
if(!pass) return
var/datum/vampire/vampire = mind.vampire
if(!vampire) return
var/list/victims = list()
for(var/mob/living/carbon/C in view(active_range))
if(C==src) continue
victims += C
var/mob/living/carbon/T = input(src, "Victim?") as null|anything in victims
if(!T) return
if(!(T in view(active_range))) return
if(!vampire_can_reach(T, active_range)) return
if(!vampire_power(required_blood, max_stat)) return
return T
/client/vampire/proc/vampire_rejuvinate()
set category = "Abilities"
set name = "Rejuvinate "
set desc= "Flush your system with spare blood to remove any incapacitating effects"
var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(0, 1))
M.current.weakened = 0
M.current.stunned = 0
M.current.paralysis = 0
//M.vampire.bloodusable -= 10
M.current << "\blue You flush your system with clean blood and remove any incapacitating effects."
spawn(1)
if(M.vampire.bloodtotal >= 200)
for(var/i = 0; i < 5; i++)
M.current.adjustBruteLoss(-2)
M.current.adjustOxyLoss(-5)
M.current.adjustToxLoss(-2)
M.current.adjustFireLoss(-2)
sleep(35)
M.current.verbs -= /client/vampire/proc/vampire_rejuvinate
spawn(200)
M.current.verbs += /client/vampire/proc/vampire_rejuvinate
/client/vampire/proc/vampire_hypnotise()
set category = "Abilities"
set name = "Hypnotise" // (20)
set desc= "A piercing stare that incapacitates your victim for a good length of time."
var/datum/mind/M = usr.mind
if(!M) return
var/mob/living/carbon/C = M.current.vampire_active(0, 0, 1) //(20, 0, 1)
if(!C) return
if(C==usr)
M.current << "\red You can't do that to yourself"
return
if(!M.current.has_eyes())
M.current << "\red You don't have eyes"
return
var/vampgender
if(M.current.gender == "male")
vampgender = "he"
else
vampgender = "she"
M.current.visible_message("<span class='warning'>[M]'s eyes flash briefly as [vampgender] stares into [C.name]'s eyes</span>")
// M.current.remove_vampire_blood(20) Moved to remove if it works only.
if(M.current.vampire_power(0, 0)) //if(M.current.vampire_power(20, 0))
M.current.verbs -= /client/vampire/proc/vampire_hypnotise
spawn(1200)
M.current.verbs += /client/vampire/proc/vampire_hypnotise
if(do_mob(M.current, C, 50))
if(C.mind && C.mind.vampire)
M.current << "\red Your piercing gaze fails to knock out [C.name]."
C << "\blue [M.current]'s feeble gaze is ineffective."
return
else
M.current << "\red Your piercing gaze knocks out [C.name]."
C << "\red You find yourself unable to move and barely able to speak"
C.Weaken(20)
C.Stun(20)
C.stuttering = 20
// M.current.remove_vampire_blood(20)
else
M.current << "\red You broke your gaze."
return
/client/vampire/proc/vampire_disease()
set category = "Abilities"
set name = "Diseased Touch (200)"
set desc = "Touches your victim with infected blood giving them the Shutdown Syndrome which quickly shutsdown their major organs resulting in a quick painful death."
var/datum/mind/M = usr.mind
if(!M) return
var/mob/living/carbon/C = M.current.vampire_active(200, 0, 1)
if(!C) return
if(C==usr)
M.current << "\red You can't do that to yourself"
return
if(C.get_species() == "Machine")
M.current << "\red You can't to that to a machine"
return
if(!M.current.vampire_can_reach(C, 1))
M.current << "\red <b>You cannot touch [C.name] from where you are standing!"
return
M.current << "\red You stealthily infect [C.name] with your diseased touch."
/*var/t_him = "it"
if (src.gender == MALE)
t_him = "him"
else if (src.gender == FEMALE)
t_him = "her"
M.current.visible_message("\blue [M] shakes [src] trying to wake [t_him] up!" )
playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)*/
C.help_shake_act(M.current) // i use da colon
if(!C.vampire_affected(M))
M.current << "\red They seem to be unaffected."
return
var/datum/disease2/disease/shutdown = new /datum/disease2/disease
var/datum/disease2/effectholder/holder = new /datum/disease2/effectholder
var/datum/disease2/effect/organs/vampire/O = new /datum/disease2/effect/organs/vampire
holder.effect += O
holder.chance = 10
shutdown.infectionchance = 100
shutdown.antigen |= text2num(pick(ALL_ANTIGENS))
shutdown.antigen |= text2num(pick(ALL_ANTIGENS))
shutdown.spreadtype = "None"
shutdown.uniqueID = rand(0,10000)
shutdown.effects += holder
shutdown.speed = 1
shutdown.stage = 2
shutdown.clicks = 185
msg_admin_attack("[key_name_admin(usr)] gave [key_name_admin(C)] the shutdown disease - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[C.x];Y=[C.y];Z=[C.z]'>JMP</a>")
usr.attack_log += text("\[[time_stamp()]\] <font color='red'>Gave [C.name] ([C.ckey]) the shutdown disease</font>")
C.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been given the shutdown disease by [usr.name] ([usr.ckey])</font>")
infect_virus2(C,shutdown,0)
M.current.remove_vampire_blood(200)
M.current.verbs -= /client/vampire/proc/vampire_disease
spawn(1800) M.current.verbs += /client/vampire/proc/vampire_disease
/client/vampire/proc/vampire_glare()
set category = "Abilities"
set name = "Glare"
set desc= "A scary glare that incapacitates people for a short while around you."
var/datum/mind/M = usr.mind
if(!M) return
if(!M.current.has_eyes())
M.current << "\red You don't have eyes"
return
if(M.current.vampire_power(0, 1))
M.current.visible_message("\red <b>[M.current]'s eyes emit a blinding flash!")
//M.vampire.bloodusable -= 10
M.current.verbs -= /client/vampire/proc/vampire_glare
spawn(800)
M.current.verbs += /client/vampire/proc/vampire_glare
if(istype(M.current:glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
M.current << "<span class='warning'>You're blindfolded!</span>"
return
for(var/mob/living/carbon/C in view(1))
if(C == M.current) continue //Don't stunn yourself
if(!C.vampire_affected(M) && !C.get_species() == "Machine") //Or machines
continue
if(!M.current.vampire_can_reach(C, 1)) continue
// C.Stun(8)
C.Weaken(8)
C.stuttering = 20
C << "\red You are blinded by [M.current]'s glare"
/client/vampire/proc/vampire_shapeshift() //Hi. I'm stupid and there are missing procs all around. Namely the randomname proc. I can't find it and can't code a new one because I am bad. Sorry!
set category = "Abilities"
set name = "Shapeshift (50)"
set desc = "This does nothing. It's broken. Sorry!"//orig text: Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes.
/* var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(50, 0))
M.current.visible_message("<span class='warning'>[M.current.name] transforms!</span>")
M.current.client.prefs.real_name = M.current.generate_name() //random_name(M.current.gender)
M.current.client.prefs.randomize_appearance_for(M.current)
M.current.regenerate_icons()
M.current.remove_vampire_blood(50)
M.current.verbs -= /client/vampire/proc/vampire_shapeshift
spawn(1800) M.current.verbs += /client/vampire/proc/vampire_shapeshift
*/
/client/vampire/proc/vampire_screech()
set category = "Abilities"
set name = "Chiropteran Screech (90)"
set desc = "An extremely loud shriek that stuns nearby humans in a four-tile radius, as well as shattering the windows."
var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(90, 0))
M.current.visible_message("\red [M.current.name] lets out an ear piercing shriek!", "\red You let out a loud shriek.", "\red You hear a loud painful shriek!")
for(var/mob/living/carbon/C in hearers(4, M.current))
if(C == M.current) continue
if(ishuman(C) && (C:l_ear || C:r_ear) && istype((C:l_ear || C:r_ear), /obj/item/clothing/ears/earmuffs)) continue
if(!C.vampire_affected(M))
if(!C.get_species() == "Machine")
continue
C << "<span class='warning'><font size='3'><b>You hear a ear piercing shriek and your senses dull!</font></b></span>"
C.Weaken(5)
C.ear_deaf = 20
C.stuttering = 20
C.Stun(5)
// C.Jitter(150)
for(var/obj/structure/window/W in view(7))
W.shatter()
playsound(M.current.loc, 'sound/effects/creepyshriek.ogg', 100, 1)
M.current.remove_vampire_blood(90)
M.current.verbs -= /client/vampire/proc/vampire_screech
spawn(3600) M.current.verbs += /client/vampire/proc/vampire_screech
/client/vampire/proc/vampire_enthrall()
set category = "Abilities"
set name = "Enthrall (150)"
set desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
var/datum/mind/M = usr.mind
if(!M) return
var/mob/living/carbon/C = M.current.vampire_active(150, 0, 1)
if(!C) return
if(C==usr)
M.current << "\red You can't do that to yourself"
return
if(C.get_species() == "Machine")
M.current << "\red You can only enthrall humans"
return
M.current.visible_message("\red [M.current.name] bites [C.name]'s neck!", "\red You bite [C.name]'s neck and begin the flow of power.")
C << "<span class='warning'>You feel the tendrils of evil invade your mind.</span>"
if(!ishuman(C))
M.current << "\red You can only enthrall humans"
return
if(do_mob(M.current, C, 50))
if(M.current.can_enthrall(C)) // recheck
if(M.current.vampire_power(150, 0))
M.current.handle_enthrall(C)
M.current.remove_vampire_blood(150)
M.current.verbs -= /client/vampire/proc/vampire_enthrall
spawn(1800) M.current.verbs += /client/vampire/proc/vampire_enthrall
return
else
M.current << "\red You or your target either moved or you dont have enough usable blood."
return
/client/vampire/proc/vampire_cloak()
set category = "Abilities"
set name = "Cloak of Darkness (toggle)"
set desc = "Toggles whether you are currently cloaking yourself in darkness."
var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(0, 0))
M.vampire.iscloaking = !M.vampire.iscloaking
M.current << "\blue You will now be [M.vampire.iscloaking ? "hidden" : "seen"] in darkness."
/mob/proc/handle_vampire_cloak()
if(!mind || !mind.vampire || !ishuman(src))
alpha = 255
return
var/turf/simulated/T = get_turf(src)
if(!istype(T))
return 0
if(!mind.vampire.iscloaking)
alpha = 255
return 0
// if(T.lighting_lumcount <= 2)
// alpha = round((255 * 0.15))
// return 1
else
alpha = round((255 * 0.80))
/mob/proc/can_enthrall(mob/living/carbon/C)
var/enthrall_safe = 0
var/datum/vampire/vampire = src.mind.vampire
for(var/obj/item/weapon/implant/loyalty/L in C)
if(L && L.implanted)
enthrall_safe = 1
break
// for(var/obj/item/weapon/implant/traitor/T in C)
// if(T && T.implanted)
// enthrall_safe = 1
// break
if(!C)
world.log << "something bad happened on enthralling a mob src is [src] [src.key] \ref[src]"
return 0
if(!C.mind)
src << "\red [C.name]'s mind is not there for you to enthrall."
return 0
if(enthrall_safe || ( C.mind in vampire.vampires )||( C.mind.vampire )||( C.mind in vampire.enthralled ))
C.visible_message("\red [C] seems to resist the takeover!", "\blue You feel a familiar sensation in your skull that quickly dissipates.")
return 0
if(!C.vampire_affected(mind))
C.visible_message("\red [C] seems to resist the takeover!", "\blue Your faith of [ticker.Bible_deity_name] has kept your mind clear of all evil")
return 0
if(!ishuman(C))
src << "\red You can only enthrall humans!"
return 0
return 1
/mob/proc/handle_enthrall(mob/living/carbon/human/H as mob)
if(!istype(H))
//msg_scopes("handle_enthrall fucked up with no H < [src]")
src << "<b>\red SOMETHING WENT WRONG, YELL AT POMF OR NEXIS</b>"
return 0
var/ref = "\ref[src.mind]"
if(!(src.mind.vampire.thralls))
src.mind.vampire.thralls[ref] = list(H.mind)
else
src.mind.vampire.thralls[ref] += H.mind
//msg_scopes("[H.name] Changed in handle_enthrall") //purely here to see live changes incase of unexpected things
src.mind.vampire.enthralled.Add(H.mind)
src.mind.vampire.enthralled[H.mind] = src.mind
H.mind.special_role = "VampThrall"
H << "<b>\red You have been Enthralled by [name]. Follow their every command.</b>"
src << "\red You have successfully Enthralled [H.name]. <i>If they refuse to do as you say just adminhelp.</i>"
var/client/vampire/c = src
c.update_vampire_icons_added(H.mind)
c.update_vampire_icons_added(src.mind)
msg_admin_attack("[key_name_admin(src)] has mind-slaved [key_name_admin(H)] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[H.x];Y=[H.y];Z=[H.z]'>JMP</a>.")
/client/vampire/proc/vampire_bats()
set category = "Abilities"
set name = "Summon Bats (60)"
set desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead."
var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(60, 0))
var/list/turf/locs = new
var/number = 0
for(var/direction in alldirs) //looking for bat spawns
if(locs.len == 2) //we found 2 locations and thats all we need
break
var/turf/T = get_step(M.current,direction) //getting a loc in that direction
if(AStar(M.current.loc, T, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 1)) // if a path exists, so no dense objects in the way its valid salid
locs += T
if(locs.len)
for(var/turf/tospawn in locs)
number++
new /mob/living/simple_animal/hostile/scarybat(tospawn, M.current)
if(number != 2) //if we only found one location, spawn one on top of our tile so we dont get stacked bats
new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
else // we had no good locations so make two on top of us
new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current)
M.current.remove_vampire_blood(60)
M.current.verbs -= /client/vampire/proc/vampire_bats
spawn(1200) M.current.verbs += /client/vampire/proc/vampire_bats
/client/vampire/proc/vampire_jaunt()
//AHOY COPY PASTE INCOMING
set category = "Abilities"
set name = "Mist Form (30)"
set desc = "You take on the form of mist for a short period of time."
var/jaunt_duration = 50 //in deciseconds
var/datum/mind/M = usr.mind
if(!M) return
if(M.current.vampire_power(30, 0))
if(M.current.buckled) M.current.buckled.unbuckle_mob()
spawn(0)
var/originalloc = get_turf(M.current.loc)
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( originalloc )
var/atom/movable/overlay/animation = new /atom/movable/overlay( originalloc )
animation.name = "water"
animation.density = 0
animation.anchored = 1
animation.icon = 'icons/mob/mob.dmi'
animation.icon_state = "liquify"
animation.layer = 5
animation.master = holder
M.current.ExtinguishMob()
M.current.weakened = 0
M.current.stunned = 0
if(M.current.buckled)
M.current.buckled.unbuckle_mob()
flick("liquify",animation)
M.current.loc = holder
M.current.client.eye = holder
var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread()
steam.set_up(10, 0, originalloc)
steam.start()
sleep(jaunt_duration)
var/mobloc = get_turf(M.current.loc)
/* if(get_area(mobloc) == /area/security/armoury/gamma)
M << "A strange energy repels you!"
mobloc = originalloc*/
animation.loc = mobloc
steam.location = mobloc
steam.start()
M.current.canmove = 0
sleep(20)
flick("reappear",animation)
sleep(5)
if(!M.current.Move(mobloc))
for(var/direction in list(1,2,4,8,5,6,9,10))
var/turf/T = get_step(mobloc, direction)
if(T)
if(M.current.Move(T))
break
M.current.canmove = 1
M.current.client.eye = M.current
qdel(animation)
qdel(holder)
M.current.remove_vampire_blood(30)
M.current.verbs -= /client/vampire/proc/vampire_jaunt
spawn(600) M.current.verbs += /client/vampire/proc/vampire_jaunt
// Blink for vamps
// Less smoke spam.
/client/vampire/proc/vampire_shadowstep()
set category = "Abilities"
set name = "Shadowstep (30)"
set desc = "Vanish into the shadows."
var/datum/mind/M = usr.mind
if(!M) return
// Teleport radii
var/inner_tele_radius = 0
var/outer_tele_radius = 6
// Maximum lighting_lumcount.
// var/max_lum = 1
if(M.current.vampire_power(30, 0))
if(M.current.buckled) M.current.buckled.unbuckle_mob()
spawn(0)
var/list/turfs = new/list()
for(var/turf/T in range(usr,outer_tele_radius))
if(T in range(usr,inner_tele_radius)) continue
if(istype(T,/turf/space)) continue
if(T.density) continue
if(T.x>world.maxx-outer_tele_radius || T.x<outer_tele_radius) continue //putting them at the edge is dumb
if(T.y>world.maxy-outer_tele_radius || T.y<outer_tele_radius) continue
// LIGHTING CHECK
// if(T.lighting_lumcount > max_lum) continue
// turfs += T
//M.current.remove_vampire_blood(30) This isn't the right place for this either.
if(!turfs.len)
usr << "\red You cannot find darkness to step to."
return
var/turf/picked = pick(turfs)
if(!picked || !isturf(picked))
return
M.current.ExtinguishMob()
if(M.current.buckled)
M.current.buckled.unbuckle_mob()
var/atom/movable/overlay/animation = new /atom/movable/overlay( get_turf(usr) )
animation.name = usr.name
animation.density = 0
animation.anchored = 1
animation.icon = usr.icon
animation.alpha = 127
animation.layer = 5
//animation.master = src
usr.loc = picked
M.current.remove_vampire_blood(30)
spawn(10)
del(animation)
// M.current.remove_vampire_blood(30)
M.current.verbs -= /client/vampire/proc/vampire_shadowstep
spawn(20)
M.current.verbs += /client/vampire/proc/vampire_shadowstep
/mob/proc/remove_vampire_blood(amount = 0)
var/bloodold
if(!mind || !mind.vampire)
return
bloodold = mind.vampire.bloodusable
mind.vampire.bloodusable = max(0, (mind.vampire.bloodusable - amount))
if(bloodold != mind.vampire.bloodusable)
src << "\blue <b>You have [mind.vampire.bloodusable] left to use.</b>"
//prepare for copypaste
/client/vampire/proc/update_vampire_icons_added(datum/mind/vampire_mind)
var/ref = "\ref[vampire_mind]"
if(ref in vampire_mind.vampire.thralls)
if(vampire_mind.current)
if(vampire_mind.current.client)
var/I = image('icons/mob/mob.dmi', loc = vampire_mind.current, icon_state = "vampire")
vampire_mind.current.client.images += I
for(var/headref in vampire_mind.vampire.thralls)
for(var/datum/mind/t_mind in vampire_mind.vampire.thralls[headref])
var/datum/mind/head = locate(headref)
if(head)
if(head.current)
if(head.current.client)
var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall")
head.current.client.images += I
if(t_mind.current)
if(t_mind.current.client)
var/I = image('icons/mob/mob.dmi', loc = head.current, icon_state = "vampire")
t_mind.current.client.images += I
if(t_mind.current)
if(t_mind.current.client)
var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall")
t_mind.current.client.images += I
/client/vampire/proc/update_vampire_icons_removed(datum/mind/vampire_mind)
for(var/headref in vampire_mind.vampire.thralls)
var/datum/mind/head = locate(headref)
for(var/datum/mind/t_mind in vampire_mind.vampire.thralls[headref])
if(t_mind.current)
if(t_mind.current.client)
for(var/image/I in t_mind.current.client.images)
if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current)
//world.log << "deleting [vampire_mind] overlay"
del(I)
if(head)
//world.log << "found [head.name]"
if(head.current)
if(head.current.client)
for(var/image/I in head.current.client.images)
if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current)
//world.log << "deleting [vampire_mind] overlay"
del(I)
if(vampire_mind.current)
if(vampire_mind.current.client)
for(var/image/I in vampire_mind.current.client.images)
if(I.icon_state == "vampthrall" || I.icon_state == "vampire")
del(I)
/client/vampire/proc/remove_vampire_mind(datum/mind/vampire_mind, datum/mind/head)
//var/list/removal
if(!istype(head))
head = vampire_mind //workaround for removing a thrall's control over the enthralled
var/ref = "\ref[head]"
if(vampire_mind.vampire.thralls)
vampire_mind.vampire.thralls[ref] -= vampire_mind
vampire_mind.vampire.enthralled -= vampire_mind
//vampire.special_role = null
update_vampire_icons_removed(vampire_mind)
//world << "Removed [vampire_mind.current.name] from vampire shit"
vampire_mind.current << "\red <FONT size = 3><B>The fog clouding your mind clears. You remember nothing from the moment you were enthralled until now.</B></FONT>"
/mob/living/carbon/human/proc/check_sun()
var/ax = x
var/ay = y
for(var/i = 1 to 20)
ax += sun.dx
ay += sun.dy
var/turf/T = locate( round(ax,0.5),round(ay,0.5),z)
if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy)
break
if(T.density)
return
if(prob(35))
switch(health)
if(80 to 100)
src << "\red Your skin flakes away..."
if(60 to 80)
src << "<span class='warning'>Your skin sizzles!</span>"
// if((-INFINITY) to 60)
// if(!on_fire)
// src << "<b>\red Your skin catches fire!</b>"
// else
// src << "<b>\red You continue to burn!</b>"
// fire_stacks += 5
// IgniteMob()
// emote("scream")
//else
// switch(health)
// if((-INFINITY) to 60)
// fire_stacks++
// IgniteMob()
adjustFireLoss(30) //Original value was 3. Barely did anything. Vamps should vaporize in starlight.
/mob/living/carbon/human/proc/handle_vampire()
/* if(hud_used)
if(!hud_used.vampire_blood_display)
hud_used.vampire_hud()
hud_used.human_hud('icons/mob/screen1_Vampire.dmi')
hud_used.vampire_blood_display.maptext_width = 64
hud_used.vampire_blood_display.maptext_height = 26
hud_used.vampire_blood_display.maptext = "<div align='left' valign='top' style='position:relative; top:0px; left:6px'> U:<font color='#33FF33' size='1'>[mind.vampire.bloodusable]</font><br> T:<font color='#FFFF00' size='1'>[mind.vampire.bloodtotal]</font></div>"
*/
handle_vampire_cloak()
if(istype(loc, /turf/space))
check_sun()
mind.vampire.nullified = max(0, mind.vampire.nullified - 1)
+2 -1
View File
@@ -10,7 +10,8 @@
selection_color = "#dddddd"
access = list() //See /datum/job/assistant/get_access()
minimal_access = list() //See /datum/job/assistant/get_access()
alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor")
//alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Security Cadet", "Visitor")
alt_titles = list("Visitor")
/datum/job/assistant/equip(var/mob/living/carbon/human/H)
if(!H) return 0
+19 -5
View File
@@ -31,7 +31,12 @@
H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/head_of_security(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/device/pda/heads/hos(H), slot_belt)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
if(H.species.name == "Tajaran")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves)
if(H.species.name == "Unathi")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves)
else
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
// H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(H), slot_wear_mask) //Grab one from the armory you donk
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud(H), slot_glasses)
H.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(H), slot_s_store)
@@ -68,7 +73,12 @@
H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/warden(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/device/pda/warden(H), slot_belt)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
if(H.species.name == "Tajaran")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves)
if(H.species.name == "Unathi")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves)
else
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud(H), slot_glasses)
// H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(H), slot_wear_mask) //Grab one from the armory you donk
H.equip_to_slot_or_del(new /obj/item/device/flash(H), slot_l_store)
@@ -106,16 +116,20 @@
H.equip_to_slot_or_del(new /obj/item/clothing/under/det(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/device/pda/detective(H), slot_belt)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
if(H.species.name == "Tajaran")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/tajara(H), slot_gloves)
if(H.species.name == "Unathi")
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black/unathi(H), slot_gloves)
else
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(H), slot_gloves)
H.equip_to_slot_or_del(new /obj/item/weapon/flame/lighter/zippo(H), slot_l_store)
if(H.backbag == 1)//Why cant some of these things spawn in his office?
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_l_hand)
H.equip_to_slot_or_del(new /obj/item/device/detective_scanner(H), slot_r_store)
else
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/device/detective_scanner(H), slot_in_backpack)
if(H.mind.role_alt_title && H.mind.role_alt_title == "Forensic Technician")
H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/forensics/blue(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit, slot_r_hand)
else
H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/det_suit(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/head/det_hat(H), slot_head)
+14 -5
View File
@@ -11,6 +11,8 @@ var/const/ENGINEER =(1<<6)
var/const/ATMOSTECH =(1<<7)
var/const/AI =(1<<8)
var/const/CYBORG =(1<<9)
var/const/INTERN_SEC =(1<<10)
var/const/INTERN_ENG =(1<<11)
var/const/MEDSCI =(1<<1)
@@ -26,7 +28,8 @@ var/const/PSYCHIATRIST =(1<<7)
var/const/ROBOTICIST =(1<<8)
var/const/XENOBIOLOGIST =(1<<9)
var/const/PARAMEDIC =(1<<10)
var/const/INTERN_MED =(1<<11)
var/const/INTERN_SCI =(1<<12)
var/const/CIVILIAN =(1<<2)
@@ -64,6 +67,7 @@ var/list/engineering_positions = list(
"Chief Engineer",
"Station Engineer",
"Atmospheric Technician",
"Engineering Apprentice"
)
@@ -73,7 +77,8 @@ var/list/medical_positions = list(
"Geneticist",
"Psychiatrist",
"Chemist",
"Paramedic"
"Paramedic",
"Nursing Intern"
)
@@ -82,7 +87,8 @@ var/list/science_positions = list(
"Scientist",
"Geneticist", //Part of both medical and science
"Roboticist",
"Xenobiologist"
"Xenobiologist",
"Lab Assistant"
)
//BS12 EDIT
@@ -106,7 +112,8 @@ var/list/security_positions = list(
"Head of Security",
"Warden",
"Detective",
"Security Officer"
"Security Officer",
"Security Cadet"
)
@@ -118,7 +125,7 @@ var/list/nonhuman_positions = list(
/proc/guest_jobbans(var/job)
return ((job in command_positions) || (job in nonhuman_positions) || (job in security_positions))
return ((job in command_positions))
/proc/get_job_datums()
var/list/occupations = list()
@@ -140,3 +147,5 @@ var/list/nonhuman_positions = list(
titles = J.alt_titles
return titles
//Mahzel : Job preview not added because code don't exist in BS12
+62 -20
View File
@@ -3,49 +3,91 @@
var/list/whitelist = list()
/hook/startup/proc/loadWhitelist()
if(config.usewhitelist)
if (config.usewhitelist)
load_whitelist()
return 1
/proc/load_whitelist()
whitelist = file2list(WHITELISTFILE)
if(!whitelist.len) whitelist = null
if (config.sql_whitelists)
establish_db_connection()
if (!dbcon.IsConnected())
//Continue with the old code if we have no database.
error("Database connection failed while loading whitelists. Reverting to legacy system.")
config.sql_whitelists = 0
else
return
whitelist = file2list(WHITELISTFILE)
if (!whitelist.len)
whitelist = null
/proc/check_whitelist(mob/M)
if (config.sql_whitelists)
var/head_of_staff_whitelist = 1
if (M.client && M.client.whitelist_status)
return (M.client.whitelist_status & head_of_staff_whitelist)
/proc/check_whitelist(mob/M /*, var/rank*/)
if(!whitelist)
return 0
return ("[M.ckey]" in whitelist)
else
if (!whitelist)
return 0
return ("[M.ckey]" in whitelist)
/var/list/alien_whitelist = list()
/hook/startup/proc/loadAlienWhitelist()
if(config.usealienwhitelist)
if (config.usealienwhitelist)
load_alienwhitelist()
return 1
/proc/load_alienwhitelist()
if (config.sql_whitelists)
establish_db_connection()
if (!dbcon.IsConnected())
//Continue with the old code if we have no database.
error("Database connection failed while loading alien whitelists. Reverting to legacy system.")
config.sql_whitelists = 0
else
var/DBQuery/query = dbcon.NewQuery("SELECT status_name, flag FROM ss13_whitelist_statuses")
query.Execute()
while (query.NextRow())
if (query.item[1] in whitelisted_species)
whitelisted_species[query.item[1]] = text2num(query.item[2])
return
var/text = file2text("config/alienwhitelist.txt")
if (!text)
log_misc("Failed to load config/alienwhitelist.txt")
else
alien_whitelist = text2list(text, "\n")
//todo: admin aliens
/proc/is_alien_whitelisted(mob/M, var/species)
if(!config.usealienwhitelist)
if (!config.usealienwhitelist)
return 1
if(species == "human" || species == "Human")
return 1
if(check_rights(R_ADMIN, 0))
return 1
if(!alien_whitelist)
if (!M || !species)
return 0
if(M && species)
for (var/s in alien_whitelist)
if(findtext(s,"[M.ckey] - [species]"))
return 1
if(findtext(s,"[M.ckey] - All"))
return 1
if (lowertext(species) == "human")
return 1
if (!alien_whitelist && !config.sql_whitelists)
return 0
if (config.sql_whitelists)
if (M.client && M.client.whitelist_status)
return (M.client.whitelist_status & whitelisted_species[species])
else
if (M && species)
for (var/s in alien_whitelist)
if (findtext(s,"[M.ckey] - [species]"))
return 1
if (findtext(s,"[M.ckey] - All"))
return 1
return 0
#undef WHITELISTFILE
-2
View File
@@ -15,6 +15,4 @@
return src.attack_hand(user)
/obj/machinery/button/attackby(obj/item/weapon/W, mob/user as mob)
if(istype(W, /obj/item/device/detective_scanner))
return
return src.attack_hand(user)
+1 -17
View File
@@ -24,23 +24,7 @@
user << "Error, no route to host."
/obj/machinery/button/remote/attackby(obj/item/weapon/W, mob/user as mob)
/* For later implementation
if (istype(W, /obj/item/weapon/screwdriver))
{
if(wiresexposed)
icon_state = "doorctrl0"
wiresexposed = 0
else
icon_state = "doorctrl-open"
wiresexposed = 1
return
}
*/
if(istype(W, /obj/item/device/detective_scanner))
return
if(istype(W, /obj/item/weapon/card/emag))
if (istype(W, /obj/item/weapon/card/emag))
req_access = list()
req_one_access = list()
playsound(src.loc, "sparks", 100, 1)
+18 -20
View File
@@ -30,7 +30,7 @@
var/hasShocked = 0 //Prevents multiple shocks from happening
var/secured_wires = 0
var/datum/wires/airlock/wires = null
var/obj/item/device/magnetic_lock/bracer = null
var/open_sound_powered = 'sound/machines/airlock.ogg'
var/open_sound_unpowered = 'sound/machines/airlock_creaking.ogg'
@@ -481,7 +481,6 @@ About the new airlock wires panel:
else
return 0
/obj/machinery/door/airlock/update_icon()
if(overlays) overlays.Cut()
if(density)
@@ -728,20 +727,26 @@ About the new airlock wires panel:
else if (activate && !src.lights)
lights = 1
usr << "The door bolt lights have been enabled."
update_icon()
return 1
/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob)
//world << text("airlock attackby src [] obj [] mob []", src, C, user)
if(!istype(usr, /mob/living/silicon))
if(src.isElectrified())
if(src.shock(user, 75))
return
if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll))
if(istype(C, /obj/item/taperoll))
return
src.add_fingerprint(user)
if (istype(C, /obj/item/device/magnetic_lock))
if (bracer)
user << "<span class='notice'>There is already a [bracer] on [src]!</span>"
return
var/obj/item/device/magnetic_lock/newbracer = C
newbracer.attachto(src, user)
return
if(!repairing && (istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
var/obj/item/weapon/weldingtool/W = C
if(W.remove_fuel(0,user))
@@ -792,16 +797,13 @@ About the new airlock wires panel:
da.state = 1
da.created_name = src.name
da.update_state()
if(operating == -1 || (stat & BROKEN))
new /obj/item/weapon/circuitboard/broken(src.loc)
operating = 0
else
if (!electronics) create_electronics()
electronics.loc = src.loc
electronics = null
qdel(src)
return
else if(arePowerSystemsOn())
@@ -819,6 +821,7 @@ About the new airlock wires panel:
user << "<span class='notice'>The airlock's bolts prevent it from being forced.</span>"
else if( !welded && !operating )
if(density)
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(F.wielded)
spawn(0) open(1)
@@ -830,7 +833,6 @@ About the new airlock wires panel:
spawn(0) close(1)
else
user << "<span class='warning'>You need to be wielding \the [C] to do that.</span>"
else
..()
return
@@ -852,12 +854,12 @@ About the new airlock wires panel:
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
update_icon()
return
/obj/machinery/door/airlock/open(var/forced=0)
if(!can_open(forced))
return 0
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
@@ -875,7 +877,9 @@ About the new airlock wires panel:
if(!forced)
if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
return 0
if (bracer)
visible_message("<span class='notice'>[src]'s actuators whirr, but the door does not open.</span>")
return 0
if(locked || welded)
return 0
return ..()
@@ -883,12 +887,10 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/can_close(var/forced=0)
if(locked || welded)
return 0
if(!forced)
//despite the name, this wire is for general door control.
if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR))
return 0
return ..()
/atom/movable/proc/blocks_airlock()
@@ -941,22 +943,20 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/close(var/forced=0)
if(!can_close(forced))
return 0
if(safe)
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
if(AM.blocks_airlock())
if(world.time > next_beep_at)
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
next_beep_at = world.time + SecondsToTicks(10)
close_door_at = world.time + 6
return
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
if(AM.airlock_crush(DOOR_CRUSH_DAMAGE))
take_damage(DOOR_CRUSH_DAMAGE)
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
if(arePowerSystemsOn())
playsound(src.loc, open_sound_powered, 100, 1)
@@ -972,9 +972,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/lock(var/forced=0)
if(locked)
return 0
if (operating && !forced) return 0
src.locked = 1
for(var/mob/M in range(1,src))
M.show_message("You hear a click from the bottom of the door.", 2)
@@ -984,10 +982,8 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/unlock(var/forced=0)
if(!src.locked)
return
if (!forced)
if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return
src.locked = 0
for(var/mob/M in range(1,src))
M.show_message("You hear a click from the bottom of the door.", 2)
@@ -1081,6 +1077,8 @@ About the new airlock wires panel:
update_icon()
/obj/machinery/door/airlock/proc/prison_open()
if (bracer)
return
src.unlock()
src.open()
src.lock()
+40 -1
View File
@@ -26,7 +26,10 @@
var/timing = 1 // boolean, true/1 timer is on, false/0 means it's not timing
var/picture_state // icon_state of alert picture, if not displaying text/numbers
var/list/obj/machinery/targets = list()
var/list/obj/item/clothing/under/color/orange/uniforms = list()
var/timetoset = 0 // Used to set releasetime upon starting the timer
var/alerted = 0
var/spamcheck = 0
maptext_height = 26
maptext_width = 32
@@ -47,6 +50,10 @@
if(C.id == src.id)
targets += C
for(var/obj/item/clothing/under/color/orange/D in world)
if(D.id == id)
uniforms += D
if(targets.len==0)
stat |= BROKEN
update_icon()
@@ -68,6 +75,8 @@
if(timeleft > 1e5)
src.releasetime = 0
if(timeleft < 30 && !alerted)
alertuniforms()
if(world.timeofday > src.releasetime)
src.timer_end() // open doors, reset timer, clear status screen
@@ -152,6 +161,35 @@
/obj/machinery/door_timer/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
// Alert the uniform wearers that their timer is about to end up
/obj/machinery/door_timer/proc/alertuniforms()
if(stat & (NOPOWER|BROKEN)) return
if(!uniforms.len)
alerted = 1
return
for(var/obj/item/clothing/under/color/orange/D in uniforms)
if(!ishuman(D.loc)) continue
D.loc << "A speaker in the collar of your suit pings:\n\blue Your cell timer will expire in 30 seconds or less. Please go to your cell to speed up processing."
alerted = 1
return
// Alert the uniform wearers that they are needed at their cell
/obj/machinery/door_timer/proc/summonuniforms()
if(stat & (NOPOWER|BROKEN)) return
if(spamcheck) return
if(!uniforms.len) return
for(var/obj/item/clothing/under/color/orange/D in uniforms)
if(!ishuman(D.loc)) continue
D.loc << "A speaker in the collar of your suit pings:\n\red You have been summoned to your cell!"
spamcheck = 1
spawn(30)
spamcheck = 0
return
//Allows humans to use door_timer
//Opens dialog window when someone clicks on door timer
@@ -249,7 +287,8 @@
if(href_list["change"])
src.timer_start()
if(href_list["summon"])
summonuniforms()
src.add_fingerprint(usr)
src.updateUsrDialog()
src.update_icon()
-2
View File
@@ -208,8 +208,6 @@
..()
/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/device/detective_scanner))
return
src.add_fingerprint(user)
if(istype(I, /obj/item/stack/material) && I.get_material_name() == src.get_material_name())
-2
View File
@@ -72,8 +72,6 @@
// src.sd_SetLuminosity(0)
/obj/machinery/sparker/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/device/detective_scanner))
return
if (istype(W, /obj/item/weapon/screwdriver))
add_fingerprint(user)
src.disable = !src.disable
+9 -2
View File
@@ -106,6 +106,15 @@
move_into_gibber(user,G.affecting)
// Grab() process should clean up the grab item, no need to del it.
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/M = user
if(M.h_style == "Floorlength Braid" || M.h_style == "Very Long Hair")
if(prob(10))
M.apply_damage(30, BRUTE, "head")
M.apply_damage(45, HALLOSS)
M.visible_message("\red [user]'s hair catches in the [src]!", "\red Your hair gets caught in the [src]!")
M.say("*scream")
/obj/machinery/gibber/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.restrained())
return
@@ -235,5 +244,3 @@
thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(0,3),emagged ? 100 : 50) // Being pelted with bits of meat and bone would hurt.
update_icon()
+1 -1
View File
@@ -50,7 +50,7 @@ datum/book_manager/proc/freeid()
if(!dbcon.IsConnected())
alert("Connection to Archive has been severed. Aborting.")
else
var/DBQuery/query = dbcon.NewQuery("DELETE FROM library WHERE id=[isbn]")
var/DBQuery/query = dbcon.NewQuery("DELETE FROM ss13_library WHERE id=[isbn]")
if(!query.Execute())
usr << query.ErrorMsg()
dbcon.Disconnect()
+47
View File
@@ -553,6 +553,14 @@
/obj/machinery/mecha_part_fabricator/attack_hand(mob/user as mob)
var/dat, left_part
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/M = user
if(M.h_style == "Floorlength Braid" || M.h_style == "Very Long Hair")
if(prob(10))
M.apply_damage(30, BRUTE, "head")
M.apply_damage(45, HALLOSS)
M.visible_message("\red [user]'s hair catches in the [src]!", "\red Your hair gets caught in the [src]!")
M.say("*scream")
if (..())
return
if(!operation_allowed(user))
@@ -851,3 +859,42 @@
else
user << "The fabricator cannot hold more [sname]."
return
/obj/machinery/mecha_part_fabricator/MouseDrop_T(mob/living/carbon/human/target as mob, mob/user as mob)
if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
return
if(target == user)
if(target.h_style == "Floorlength Braid" || target.h_style == "Very Long Hair")
user.visible_message("\blue [user] looks like they're about to feed their own hair into the [src], but think better of it.", "\blue You grasp your hair and are about to feed it into the [src], but stop and come to your sense.")
return
src.add_fingerprint(user)
var/target_loc = target.loc
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
if(target.h_style != "Cut Hair" || target.h_style != "Short Hair" || target.h_style != "Skinhead" || target.h_style != "Buzzcut" || target.h_style != "Crewcut" || target.h_style != "Bald" || target.h_style != "Balding Hair")
user.visible_message("\red [user] starts feeding [target]'s hair into the [src]!", "\red You start feeding [target]'s hair into the [src]!")
if(!do_after(usr, 50))
return
if(target_loc != target.loc)
return
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
user.visible_message("\red [user] feeds the [target]'s hair into the [src] and flicks it on!", "\red You turn the [src] on!")
target.apply_damage(30, BRUTE, "head")
target.apply_damage(25, HALLOSS)
target.say("*scream")
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Has fed [target.name]'s ([target.ckey]) hair into a [src].</font>")
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their hair fed into [src] by [user.name] ([user.ckey])</font>")
msg_admin_attack("[key_name_admin(user.ckey)] fed [key_name_admin(target)] in a [src]. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
else
return
if(!do_after(usr, 35))
return
if(target_loc != target.loc)
return
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
user.visible_message("\red [user] starts tugging on [target]'s head as the [src] keeps running!", "\red You start tugging on [target]'s head!")
target.apply_damage(25, BRUTE, "head")
target.apply_damage(10, HALLOSS)
target.say("*scream")
spawn(10)
user.visible_message("\red [user] stops the [src] and leaves [target] resting as they are.", "\red You turn the [src] off and let go of [target].")
@@ -22,6 +22,20 @@ var/global/list/image/splatter_cache=list()
var/amount = 5
var/drytime
/obj/effect/decal/cleanable/blood/reveal_blood()
if(!fluorescent)
fluorescent = 1
basecolor = COLOR_LUMINOL
update_icon()
/obj/effect/decal/cleanable/blood/clean_blood()
fluorescent = 0
if(invisibility != 100)
invisibility = 100
amount = 0
processing_objects -= src
..(ignore=1)
/obj/effect/decal/cleanable/blood/Destroy()
for(var/datum/disease/D in viruses)
D.cure(0)
@@ -29,6 +29,13 @@ var/global/list/image/fluidtrack_cache=list()
src.basecolor=_color
src.wet=_wet
/obj/effect/decal/cleanable/blood/tracks/reveal_blood()
if(!fluorescent)
if(stack && stack.len)
for(var/datum/fluidtrack/track in stack)
track.basecolor = COLOR_LUMINOL
..()
// Footprints, tire trails...
/obj/effect/decal/cleanable/blood/tracks
amount = 0
@@ -114,7 +121,8 @@ var/global/list/image/fluidtrack_cache=list()
updated=1
dirs |= comingdir|realgoing
blood_DNA |= DNA.Copy()
if (islist(blood_DNA))
blood_DNA |= DNA.Copy()
if(updated)
update_icon()
@@ -162,4 +170,4 @@ var/global/list/image/fluidtrack_cache=list()
desc = "They look like tracks left by wheels."
gender = PLURAL
random_icon_states = null
amount = 0
amount = 0
@@ -1,6 +1,12 @@
/obj/effect/decal/cleanable
var/list/random_icon_states = list()
/obj/effect/decal/cleanable/clean_blood(var/ignore = 0)
if(!ignore)
qdel(src)
return
..()
/obj/effect/decal/cleanable/New()
if (random_icon_states && length(src.random_icon_states) > 0)
src.icon_state = pick(src.random_icon_states)
+9 -1
View File
@@ -27,6 +27,9 @@
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
var/flags_inv //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
var/body_parts_covered = 0 //see setup.dm for appropriate bit flags
var/item_flags = 0 //Miscellaneous flags pertaining to equippable objects.
//var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible
var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets)
var/permeability_coefficient = 1 // for chemicals/diseases
@@ -494,6 +497,12 @@ var/list/global/slot_flags_enumeration = list(
var/obj/item/clothing/gloves/G = src
G.transfer_blood = 0
/obj/item/reveal_blood()
if(was_bloodied && !fluorescent)
fluorescent = 1
blood_color = COLOR_LUMINOL
blood_overlay.color = COLOR_LUMINOL
update_icon()
/obj/item/add_blood(mob/living/carbon/human/M as mob)
if (!..())
@@ -609,6 +618,5 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
return
/obj/item/proc/pwr_drain()
return 0 // Process Kill
+18
View File
@@ -68,6 +68,24 @@
if(safety <= 0)
M.Weaken(10)
flick("e_flash", M.flash)
//Vaurca damage 15/01/16
var/mob/living/carbon/human/H = M
if(H.species.flags & IS_BUG)
var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"]
if(!E)
return
usr << "\red Your eyes burn with the intense light of the flash!."
E.damage += rand(10, 11)
if(E.damage > 12)
M.eye_blurry += rand(3,6)
if (E.damage >= E.min_broken_damage)
M.sdisabilities |= BLIND
else if (E.damage >= E.min_bruised_damage)
M.eye_blind = 5
M.eye_blurry = 5
M.disabilities |= NEARSIGHTED
spawn(100)
M.disabilities &= ~NEARSIGHTED
if(ishuman(M) && ishuman(user) && M.stat!=DEAD)
if(user.mind && user.mind in revs.current_antagonists)
@@ -0,0 +1,323 @@
#define STATUS_INACTIVE 0
#define STATUS_ACTIVE 1
#define STATUS_BROKEN 2
#define LAYER_ATTACHED 3.2
#define LAYER_NORMAL 3
/obj/item/device/magnetic_lock
name = "magnetic door lock"
desc = "A large, ID locked device used for completely locking down airlocks."
icon = 'icons/obj/magnetic_locks/centcom.dmi'
icon_state = "inactive"
w_class = 3
req_access = list(103)
health = 90
var/department = "CENTCOM"
var/status = 0
var/constructionstate = 0
var/drainamount = 20
var/obj/machinery/door/airlock/target = null
var/obj/item/weapon/cell/powercell
/obj/item/device/magnetic_lock/security
icon = 'icons/obj/magnetic_locks/security.dmi'
department = "Security"
req_access = list(1)
/obj/item/device/magnetic_lock/engineering
icon = 'icons/obj/magnetic_locks/engineering.dmi'
department = "Engineering"
req_access = null
req_one_access = list(11, 24)
/obj/item/device/magnetic_lock/New()
..()
powercell = new /obj/item/weapon/cell/high()
/obj/item/device/magnetic_lock/examine()
..()
if (status == STATUS_BROKEN)
usr << "<span class='danger'>It looks broken!</span>"
else
if (powercell)
var/power = round(powercell.charge / powercell.maxcharge * 100)
usr << "\blue The powercell is at [power]% charge."
else
usr << "\red It has no powercell to power it!"
/obj/item/device/magnetic_lock/attack_hand(var/mob/user)
if (status == STATUS_ACTIVE)
ui_interact(user)
else
..()
/obj/item/device/magnetic_lock/bullet_act(var/obj/item/projectile/Proj)
takedamage(Proj.damage)
..()
/obj/item/device/magnetic_lock/attackby(var/obj/item/I, var/mob/user)
if (status == STATUS_BROKEN)
user << "<span class='danger'>[src] is broken beyond repair!</span>"
return
if (istype(I, /obj/item/weapon) && user.a_intent == "hurt")
if (I.force >= 8)
user.visible_message("<span class='danger'>[user] bashes [src] with [I]!</span>", "<span class='danger'>You strike [src] with [I], damaging it!</span>")
takedamage(I.force)
return
else
user.visible_message("<span class='notice'>[user] hits [src] with [I] to no visible effect.</span>", "<span class='notice'>You hit [src] with [I], but it appears to have no effect.</span>")
return
switch (constructionstate)
if (0)
if (istype(I, /obj/item/weapon/card/emag))
var/obj/item/weapon/card/emag/emagcard = I
emagcard.uses--
visible_message("<span class='danger'>[src] sparks and falls off the door!</span>", "<span class='danger'>You emag [src], frying its circuitry[status == STATUS_ACTIVE ? " and making it drop onto the floor" : ""]!</span>")
setstatus(STATUS_BROKEN)
return
if (status == STATUS_ACTIVE && istype(I, /obj/item/weapon/card/id))
if (check_access(I) && !constructionstate)
user << "<span class='notice'>You swipe your [I] through [src], making it drop onto the floor with a thud.</span>"
setstatus(STATUS_INACTIVE)
return
else if (constructionstate)
user << "<span class='danger'>You cannot swipe your [I] through [src] with it partially dismantled!</span>"
return
else
user << "<span class='danger'>A red light flashes on [src] as you swipe your [I] through it.</span>"
flick("deny",src)
return
if (istype(I, /obj/item/weapon/screwdriver))
user << "<span class='notice'>You unfasten and remove the plastic cover from [src], revealing a thick metal shell.</span>"
playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
setconstructionstate(1)
return
if (1)
if (istype(I, /obj/item/weapon/screwdriver))
user << "<span class='notice'>You put the metal cover of back onto [src], and screw it tight.</span>"
playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
setconstructionstate(0)
return
if (istype(I, /obj/item/weapon/cell))
user.drop_item()
I.loc = src
powercell = I
return
if (istype(I, /obj/item/weapon/crowbar))
user << "<span class='notice'>You remove \the [powercell] from \the [src].</span>"
powercell.loc = loc
powercell = null
return
if (istype(I, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = I
if (WT.remove_fuel(1, user))
user.visible_message("<span class='notice'>[user] starts welding through the metal shell of [src].</span>", "<span class='notice'>You start welding through the metal covering of [src]</span>")
playsound(loc, 'sound/items/Welder.ogg', 50, 1)
if (do_after(user, 25))
user << "<span class='notice'>You are able to weld through the metal shell of [src].</span>"
setconstructionstate(2)
return
if (2)
if (istype(I, /obj/item/weapon/crowbar))
user << "<span class='notice'>You pry off the metal covering from [src].</span>"
playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
setconstructionstate(3)
return
if (3)
if (istype(I, /obj/item/weapon/wirecutters))
user << "<span class='notice'>You cut the wires connecting the [src]'s magnets to their powersupply, [target ? "making the device fall off [target] and rendering it unusable." : "rendering the device unusable."]</span>"
playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1)
setconstructionstate(4)
return
/obj/item/device/magnetic_lock/process()
if (powercell && powercell.charge > drainamount)
powercell.charge -= drainamount
else
if (powercell)
powercell.charge = 0
visible_message("<span class='danger'>[src] beeps loudly and falls off \the [target]; its powercell having run out of power.</span>")
setstatus(STATUS_INACTIVE)
/obj/item/device/magnetic_lock/proc/attachto(var/obj/machinery/door/airlock/newtarget, var/mob/user as mob)
if (status == STATUS_BROKEN)
user << "<span class='danger'>[src] is damaged beyond repair! It cannot be used!</span>"
return
if (!newtarget.density || newtarget.operating)
user << "<span class='danger'>[newtarget] must be closed before you can attach [src] to it!</span>"
return
if (newtarget.p_open)
user << "<span class='danger'>You must close [newtarget]'s maintenance panel before attaching [src] to it!</span>"
return
user.visible_message("<span class='notice'>[user] starts mounting [src] onto [newtarget].</span>", "<span class='notice'>You begin mounting [src] onto [newtarget].</span>")
if (do_after(user, 35, 1))
if (status == STATUS_BROKEN)
user << "<span class='danger'>[src] is damaged beyond repair! It cannot be used!</span>"
return
if (!newtarget.density)
user << "<span class='danger'>[newtarget] must be closed before you can attach [src] to it!</span>"
return
if (newtarget.p_open)
user << "<span class='danger'>You must close [newtarget]'s maintenance panel before attaching [src] to it!</span>"
return
user.visible_message("<span class='notice'>[user] attached [src] onto [newtarget] and flicks it on. The magnetic lock now seals [newtarget].</span>", "<span class='notice'>You attached [src] onto [newtarget] and switched on the magnetic lock.</span>")
user.drop_item()
setstatus(STATUS_ACTIVE, newtarget)
return
/obj/item/device/magnetic_lock/proc/setstatus(var/newstatus, var/obj/machinery/door/airlock/newtarget as obj)
switch (newstatus)
if (STATUS_INACTIVE)
if (status != STATUS_ACTIVE)
return
if (!target)
return
detach()
icon_state = "inactive"
status = newstatus
if (STATUS_ACTIVE)
if (status != STATUS_INACTIVE)
return
if (!newtarget)
return
attach(newtarget)
icon_state = "active"
status = newstatus
if (STATUS_BROKEN)
spark()
if (target)
var/playflick = 1
if (constructionstate)
playflick = 0
detach(playflick)
icon_state = "broken"
status = newstatus
/obj/item/device/magnetic_lock/proc/setconstructionstate(var/newstate)
constructionstate = newstate
if (newstate == 0)
if (status == STATUS_ACTIVE)
icon_state = "active"
else
icon_state = "inactive"
else if (newstate == 2)
flick("deconstruct_2_anim", src)
else if (newstate == 4)
setstatus(STATUS_BROKEN)
else
icon_state = "deconstruct_[constructionstate]"
/obj/item/device/magnetic_lock/proc/detach(var/playflick = 1)
if (target)
if (playflick)
spawn(-15) flick("release", src)
adjustsprite(null)
layer = LAYER_NORMAL
target.bracer = null
processing_objects.Remove(src)
anchored = 0
/obj/item/device/magnetic_lock/proc/attach(var/obj/machinery/door/airlock/newtarget as obj)
adjustsprite(newtarget)
layer = LAYER_ATTACHED
flick("deploy", src)
newtarget.bracer = src
target = newtarget
processing_objects.Add(src)
anchored = 1
/obj/item/device/magnetic_lock/proc/adjustsprite(var/obj/target as obj)
if (target)
switch (get_dir(src, target))
if (NORTH)
pixel_x = 0
pixel_y = 32
if (NORTHEAST)
pixel_x = 32
pixel_y = 32
if (EAST)
pixel_x = 32
pixel_y = 0
if (SOUTHEAST)
pixel_x = 32
pixel_y = -32
if (SOUTH)
pixel_x = 0
pixel_y = -32
if (SOUTHWEST)
pixel_x = -32
pixel_y = -32
if (WEST)
pixel_x = -32
pixel_y = 0
if (NORTHWEST)
pixel_x = -32
pixel_y = 32
else
pixel_x = 0
pixel_y = 0
/obj/item/device/magnetic_lock/proc/takedamage(var/damage)
health -= damage
if (damage >= 40 && prob(50))
health = 0
if (health <= 0)
visible_message("<span class='danger'>[src] sparks[target ? " and falls off of \the [target]!" : "!"] It is now completely unusable!</span>")
setstatus(STATUS_BROKEN)
return
if (prob(50))
spark()
/obj/item/device/magnetic_lock/proc/spark()
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
if (target)
s.set_up(5, 1, target)
else
s.set_up(5, 1, src)
s.start()
spawn(5)
del(s)
#undef STATUS_INACTIVE
#undef STATUS_ACTIVE
#undef STATUS_BROKEN
#undef LAYER_ATTACHED
#undef LAYER_NORMAL
+17
View File
@@ -0,0 +1,17 @@
/obj/item/shoe_cover
name = "strange fabric"
desc = "A fabirc that allows for silent walking."
icon = 'icons/obj/items.dmi'
icon_state = "sheet-cloth"
/obj/item/shoe_cover/afterattack(var/obj/A as obj, mob/user as mob, proximity)
if(!proximity)
return
if (istype(A, /obj/item/clothing/shoes) && get_dist(src,A) <= 1)
var/obj/item/clothing/shoes/S = A
user << "You attahed the [src] to [S] making movement silent"
S.silent = 1
S.desc += " They appear to have some type of fabric soles"
user.drop_from_inventory(src)
del(src)
@@ -1,5 +1,5 @@
#ifndef T_BOARD
#error T_BOARD macro is not defined but we need it!
#error T_BOARD macro is not defined but we need it!
#endif
/obj/item/weapon/circuitboard/message_monitor
@@ -60,11 +60,11 @@
/obj/item/weapon/circuitboard/stationalert_engineering
name = T_BOARD("station alert console (engineering)")
build_path = /obj/machinery/computer/station_alert
/obj/item/weapon/circuitboard/stationalert_security
name = T_BOARD("station alert console (security)")
build_path = /obj/machinery/computer/station_alert
/obj/item/weapon/circuitboard/stationalert_all
name = T_BOARD("station alert console (all)")
build_path = /obj/machinery/computer/station_alert/all
@@ -196,3 +196,8 @@
name = T_BOARD("RCON remote control console")
build_path = /obj/machinery/computer/rcon
origin_tech = "programming=4;engineering=3;powerstorage=5"
/obj/item/weapon/circuitboard/telesci_console
name = T_BOARD("Telescience Console")
build_path = /obj/machinery/computer/telescience
origin_tech = "programming=3;bluespace=2"
@@ -1,5 +1,5 @@
#ifndef T_BOARD
#error T_BOARD macro is not defined but we need it!
#error T_BOARD macro is not defined but we need it!
#endif
obj/item/weapon/circuitboard/rdserver
@@ -62,3 +62,14 @@ obj/item/weapon/circuitboard/rdserver
"/obj/item/weapon/stock_parts/manipulator" = 1,
"/obj/item/weapon/stock_parts/micro_laser" = 1,
"/obj/item/weapon/stock_parts/console_screen" = 1)
/obj/item/weapon/circuitboard/telesci_pad
name = T_BOARD("telepad")
build_path = "/obj/machinery/telepad"
board_type = "machine"
origin_tech = "programming=4;engineering=3;materials=3;bluespace=4"
req_components = list(
"/obj/item/bluespace_crystal" = 2,
"/obj/item/weapon/stock_parts/capacitor" = 1,
"/obj/item/stack/cable_coil" = 1,
"/obj/item/weapon/stock_parts/console_screen" = 1)
@@ -53,6 +53,24 @@
flick("e_flash", M.flash)
M.Stun(2)
M.Weaken(10)
//Vaurca damage 15/01/16
var/mob/living/carbon/human/H = M
if(H.species.flags & IS_BUG)
var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"]
if(!E)
return
usr << "\red Your eyes burn with the intense light of the flash!."
E.damage += rand(10, 11)
if(E.damage > 12)
M.eye_blurry += rand(3,6)
if (E.damage >= E.min_broken_damage)
M.sdisabilities |= BLIND
else if (E.damage >= E.min_bruised_damage)
M.eye_blind = 5
M.eye_blurry = 5
M.disabilities |= NEARSIGHTED
spawn(100)
M.disabilities &= ~NEARSIGHTED
+15 -12
View File
@@ -33,19 +33,22 @@
return
//check for an aggressive grab (or robutts)
var/can_place
if(istype(user, /mob/living/silicon/robot))
can_place = 1
else
for (var/obj/item/weapon/grab/G in C.grabbed_by)
if (G.loc == user && G.state >= GRAB_AGGRESSIVE)
can_place = 1
break
// var/can_place
// if(istype(user, /mob/living/silicon/robot))
// can_place = 1
// else
// for (var/obj/item/weapon/grab/G in C.grabbed_by)
// if (G.loc == user && G.state >= GRAB_AGGRESSIVE)
// can_place = 1
// break
//
// if(can_place)
// place_handcuffs(C, user)
// else
// user << "<span class='danger'>You need to have a firm grip on [C] before you can put \the [src] on!</span>"
if(can_place)
place_handcuffs(C, user)
else
user << "<span class='danger'>You need to have a firm grip on [C] before you can put \the [src] on!</span>"
//Or just. You know. Don't check for it and place the handcuffs anyways!
place_handcuffs(C, user)
/obj/item/weapon/handcuffs/proc/place_handcuffs(var/mob/living/carbon/target, var/mob/user)
playsound(src.loc, cuff_sound, 30, 1, -2)
@@ -86,3 +86,12 @@
New()
..()
new /obj/item/weapon/grenade/flashbang/clusterbang(src)
/obj/item/weapon/storage/lockbox/lawgiver
name = "Weapons lockbox"
desc = "A high security weapons lockbox"
req_access = list(access_armory)
New()
..()
new /obj/item/weapon/gun/energy/lawgiver(src)
+21 -4
View File
@@ -237,11 +237,28 @@
playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6)
return
else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && src.welding)
message_admins("[key_name_admin(user)] triggered a fueltank explosion with a welding tool.")
log_game("[key_name(user)] triggered a fueltank explosion with a welding tool.")
user << "\red You begin welding on the fueltank and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done."
var/obj/structure/reagent_dispensers/fueltank/tank = O
tank.explode()
if(tank.armed)
user << "You are already heating the [O]"
return
tank.armed = 1
user.visible_message("[user] begins heating the [O].", "You start to heat the [O].")
message_admins("[key_name_admin(user)] is attempting a welder bomb at ([loc.x],[loc.y],[loc.z]) - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[O.x];Y=[O.y];Z=[O.z]'>JMP</a>")
if(do_after(user,100))
if(tank.defuse)
user.visible_message("[user] melts some of the framework on the [O].", "You melt some of the framework.")
tank.defuse = 0
tank.armed = 0
return
message_admins("[key_name_admin(user)] triggered a fueltank explosion.")
log_game("[key_name(user)] triggered a fueltank explosion with a welding tool.")
user << "\red That was stupid of you."
tank.explode()
return
else
tank.armed = 0
user << "You thought better of yourself."
return
return
if (src.welding)
remove_fuel(1)
+23 -6
View File
@@ -47,12 +47,29 @@
user.Paralyse(20)
return
if (M.stat !=2)
if(cult && (M.mind in cult.current_antagonists) && prob(33))
M << "<span class='danger'>The power of [src] clears your mind of the cult's influence!</span>"
user << "<span class='danger'>You wave [src] over [M]'s head and see their eyes become clear, their mind returning to normal.</span>"
cult.remove_antagonist(M.mind)
M.visible_message("<span class='danger'>\The [user] waves \the [src] over \the [M]'s head.</span>")
if (M.stat !=2 && ishuman(M))
var/mob/living/K = M
if(cult && (K.mind in cult.current_antagonists) && prob(33))
if(do_after(user, 15))
K.visible_message("<span class='danger'>\The [user] waves \the [src] over \the [K]'s head, [K] looks captivated by it.</span>", "\red [user] wave's the [src] over your head. <b>You see a foreign light, asking you to follow it. Its presence burns and blinds.</b>")
var/choice = alert(K,"Do you want to give up your goal?","Become cleansed","Resist","Give in")
switch(choice)
if("Resist")
K.visible_message("\red The gaze in [K]'s eyes remains determined.", "\blue You turn away from the light, remaining true to your dark lord. The light burns you due to rejection!")
K.say("*scream")
K.take_overall_damage(5, 15)
if("Give in")
K.visible_message("\blue [K]'s eyes become clearer, the evil gone, but not without leaving scars.")
K.take_overall_damage(15, 30)
cult.remove_antagonist(K.mind)
else
user.visible_message("\red [user]'s concentration is broken!", "\red Your concentration is broken! You and your target need to stay uninterrupted for longer!")
return
else if(M.mind && M.mind.vampire)
if(!(VAMP_FULL in M.mind.vampire.powers))
user << "\red The rod burns cold in your hand, filling you with grim determination. You feel the creature's power weaken."
M << "<span class='warning'>The nullrod's power interferes with your own! They are on to you!</span>"
M.mind.vampire.nullified = max(8, M.mind.vampire.nullified + 8)
else if(prob(10))
user << "<span class='danger'>The rod slips in your hand.</span>"
..()
+9
View File
@@ -16,6 +16,8 @@
var/damtype = "brute"
var/force = 0
var/being_shocked = 0
/obj/Destroy()
processing_objects -= src
nanomanager.close_uis(src)
@@ -146,3 +148,10 @@
/obj/proc/see_emote(mob/M as mob, text, var/emote_type)
return
/obj/proc/tesla_act(var/power)
being_shocked = 1
var/power_bounced = power / 2
tesla_zap(src, 5, power_bounced)
spawn(10)
being_shocked = 0
@@ -258,7 +258,6 @@
new /obj/item/clothing/shoes/brown(src)
new /obj/item/weapon/storage/box/evidence(src)
new /obj/item/device/radio/headset/headset_sec(src)
new /obj/item/device/detective_scanner(src)
new /obj/item/clothing/suit/storage/vest/detective(src)
new /obj/item/ammo_magazine/c45m/rubber(src)
new /obj/item/ammo_magazine/c45m/rubber(src)
+24 -1
View File
@@ -7,6 +7,18 @@ var/list/clown_sound = list('sound/effects/clownstep1.ogg','sound/effects/clowns
var/list/swing_hit_sound = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')
var/list/hiss_sound = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
var/list/page_sound = list('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')
//FOOTSTEPS
var/list/defaultfootsteps = list('sound/effects/footsteps/tile1.wav','sound/effects/footsteps/tile2.wav','sound/effects/footsteps/tile3.wav','sound/effects/footsteps/tile4.wav')
var/list/concretefootsteps = list('sound/effects/footsteps/concrete1.wav','sound/effects/footsteps/concrete2.wav','sound/effects/footsteps/concrete3.wav','sound/effects/footsteps/concrete4.wav')
var/list/grassfootsteps = list('sound/effects/footsteps/grass1.wav','sound/effects/footsteps/grass2.wav','sound/effects/footsteps/grass3.wav','sound/effects/footsteps/grass4.wav')
var/list/dirtfootsteps = list('sound/effects/footsteps/dirt1.wav','sound/effects/footsteps/dirt2.wav','sound/effects/footsteps/dirt3.wav','sound/effects/footsteps/dirt4.wav')
var/list/waterfootsteps = list('sound/effects/footsteps/slosh1.wav','sound/effects/footsteps/slosh2.wav','sound/effects/footsteps/slosh3.wav','sound/effects/footsteps/slosh4.wav')
var/list/sandfootsteps = list('sound/effects/footsteps/sand1.wav','sound/effects/footsteps/sand2.wav','sound/effects/footsteps/sand3.wav','sound/effects/footsteps/sand4.wav')
var/list/gravelstep = list('sound/effects/footsteps/gravel1.wav','sound/effects/footsteps/gravel2.wav','sound/effects/footsteps/gravel3.wav','sound/effects/footsteps/gravel4.wav')
var/list/footstepfx = list("defaultstep","concretestep","grassstep","dirtstep","waterstep","sandstep")
//var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg')
/proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, var/is_global)
@@ -37,6 +49,11 @@ var/const/FALLOFF_SOUNDS = 0.5
/mob/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global)
if(!src.client || ear_deaf > 0) return
if(soundin in footstepfx)
if(!(src.client.prefs.asfx_togs & ASFX_FOOTSTEPS))
return
soundin = get_sfx(soundin)
var/sound/S = sound(soundin)
@@ -116,4 +133,10 @@ var/const/FALLOFF_SOUNDS = 0.5
if ("hiss") soundin = pick(hiss_sound)
if ("pageturn") soundin = pick(page_sound)
//if ("gunshot") soundin = pick(gun_sound)
return soundin
if ("defaultstep") soundin = pick(defaultfootsteps)
if ("concretestep") soundin = pick(concretefootsteps)
if ("grassstep") soundin = pick(grassfootsteps)
if ("dirtstep") soundin = pick(dirtfootsteps)
if ("waterstep") soundin = pick(waterfootsteps)
if ("sandstep") soundin = pick(sandfootsteps)
return soundin
+7
View File
@@ -10,6 +10,11 @@
var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to
var/dirt = 0
/turf/simulated/clean_blood()
for(var/obj/effect/decal/cleanable/blood/B in contents)
B.clean_blood()
..()
/turf/simulated/New()
..()
if(istype(loc, /area/chapel))
@@ -110,6 +115,8 @@
if(istype(M))
for(var/obj/effect/decal/cleanable/blood/B in contents)
if(!B.blood_DNA)
B.blood_DNA = list()
if(!B.blood_DNA[M.dna.unique_enzymes])
B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
B.virus2 = virus_copylist(M.virus2)
+7 -5
View File
@@ -45,6 +45,8 @@ var/list/wood_icons = list("wood","wood-broken")
var/floor_type = /obj/item/stack/tile/steel
var/lightfloor_state // for light floors, this is the state of the tile. 0-7, 0x4 is on-bit - use the helper procs below
footstep_sound = "defaultstep"
proc/get_lightfloor_state()
return lightfloor_state & LIGHTFLOOR_STATE_BITS
@@ -102,7 +104,7 @@ var/list/wood_icons = list("wood","wood-broken")
return
/turf/simulated/floor/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
var/temp_destroy = get_damage_temperature()
if(!burnt && prob(5))
burn_tile(exposed_temperature)
@@ -309,16 +311,16 @@ turf/simulated/floor/proc/update_icon()
/turf/simulated/floor/proc/burn_tile(var/exposed_temperature)
if(istype(src,/turf/simulated/floor/engine)) return
if(istype(src,/turf/simulated/floor/plating/airless/asteroid)) return//Asteroid tiles don't burn
var/damage_temp = get_damage_temperature()
if(broken) return
if(burnt)
if(is_steel_floor() && exposed_temperature >= damage_temp) //allow upgrading from scorched tiles to damaged tiles
src.icon_state = "damaged[pick(1,2,3,4,5)]"
broken = 1
return
if(is_steel_floor() && exposed_temperature >= T0C+300) //enough to char the floor, but not hot enough to actually burn holes in it
src.icon_state = "floorscorched[pick(1,2)]"
burnt = 1
@@ -601,4 +603,4 @@ turf/simulated/floor/proc/update_icon()
#undef LIGHTFLOOR_STATE_FLICKER
#undef LIGHTFLOOR_STATE_BREAKING
#undef LIGHTFLOOR_STATE_BROKEN
#undef LIGHTFLOOR_STATE_BITS
#undef LIGHTFLOOR_STATE_BITS
+9
View File
@@ -132,11 +132,13 @@
/turf/simulated/shuttle/floor
name = "floor"
icon_state = "floor"
footstep_sound = "concretefootsteps"
/turf/simulated/shuttle/plating
name = "plating"
icon = 'icons/turf/floors.dmi'
icon_state = "plating"
footstep_sound = "concretefootsteps"
/turf/simulated/shuttle/plating/vox //Skipjack plating
oxygen = 0
@@ -154,19 +156,23 @@
/turf/simulated/floor/beach
name = "Beach"
icon = 'icons/misc/beach.dmi'
footstep_sound = "sandstep"
/turf/simulated/floor/beach/sand
name = "Sand"
icon_state = "sand"
footstep_sound = "sandstep"
/turf/simulated/floor/beach/coastline
name = "Coastline"
icon = 'icons/misc/beach2.dmi'
icon_state = "sandwater"
footstep_sound = "sandstep"
/turf/simulated/floor/beach/water
name = "Water"
icon_state = "water"
footstep_sound = "waterstep"
/turf/simulated/floor/beach/water/New()
..()
@@ -176,6 +182,7 @@
name = "Grass patch"
icon_state = "grass1"
floor_type = /obj/item/stack/tile/grass
footstep_sound = "grassstep"
New()
icon_state = "grass[pick("1","2","3","4")]"
@@ -192,6 +199,7 @@
name = "Carpet"
icon_state = "carpet"
floor_type = /obj/item/stack/tile/carpet
footstep_sound = null
New()
if(!icon_state)
@@ -216,6 +224,7 @@
name = "snow"
icon = 'icons/turf/snow.dmi'
icon_state = "snow"
footstep_sound = "grassstep"
/turf/simulated/floor/plating/snow/ex_act(severity)
return
+1
View File
@@ -7,6 +7,7 @@ var/list/accessible_z_levels = list("1" = 5, "3" = 10, "4" = 15, "5" = 10, "6" =
name = "\proper space"
icon_state = "0"
dynamic_lighting = 0
footstep_sound = null //Override to make sure because yeah
temperature = T20C
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
+19
View File
@@ -26,6 +26,8 @@
var/has_resources
var/list/resources
var/footstep_sound = null
// Flick animation
var/atom/movable/overlay/c_animation = null
@@ -139,6 +141,20 @@
if(M.lastarea.has_gravity == 0)
inertial_drift(M)
var/mob/living/carbon/human/MOB = M
if(istype(MOB) && !MOB.lying && footstep_sound)
if(istype(MOB.shoes, /obj/item/clothing/shoes) && !MOB.shoes:silent)
if(MOB.m_intent == "run")
if(MOB.footstep >= 2)
MOB.footstep = 0
else
MOB.footstep++
if(MOB.footstep == 0)
playsound(MOB, footstep_sound, 50, 1) // this will get annoying very fast. - Tell them to mute it then -_-
else
playsound(MOB, footstep_sound, 40, 1)
else if(!istype(src, /turf/space))
M.inertia_dir = 0
M.make_floating(0)
@@ -410,3 +426,6 @@
else
user << "<span class='warning'>\The [source] is too dry to wash that.</span>"
source.reagents.trans_to_turf(src, 1, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly.
/turf/proc/update_blood_overlays()
return
+4
View File
@@ -1,19 +1,23 @@
/turf/unsimulated/beach
name = "Beach"
icon = 'icons/misc/beach.dmi'
footstep_sound = "sandstep"
/turf/unsimulated/beach/sand
name = "Sand"
icon_state = "sand"
footstep_sound = "sandstep"
/turf/unsimulated/beach/coastline
name = "Coastline"
icon = 'icons/misc/beach2.dmi'
icon_state = "sandwater"
footstep_sound = "sandstep"
/turf/unsimulated/beach/water
name = "Water"
icon_state = "water"
footstep_sound = "waterstep"
/turf/unsimulated/beach/water/New()
..()
-6
View File
@@ -193,11 +193,6 @@ var/sqlport = "3306"
var/sqldb = "tgstation"
var/sqllogin = "root"
var/sqlpass = ""
// Feedback gathering sql connection
var/sqlfdbkdb = "test"
var/sqlfdbklogin = "root"
var/sqlfdbkpass = ""
var/sqllogging = 0 // Should we log deaths, population stats, etc.?
// Forum MySQL configuration. (for use with forum account/key authentication)
@@ -218,7 +213,6 @@ var/custom_event_msg = null
// Database connections. A connection is established on world creation.
// Ideally, the connection dies when the server restarts (After feedback logging.).
var/DBConnection/dbcon = new() // Feedback database (New database)
var/DBConnection/dbcon_old = new() // /tg/station database (Old database) -- see the files in the SQL folder for information on what goes where.
// Reference list for disposal sort junctions. Filled up by sorting junction's New()
/var/list/tagger_locations = list()
+10 -10
View File
@@ -44,7 +44,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
computerid = bancid
ip = banip
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'")
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM ss13_player WHERE ckey = '[ckey]'")
query.Execute()
var/validckey = 0
if(query.NextRow())
@@ -79,7 +79,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
reason = sql_sanitize_text(reason)
var/sql = "INSERT INTO erro_ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)"
var/sql = "INSERT INTO ss13_ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)"
var/DBQuery/query_insert = dbcon.NewQuery(sql)
query_insert.Execute()
usr << "\blue Ban saved to database."
@@ -118,7 +118,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
else
bantype_sql = "bantype = '[bantype_str]'"
var/sql = "SELECT id FROM erro_ban WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
var/sql = "SELECT id FROM ss13_ban WHERE ckey = '[ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
if(job)
sql += " AND job = '[job]'"
@@ -159,7 +159,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
usr << "Cancelled"
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM ss13_ban WHERE id = [banid]")
query.Execute()
var/eckey = usr.ckey //Editing admin ckey
@@ -187,7 +187,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
usr << "Cancelled"
return
var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
var/DBQuery/update_query = dbcon.NewQuery("UPDATE ss13_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
update_query.Execute()
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1)
if("duration")
@@ -197,7 +197,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
usr << "Cancelled"
return
var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
var/DBQuery/update_query = dbcon.NewQuery("UPDATE ss13_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1)
update_query.Execute()
if("unban")
@@ -215,7 +215,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
if(!check_rights(R_BAN)) return
var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]"
var/sql = "SELECT ckey FROM ss13_ban WHERE id = [id]"
establish_db_connection()
if(!dbcon.IsConnected())
@@ -245,7 +245,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
var/unban_computerid = src.owner:computer_id
var/unban_ip = src.owner:address
var/sql_update = "UPDATE erro_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]"
var/sql_update = "UPDATE ss13_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]"
message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1)
var/DBQuery/query_update = dbcon.NewQuery(sql_update)
@@ -302,7 +302,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
output += "<option value='[j]'>[j]</option>"
for(var/j in nonhuman_positions)
output += "<option value='[j]'>[j]</option>"
var/list/bantypes = list("traitor","changeling","operative","revolutionary","cultist","wizard") //For legacy bans.
var/list/bantypes = list("traitor","changeling","vampire","operative","revolutionary","cultist","wizard") //For legacy bans.
for(var/antag_type in all_antag_types) // Grab other bans.
var/datum/antagonist/antag = all_antag_types[antag_type]
bantypes |= antag.bantype
@@ -399,7 +399,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
else
bantypesearch += "'PERMABAN' "
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100")
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM ss13_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100")
select_query.Execute()
var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year)
+1 -1
View File
@@ -52,7 +52,7 @@ world/IsBanned(key,address,computer_id)
failedcid = 0
cidquery = " OR computerid = '[computer_id]' "
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM ss13_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
query.Execute()
+53 -41
View File
@@ -8,14 +8,14 @@ var/global/floorIsLava = 0
msg = "<span class=\"log_message\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message\">[msg]</span></span>"
log_adminwarn(msg)
for(var/client/C in admins)
if(R_ADMIN & C.holder.rights)
if((R_ADMIN|R_MOD) & C.holder.rights)
C << msg
/proc/msg_admin_attack(var/text) //Toggleable Attack Messages
log_attack(text)
var/rendered = "<span class=\"log_message\"><span class=\"prefix\">ATTACK:</span> <span class=\"message\">[text]</span></span>"
for(var/client/C in admins)
if(R_ADMIN & C.holder.rights)
if((R_ADMIN|R_MOD) & C.holder.rights)
if(C.prefs.toggles & CHAT_ATTACKLOGS)
var/msg = rendered
C << msg
@@ -62,6 +62,7 @@ proc/admin_notice(var/message, var/rights)
<b>Mob type</b> = [M.type]<br><br>
<A href='?src=\ref[src];boot2=\ref[M]'>Kick</A> |
<A href='?_src_=holder;warn=[M.ckey]'>Warn</A> |
<a href='?src=\ref[src];warnsearchckey=[M.ckey]'>Warnings</a> |
<A href='?src=\ref[src];newban=\ref[M]'>Ban</A> |
<A href='?src=\ref[src];jobban2=\ref[M]'>Jobban</A> |
<A href='?src=\ref[src];notes=show;mob=\ref[M]'>Notes</A>
@@ -69,6 +70,7 @@ proc/admin_notice(var/message, var/rights)
if(M.client)
body += "| <A HREF='?src=\ref[src];sendtoprison=\ref[M]'>Prison</A> | "
body += "<a href='?src=\ref[src];admin_wind_player=\ref[M]'>Wind</a>"
var/muted = M.client.prefs.muted
body += {"<br><b>Mute: </b>
\[<A href='?src=\ref[src];mute=\ref[M];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> |
@@ -220,7 +222,12 @@ proc/admin_notice(var/message, var/rights)
if (!istype(src,/datum/admins))
usr << "Error: you are not an admin!"
return
PlayerNotesPage(1)
if (!check_rights(R_ADMIN|R_MOD))
return
if (config.ban_legacy_system)
PlayerNotesPage(1)
else
show_notes_sql()
/datum/admins/proc/PlayerNotesPage(page)
var/dat = "<B>Player notes</B><HR>"
@@ -278,45 +285,47 @@ proc/admin_notice(var/message, var/rights)
if (!istype(src,/datum/admins))
usr << "Error: you are not an admin!"
return
var/dat = "<html><head><title>Info on [key]</title></head>"
dat += "<body>"
var/p_age = "unknown"
for(var/client/C in clients)
if(C.ckey == key)
p_age = C.player_age
break
dat +="<span style='color:#000000; font-weight: bold'>Player age: [p_age]</span><br>"
if (config.ban_legacy_system)
var/dat = "<html><head><title>Info on [key]</title></head>"
dat += "<body>"
var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
var/list/infos
info >> infos
if(!infos)
dat += "No information found on the given key.<br>"
var/p_age = "unknown"
for(var/client/C in clients)
if(C.ckey == key)
p_age = C.player_age
break
dat +="<span style='color:#000000; font-weight: bold'>Player age: [p_age]</span><br>"
var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
var/list/infos
info >> infos
if(!infos)
dat += "No information found on the given key.<br>"
else
var/update_file = 0
var/i = 0
for(var/datum/player_info/I in infos)
i += 1
if(!I.timestamp)
I.timestamp = "Pre-4/3/2012"
update_file = 1
if(!I.rank)
I.rank = "N/A"
update_file = 1
dat += "<font color=#008800>[I.content]</font> <i>by [I.author] ([I.rank])</i> on <i><font color=blue>[I.timestamp]</i></font> "
if(I.author == usr.key || I.author == "Adminbot" || ishost(usr))
dat += "<A href='?src=\ref[src];remove_player_info=[key];remove_index=[i]'>Remove</A>"
dat += "<br><br>"
if(update_file) info << infos
dat += "<br>"
dat += "<A href='?src=\ref[src];add_player_info=[key]'>Add Comment</A><br>"
dat += "</body></html>"
usr << browse(dat, "window=adminplayerinfo;size=480x480")
else
var/update_file = 0
var/i = 0
for(var/datum/player_info/I in infos)
i += 1
if(!I.timestamp)
I.timestamp = "Pre-4/3/2012"
update_file = 1
if(!I.rank)
I.rank = "N/A"
update_file = 1
dat += "<font color=#008800>[I.content]</font> <i>by [I.author] ([I.rank])</i> on <i><font color=blue>[I.timestamp]</i></font> "
if(I.author == usr.key || I.author == "Adminbot" || ishost(usr))
dat += "<A href='?src=\ref[src];remove_player_info=[key];remove_index=[i]'>Remove</A>"
dat += "<br><br>"
if(update_file) info << infos
dat += "<br>"
dat += "<A href='?src=\ref[src];add_player_info=[key]'>Add Comment</A><br>"
dat += "</body></html>"
usr << browse(dat, "window=adminplayerinfo;size=480x480")
show_notes_sql(key)
/datum/admins/proc/access_news_network() //MARKER
set category = "Fun"
@@ -1408,16 +1417,19 @@ proc/admin_notice(var/message, var/rights)
/datum/admins/proc/paralyze_mob(mob/living/H as mob)
set category = "Admin"
set name = "Toggle Paralyze"
set name = "Toggle Wind"
set desc = "Paralyzes a player. Or unparalyses them."
var/msg
if(check_rights(R_ADMIN))
if(check_rights(R_ADMIN|R_MOD))
if (H.paralysis == 0)
H.paralysis = 8000
msg = "has paralyzed [key_name(H)]."
H.visible_message("<font color='#002eb8'><b>OOC Information:</b></font> <font color='red'>[src] has been winded by a member of staff! Please freeze all roleplay involving their character until the matter is resolved! Adminmhelp if you have further questions.</font>", "<font color='red'><b>You have been winded by a member of staff! Please stand by until they contact you!</b></font>")
else
H.paralysis = 0
msg = "has unparalyzed [key_name(H)]."
H.visible_message("<font color='#002eb8'><b>OOC Information:</b></font> <font color='green'>[src] has been unwinded by a member of staff!</font>", "<font color='red'><b>You have been unwinded by a member of staff!</b></font>")
log_and_message_admins(msg)
feedback_add_details("admin_verb", "WIND")
+1 -1
View File
@@ -109,7 +109,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights
load_admins()
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM ss13_admin")
query.Execute()
while(query.NextRow())
var/ckey = query.item[1]
+2 -43
View File
@@ -96,7 +96,8 @@ var/list/admin_verbs_admin = list(
)
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
/client/proc/jobbans
/client/proc/jobbans,
/client/proc/warning_panel
)
var/list/admin_verbs_sounds = list(
/client/proc/play_local_sound,
@@ -514,48 +515,6 @@ var/list/admin_verbs_mentor = list(
message_admins("[key_name_admin(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]", 1)
feedback_add_details("admin_verb","SM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
#define MAX_WARNS 3
#define AUTOBANTIME 10
/client/proc/warn(warned_ckey)
if(!check_rights(R_ADMIN)) return
if(!warned_ckey || !istext(warned_ckey)) return
if(warned_ckey in admin_datums)
usr << "<font color='red'>Error: warn(): You can't warn admins.</font>"
return
var/datum/preferences/D
var/client/C = directory[warned_ckey]
if(C) D = C.prefs
else D = preferences_datums[warned_ckey]
if(!D)
src << "<font color='red'>Error: warn(): No such ckey found.</font>"
return
if(++D.warns >= MAX_WARNS) //uh ohhhh...you'reee iiiiin trouuuubble O:)
ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [AUTOBANTIME] minute autoban.")
if(C)
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban.")
C << "<font color='red'><BIG><B>You have been autobanned due to a warning by [ckey].</B></BIG><br>This is a temporary ban, it will be removed in [AUTOBANTIME] minutes."
qdel(C)
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban.")
AddBan(warned_ckey, D.last_id, "Autobanning due to too many formal warnings", ckey, 1, AUTOBANTIME)
feedback_inc("ban_warn",1)
else
if(C)
C << "<font color='red'><BIG><B>You have been formally warned by an administrator.</B></BIG><br>Further warnings will result in an autoban.</font>"
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)]. They have [MAX_WARNS-D.warns] strikes remaining.")
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] (DC). They have [MAX_WARNS-D.warns] strikes remaining.")
feedback_add_details("admin_verb","WARN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
#undef MAX_WARNS
#undef AUTOBANTIME
/client/proc/drop_bomb() // Some admin dickery that can probably be done better -- TLE
set category = "Special Verbs"
set name = "Drop Bomb"
+2 -2
View File
@@ -73,7 +73,7 @@ DEBUG
return
//Job permabans
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM ss13_ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
query.Execute()
while(query.NextRow())
@@ -83,7 +83,7 @@ DEBUG
jobban_keylist.Add("[ckey] - [job]")
//Job tempbans
var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
var/DBQuery/query1 = dbcon.NewQuery("SELECT ckey, job FROM ss13_ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()")
query1.Execute()
while(query1.NextRow())
@@ -71,7 +71,7 @@
if(!istext(adm_ckey) || !istext(new_rank))
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'")
var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM ss13_admin WHERE ckey = '[adm_ckey]'")
select_query.Execute()
var/new_admin = 1
@@ -81,16 +81,16 @@
admin_id = text2num(select_query.item[1])
if(new_admin)
var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `ss13_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`ss13_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
log_query.Execute()
usr << "\blue New admin added."
else
if(!isnull(admin_id) && isnum(admin_id))
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admin` SET rank = '[new_rank]' WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`ss13_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
log_query.Execute()
usr << "\blue Admin rank changed."
@@ -123,7 +123,7 @@
if(!istext(adm_ckey) || !isnum(new_permission))
return
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'")
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM ss13_admin WHERE ckey = '[adm_ckey]'")
select_query.Execute()
var/admin_id
@@ -136,14 +136,14 @@
return
if(admin_rights & new_permission) //This admin already has this permission, so we are removing it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`ss13_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
log_query.Execute()
usr << "\blue Permission removed."
else //This admin doesn't have this permission, so we are adding it.
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `ss13_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]")
insert_query.Execute()
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`ss13_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')")
log_query.Execute()
usr << "\blue Permission added."
+262
View File
@@ -0,0 +1,262 @@
//System will now support SQL pulls for fetching player notes.
//Yay!
/proc/notes_add_sql(var/player_ckey, var/note, var/mob/user, var/player_address, var/player_computerid)
if(!player_ckey || !note)
return
var/list/query_details = list(":ckey" = player_ckey, ":address" = player_address ? player_address : null, ":computer_id" = player_computerid ? player_computerid : null, ":a_ckey" = null, ":note" = note)
if (!user)
query_details[":a_ckey"] = "Adminbot"
else
query_details[":a_ckey"] = user.ckey
establish_db_connection()
if (!dbcon.IsConnected())
alert("SQL connection failed while trying to add a note!")
return
if (!player_address || !player_computerid)
var/DBQuery/init_query = dbcon.NewQuery("SELECT ip, computerid FROM ss13_player WHERE ckey = :ckey")
init_query.Execute(list(":ckey" = player_ckey))
if (init_query.NextRow())
if (!query_details[":address"])
query_details[":address"] = init_query.item[1]
if (!query_details[":computer_id"])
query_details[":computer_id"] = init_query.item[2]
var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO ss13_notes (id, adddate, ckey, ip, computerid, a_ckey, content) VALUES (null, Now(), :ckey, :address, :computer_id, :a_ckey, :note)")
insert_query.Execute(query_details)
message_admins("\blue [key_name_admin(user)] has edited [player_ckey]'s notes.")
log_admin("[key_name(user)] has edited [player_ckey]'s notes.")
/proc/notes_edit_sql(var/note_id, var/note_edit)
if (!note_id || !note_edit)
return
establish_db_connection()
if (!dbcon.IsConnected())
error("SQL connection failed while attempting to delete a note!")
return
var/count = 0 //failsafe from unban procs
var/ckey
var/note
var/DBQuery/init_query = dbcon.NewQuery("SELECT ckey, content FROM ss13_notes WHERE id = :note_id")
init_query.Execute(list(":note_id" = note_id))
while (init_query.NextRow())
ckey = init_query.item[1]
note = init_query.item[2]
count++
if (count == 0)
usr << "\red Database update failed due to a note id not being present in the database."
error("Database update failed due to a note id not being present in the database.")
return
if (count > 1)
usr << "\red Database update failed due to multiple notes having the same ID. Contact the database admin."
error("Database update failed due to multiple notes having the same ID. Contact the database admin.")
return
switch (note_edit)
if ("delete")
if(alert("Delete this note?", "Delete?", "Yes", "No") == "Yes")
var/DBQuery/deletequery = dbcon.NewQuery("UPDATE ss13_notes SET visible = 0 WHERE id = :note_id")
deletequery.Execute(list(":note_id" = note_id))
message_admins("\blue [key_name_admin(usr)] deleted one of [ckey]'s notes.")
log_admin("[key_name(usr)] deleted one of [ckey]'s notes.")
else
usr << "Cancelled"
return
if ("content")
var/new_content = input("Edit this note's contents.", "New Contents", note, null) as null|text
if (!new_content)
usr << "Cancelled"
return
var/DBQuery/editquery = dbcon.NewQuery("UPDATE ss13_notes SET content = :new_content, lasteditor = :a_ckey, lasteditdate = Now(), edited = 1 WHERE id = :note_id")
editquery.Execute(list(":new_conent" = new_content, ":a_ckey" = usr.client.ckey, ":note_id" = note_id))
/datum/admins/proc/show_notes_sql(var/player_ckey = null, var/admin_ckey = null)
if (!check_rights(R_ADMIN|R_MOD))
return
if (admin_ckey == "Adminbot")
usr << "Adminbot is not an actual admin. You were lied to."
//The fucking size of this request would be astronomical. Please do not!
return
player_ckey = ckey(player_ckey)
admin_ckey = ckey(admin_ckey)
establish_db_connection()
if (!dbcon.IsConnected())
error("SQL connection failed while attempting to view a player's notes!")
return
var/dat = "<div align='center'><h3>Notes Look-up Panel</h3><br>"
//Totally not stealing code from the DB_ban_panel
dat += "<form method='GET' action='?src=\ref[src]'><b>Search:</b> "
dat += "<input type='hidden' name='src' value='\ref[src]'>"
dat += "<b>Ckey:</b> <input type='text' name='notessearchckey' value='[player_ckey]'>"
dat += "<b>Admin ckey:</b> <input type='text' name='notessearchadmin' value='[admin_ckey]'>"
dat += "<input type='submit' value='search'>"
dat += "</form></div>"
dat += "<table width='90%' bgcolor='#e3e3e3' cellpadding='5' cellspacing='0' align='center'>"
dat += "<tr>"
dat += "<th width='10%'>ISSUED TO</th>"
dat += "<th width='10%'>ISSUED BY</th>"
dat += "<th width='20%'>TIME ISSUED</th>"
dat += "<th width='50%'>CONTENT</th>"
dat += "</tr>"
if (player_ckey)
var/list/query_details = list(":player_ckey" = player_ckey)
dat += "<tr><td align='center' colspan='4' bgcolor='white'><b><a href='?src=\ref[src];add_player_info=[player_ckey]'>Add Note</a></b></td></tr>"
var/DBQuery/init_query = dbcon.NewQuery("SELECT ip, computerid FROM ss13_player WHERE ckey = :player_ckey")
init_query.Execute(query_details)
if (init_query.NextRow())
query_details += ":player_address"
query_details += ":player_computerid"
query_details[":player_address"] = init_query.item[1]
query_details[":player_computerid"] = init_query.item[2]
var/query_content = "SELECT id, adddate, ckey, a_ckey, content, edited, lasteditor, lasteditdate FROM ss13_notes WHERE ckey = :player_ckey AND visible = '1'"
if (query_details[":player_address"])
query_content += " OR ip = :player_address AND visible = '1'"
if (query_details[":player_computerid"])
query_content += " OR computerid = :player_computerid AND visible = '1'"
query_content += " ORDER BY adddate ASC"
var/DBQuery/query = dbcon.NewQuery(query_content)
query.Execute(query_details, 1)
while (query.NextRow())
var/id = text2num(query.item[1])
var/date = query.item[2]
var/p_ckey = query.item[3]
var/a_ckey = query.item[4]
var/content = query.item[5]
var/edited = text2num(query.item[6])
if (admin_ckey && ckey(a_ckey) != ckey(admin_ckey))
continue
else
dat += "<tr bgcolor='#ffeeee'><td align='center'><b>[p_ckey]</b></td><td align='center'><b>[a_ckey]</b></td><td align='center'>[date]</td><td align='center'>[content]</td></tr>"
if (edited)
var/lasteditor = query.item[7]
var/editdate = query.item[8]
dat += "<tr><td align='center' colspan='4'><b>Note last edited: [editdate], by: [lasteditor].</b></td></tr>"
dat += "<tr><td align='center' colspan='4'><b>(<a href=\"byond://?src=\ref[src];dbnoteedit=delete;dbnote_id=[id]\">Delete</a>) (<a href=\"byond://?src=\ref[src];dbnoteedit=content;dbnote_id=[id]\">Edit</a>)</b></td></tr>"
dat += "<tr><td colspan='4' bgcolor='white'>&nbsp</td></tr>"
else if (admin_ckey && !player_ckey)
var/aquery_content = "SELECT id, adddate, ckey, content, edited, lasteditor, lasteditdate FROM ss13_notes WHERE a_ckey = :a_ckey AND visible = '1' ORDER BY adddate ASC"
var/DBQuery/admin_query = dbcon.NewQuery(aquery_content)
admin_query.Execute(list(":a_ckey" = admin_ckey))
while (admin_query.NextRow())
var/id = text2num(admin_query.item[1])
var/date = admin_query.item[2]
var/p_ckey = admin_query.item[3]
var/content = admin_query.item[4]
var/edited = text2num(admin_query.item[5])
dat += "<tr bgcolor='#ffeeee'><td align='center'><b>[p_ckey]</b></td><td align='center'><b>[admin_ckey]</b></td><td align='center'>[date]</td><td align='center'>[content]</td></tr>"
if (edited)
var/lasteditor = admin_query.item[6]
var/editdate = admin_query.item[7]
dat += "<tr><td align='center' colspan='4'><b>Note last edited: [editdate], by: [lasteditor].</b></td></tr>"
dat += "<tr><td align='center' colspan='4'><b>(<a href=\"byond://?src=\ref[src];dbnoteedit=delete;dbnote_id=[id]\">Delete</a>) (<a href=\"byond://?src=\ref[src];dbnoteedit=content;dbnote_id=[id]\">Edit</a>)</b></td></tr>"
dat += "<tr><td colspan='4' bgcolor='white'>&nbsp</td></tr>"
dat += "</table>"
usr << browse(dat,"window=lookupnotes;size=900x500")
/*/proc/notes_transfer()
msg_scopes("Locating master list.")
var/savefile/note_list = new("data/player_notes.sav")
var/list/note_keys
note_list >> note_keys
msg_scopes("Establishing DB connection!")
establish_db_connection()
if(!dbcon.IsConnected())
msg_scopes("No DB connection!")
return
for(var/t in note_keys)
var/IP = null
var/CID = null
var/DBQuery/query = dbcon.NewQuery("SELECT ip, computerid FROM ss13_player WHERE ckey = '[t]'")
query.Execute()
if(query.NextRow())
IP = query.item[1]
CID = query.item[2]
var/savefile/info = new("data/player_saves/[copytext(t, 1, 2)]/[t]/info.sav")
var/list/infos
info >> infos
for(var/datum/player_info/I in infos)
var/a_ckey = sanitizeSQL(I.author)
var/timeY = copytext(I.timestamp, findtext(I.timestamp, "of") + 3)
var/timeM
var/timeD = copytext(I.timestamp, findtext(I.timestamp, " ", 6) + 1, findtext(I.timestamp, " ", 6) + 3)
if(findtext(timeD, "s") || findtext(timeD, "n") || findtext(timeD, "r") || findtext(timeD, "t"))
timeD = "0[copytext(timeD, 1, 2)]"
// msg_scopes("Timestamp: [I.timestamp].")
var/temp = copytext(I.timestamp, 6, findtext(I.timestamp, " ", 6))
// msg_scopes("The day? [timeD].")
// msg_scopes("The month? [temp].")
// msg_scopes("The year? [timeY].")
switch(temp)
if("January")
timeM = "01"
if("February")
timeM = "02"
if("March")
timeM = "03"
if("April")
timeM = "04"
if("May")
timeM = "05"
if("June")
timeM = "06"
if("July")
timeM = "07"
if("August")
timeM = "08"
if("September")
timeM = "09"
if("October")
timeM = "10"
if("November")
timeM = "11"
if("December")
timeM = "12"
var/DTG = "[timeY]-[timeM]-[timeD] 00:00:00"
// msg_scopes("Full DTG: [DTG]")
var/insertionstuff
if(IP && CID)
insertionstuff = "INSERT INTO ss13_notes (id, adddate, ckey, ip, computerid, a_ckey, content) VALUES (null, '[DTG]', '[t]', '[IP]', '[CID]', '[a_ckey]', '[I.content]')"
else
insertionstuff = "INSERT INTO ss13_notes (id, adddate, ckey, ip, computerid, a_ckey, content) VALUES (null, '[DTG]', '[t]', null, null, '[a_ckey]', '[I.content]')"
var/DBQuery/insertquery = dbcon.NewQuery(insertionstuff)
insertquery.Execute()
if(insertquery.ErrorMsg())
msg_scopes(insertquery.ErrorMsg())
else
msg_scopes("Transfer successful.")*/
+1
View File
@@ -82,6 +82,7 @@
body += "<a href='?src=\ref[usr];priv_msg=\ref"+ref+"'>PM</a> - "
body += "<a href='?src=\ref[src];subtlemessage="+ref+"'>SM</a> - "
body += "<a href='?src=\ref[src];adminplayerobservejump="+ref+"'>JMP</a><br>"
body += "<a hreF='?src=\ref[src];admin_wind_player="+ref+"'>WIND</a><br>"
if(antagonist > 0)
body += "<font size='2'><a href='?src=\ref[src];check_antagonist=1'><font color='red'><b>Antagonist</b></font></a></font>";
+43
View File
@@ -2641,6 +2641,49 @@
PlayerNotesPage(text2num(href_list["index"]))
return
else if(href_list["warnsearchckey"] || href_list["warnsearchadmin"])
var/adminckey = href_list["warnsearchadmin"]
var/playerckey = href_list["warnsearchckey"]
warning_panel(adminckey, playerckey)
return
else if(href_list["dbwarningedit"])
var/warningEdit = href_list["dbwarningedit"]
var/warningId = text2num(href_list["dbwarningid"])
if(!warningEdit || !warningId)
return
warningsEdit(warningId, warningEdit)
return
else if(href_list["dbnoteedit"])
var/noteedit = href_list["dbnoteedit"]
var/noteid = text2num(href_list["dbnoteid"])
if(!noteedit || !noteid)
return
notes_edit_sql(noteid, noteedit)
return
else if(href_list["notessearchckey"] || href_list["notessearchadmin"])
var/adminckey = href_list["notessearchadmin"]
var/playerckey = href_list["notessearchckey"]
show_notes_sql(playerckey, adminckey)
return
else if(href_list["admin_wind_player"])
var/mob/M = locate(href_list["admin_wind_player"])
if(!ismob(M))
usr << "This can only be used on instances of type /mob"
return
paralyze_mob(M)
return
mob/living/proc/can_centcom_reply()
return 0
@@ -55,7 +55,7 @@ var/inactive_keys = "None<br>"
//run a query to get all ckeys inactive for over 2 months
var/list/inactive_ckeys = list()
if(ckeys_with_customitems.len)
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM erro_player WHERE datediff(Now(), lastseen) > 60")
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM ss13_player WHERE datediff(Now(), lastseen) > 60")
query_inactive.Execute()
while(query_inactive.NextRow())
var/cur_ckey = query_inactive.item[1]
@@ -67,7 +67,7 @@ var/inactive_keys = "None<br>"
//if there are ckeys left over, check whether they have a database entry at all
if(ckeys_with_customitems.len)
for(var/cur_ckey in ckeys_with_customitems)
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ckey = '[cur_ckey]'")
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM ss13_player WHERE ckey = '[cur_ckey]'")
query_inactive.Execute()
if(!query_inactive.RowCount())
inactive_ckeys += cur_ckey
+412
View File
@@ -0,0 +1,412 @@
/*
* DB based warning proc
*/
/client/proc/warn(warned_ckey)
if (!check_rights(R_ADMIN|R_MOD))
return
if (!warned_ckey || !istext(warned_ckey))
return
establish_db_connection()
if (!dbcon.IsConnected())
usr << "<font color='red'>Error: warn(): Database Connection failed, reverting to legacy systems.</font>"
usr.client.warn_legacy(warned_ckey)
return
var/warning_reason = input("Add Warning Reason. This is visible to the player.") as null|text
if (!warning_reason)
return
var/warning_notes = input("Add additional informatoin. This is visible only to staff.") as null|text
var/warning_severity
switch (alert("Set warning severity", null, "Standard", "Severe"))
if ("standard")
warning_severity = 0
if ("Severe")
warning_severity = 1
var/warned_computerid = null
var/warned_ip = null
var/client/C = directory[warned_ckey]
if (C)
warned_computerid = C.computer_id
warned_ip = C.address
else
var/DBQuery/lookup_query = dbcon.NewQuery("SELECT ip, computerid FROM ss13_player WHERE ckey = :ckey")
lookup_query.Execute(list(":ckey" = warned_ckey))
if (lookup_query.NextRow())
warned_ip = lookup_query.item[1]
warned_computerid = lookup_query.item[2]
var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO ss13_warnings (id, time, severity, reason, notes, ckey, computerid, ip, a_ckey, a_ip, a_computerid) VALUES (null, Now(), :warning_severity, :warning_reason, :warning_notes, :warned_ckey, :warned_computerid, :warned_ip, :a_ckey, :a_ip, :a_computerid)")
insert_query.Execute(list(":warning_severity" = warning_severity, ":warning_reason" = warning_reason, ":warning_notes" = warning_notes, ":warned_ckey" = warned_ckey, ":warned_computerid" = warned_computerid, ":warned_ip" = warned_ip, ":a_ckey" = ckey, ":a_ip" = address, ":a_computerid" = computer_id))
notes_add_sql(warned_ckey, "Warning added by [ckey], for: [warning_reason]. || Notes regarding the warning: [warning_notes].", src, warned_ip, warned_computerid)
feedback_add_details("admin_verb", "WARN-DB")
if (C)
C << "<font color='red'><BIG><B>You have been warned by an administrator.</B></BIG><br>Click <a href='byond://?src=\ref[src];warnview=1'>here</a> to review and acknowledge them!</font>"
message_admins("[key_name_admin(src)] has warned [warned_ckey] for: [warning_reason].")
/*
* Legacy warning proc
*/
#define MAX_WARNS 3
#define AUTOBANTIME 10
/client/proc/warn_legacy(warned_ckey)
if (!warned_ckey)
usr << "<font color='red'>Error: warn_legacy(): No ckey passed!</font>"
return
var/datum/preferences/D
var/client/C = directory[warned_ckey]
if(C) D = C.prefs
else D = preferences_datums[warned_ckey]
if(!D)
src << "<font color='red'>Error: warn_legacy(): No such ckey found.</font>"
return
if(++D.warns >= MAX_WARNS) //uh ohhhh...you'reee iiiiin trouuuubble O:)
ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [AUTOBANTIME] minute autoban.")
if(C)
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban.")
C << "<font color='red'><BIG><B>You have been autobanned due to a warning by [ckey].</B></BIG><br>This is a temporary ban, it will be removed in [AUTOBANTIME] minutes."
qdel(C)
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban.")
AddBan(warned_ckey, D.last_id, "Autobanning due to too many formal warnings", ckey, 1, AUTOBANTIME)
feedback_inc("ban_warn",1)
else
if(C)
C << "<font color='red'><BIG><B>You have been warned by an administrator.</B></BIG><br>Further warnings will result in an autoban.</font>"
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)]. They have [MAX_WARNS-D.warns] strikes remaining.")
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] (DC). They have [MAX_WARNS-D.warns] strikes remaining.")
feedback_add_details("admin_verb","WARN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
#undef MAX_WARNS
#undef AUTOBANTIME
/*
* A proc for a player to check their own warnings
*/
/client/verb/warnings_check()
set name = "My warnings"
set category = "OOC"
set desc = "Display warnings issued to you."
var/lcolor = "#ffeeee" //light colour, severity = 0
var/dcolor = "#ffaaaa" //dark colour, severity = 1
var/ecolor = "#e3e3e3" //gray colour, expired = 1
establish_db_connection()
if (!dbcon.IsConnected())
alert("Connection to the SQL database lost. Aborting. Please alert an Administrator or a member of staff.")
return
var/dat = "<div align='center'><h3>Warnings received</h3></div><br>"
dat += "<table width='90%' bgcolor='#e3e3e3' cellpadding='5' cellspacing='0' align='center'>"
dat += "<tr>"
dat += "<th width='20%'>ADMIN</th>"
dat += "<th width='20%'>TIME ISSUED</th>"
dat += "<th width='60%'>REASON</th>"
dat += "</tr>"
var/DBQuery/search_query = dbcon.NewQuery("SELECT id, time, severity, reason, a_ckey, acknowledged, expired FROM ss13_warnings WHERE visible = 1 AND (ckey = :ckey OR computerid = :computer_id OR ip = :address) ORDER BY time DESC;")
search_query.Execute(list(":ckey" = ckey, ":computer_id" = computer_id, ":address" = address))
while (search_query.NextRow())
var/id = text2num(search_query.item[1])
var/time = search_query.item[2]
var/severity = text2num(search_query.item[3])
var/reason = search_query.item[4]
var/a_ckey = search_query.item[5]
var/ackn = text2num(search_query.item[6])
var/expired = text2num(search_query.item[7])
var/bgcolor = lcolor
if (severity)
bgcolor = dcolor
if (expired)
bgcolor = ecolor
dat += "<tr bgcolor='[bgcolor]' align='center'>"
dat += "<td>[a_ckey]</td>"
dat += "<td>[time]</td>"
dat += "<td>[reason]</td>"
dat += "</tr>"
if (!ackn)
dat += "<tr><td align='center' colspan='3'><b>(<a href='byond://?src=\ref[src];warnacknowledge=[id]'>Acknowledge Warning</a>)</b></td></tr>"
else if (expired)
dat += "<tr><td align='center' colspan='3'><b>Warning expired and no longer active!</b></td></tr>"
else
dat += "<tr><td align='center' colspan='3'><b>Warning acknowledged!</b></td></tr>"
dat += "<tr>"
dat += "<td colspan='5' bgcolor='white'>&nbsp</td>"
dat += "</tr>"
dat += "</table>"
usr << browse(dat, "window=mywarnings;size=900x500")
/*
* A proc for acknowledging a warning
*/
/client/proc/warnings_acknowledge(warning_id)
if (!warning_id)
return
establish_db_connection()
if (!dbcon.IsConnected())
alert("Connection to SQL database failed while attempting to update your warning's status!")
return
var/DBQuery/query = dbcon.NewQuery("UPDATE ss13_warnings SET acknowledged = 1 WHERE id = :warning_id;")
query.Execute(list(":warning_id" = warning_id))
warnings_check()
/*
* A proc to alert you if you have unacknowledged warnings.
* Called in /client/New (client procs.dm)
*/
/client/proc/warnings_alert()
var/count = 0
var/count_expire = 0
establish_db_connection()
if (!dbcon.IsConnected())
return
var/list/client_details = list(":ckey" = ckey, ":computer_id" = computer_id, ":address" = address)
var/DBQuery/expire_query = dbcon.NewQuery("SELECT id FROM ss13_warnings WHERE (acknowledged = 1 AND expired = 0 AND DATE_SUB(CURDATE(),INTERVAL 3 MONTH) > time) AND (ckey = :ckey OR computerid = :computer_id OR ip = :address)")
expire_query.Execute(client_details)
while (expire_query.NextRow())
var/warning_id = text2num(expire_query.item[1])
var/DBQuery/update_query = dbcon.NewQuery("UPDATE ss13_warnings SET expired = 1 WHERE id = :warning_id")
update_query.Execute(list(":warning_id" = warning_id))
count_expire++
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM ss13_warnings WHERE (visible = 1 AND acknowledged = 0 AND expired = 0) AND (ckey = :ckey OR computerid = :computer_id OR ip = :address)")
query.Execute(client_details)
while (query.NextRow())
count++
if (count)
src << "<br>"
src << "<font color=red><b>You have [count] unread [count > 1 ? "warnings" : "warning"]! Click <a href='byond://?src=\ref[src];warnview=1'>here</a> to review and acknowledge them!</b></font>"
if (count_expire)
src << "<br>"
src << "<font color=blue><b>[count_expire] of your warnings expired.</b></font>"
/*
* A proc for an admin/moderator to look up a member's warnings.
*/
/client/proc/warning_panel()
set category = "Admin"
set name = "Warnings Panel"
set desc = "Look-up warnings assigned to players."
if(!holder)
return
holder.warning_panel()
/datum/admins/proc/warning_panel(var/adminckey = null, var/playerckey = null)
if (!check_rights(R_ADMIN|R_MOD))
return
var/lcolor = "#ffeeee" //light colour, severity = 0
var/dcolor = "#ffdddd" //dark colour, severity = 1
var/ecolor = "#e3e3e3" //gray colour, expired = 1
establish_db_connection()
if (!dbcon.IsConnected())
alert("Connection to the SQL database lost. Aborting. Please alert the database admin!")
return
var/dat = "<div align='center'><h3>Warning Look-up Panel</h3><br>"
//Totally not stealing code from the DB_ban_panel
dat += "<form method='GET' action='?src=\ref[src]'><b>Search:</b> "
dat += "<input type='hidden' name='src' value='\ref[src]'>"
dat += "<b>Ckey:</b> <input type='text' name='warnsearchckey' value='[playerckey]'>"
dat += "<b>Admin ckey:</b> <input type='text' name='warnsearchadmin' value='[adminckey]'>"
dat += "<input type='submit' value='search'>"
dat += "</form></div>"
if (adminckey || playerckey)
dat += "<table width='90%' bgcolor='#e3e3e3' cellpadding='5' cellspacing='0' align='center'>"
dat += "<tr>"
dat += "<th width='10%'>ISSUED TO</th>"
dat += "<th width='10%'>ISSUED BY</th>"
dat += "<th width='10%'>TIME ISSUED</th>"
dat += "<th width='60%'>REASON</th>"
dat += "</tr>"
var/list/query_details = list("a_ckey", "ckey")
var/paramone = ""
var/paramtwo = ""
if(adminckey)
paramone = "AND a_ckey = :a_ckey "
query_details["a_ckey"] = adminckey
if(playerckey)
paramtwo = "AND ckey = :ckey "
query_details["ckey"] = playerckey
var/DBQuery/search_query = dbcon.NewQuery("SELECT id, time, severity, reason, notes, ckey, a_ckey, acknowledged, expired, edited, lasteditor, lasteditdate FROM ss13_warnings WHERE visible = 1 [paramone] [paramtwo] ORDER BY time DESC;")
search_query.Execute(query_details, 1)
while (search_query.NextRow())
var/id = text2num(search_query.item[1])
var/time = search_query.item[2]
var/severity = text2num(search_query.item[3])
var/reason = search_query.item[4]
var/notes = search_query.item[5]
var/ckey = search_query.item[6]
var/a_ckey = search_query.item[7]
var/ackn = text2num(search_query.item[8])
var/expired = text2num(search_query.item[9])
var/edited = text2num(search_query.item[10])
var/bgcolor = lcolor
if(severity)
bgcolor = dcolor
if(expired)
bgcolor = ecolor
dat += "<tr bgcolor='[bgcolor]' align='center'>"
dat += "<td>[ckey]</td>"
dat += "<td>[a_ckey]</td>"
dat += "<td>[time]</td>"
dat += "<td>[reason]</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<td align='center' colspan='5'><b>Staff Notes:</b> <cite>\"[notes]\"</cite></td>"
dat += "</tr>"
if(!ackn)
dat += "<tr><td align='center' colspan='5'>Warning has not been acknolwedged by recipient.</td></tr>"
if(expired)
dat += "<tr><td align='center' colspan='5'>The warning has expired.</td></tr>"
if(edited)
var/lastEditor = search_query.item[11]
var/lastEditDate = search_query.item[12]
dat += "<tr><td align='center' colspan='5'><b>Warning last edited: [lastEditDate], by: [lastEditor].</b></td></tr>"
dat += "<tr>"
dat += "<td align='center' colspan='5'><b>Options:</b> "
if(check_rights(R_ADMIN) || a_ckey == sanitizeSQL(ckey))
dat += "<a href=\"byond://?src=\ref[src];dbwarningedit=editReason;dbwarningid=[id]\">Edit Reason</a> "
dat += "<a href=\"byond://?src=\ref[src];dbwarningedit=editNotes;dbwarningid=[id]\">Edit Note</a> "
dat += "<a href=\"byond://?src=\ref[src];dbwarningedit=delete;dbwarningid=[id]\">Delete Warning</a>"
else
dat += "You can only edit or delete notes that you have issued."
dat += "</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<td colspan='5' bgcolor='white'>&nbsp</td>"
dat += "</tr>"
dat +="</table>"
usr << browse(dat, "window=lookupwarns;size=900x500")
feedback_add_details("admin_verb","WARN-LKUP")
/*
* A proc for editing and deleting warnings issued
*/
/proc/warningsEdit(var/warning_id, var/warning_edit)
if(!warning_id || !warning_edit)
return
establish_db_connection()
if(!dbcon.IsConnected())
alert("Connection to the SQL database lost. Aborting. Please alert the database admin!")
return
var/count = 0 //failsafe
var/ckey
var/reason
var/notes
var/list/query_details = list(":warning_id" = warning_id, ":a_ckey" = usr.ckey)
var/DBQuery/initial_query = dbcon.NewQuery("SELECT ckey, reason, notes FROM ss13_warnings WHERE id = :warning_id")
initial_query.Execute(query_details, 1)
while (initial_query.NextRow())
ckey = initial_query.item[1]
reason = initial_query.item[2]
notes = initial_query.item[3]
count++
if (count == 0)
usr << "\red Database update failed due to a warning id not being present in the database."
error("Database update failed due to a warning id not being present in the database.")
return
if (count > 1)
usr << "\red Database update failed due to multiple warnings having the same ID. Contact the database admin."
error("Database update failed due to multiple warnings having the same ID. Contact the database admin.")
return
switch (warning_edit)
if ("delete")
if(alert("Delete this warning?", "Delete?", "Yes", "No") == "Yes")
var/DBQuery/deleteQuery = dbcon.NewQuery("UPDATE ss13_warnings SET visible = 0 WHERE id = :warning_id")
deleteQuery.Execute(query_details)
message_admins("\blue [key_name_admin(usr)] deleted one of [ckey]'s warnings.")
log_admin("[key_name(usr)] deleted one of [ckey]'s warnings.")
else
usr << "Cancelled"
return
if ("editReason")
query_details += ":new_reason"
query_details[":new_reason"] = input("Edit this warning's reason.", "New Reason", reason, null) as null|text
if(!query_details[":new_reason"] || query_details[":new_reason"] == reason)
usr << "Cancelled"
return
var/DBQuery/reason_query = dbcon.NewQuery("UPDATE ss13_warnings SET reason = :new_reason, edited = 1, lasteditor = :a_ckey, lasteditdate = NOW() WHERE id = :warning_id")
reason_query.Execute(query_details, 1)
message_admins("\blue [key_name_admin(usr)] edited one of [ckey]'s warning reasons.")
log_admin("[key_name(usr)] edited one of [ckey]'s warning reasons.")
if("editNotes")
query_details += ":new_notes"
query_details[":new_notes"] = input("Edit this warning's notes.", "New Notes", notes, null) as null|text
if(!query_details[":new_notes"] || query_details[":new_notes"] == notes)
usr << "Cancelled"
return
var/DBQuery/notes_query = dbcon.NewQuery("UPDATE ss13_warnings SET notes = :new_notes, edited = 1, lasteditor = :a_ckey, lasteditdate = NOW() WHERE id = :warning_id")
notes_query.Execute(query_details, 1)
message_admins("\blue [key_name_admin(usr)] edited one of [ckey]'s warning notes.")
log_admin("[key_name(usr)] edited one of [ckey]'s warning notes.")
+1
View File
@@ -45,5 +45,6 @@
var/player_age = "Requires database" //So admins know why it isn't working - Used to determine how old the account is - in days.
var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip
var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id
var/whitelist_status = 0 //Used to determine what whitelists the player has access to. Uses bitflag values!
preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
+10 -7
View File
@@ -164,6 +164,8 @@
sleep(2) // wait a bit more, possibly fixes hardware mode not re-activating right
winset(src, null, "command=\".configure graphics-hwmode on\"")
warnings_alert()
log_client_to_db()
send_resources()
@@ -200,7 +202,7 @@
var/sql_ckey = sql_sanitize_text(ckey(key))
var/DBQuery/query = dbcon.NewQuery("SELECT datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'")
var/DBQuery/query = dbcon.NewQuery("SELECT datediff(Now(),firstseen) as age FROM ss13_player WHERE ckey = '[sql_ckey]'")
query.Execute()
if(query.NextRow())
@@ -220,23 +222,24 @@
var/sql_ckey = sql_sanitize_text(src.ckey)
var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'")
var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age, whitelist_status FROM ss13_player WHERE ckey = '[sql_ckey]'")
query.Execute()
var/sql_id = 0
player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if their is a record.
while(query.NextRow())
sql_id = query.item[1]
player_age = text2num(query.item[2])
whitelist_status = text2num(query.item[3])
break
var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ip = '[address]'")
var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM ss13_player WHERE ip = '[address]'")
query_ip.Execute()
related_accounts_ip = ""
while(query_ip.NextRow())
related_accounts_ip += "[query_ip.item[1]], "
break
var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE computerid = '[computer_id]'")
var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM ss13_player WHERE computerid = '[computer_id]'")
query_cid.Execute()
related_accounts_cid = ""
while(query_cid.NextRow())
@@ -261,16 +264,16 @@
if(sql_id)
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
var/DBQuery/query_update = dbcon.NewQuery("UPDATE ss13_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
query_update.Execute()
else
//New player!! Need to insert all the stuff
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO ss13_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
query_insert.Execute()
//Logging player access
var/serverip = "[world.internet_address]:[world.port]"
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');")
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `ss13_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');")
query_accesslog.Execute()
+5 -3
View File
@@ -19,7 +19,8 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
"raider" = IS_MODE_COMPILED("heist"), // 11
"diona" = 1, // 12
"loyalist" = IS_MODE_COMPILED("revolution"), // 13
"pAI candidate" = 1, // -- TLE // 14
"vampire" = IS_MODE_COMPILED("vampire"), // 14
"pAI candidate" = 1, // -- TLE // 15
)
//used for alternate_option
@@ -45,6 +46,7 @@ datum/preferences
var/be_special = 0 //Special role selection
var/UI_style = "Midnight"
var/toggles = TOGGLES_DEFAULT
var/asfx_togs = ASFX_DEFAULT
var/UI_style_color = "#ffffff"
var/UI_style_alpha = 255
@@ -647,7 +649,7 @@ datum/preferences
if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it!
if(!(current_species.flags & CAN_JOIN))
restricted = 2
else if((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(user,current_species))
else if((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(user,current_species.name))
restricted = 1
if(restricted)
@@ -655,7 +657,7 @@ datum/preferences
dat += "<font color='red'><b>You cannot play as this species.</br><small>If you wish to be whitelisted, you can make an application post on <a href='?src=\ref[user];preference=open_whitelist_forum'>the forums</a>.</small></b></font></br>"
else if(restricted == 2)
dat += "<font color='red'><b>You cannot play as this species.</br><small>This species is not available for play as a station race..</small></b></font></br>"
if(!restricted || check_rights(R_ADMIN, 0))
if(!restricted)
dat += "\[<a href='?src=\ref[user];preference=species;task=input;newspecies=[species_preview]'>select</a>\]"
dat += "</center></body>"
@@ -0,0 +1,54 @@
/var/global/asfx_togs = list(
// /client/proc/Toggle_asfx,
// /client/proc/Toggle_footsteps,
/client/proc/Toggle_asfx_vote
)
/client/verb/asf_toggle()
set name = "Open ASFX Tab"
set category = "Preferences"
set desc = "Open the ambiance sound effects toggle tab"
verbs ^= asfx_togs
return
/client/verb/Toggle_asfx() //Allgnew ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful
set name = "Hear/Silence Ambience"
// set category = "SoundFx Prefs"
set category = "Preferences"
set desc = "Toggles hearing ambient sound effects"
prefs.asfx_togs ^= ASFX_AMBIENCE
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_AMBIENCE)
src << "You will now hear ambient sounds."
else
src << "<font color='red'>You will no longer hear ambient sounds.</font>"
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
feedback_add_details("admin_verb","TSFXAmbi") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/Toggle_footsteps()
set name = "Hear/Silence Footsteps"
set category = "SoundFx Prefs"
set desc = "Toggles hearing footstep sound effects"
prefs.asfx_togs ^= ASFX_FOOTSTEPS
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_FOOTSTEPS)
src << "You will now hear footstep sounds."
else
src << "<font color='red'>You will no longer hear footstep sounds.</font>"
feedback_add_details("admin_verb","TSFXFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/Toggle_asfx_vote()
set name = "Hear/Silence Vote Alarm"
set category = "SoundFx Prefs"
set desc = "Toggles hearing of the vote alarm"
prefs.asfx_togs ^= ASFX_VOTE
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_VOTE)
src << "You will now hear the vote alarm."
else
src << "<font color='red'>You will no longer hear the vote alarm.</font>"
feedback_add_details("admin_verb","TSFXFV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+4 -1
View File
@@ -56,6 +56,7 @@
S["toggles"] >> toggles
S["UI_style_color"] >> UI_style_color
S["UI_style_alpha"] >> UI_style_alpha
S["asfx_togs"] >> asfx_togs
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
@@ -64,6 +65,7 @@
be_special = sanitize_integer(be_special, 0, 65535, initial(be_special))
default_slot = sanitize_integer(default_slot, 1, config.character_slots, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 65535, initial(toggles))
asfx_togs = sanitize_integer(asfx_togs, 0, 65535, initial(asfx_togs))
UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color))
UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha))
@@ -84,6 +86,7 @@
S["be_special"] << be_special
S["default_slot"] << default_slot
S["toggles"] << toggles
S["asfx_togs"] << asfx_togs
return 1
@@ -346,4 +349,4 @@
#undef SAVEFILE_VERSION_MAX
#undef SAVEFILE_VERSION_MIN
#undef SAVEFILE_VERSION_MIN
+8 -1
View File
@@ -10,11 +10,17 @@
while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. vox wearing jumpsuits).
*/
var/list/sprite_sheets_refit = null
var/gunshot_residue
//Updates the icons of the mob wearing the clothing item, if any.
/obj/item/clothing/proc/update_clothing_icon()
return
// Aurora forensics port.
/obj/item/clothing/clean_blood()
..()
gunshot_residue = null
//BS12: Species-restricted clothing check.
/obj/item/clothing/mob_can_equip(M as mob, slot)
@@ -331,6 +337,7 @@ BLIND // can't see anything
var/overshoes = 0
species_restricted = list("exclude","Unathi","Tajara")
sprite_sheets = list("Vox" = 'icons/mob/species/vox/shoes.dmi')
var/silent = 0
/obj/item/clothing/shoes/proc/handle_movement(var/turf/walking, var/running)
return
@@ -606,4 +613,4 @@ BLIND // can't see anything
if(accessories.len)
for(var/obj/item/clothing/accessory/A in accessories)
A.emp_act(severity)
..()
..()
+29 -1
View File
@@ -16,7 +16,7 @@
New()
//average of 0.5, somewhat better than regular gloves' 0.75
siemens_coefficient = pick(0,0.1,0.3,0.5,0.5,0.75,1.35)
siemens_coefficient = pick(0,0.1,0.3,0.5,0.5,0.75,1.35)
/obj/item/clothing/gloves/black
desc = "These work gloves are thick and fire-resistant."
@@ -84,3 +84,31 @@
desc = "A pair of gloves, they don't look special in any way."
icon_state = "brown"
item_state = "browngloves"
/obj/item/clothing/gloves/yellow/specialt
desc = "These gloves will protect the wearer from electric shock. Made special for Tajaran use"
name = "Tajaran electrical gloves"
icon_state = "yellow"
item_state = "ygloves"
siemens_coefficient = 0
permeability_coefficient = 0.05
species_restricted = list("Tajaran")
/obj/item/clothing/gloves/yellow/specialu
desc = "These gloves will protect the wearer from electric shock. Made special for Unathi use"
name = "Unathi electrical gloves"
icon_state = "yellow"
item_state = "ygloves"
siemens_coefficient = 0
permeability_coefficient = 0.05
species_restricted = list("Unathi")
/obj/item/clothing/gloves/black/unathi
name = "black gloves"
desc = "black gloves made for Unathi use."
species_restricted = list("Unathi")
/obj/item/clothing/gloves/black/tajara
name = "black gloves"
desc = "black gloves made for Tajara use."
species_restricted = list("Tajaran")
@@ -51,3 +51,125 @@
item_state = "ggloves"
permeability_coefficient = 0.05
siemens_coefficient = 0.50 //thick work gloves
/obj/item/clothing/gloves/latex/unathi
name = "unathi latex gloves"
desc = "Sterile latex gloves. Designed for Unathi use."
species_restricted = list("Unathi")
/obj/item/clothing/gloves/latex/tajara
name = "tajara latex gloves"
desc = "Sterile latex gloves. Designed for Tajara use."
species_restricted = list("Tajaran")
/obj/item/clothing/gloves/watch
desc = "A small wristwatch, capable of telling time."
name = "watch"
icon_state = "watch"
item_state = "watchgloves"
w_class = 1
wired = 1
species_restricted = null
verb/checktime()
set category = "Object"
set name = "Check Time"
set src in usr
if(wired && !clipped)
usr << "You check your watch, spotting a digital collection of numbers reading '[worldtime2text()]'. Today's date is '[time2text(world.time, "Month DD")]. [game_year]'."
if (emergency_shuttle.get_status_panel_eta())
usr << "\red The shuttle's status is reported as: [emergency_shuttle.get_status_panel_eta()]."
else if(wired && clipped)
usr << "You check your watch realising it's still open"
else
usr << "You check your watch as it dawns on you that it's broken"
verb/pointatwatch()
set category = "Object"
set name = "Point at watch"
set src in usr
if(wired && !clipped)
usr.visible_message ("<span class='notice'>[usr] taps their foot on the floor, arrogantly pointing at the [src] on their wrist with a look of derision in their eyes.</span>", "<span class='notice'>You point down at the [src], an arrogant look about your eyes.</span>")
else if(wired && clipped)
usr.visible_message ("<span class='notice'>[usr] taps their foot on the floor, arrogantly pointing at the [src] on their wrist with a look of derision in their eyes, not noticing it's open</span>", "<span class='notice'>You point down at the [src], an arrogant look about your eyes.</span>")
else
usr.visible_message ("<span class='notice'>[usr] taps their foot on the floor, arrogantly pointing at the [src] on their wrist with a look of derision in their eyes, not noticing it's broken</span>", "<span class='notice'>You point down at the [src], an arrogant look about your eyes.</span>")
examine(mob/user)
..()
if (get_dist(src, user) <= 1)
checktime()
attackby(obj/item/weapon/W, mob/user)
if(istype(W, /obj/item/weapon/screwdriver))
if (clipped) //Using clipped because adding a new var for something is dumb
user.visible_message("\blue [user] screws the cover of the [src] closed.","\blue You screw the cover of the [src] closed..")
clipped = 0
return
// playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
user.visible_message("\blue [user] unscrew the cover of the [src].","\blue You unscrew the cover of the [src].")
clipped = 1
return
if(wired)
return
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if (!clipped)
user << "<span class='notice'>The [src] is not open.</span>"
return
if(wired)
user << "<span class='notice'>The [src] are already wired.</span>"
return
if(C.amount < 2)
user << "<span class='notice'>There is not enough wire to cover the [src].</span>"
return
C.use(2)
wired = 1
user << "<span class='notice'>You repair some wires in the [src].</span>"
return
emp_act(severity)
if(prob(50/severity))
wired = 0
..()
/*
Forcegloves. They amplify force from melee hits as well as muck up disarm and stuff a little.
Has bits of code in item_attack.dm, stungloves.dm, human_attackhand, human_defense
*/
/obj/item/clothing/gloves/force // this pair should be put in r&d if you choose to do so. and also the hos office locker. do it okay
desc = "These gloves bend gravity and bluespace, dampening inertia and augmenting the wearer's melee capabilities."
name = "force gloves"
icon_state = "black"
item_state = "swat_gl"
siemens_coefficient = 0.6
permeability_coefficient = 0.05
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE
var/active = 1 //i am actually too lazy to code an on/off switch so if you want it off, take them off for now. yes.
var/amplification = 2
/obj/item/clothing/gloves/force/basic //dooo iiiitttttt
desc = "These gloves bend gravity and bluespace, providing a cheap boost to the effectiveness of your average security staff."
name = "basic force gloves" //do it skull do it give it to all sec the forums agree go
amplification = 1 //just do it
/obj/item/clothing/gloves/force/syndicate //for syndies. pda, *maybe* nuke team or ert. up to you. maybe just use the amp 2 variant.
desc = "These gloves bend gravity and bluespace, dampening inertia and augmenting the wearer's melee capabilities."
name = "enhanced force gloves"
icon_state = "black"
item_state = "swat_gl"
amplification = 2.5 //because *2.5 is kind of scary okay. sometimes you want the scary effect. sometimes not.
@@ -0,0 +1,93 @@
/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user)
if(istype(src, /obj/item/clothing/gloves/boxing)) //quick fix for stunglove overlay not working nicely with boxing gloves.
user << "<span class='notice'>That won't work.</span>" //i'm not putting my lips on that!
..()
return
else if(istype(src, /obj/item/clothing/gloves/force))
user << "<span class='notice'>That seems like a terrible idea.</span>"
..()
return
//add wires
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if (clipped)
user << "<span class='notice'>The [src] are too badly mangled for wiring.</span>"
return
if(wired)
user << "<span class='notice'>The [src] are already wired.</span>"
return
if(C.amount < 2)
user << "<span class='notice'>There is not enough wire to cover the [src].</span>"
return
C.use(2)
wired = 1
siemens_coefficient = 3.0
user << "<span class='notice'>You wrap some wires around the [src].</span>"
update_icon()
return
//add cell
else if(istype(W, /obj/item/weapon/cell))
if(!wired)
user << "<span class='notice'>The [src] need to be wired first.</span>"
else if(!cell)
user.drop_item()
W.loc = src
cell = W
w_class = 3.0
user << "<span class='notice'>You attach the [cell] to the [src].</span>"
update_icon()
else
user << "<span class='notice'>A [cell] is already attached to the [src].</span>"
return
else if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel))
//stunglove stuff
if(cell)
cell.update_icon()
user << "<span class='notice'>You cut the [cell] away from the [src].</span>"
cell.loc = get_turf(src.loc)
cell = null
w_class = 2.0
update_icon()
return
if(wired) //wires disappear into the void because fuck that shit
wired = 0
siemens_coefficient = initial(siemens_coefficient)
user << "<span class='notice'>You cut the wires away from the [src].</span>"
update_icon()
return
//clipping fingertips
if(!clipped)
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
user.visible_message("\red [user] cuts the fingertips off of the [src].","\red You cut the fingertips off of the [src].")
clipped = 1
name = "mangled [name]"
desc = "[desc]<br>They have had the fingertips cut off of them."
if("exclude" in species_restricted)
species_restricted -= "Unathi"
species_restricted -= "Tajaran"
return
else
user << "<span class='notice'>The [src] have already been clipped!</span>"
update_icon()
return
return
..()
/obj/item/clothing/gloves/update_icon()
..()
overlays.Cut()
if(wired)
overlays += "gloves_wire"
if(cell)
overlays += "gloves_cell"
@@ -15,7 +15,7 @@
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
species_restricted = list("exclude","Diona", "Xenomorph")
species_restricted = list("exclude","Diona","Xenomorph","Vaurca")
var/obj/machinery/camera/camera
var/list/camera_networks
@@ -61,7 +61,7 @@
cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
species_restricted = list("exclude","Diona", "Xenomorph")
species_restricted = list("exclude","Diona","Xenomorph","Vaurca")
var/list/supporting_limbs //If not-null, automatically splints breaks. Checked when removing the suit.
+2 -2
View File
@@ -100,7 +100,7 @@
item_state = "det_suit"
blood_overlay_type = "coat"
body_parts_covered = UPPER_TORSO|ARMS
allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter,/obj/item/device/detective_scanner,/obj/item/device/taperecorder)
allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter,/obj/item/device/taperecorder)
armor = list(melee = 50, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0)
sprite_sheets = list("Vox" = 'icons/mob/species/vox/suit.dmi')
@@ -113,7 +113,7 @@
desc = "A forensics technician jacket."
item_state = "det_suit"
body_parts_covered = UPPER_TORSO|ARMS
allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/device/detective_scanner,/obj/item/device/taperecorder)
allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/device/taperecorder)
armor = list(melee = 10, bullet = 10, laser = 15, energy = 10, bomb = 0, bio = 0, rad = 0)
/obj/item/clothing/suit/storage/forensics/red
+17
View File
@@ -37,6 +37,23 @@
worn_state = "orange"
has_sensor = 2
sensor_mode = 3
var/id
/obj/item/clothing/under/color/orange/cell1
desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position.\nThis one has \"Cell 1\" marked on it."
id = "Cell 1"
/obj/item/clothing/under/color/orange/cell2
desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position.\nThis one has \"Cell 2\" marked on it."
id = "Cell 2"
/obj/item/clothing/under/color/orange/cell3
desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position.\nThis one has \"Cell 3\" marked on it."
id = "Cell 3"
/obj/item/clothing/under/color/orange/cell4
desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position.\nThis one has \"Cell 4\" marked on it."
id = "Cell 4"
/obj/item/clothing/under/color/pink
name = "pink jumpsuit"
@@ -1,47 +0,0 @@
/mob
var/bloody_hands = 0
var/mob/living/carbon/human/bloody_hands_mob
var/track_blood = 0
var/list/feet_blood_DNA
var/track_blood_type
var/feet_blood_color
/obj/item/clothing/gloves
var/transfer_blood = 0
var/mob/living/carbon/human/bloody_hands_mob
/obj/item/clothing/shoes/
var/track_blood = 0
/obj/item/weapon/reagent_containers/glass/rag
name = "damp rag"
desc = "For cleaning up messes, you suppose."
w_class = 1
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 5
can_be_placed_into = null
flags = OPENCONTAINER | NOBLUDGEON
unacidable = 0
/obj/item/weapon/reagent_containers/glass/rag/attack_self(mob/user as mob)
return
/obj/item/weapon/reagent_containers/glass/rag/attack(atom/target as obj|turf|area, mob/user as mob , flag)
if(ismob(target) && target.reagents && reagents.total_volume)
user.visible_message("\red \The [target] has been smothered with \the [src] by \the [user]!", "\red You smother \the [target] with \the [src]!", "You hear some struggling and muffled cries of surprise")
reagents.trans_to_mob(target, reagents.total_volume, CHEM_INGEST)
return
else
..()
/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity)
if(!proximity) return
if(istype(A) && src in user)
user.visible_message("[user] starts to wipe down [A] with [src]!")
if(do_after(user,30))
user.visible_message("[user] finishes wiping off the [A]!")
A.clean_blood()
return
+4
View File
@@ -1,3 +1,7 @@
/obj/item/weapon/forensics
icon = 'icons/obj/forensics.dmi'
w_class = 1
//This is the output of the stringpercent(print) proc, and means about 80% of
//the print must be there for it to be complete. (Prints are 32 digits)
var/const/FINGERPRINT_COMPLETE = 6
@@ -0,0 +1,153 @@
//DNA machine
/obj/machinery/dnaforensics
name = "DNA analyzer"
desc = "A high tech machine that is designed to read DNA samples properly."
icon = 'icons/obj/forensics.dmi'
icon_state = "dnaopen"
anchored = 1
density = 1
var/obj/item/weapon/forensics/swab/bloodsamp = null
var/closed = 0
var/scanning = 0
var/scanner_progress = 0
var/scanner_rate = 2.50
var/last_process_worldtime = 0
var/report_num = 0
/obj/machinery/dnaforensics/attackby(var/obj/item/W, mob/user as mob)
if(bloodsamp)
user << "<span class='warning'>There is already a sample in the machine.</span>"
return
if(closed)
user << "<span class='warning'>Open the cover before inserting the sample.</span>"
return
var/obj/item/weapon/forensics/swab/swab = W
if(istype(swab) && swab.is_used())
user.unEquip(W)
src.bloodsamp = swab
swab.loc = src
user << "<span class='notice'>You insert \the [W] into \the [src].</span>"
else
user << "<span class='warning'>\The [src] only accepts used swabs.</span>"
return
/obj/machinery/dnaforensics/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null)
if(stat & (NOPOWER)) return
if(user.stat || user.restrained()) return
var/list/data = list()
data["scan_progress"] = round(scanner_progress)
data["scanning"] = scanning
data["bloodsamp"] = (bloodsamp ? bloodsamp.name : "")
data["bloodsamp_desc"] = (bloodsamp ? (bloodsamp.desc ? bloodsamp.desc : "No information on record.") : "")
data["lidstate"] = closed
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
ui = new(user, src, ui_key, "dnaforensics.tmpl", "QuikScan DNA Analyzer", 540, 326)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/dnaforensics/Topic(href, href_list)
if(..()) return 1
if(stat & (NOPOWER))
return 0 // don't update UIs attached to this object
if(href_list["scanItem"])
if(scanning)
scanning = 0
else
if(bloodsamp)
if(closed == 1)
scanner_progress = 0
scanning = 1
usr << "<span class='notice'>Scan initiated.</span>"
update_icon()
else
usr << "<span class='notice'>Please close sample lid before initiating scan.</span>"
else
usr << "<span class='warning'>Insert an item to scan.</span>"
if(href_list["ejectItem"])
if(bloodsamp)
bloodsamp.forceMove(src.loc)
bloodsamp = null
if(href_list["toggleLid"])
toggle_lid()
return 1
/obj/machinery/dnaforensics/process()
if(scanning)
if(!bloodsamp || bloodsamp.loc != src)
bloodsamp = null
scanning = 0
else if(scanner_progress >= 100)
complete_scan()
return
else
//calculate time difference
var/deltaT = (world.time - last_process_worldtime) * 0.1
scanner_progress = min(100, scanner_progress + scanner_rate * deltaT)
last_process_worldtime = world.time
/obj/machinery/dnaforensics/proc/complete_scan()
src.visible_message("<span class='notice'>\icon[src] makes an insistent chime.</span>", 2)
update_icon()
if(bloodsamp)
var/obj/item/weapon/paper/P = new(src)
P.name = "[src] report #[++report_num]: [bloodsamp.name]"
P.stamped = list(/obj/item/weapon/stamp)
P.overlays = list("paper_stamped")
//dna data itself
var/data = "No scan information available."
if(bloodsamp.dna != null)
data = "Spectometric analysis on provided sample has determined the presence of [bloodsamp.dna.len] strings of DNA.<br><br>"
for(var/blood in bloodsamp.dna)
data += "\blue Blood type: [bloodsamp.dna[blood]]<br>\nDNA: [blood]<br><br>"
else
data += "No DNA found.<br>"
P.info = "<b>[src] analysis report #[report_num]</b><br>"
P.info += "<b>Scanned item:</b><br>[bloodsamp.name]<br>[bloodsamp.desc]<br><br>" + data
P.forceMove(src.loc)
P.update_icon()
scanning = 0
update_icon()
return
/obj/machinery/dnaforensics/attack_ai(mob/user as mob)
ui_interact(user)
/obj/machinery/dnaforensics/attack_hand(mob/user as mob)
ui_interact(user)
/obj/machinery/dnaforensics/verb/toggle_lid()
set category = "Object"
set name = "Toggle Lid"
set src in oview(1)
if(usr.stat || !isliving(usr))
return
if(scanning)
usr << "<span class='warning'>You can't do that while [src] is scanning!</span>"
return
closed = !closed
src.update_icon()
/obj/machinery/dnaforensics/update_icon()
..()
if(!(stat & NOPOWER) && scanning)
icon_state = "dnaworking"
else if(closed)
icon_state = "dnaclosed"
else
icon_state = "dnaopen"
@@ -0,0 +1,116 @@
//microscope code itself
/obj/machinery/microscope
name = "high powered electron microscope"
desc = "A highly advanced microscope capable of zooming up to 3000x."
icon = 'icons/obj/forensics.dmi'
icon_state = "microscope"
anchored = 1
density = 1
var/obj/item/weapon/sample = null
var/report_num = 0
/obj/machinery/microscope/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(sample)
user << "<span class='warning'>There is already a slide in the microscope.</span>"
return
if(istype(W, /obj/item/weapon/forensics/slide) || istype(W, /obj/item/weapon/sample/print))
user << "<span class='notice'>You insert \the [W] into the microscope.</span>"
user.unEquip(W)
W.forceMove(src)
sample = W
update_icon()
return
/obj/machinery/microscope/attack_hand(mob/user)
if(!sample)
user << "<span class='warning'>The microscope has no sample to examine.</span>"
return
user << "<span class='notice'>The microscope whirrs as you examine \the [sample].</span>"
if(!do_after(user, 25) || !sample)
return
user << "<span class='notice'>Printing findings now...</span>"
var/obj/item/weapon/paper/report = new(get_turf(src))
report.stamped = list(/obj/item/weapon/stamp)
report.overlays = list("paper_stamped")
report_num++
if(istype(sample, /obj/item/weapon/forensics/slide))
var/obj/item/weapon/forensics/slide/slide = sample
if(slide.has_swab)
var/obj/item/weapon/forensics/swab/swab = slide.has_swab
report.name = "GSR report #[++report_num]: [swab.name]"
report.info = "<b>Scanned item:</b><br>[swab.name]<br><br>"
if(swab.gsr)
report.info += "Residue from a [swab.gsr] bullet detected."
else
report.info += "No gunpowder residue found."
else if(slide.has_sample)
var/obj/item/weapon/sample/fibers/fibers = slide.has_sample
report.name = "Fiber report #[++report_num]: [fibers.name]"
report.info = "<b>Scanned item:</b><br>[fibers.name]<br><br>"
if(fibers.evidence)
report.info = "Molecular analysis on provided sample has determined the presence of unique fiber strings.<br><br>"
for(var/fiber in fibers.evidence)
report.info += "<span class='notice'>Most likely match for fibers: [fiber]</span><br><br>"
else
report.info += "No fibers found."
else
report.name = "Empty slide report #[report_num]"
report.info = "Evidence suggests that there's nothing in this slide."
else if(istype(sample, /obj/item/weapon/sample/print))
report.name = "Fingerprint report #[report_num]: [sample.name]"
report.info = "<b>Fingerprint analysis report #[report_num]</b>: [sample.name]<br>"
var/obj/item/weapon/sample/print/card = sample
if(card.evidence && card.evidence.len)
report.info += "Surface analysis has determined unique fingerprint strings:<br><br>"
for(var/prints in card.evidence)
report.info += "<span class='notice'>Fingerprint string: </span>"
if(!is_complete_print(prints))
report.info += "INCOMPLETE PRINT"
else
report.info += "[prints]"
report.info += "<br>"
else
report.info += "No information available."
if(report)
report.update_icon()
if(report.info)
user << report.info
return
/obj/machinery/microscope/proc/remove_sample(var/mob/living/remover)
if(!istype(remover) || remover.stat || !Adjacent(remover))
return ..()
if(!sample)
remover << "<span class='warning'>\The [src] does not have a sample in it.</span>"
return
remover << "<span class='notice'>You remove \the [sample] from \the [src].</span>"
sample.forceMove(get_turf(src))
remover.put_in_hands(sample)
sample = null
update_icon()
/obj/machinery/microscope/AltClick()
remove_sample(usr)
/obj/machinery/microscope/MouseDrop(var/atom/other)
if(usr == other)
remove_sample(usr)
else
return ..()
/obj/machinery/microscope/update_icon()
icon_state = "microscope"
if(sample)
icon_state += "slide"
@@ -0,0 +1,42 @@
/obj/item/weapon/forensics/slide
name = "microscope slide"
desc = "A pair of thin glass panes used in the examination of samples beneath a microscope."
icon_state = "slide"
var/obj/item/weapon/forensics/swab/has_swab
var/obj/item/weapon/sample/fibers/has_sample
/obj/item/weapon/forensics/slide/attackby(var/obj/item/weapon/W, var/mob/user)
if(has_swab || has_sample)
user << "<span class='warning'>There is already a sample in the slide.</span>"
return
if(istype (W, /obj/item/weapon/forensics/swab))
has_swab = W
else if(istype(W, /obj/item/weapon/sample/fibers))
has_sample = W
else
user << "<span class='warning'>You don't think this will fit.</span>"
return
user << "<span class='notice'>You insert the sample into the slide.</span>"
user.unEquip(W)
W.forceMove(src)
update_icon()
/obj/item/weapon/forensics/slide/attack_self(var/mob/user)
if(has_swab || has_sample)
user << "<span class='notice'>You remove \the sample from \the [src].</span>"
if(has_swab)
has_swab.loc = get_turf(src)
has_swab = null
if(has_sample)
has_sample.forceMove(get_turf(src))
has_sample = null
update_icon()
return
/obj/item/weapon/forensics/slide/update_icon()
if(!has_swab && !has_sample)
icon_state = "slide"
else if(has_swab)
icon_state = "slideswab"
else if(has_sample)
icon_state = "slidefiber"
-115
View File
@@ -1,115 +0,0 @@
/obj/item/device/detective_scanner
name = "forensic scanner"
desc = "Used to scan objects for DNA and fingerprints."
icon_state = "forensic1"
var/list/stored = list()
w_class = 3.0
item_state = "electronic"
flags = CONDUCT | NOBLUDGEON
slot_flags = SLOT_BELT
/obj/item/device/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
if (!ishuman(M))
user << "<span class='warning'>[M] is not human and cannot have the fingerprints.</span>"
flick("forensic0",src)
return 0
if (( !( istype(M.dna, /datum/dna) ) || M.gloves) )
user << "<span class='notice'>No fingerprints found on [M]</span>"
flick("forensic0",src)
return 0
else
var/obj/item/weapon/f_card/F = new /obj/item/weapon/f_card( user.loc )
F.amount = 1
F.add_fingerprint(M)
F.icon_state = "fingerprint1"
F.name = text("FPrintC- '[M.name]'")
user << "<span class='notice'>Done printing."
user << "<span class='notice'>[M]'s Fingerprints: [md5(M.dna.uni_identity)]"
if ( M.blood_DNA && M.blood_DNA.len )
user << "<span class='notice'>Blood found on [M]. Analysing...</span>"
spawn(15)
for(var/blood in M.blood_DNA)
user << "<span class='notice'>Blood type: [M.blood_DNA[blood]]\nDNA: [blood]</span>"
return
/obj/item/device/detective_scanner/afterattack(atom/A as obj|turf, mob/user, proximity)
if(!proximity) return
if(ismob(A))
return
if(istype(A,/obj/machinery/computer/forensic_scanning))
user.visible_message("[user] takes a cord out of [src] and hooks its end into [A]" ,\
"<span class='notice'>You download data from [src] to [A]</span>")
var/obj/machinery/computer/forensic_scanning/F = A
F.sync_data(stored)
return
if(istype(A,/obj/item/weapon/f_card))
user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\""
flick("forensic0",src)
return
add_fingerprint(user)
//General
if ((!A.fingerprints || !A.fingerprints.len) && !A.suit_fibers && !A.blood_DNA)
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
"<span class='warning'>Unable to locate any fingerprints, materials, fibers, or blood on [A]!</span>",\
"You hear a faint hum of electrical equipment.")
flick("forensic0",src)
return 0
if(add_data(A))
user << "<span class='notice'>Object already in internal memory. Consolidating data...</span>"
flick("forensic2",src)
return
//PRINTS
if(A.fingerprints && A.fingerprints.len)
user << "<span class='notice'>Isolated [A.fingerprints.len] fingerprints:</span>"
user << "Data Stored: Scan with Hi-Res Forensic Scanner to retrieve.</span>"
var/list/complete_prints = list()
for(var/i in A.fingerprints)
var/print = A.fingerprints[i]
if(stringpercent(print) <= FINGERPRINT_COMPLETE)
complete_prints += print
if(complete_prints.len < 1)
user << "<span class='notice'>No intact prints found</span>"
else
user << "<span class='notice'>Found [complete_prints.len] intact prints</span>"
for(var/i in complete_prints)
user << "<span class='notice'>&nbsp;&nbsp;&nbsp;&nbsp;[i]</span>"
//FIBERS
if(A.suit_fibers && A.suit_fibers.len)
user << "<span class='notice'>Fibers/Materials Data Stored: Scan with Hi-Res Forensic Scanner to retrieve."
flick("forensic2",src)
//Blood
if (A.blood_DNA && A.blood_DNA.len)
user << "<span class='notice'>Blood detected. Analysing...</span>"
spawn(15)
for(var/blood in A.blood_DNA)
user << "Blood type: \red [A.blood_DNA[blood]] \t \black DNA: \red [blood]"
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
"<span class='notice'>You finish scanning \the [A].</span>",\
"You hear a faint hum of electrical equipment.")
flick("forensic2",src)
return 0
/obj/item/device/detective_scanner/proc/add_data(atom/A as mob|obj|turf|area)
var/datum/data/record/forensic/old = stored["\ref [A]"]
var/datum/data/record/forensic/fresh = new(A)
if(old)
fresh.merge(old)
. = 1
stored["\ref [A]"] = fresh
/obj/item/device/detective_scanner/verb/wipe()
set name = "Wipe Forensic Data"
set category = "Object"
set src in view(1)
if (alert("Are you sure you want to wipe all data from [src]?",,"Yes","No") == "Yes")
stored = list()
usr << "<span class='notice'>Forensic data erase complete.</span>"
@@ -1,312 +0,0 @@
/obj/machinery/computer/forensic_scanning
name = "high-res forensic scanning computer"
icon_state = "forensic"
var/screen = "database"
var/authenticated = 0
req_access = list(access_forensics_lockers)
var/scan_progress = -1
var/obj/item/scanning
var/datum/data/record/forensic/current
var/list/filters = list()
var/list/current_list = list()
var/list/files = list()
/obj/machinery/computer/forensic_scanning/proc/get_printable_data(var/datum/data/record/forensic/fresh)
. += "<h2>[fresh.fields["name"]]</h2>"
. += "Scanned in [fresh.fields["area"]] at [worldtime2text(fresh.fields["time"])]<br>"
var/list/prints = fresh.fields["fprints"]
if(prints.len)
. += "<h3>Fingerprints:</h3>"
var/incomplete = 0
for(var/fullprint in prints)
var/print = prints[fullprint]
if(is_complete_print(print))
. += "[print]<br>"
else
incomplete++
if(incomplete)
. += "[incomplete] incomplete fingerprints."
else
. += "<br>No fingerprints recorded.<br>"
var/list/fibers = fresh.fields["fibers"]
if(fibers.len)
. += "<h3>Fibers:</h3>"
. += "<ul>"
for(var/fiber in fibers)
. += "<li>[fiber]</li>"
. += "</ul>"
else
. += "<br>No fibers recorded."
var/list/bloods = fresh.fields["blood"]
if(bloods.len)
. += "<h3>Blood:</h3>"
. += "<ul>"
for(var/blood in bloods)
. += "<li>DNA: [blood] Type: [bloods[blood]]</li>"
. += "</ul>"
else
. += "<br>No blood recorded."
/obj/machinery/computer/forensic_scanning/proc/add_record(var/datum/data/record/forensic/fresh)
var/datum/data/record/forensic/old = files[fresh.uid]
if(old)
fresh.merge(old)
fresh.fields["label"] = old.fields["label"]
files[fresh.uid] = fresh
//updating partial prints on other things
var/list/fprints = fresh.fields["fprints"]
if(fprints.len)
for(var/id in files)
var/datum/data/record/forensic/rec = files[id]
if(rec.update_prints(fprints))
files[id] = rec
/obj/machinery/computer/forensic_scanning/proc/process_card(var/obj/item/weapon/f_card/card)
if(card.fingerprints)
usr << "<span class='notice'>\The [src] sucks in \the [card] and whirrs, scanning it.</span>"
var/found = 0
for(var/id in files)
var/datum/data/record/forensic/rec = files[id]
found = rec.update_prints(card.fingerprints)
if (found)
files[id] = rec
if(found)
usr << "<span class='notice'>Complete match found.</span>"
else
usr << "<span class='notice'>No match found.</span>"
return 1
else
usr << "<span class='warning'>No fingerprints detected on [card].</span>"
return 0
//Takes a list of forensic records, with key being reference to object, and updates internal database.
/obj/machinery/computer/forensic_scanning/proc/sync_data(var/list/newdata)
for(var/id in newdata)
var/datum/data/record/forensic/fresh = newdata[id]
add_record(fresh)
/obj/machinery/computer/forensic_scanning/proc/get_filtered_set()
.= list()
for(var/id in files)
var/datum/data/record/forensic/cur = files[id]
var/add = 1
if(filters["name"])
add = 0
for(var/filter in filters["name"])
if(findtext(cur.fields["name"], filter))
add = 1
break
if(filters["area"])
add = 0
for(var/filter in filters["area"])
if(findtext(cur.fields["area"], filter))
add = 1
break
if(filters["fprints"])
add = 0
var/list/prints = cur.fields["fprints"]
for(var/pid in prints)
var/print = prints[pid]
if (is_complete_print(print))
for(var/filter in filters["fprints"])
if(findtext(print, filter))
add = 1
break
if(filters["fibers"])
add = 0
for(var/fiber in cur.fields["fibers"])
for(var/filter in filters["fibers"])
if(findtext(fiber, filter))
add = 1
break
if(filters["blood"])
add = 0
for(var/DNA in cur.fields["blood"])
for(var/filter in filters["blood"])
if(findtext(DNA, filter))
add = 1
break
if(filters["label"])
add = 0
for(var/filter in filters["label"])
if(cur.fields["label"] && findtext(cur.fields["label"], filter))
add = 1
break
if (add)
.+=cur
/obj/machinery/computer/forensic_scanning/attack_hand(mob/user)
if(..())
return
user.set_machine(src)
var/dat
if(!authenticated)
dat += "<a href='?src=\ref[src];operation=login'>{Log In}</a>"
else
dat += "<a href='?src=\ref[src];operation=logout'>{Log Out}</a>"
dat += " | "
dat += "<a href='?src=\ref[src];operation=screen;screen=database'>Database</a>"
dat += " | "
dat += "<a href='?src=\ref[src];operation=screen;screen=details'>Record details</a>"
dat += " | "
dat += "<a href='?src=\ref[src];operation=screen;screen=scan'>Scanning</a>"
dat +="<br><hr><br>"
switch(screen)
if("database") //Database screen
dat += "Search filters:<br>"
var/list/filternames = list("Object"="name", "Area"="area", "Fingerprints"="fprints", "Fibers"="fibers", "DNA"="blood", "Label"="label")
for(var/filter in filternames)
var/fname = filternames[filter]
dat += "<br>[filter]: <a href='?src=\ref[src];operation=filter;filter=[fname]'>[filters[fname] ? list2text(filters[fname], ",") : "All"]</a>"
current_list = get_filtered_set()
dat+= "<br><hr><br>"
if(current_list.len < 1)
dat += "No data matching your request found."
else
dat += "<table><tr>"
dat += "<th>Object</th><th>Area</th><th>Fingerprints</th><th>Fibers</th><th>Blood</th><th>Label</th></tr>"
for(var/datum/data/record/forensic/record in current_list)
dat += "<tr><td><a href='?src=\ref[src];operation=details;identifier=[record.uid]'>[record.fields["name"]]</td>"
dat += "<td>[record.fields["area"]]</td>"
for(var/criteria in list("fprints", "fibers", "blood"))
var/list/data = record.fields[criteria]
dat += "<td>[data.len ? data.len : "None"]</td>"
dat += "<td>[record.fields["label"] ? record.fields["label"] : ""]</td>"
dat += "<td><a href='?src=\ref[src];operation=delete;identifier=[record.uid]'>Delete</a></td>"
dat += "</tr>"
dat += "</table>"
dat += "<a href='?src=\ref[src];operation=printall'>Print all listed</a><br>"
if("details") //Details screen
if(!current)
dat += "<br>NO RECORD SELECTED"
else
dat += get_printable_data(current)
dat += "<br><b>Labels:</b> "
dat += "<a href='?src=\ref[src];operation=label'>[current.fields["label"] ? current.fields["label"] : "None"]</a><br>"
dat += "<a href='?src=\ref[src];operation=print'>Print record</a><br>"
if("scan") //Scanning screen
dat += "Object: <a href='?src=\ref[src];operation=object'>[scanning ? scanning.name : "-----"]</a><br>"
if (scanning)
if (scan_progress > 0)
dat += "Scan in progress."
dat += " <a href='?src=\ref[src];operation=cancel'>Cancel</a><br>"
else
dat += "<a href='?src=\ref[src];operation=scan'>Scan</a><br>"
dat += "Insert fingerprint card here: <a href='?src=\ref[src];operation=card'>-----</a>"
user << browse(dat,"window=fscanner")
onclose(user,"fscanner")
/obj/machinery/computer/forensic_scanning/Topic(href,href_list)
if(..()) return 1
switch(href_list["operation"])
if("login")
var/mob/M = usr
if(istype(M,/mob/living/silicon) || allowed(M))
authenticated = 1
if("logout")
authenticated = 0
if("filter")
var/filterstr = sanitize(input("Input the search criteria. Multiple values can be input, separated by a comma.", "Filter setting") as text|null)
if(filterstr)
filters[href_list["filter"]] = text2list(filterstr,",")
else
filters[href_list["filter"]] = null
if("screen")
screen = href_list["screen"]
if("details")
if(href_list["identifier"])
screen = "details"
current = files[href_list["identifier"]]
else
usr << "<spawn class='warning'>No record found.</span>"
if("delete")
if(href_list["identifier"])
if(alert("Are you sure you want to delete this record?","Record deletion", "Yes", "No") == "Yes")
files.Remove(href_list["identifier"])
if(current && current.uid == href_list["identifier"])
current = null
if("label")
if(current)
var/label = sanitize(input(usr,"Input the label for this record. Multiple values can be input, separated by a comma.", "Labeling record", current.fields["label"]) as text|null)
current.fields["label"] = label
if("object")
if(scanning)
scanning.loc = get_turf(src)
scan_progress = -1
scanning = null
else
var/mob/M = usr
var/obj/item/I = M.get_active_hand()
if(I && istype(I))
if(istype(I, /obj/item/weapon/evidencebag))
scanning = I.contents[1]
scanning.loc = src
I.overlays.Cut()
I.w_class = 1
I.icon_state = "evidenceobj"
else
scanning = I
M.drop_item()
I.loc = src
else
usr << "<spawn class='warning'>Invalid object, rejected.</span>"
if("scan")
if(scanning)
scan_progress = 10
if("cancel")
scan_progress = -1
if("card")
var/mob/M = usr
var/obj/item/I = M.get_active_hand()
if(istype(I, /obj/item/weapon/f_card))
if(process_card(I))
M.drop_item()
qdel(I)
else
usr << "<spawn class='warning'>Invalid fingerprint card, rejected.</span>"
if("print")
if(current)
var/obj/item/weapon/paper/P = new(loc)
P.name = "\improper Forensics Data ([current.fields["name"]])"
P.icon_state = "paper_words"
P.info = "<b>Forensics Database</b> - [worldtime2text(world.time)]<br><br>"
P.info += get_printable_data(current)
if("printall")
var/obj/item/weapon/paper/P = new(loc)
P.name = "\improper Forensics Data"
P.icon_state = "paper_words"
P.info = "<b>Forensics Database</b> - [worldtime2text(world.time)]<br><br>"
for(var/datum/data/record/forensic/cur in current_list)
P.info += get_printable_data(cur)
updateUsrDialog()
/obj/machinery/computer/forensic_scanning/process()
if (!..())
return
if(scanning)
if(scan_progress > 0)
scan_progress--
updateUsrDialog()
if(scan_progress == 0)
scan_progress = -1
ping("Scan complete.")
var/datum/data/record/forensic/fresh = new(scanning)
add_record(fresh)
updateUsrDialog()
@@ -0,0 +1,17 @@
//crime scene kit
/obj/item/weapon/storage/briefcase/crimekit
name = "crime scene kit"
desc = "A stainless steel-plated carrycase for all your forensic needs. Feels heavy."
icon = 'icons/obj/forensics.dmi'
icon_state = "case"
item_state = "case"
storage_slots = 14
/obj/item/weapon/storage/briefcase/crimekit/New()
..()
new /obj/item/weapon/storage/box/swabs(src)
new /obj/item/weapon/storage/box/fingerprints(src)
new /obj/item/weapon/reagent_containers/spray/luminol(src)
new /obj/item/device/uv_light(src)
new /obj/item/weapon/forensics/sample_kit(src)
new /obj/item/weapon/forensics/sample_kit/powder(src)
@@ -96,49 +96,3 @@
/obj/item/weapon/evidencebag/examine(mob/user)
..(user)
if (stored_item) user.examinate(stored_item)
/obj/item/weapon/storage/box/evidence
name = "evidence bag box"
desc = "A box claiming to contain evidence bags."
New()
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
new /obj/item/weapon/evidencebag(src)
..()
return
/obj/item/weapon/f_card
name = "finger print card"
desc = "Used to take fingerprints."
icon = 'icons/obj/card.dmi'
icon_state = "fingerprint0"
var/amount = 10.0
item_state = "paper"
throwforce = 1
w_class = 1.0
slot_flags = SLOT_EARS
throw_speed = 3
throw_range = 5
/obj/item/weapon/f_card/add_fingerprint(mob/living/M as mob, ignoregloves = 0)
if(..())
var/mob/living/carbon/human/H = M
var/full_print = md5(H.dna.uni_identity)
fingerprints[full_print] = full_print
/obj/item/weapon/f_card/examine(mob/user)
..()
if(fingerprints.len)
user << "<span class='notice'>Fingerprints on this card:</span>"
for(var/print in fingerprints)
user << "<span class='notice'>\t[fingerprints[print]]</span>"
/obj/item/weapon/fcardholder
name = "fingerprint card case"
desc = "Apply finger print card."
icon = 'icons/obj/items.dmi'
icon_state = "fcardholder0"
item_state = "clipboard"
@@ -0,0 +1,13 @@
/obj/item/weapon/reagent_containers/spray/luminol
name = "luminol bottle"
desc = "A bottle containing an odourless, colorless liquid."
icon = 'icons/obj/forensics.dmi'
icon_state = "luminol"
item_state = "cleaner"
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10)
volume = 250
/obj/item/weapon/reagent_containers/spray/luminol/New()
..()
reagents.add_reagent("luminol", 250)
+221
View File
@@ -0,0 +1,221 @@
/mob
var/bloody_hands = 0
var/mob/living/carbon/human/bloody_hands_mob
var/track_blood = 0
var/list/feet_blood_DNA
var/track_blood_type
var/feet_blood_color
/obj/item/clothing/gloves
var/transfer_blood = 0
var/mob/living/carbon/human/bloody_hands_mob
/obj/item/clothing/shoes/
var/track_blood = 0
/obj/item/weapon/reagent_containers/glass/rag
name = "rag"
desc = "For cleaning up messes, you suppose."
w_class = 1
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 10
can_be_placed_into = null
flags = OPENCONTAINER | NOBLUDGEON
unacidable = 0
var/on_fire = 0
var/burn_time = 20 //if the rag burns for too long it turns to ashes
/obj/item/weapon/reagent_containers/glass/rag/New()
..()
update_name()
/obj/item/weapon/reagent_containers/glass/rag/Destroy()
processing_objects -= src //so we don't continue turning to ash while gc'd
..()
/obj/item/weapon/reagent_containers/glass/rag/attack_self(mob/user as mob)
if(on_fire)
user.visible_message("<span class='warning'>\The [user] stamps out [src].</span>", "<span class='warning'>You stamp out [src].</span>")
user.unEquip(src)
extinguish()
else
remove_contents(user)
/obj/item/weapon/reagent_containers/glass/rag/attackby(obj/item/W, mob/user)
if(!on_fire && istype(W, /obj/item/weapon/flame))
var/obj/item/weapon/flame/F = W
if(F.lit)
ignite()
if(on_fire)
visible_message("<span class='warning'>\The [user] lights [src] with [W].</span>")
else
user << "<span class='warning'>You manage to singe [src], but fail to light it.</span>"
. = ..()
update_name()
/obj/item/weapon/reagent_containers/glass/rag/proc/update_name()
if(on_fire)
name = "burning [initial(name)]"
else if(reagents.total_volume)
name = "damp [initial(name)]"
else
name = "dry [initial(name)]"
/obj/item/weapon/reagent_containers/glass/rag/update_icon()
if(on_fire)
icon_state = "raglit"
else
icon_state = "rag"
var/obj/item/weapon/reagent_containers/food/drinks/bottle/B = loc
if(istype(B))
B.update_icon()
/obj/item/weapon/reagent_containers/glass/rag/proc/remove_contents(mob/user, atom/trans_dest = null)
if(!trans_dest && !user.loc)
return
if(reagents.total_volume)
var/target_text = trans_dest? "\the [trans_dest]" : "\the [user.loc]"
user.visible_message("<span class='danger'>\The [user] begins to wring out [src] over [target_text].</span>", "<span class='notice'>You begin to wring out [src] over [target_text].</span>")
if(do_after(user, reagents.total_volume*5)) //50 for a fully soaked rag
if(trans_dest)
reagents.trans_to(trans_dest, reagents.total_volume)
else
reagents.splash(user.loc, reagents.total_volume)
user.visible_message("<span class='danger'>\The [user] wrings out [src] over [target_text].</span>", "<span class='notice'>You finish to wringing out [src].</span>")
update_name()
/obj/item/weapon/reagent_containers/glass/rag/proc/wipe_down(atom/A, mob/user)
if(!reagents.total_volume)
user << "<span class='warning'>The [initial(name)] is dry!</span>"
else
user.visible_message("\The [user] starts to wipe down [A] with [src]!")
reagents.splash(A, 1) //get a small amount of liquid on the thing we're wiping.
update_name()
if(do_after(user,30))
user.visible_message("\The [user] finishes wiping off the [A]!")
A.clean_blood()
/obj/item/weapon/reagent_containers/glass/rag/attack(atom/target as obj|turf|area, mob/user as mob , flag)
if(isliving(target))
var/mob/living/M = target
if(on_fire)
user.visible_message("<span class='danger'>\The [user] hits [target] with [src]!</span>",)
user.do_attack_animation(src)
M.IgniteMob()
else if(reagents.total_volume)
if(user.zone_sel.selecting == "mouth")
user.do_attack_animation(src)
user.visible_message(
"<span class='danger'>\The [user] smothers [target] with [src]!</span>",
"<span class='warning'>You smother [target] with [src]!</span>",
"You hear some struggling and muffled cries of surprise"
)
//it's inhaled, so... maybe CHEM_BLOOD doesn't make a whole lot of sense but it's the best we can do for now
reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD)
update_name()
else
wipe_down(target, user)
return
return ..()
/obj/item/weapon/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob, proximity)
if(!proximity)
return
if(istype(A, /obj/structure/reagent_dispensers))
if(!reagents.get_free_space())
user << "<span class='warning'>\The [src] is already soaked.</span>"
return
if(A.reagents && A.reagents.trans_to_obj(src, reagents.maximum_volume))
user.visible_message("<span class='notice'>\The [user] soaks [src] using [A].</span>", "<span class='notice'>You soak [src] using [A].</span>")
update_name()
return
if(!on_fire && istype(A) && (src in user))
if(A.is_open_container())
remove_contents(user, A)
else if(!ismob(A)) //mobs are handled in attack() - this prevents us from wiping down people while smothering them.
wipe_down(A, user)
return
/obj/item/weapon/reagent_containers/glass/rag/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature >= 50 + T0C)
ignite()
if(exposed_temperature >= 900 + T0C)
new /obj/effect/decal/cleanable/ash(get_turf(src))
qdel(src)
//rag must have a minimum of 2 units welder fuel and at least 80% of the reagents must be welder fuel.
//maybe generalize flammable reagents someday
/obj/item/weapon/reagent_containers/glass/rag/proc/can_ignite()
var/fuel = reagents.get_reagent_amount("fuel")
return (fuel >= 2 && fuel >= reagents.total_volume*0.8)
/obj/item/weapon/reagent_containers/glass/rag/proc/ignite()
if(on_fire)
return
if(!can_ignite())
return
//also copied from matches
if(reagents.get_reagent_amount("phoron")) // the phoron explodes when exposed to fire
visible_message("<span class='danger'>\The [src] conflagrates violently!</span>")
var/datum/effect/effect/system/reagents_explosion/e = new()
e.set_up(round(reagents.get_reagent_amount("phoron") / 2.5, 1), get_turf(src), 0, 0)
e.start()
qdel(src)
return
processing_objects += src
set_light(2, null, "#E38F46")
on_fire = 1
update_name()
update_icon()
/obj/item/weapon/reagent_containers/glass/rag/proc/extinguish()
processing_objects -= src
set_light(0)
on_fire = 0
//rags sitting around with 1 second of burn time left is dumb.
//ensures players always have a few seconds of burn time left when they light their rag
if(burn_time <= 5)
visible_message("<span class='warning'>\The [src] falls apart!</span>")
new /obj/effect/decal/cleanable/ash(get_turf(src))
qdel(src)
update_name()
update_icon()
/obj/item/weapon/reagent_containers/glass/rag/process()
if(!can_ignite())
visible_message("<span class='warning'>\The [src] burns out.</span>")
extinguish()
//copied from matches
if(isliving(loc))
var/mob/living/M = loc
M.IgniteMob()
var/turf/location = get_turf(src)
if(location)
location.hotspot_expose(700, 5)
if(burn_time <= 0)
processing_objects -= src
new /obj/effect/decal/cleanable/ash(location)
qdel(src)
return
reagents.remove_reagent("fuel", reagents.maximum_volume/25)
update_name()
burn_time--
@@ -0,0 +1,158 @@
/obj/item/weapon/sample
name = "forensic sample"
icon = 'icons/obj/forensics.dmi'
w_class = 1
var/list/evidence = list()
/obj/item/weapon/sample/New(var/newloc, var/atom/supplied)
..(newloc)
if(supplied)
copy_evidence(supplied)
name = "[initial(name)] (\the [supplied])"
/obj/item/weapon/sample/print/New(var/newloc, var/atom/supplied)
..(newloc, supplied)
if(evidence && evidence.len)
icon_state = "fingerprint1"
/obj/item/weapon/sample/proc/copy_evidence(var/atom/supplied)
if(supplied.suit_fibers && supplied.suit_fibers.len)
evidence = supplied.suit_fibers.Copy()
supplied.suit_fibers.Cut()
/obj/item/weapon/sample/proc/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user)
if(!supplied.evidence || !supplied.evidence.len)
return 0
evidence |= supplied.evidence
name = "[initial(name)] (combined)"
user << "<span class='notice'>You transfer the contents of \the [supplied] into \the [src].</span>"
return 1
/obj/item/weapon/sample/print/merge_evidence(var/obj/item/weapon/sample/supplied, var/mob/user)
if(!supplied.evidence || !supplied.evidence.len)
return 0
for(var/print in supplied.evidence)
if(evidence[print])
evidence[print] = stringmerge(evidence[print],supplied.evidence[print])
else
evidence[print] = supplied.evidence[print]
name = "[initial(name)] (combined)"
user << "<span class='notice'>You overlay \the [src] and \the [supplied], combining the print records.</span>"
return 1
/obj/item/weapon/sample/attackby(var/obj/O, var/mob/user)
if(O.type == src.type)
user.unEquip(O)
if(merge_evidence(O, user))
qdel(O)
return 1
return ..()
/obj/item/weapon/sample/fibers
name = "fiber bag"
desc = "Used to hold fiber evidence for the detective."
icon_state = "fiberbag"
/obj/item/weapon/sample/print
name = "fingerprint card"
desc = "Records a set of fingerprints."
icon = 'icons/obj/card.dmi'
icon_state = "fingerprint0"
item_state = "paper"
/obj/item/weapon/sample/print/attack_self(var/mob/user)
if(evidence && evidence.len)
return
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.gloves)
user << "<span class='warning'>Take \the [H.gloves] off first.</span>"
return
user << "<span class='notice'>You firmly press your fingertips onto the card.</span>"
var/fullprint = H.get_full_print()
evidence[fullprint] = fullprint
name = "[initial(name)] (\the [H])"
icon_state = "fingerprint1"
/obj/item/weapon/sample/print/attack(var/mob/living/M, var/mob/user)
if(!ishuman(M))
return ..()
if(evidence && evidence.len)
return 0
var/mob/living/carbon/human/H = M
if(H.gloves)
user << "<span class='warning'>\The [H] is wearing gloves.</span>"
return 1
if(user != H && H.a_intent != "help" && !H.lying)
user.visible_message("<span class='danger'>\The [user] tries to take prints from \the [H], but they move away.</span>")
return 1
if(user.zone_sel.selecting == "r_hand" || user.zone_sel.selecting == "l_hand")
var/has_hand
var/obj/item/organ/external/O = H.organs_by_name["r_hand"]
if(istype(O) && !O.is_stump())
has_hand = 1
else
O = H.organs_by_name["l_hand"]
if(istype(O) && !O.is_stump())
has_hand = 1
if(!has_hand)
user << "<span class='warning'>They don't have any hands.</span>"
return 1
user.visible_message("[user] takes a copy of \the [H]'s fingerprints.")
var/fullprint = H.get_full_print()
evidence[fullprint] = fullprint
copy_evidence(src)
name = "[initial(name)] (\the [H])"
icon_state = "fingerprint1"
return 1
return 0
/obj/item/weapon/sample/print/copy_evidence(var/atom/supplied)
if(supplied.fingerprints && supplied.fingerprints.len)
for(var/print in supplied.fingerprints)
evidence[print] = supplied.fingerprints[print]
supplied.fingerprints.Cut()
/obj/item/weapon/forensics/sample_kit
name = "fiber collection kit"
desc = "A magnifying glass and tweezers. Used to lift suit fibers."
icon_state = "m_glass"
w_class = 2
var/evidence_type = "fiber"
var/evidence_path = /obj/item/weapon/sample/fibers
/obj/item/weapon/forensics/sample_kit/proc/can_take_sample(var/mob/user, var/atom/supplied)
return (supplied.suit_fibers && supplied.suit_fibers.len)
/obj/item/weapon/forensics/sample_kit/proc/take_sample(var/mob/user, var/atom/supplied)
var/obj/item/weapon/sample/S = new evidence_path(get_turf(user), supplied)
user << "<span class='notice'>You transfer [S.evidence.len] [S.evidence.len > 1 ? "[evidence_type]s" : "[evidence_type]"] to \the [S].</span>"
/obj/item/weapon/forensics/sample_kit/afterattack(var/atom/A, var/mob/user, var/proximity)
if(!proximity)
return
add_fingerprint(user)
if(can_take_sample(user, A))
take_sample(user,A)
return 1
else
user << "<span class='warning'>You are unable to locate any [evidence_type]s on \the [A].</span>"
return ..()
/obj/item/weapon/forensics/sample_kit/powder
name = "fingerprint powder"
desc = "A jar containing aluminum powder and a specialized brush."
icon_state = "dust"
evidence_type = "fingerprint"
evidence_path = /obj/item/weapon/sample/print
/obj/item/weapon/forensics/sample_kit/powder/can_take_sample(var/mob/user, var/atom/supplied)
return (supplied.fingerprints && supplied.fingerprints.len)
@@ -0,0 +1,44 @@
/obj/item/weapon/storage/box/swabs
name = "box of swab kits"
desc = "Sterilized equipment within. Do not contaminate."
icon = 'icons/obj/forensics.dmi'
icon_state = "dnakit"
can_hold = list(/obj/item/weapon/forensics/swab)
storage_slots = 14
/obj/item/weapon/storage/box/swabs/New()
..()
for(var/i=0;i<storage_slots,i++) // Fill 'er up.
new /obj/item/weapon/forensics/swab(src)
/obj/item/weapon/storage/box/slides
name = "microscope slide box"
icon_state = "solution_trays"
storage_slots = 7
/obj/item/weapon/storage/box/slides/New()
..()
for(var/i=0;i<storage_slots,i++)
new /obj/item/weapon/forensics/slide(src)
/obj/item/weapon/storage/box/evidence
name = "evidence bag box"
desc = "A box claiming to contain evidence bags."
storage_slots = 6
/obj/item/weapon/storage/box/evidence/New()
for(var/i=0;i<storage_slots,i++)
new /obj/item/weapon/evidencebag(src)
/obj/item/weapon/storage/box/fingerprints
name = "box of fingerprint cards"
desc = "Sterilized equipment within. Do not contaminate."
icon = 'icons/obj/forensics.dmi'
icon_state = "dnakit"
can_hold = list(/obj/item/weapon/sample/print)
storage_slots = 14
/obj/item/weapon/storage/box/fingerprints/New()
..()
for(var/i=0;i<storage_slots,i++)
new /obj/item/weapon/sample/print(src)

Some files were not shown because too many files have changed in this diff Show More