mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 06:22:26 +01:00
+10
-10
@@ -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,
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>"
|
||||
..()
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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."
|
||||
@@ -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'> </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'> </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.")*/
|
||||
@@ -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>";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'> </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'> </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.")
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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'> [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)
|
||||
-46
@@ -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)
|
||||
@@ -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
Reference in New Issue
Block a user