Merge tgstation13 r4570 into bs12_with_tgport

Conflicts:
	baystation12.dme
	code/defines/obj.dm
	code/defines/procs/helpers.dm
	code/defines/turf.dm
	code/game/gamemodes/changeling/modularchangling.dm
	code/game/gamemodes/cult/cult_structures.dm
	code/game/gamemodes/events.dm
	code/game/machinery/telecomms/machine_interactions.dm
	code/game/master_controller.dm
	code/game/objects/items/blueprints.dm
	code/game/objects/items/devices/uplinks.dm
	code/game/objects/items/item.dm
	code/game/objects/items/weapons/gift_wrappaper.dm
	code/game/objects/items/weapons/wires.dm
	code/game/objects/weapons.dm
	code/game/turfs/turf.dm
	code/modules/clothing/head/hardhat.dm
	code/modules/mining/mine_items.dm
	code/modules/mining/mine_turfs.dm
	code/modules/mob/living/silicon/robot/life.dm
	code/modules/mob/mob_defines.dm
	code/modules/mob/new_player/login.dm
	code/modules/paperwork/pen.dm
	code/modules/paperwork/stamps.dm
	code/unused/toilets.dm
	html/changelog.html
	icons/effects/alert.dmi

Signed-off-by: Cael_Aislinn <cael_aislinn@yahoo.com.au>
This commit is contained in:
Cael_Aislinn
2012-08-28 19:57:11 +10:00
269 changed files with 14389 additions and 13349 deletions
@@ -174,6 +174,21 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
L+=T
usr.loc = pick(L)
/mob/dead/observer/verb/follow()
set category = "Ghost"
set name = "Follow" // "Haunt"
set desc = "Follow and haunt a mob."
if(istype(usr, /mob/dead/observer))
var/mob/target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in sortAtom(mob_list)
if(target)
spawn(0)
var/turf/pos = get_turf(src)
while(src.loc == pos)
src.loc = get_turf(target)
pos = src.loc
sleep(15)
/mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
set category = "Ghost"
+27 -1
View File
@@ -50,4 +50,30 @@
else
// add some movement delay
move_delay_add = min(move_delay_add + round(amount / 2), 10) // a maximum delay of 10
return
return
/*----------------------------------------
Proc: AddInfectionImages()
Des: Gives the client of the alien an image on each infected mob.
----------------------------------------*/
/mob/living/carbon/alien/proc/AddInfectionImages()
if (client)
for (var/mob/living/carbon/C in world)
if(C.status_flags & XENO_HOST)
var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected")
client.images += I
return
/*----------------------------------------
Proc: RemoveInfectionImages()
Des: Removes all infected images from the alien.
----------------------------------------*/
/mob/living/carbon/alien/proc/RemoveInfectionImages()
if (client)
for(var/image/I in client.images)
if(I.icon_state == "infected")
del(I)
return
@@ -0,0 +1,4 @@
/mob/living/carbon/alien/humanoid/Login()
..()
AddInfectionImages()
return
@@ -0,0 +1,4 @@
/mob/living/carbon/alien/humanoid/Logout()
..()
RemoveInfectionImages()
return
@@ -0,0 +1,258 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
//TODO: Make these simple_animals
var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone
var/const/MAX_IMPREGNATION_TIME = 150
var/const/MIN_ACTIVE_TIME = 300 //time between being dropped and going idle
var/const/MAX_ACTIVE_TIME = 600
/obj/item/clothing/mask/facehugger
name = "alien"
desc = "It has some sort of a tube at the end of its tail."
icon_state = "facehugger"
item_state = "facehugger"
w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4
flags = FPRINT|TABLEPASS|MASKCOVERSMOUTH|MASKCOVERSEYES
var/stat = UNCONSCIOUS //UNCONSCIOUS is the idle state in this case
var/sterile = 0
var/strength = 5
var/attached = 0
attack_paw(user as mob) //can be picked up by aliens
if(isalien(user))
attack_hand(user)
return
else
..()
return
attack_hand(user as mob)
if(stat == CONSCIOUS && !isalien(user))
Attach(user)
return
else
..()
return
attack(mob/living/M as mob, mob/user as mob)
..()
user.drop_from_inventory(src)
Attach(M)
New()
if(aliens_allowed)
..()
else
del(src)
examine()
..()
switch(stat)
if(DEAD,UNCONSCIOUS)
usr << "\red \b [src] is not moving."
if(CONSCIOUS)
usr << "\red \b [src] seems to be active."
if (sterile)
usr << "\red \b It looks like the proboscis has been removed."
return
attackby()
Die()
return
bullet_act()
Die()
return
temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature > 300)
Die()
return
equipped(mob/M)
Attach(M)
HasEntered(atom/target)
Attach(target)
return
dropped()
..()
GoActive()
return
throw_impact(atom/hit_atom)
Attach(hit_atom)
return
proc/Attach(M as mob)
if(!isliving(M) || isalien(M))
return
if(attached)
return
else
attached++
spawn(MAX_IMPREGNATION_TIME)
attached = 0
var/mob/living/L = M //just so I don't need to use :
if(stat != CONSCIOUS) return
if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
if(issilicon(L))
for(var/mob/O in viewers(src, null))
O.show_message("\red \b [src] smashes against [L]'s frame!", 1)
Die()
return
var/mob/living/carbon/target = L
for(var/mob/O in viewers(target, null))
O.show_message("\red \b [src] leaps at [target]'s face!", 1)
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(H.head && H.head.flags & HEADCOVERSMOUTH)
for(var/mob/O in viewers(H, null))
O.show_message("\red \b [src] smashes against [H]'s [H.head]!", 1)
Die()
return
if(target.wear_mask)
if(prob(20)) return
var/obj/item/clothing/W = target.wear_mask
if(!W.canremove) return
target.drop_from_inventory(W)
for(var/mob/O in viewers(target, null))
O.show_message("\red \b [src] tears [W] off of [target]'s face!", 1)
loc = target
layer = 20
target.wear_mask = src
target.update_inv_wear_mask()
GoIdle() //so it doesn't jump the people that tear it off
if(!sterile) target.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings
spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME))
Impregnate(target)
return
proc/Impregnate(mob/living/carbon/target as mob)
if(!target || target.wear_mask != src || target.stat == DEAD) //was taken off or something
return
if(!sterile)
target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance
for(var/datum/disease/alien_embryo/A in target.viruses)
target.status_flags |= XENO_HOST
break
for(var/mob/O in viewers(target,null))
O.show_message("\red \b [src] falls limp after violating [target]'s face!", 1)
Die()
else
for(var/mob/O in viewers(target,null))
O.show_message("\red \b [src] violates [target]'s face!", 1)
target.update_inv_wear_mask()
return
proc/GoActive()
if(stat == DEAD || stat == CONSCIOUS)
return
stat = CONSCIOUS
/* for(var/mob/living/carbon/alien/alien in world)
var/image/activeIndicator = image('icons/mob/alien.dmi', loc = src, icon_state = "facehugger_active")
activeIndicator.override = 1
if(alien && alien.client)
alien.client.images += activeIndicator */
spawn(rand(MIN_ACTIVE_TIME,MAX_ACTIVE_TIME))
GoIdle()
return
proc/GoIdle()
if(stat == DEAD || stat == UNCONSCIOUS)
return
/* RemoveActiveIndicators() */
stat = UNCONSCIOUS
return
proc/Die()
if(stat == DEAD)
return
/* RemoveActiveIndicators() */
icon_state = "facehugger_dead"
stat = DEAD
for(var/mob/O in viewers(src, null))
O.show_message("\red \b[src] curls up into a ball!", 1)
return
/* proc/RemoveActiveIndicators() //removes the "active" facehugger indicator from all aliens in the world for this hugger
for(var/mob/living/carbon/alien/alien in world)
if(alien.client)
for(var/image/image in alien.client.images)
if(image.icon_state == "facehugger_active" && image.loc == src)
del(image)
return */
/obj/item/clothing/mask/facehugger/angry
stat = CONSCIOUS
/obj/item/clothing/mask/facehugger/angry/HasProximity(atom/movable/AM as mob|obj)
if(istype(AM , /mob/living/))
Attach(AM)
/*
/obj/item/clothing/mask/facehugger/angry/New()
processing_objects.Add(src)
/obj/item/clothing/mask/facehugger/angry/process()
if(!src || src.stat == (DEAD))
return
for(var/mob/living/carbon/C in range(1,src))
Attach(C)
return
for(var/mob/living/carbon/C in range(5,src))
if(isInSight(C,src))
step_to(src,C,0)
spawn(5)
if(C in range(1,src))
Attach(C)
return
step_rand(src)
return
/obj/item/clothing/mask/facehugger/angry/Attach(var/mob/M as mob)
..(M)
processing_objects.Remove(src)
*/
@@ -0,0 +1,61 @@
/obj/item/brain/examine() // -- TLE
set src in oview(12)
if (!( usr ))
return
usr << "This is \icon[src] \an [name]."
if(brainmob)//if thar be a brain inside... the brain.
usr << "You can feel the small spark of life still left in this one."
else
usr << "This one seems particularly lifeless. Perhaps it will regain some of its luster later. Probably not."
/obj/item/brain/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(!istype(M, /mob))
return
add_fingerprint(user)
if(!(user.zone_sel.selecting == ("head")) || !istype(M, /mob/living/carbon/human))
return ..()
if( !(locate(/obj/machinery/optable, M.loc) && M.resting) && ( !(locate(/obj/structure/table/, M.loc) && M.lying) && prob(50) ) )
return ..()
var/mob/living/carbon/human/H = M
if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
// you can't stab someone in the eyes wearing a mask!
user << "\blue You're going to need to remove their head cover first."
return
//since these people will be dead M != usr
if(M:brain_op_stage == 4.0)
for(var/mob/O in viewers(M, null))
if(O == (user || M))
continue
if(M == user)
O.show_message(text("\red [user] inserts [src] into his head!"), 1)
else
O.show_message(text("\red [M] has [src] inserted into his head by [user]."), 1)
if(M != user)
M << "\red [user] inserts [src] into your head!"
user << "\red You insert [src] into [M]'s head!"
else
user << "\red You insert [src] into your head!"
//this might actually be outdated since barring badminnery, a debrain'd body will have any client sucked out to the brain's internal mob. Leaving it anyway to be safe. --NEO
if(M.key)//Revised. /N
M.ghostize()
if(brainmob.mind)
brainmob.mind.transfer_to(M)
else
M.key = brainmob.key
M:brain_op_stage = 3.0
del(src)
else
..()
return
@@ -39,6 +39,9 @@
var/obj/item/l_store = null
var/obj/item/s_store = null
var/used_skillpoints = 0
var/skill_specialization = null
var/list/skills = null
var/icon/stand_icon = null
var/icon/lying_icon = null
+11 -11
View File
@@ -87,9 +87,6 @@
//stuff in the stomach
handle_stomach()
//Flashlights and such
UpdateLuminosity()
//Status updates, death etc.
handle_regular_status_updates() //TODO: optimise ~Carn
update_canmove()
@@ -745,13 +742,16 @@
if(dna && dna.mutantrace == "plant") //couldn't think of a better place to place it, since it handles nutrition -- Urist
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
if(istype(loc,/turf)) //else, there's considered to be no light
light_amount = min(10,loc:sd_lumcount) - 5 //hardcapped so it's not abused by having a ton of flashlights
if(istype(loc,/turf/simulated/shuttle))//Now not only will potatomen not starve on the shuttle, they will actually be fed
light_amount = 5
if(nutrition < 500) //so they can't store nutrition to survive without light forever
nutrition += light_amount
if(light_amount > 0) //if there's enough light, heal
if(isturf(loc)) //else, there's considered to be no light
var/turf/T = loc
var/area/A = T.loc
if(A)
if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 //hardcapped so it's not abused by having a ton of flashlights
else light_amount = 5
nutrition += light_amount
if(nutrition > 500)
nutrition = 500
if(light_amount > 2) //if there's enough light, heal
heal_overall_damage(1,1)
adjustToxLoss(-1)
adjustOxyLoss(-1)
@@ -1150,7 +1150,7 @@
//0.1% chance of playing a scary sound to someone who's in complete darkness
if(isturf(loc) && rand(1,1000) == 1)
var/turf/currentTurf = loc
if(!currentTurf.sd_lumcount)
if(!currentTurf.lighting_lumcount)
playsound_local(src,pick(scarySounds),50, 1, -1)
proc/handle_virus_updates()
@@ -53,9 +53,6 @@
if(environment) // More error checking -- TLE
handle_environment(environment)
//Flashlights and such
UpdateLuminosity()
//Status updates, death etc.
handle_regular_status_updates()
update_canmove()
+11 -76
View File
@@ -141,37 +141,6 @@ var/list/department_radio_keys = list(
if (!message)
return
//work out if we're speaking skrell or not
var/is_speaking_skrell = 0
if(copytext(message, 1, 3) == ":k" || copytext(message, 1, 3) == ":K")
message = copytext(message, 3)
if(skrell_talk_understand || universal_speak)
is_speaking_skrell = 1
//work out if we're speaking soghun or not
var/is_speaking_soghun = 0
if(copytext(message, 1, 3) == ":o" || copytext(message, 1, 3) == ":O")
message = copytext(message, 3)
if(soghun_talk_understand || universal_speak)
is_speaking_soghun = 1
//work out if we're speaking tajaran or not
var/is_speaking_tajaran = 0
if(copytext(message, 1, 3) == ":j" || copytext(message, 1, 3) == ":J")
message = copytext(message, 3)
if(tajaran_talk_understand || universal_speak)
is_speaking_soghun = 1
// if( !message_mode && (disease_symptoms & DISEASE_WHISPER))
// message_mode = "whisper"
if(src.stunned > 2 /*|| (traumatic_shock > 61 && prob(50))*/)
message_mode = "" //Stunned people shouldn't be able to physically turn on their radio/hold down the button to speak into it
message = capitalize(message) //capitalize the first letter of what they actually say
// :downs:
if (getBrainLoss() >= 60)
message = dd_replacetext(message, " am ", " ")
@@ -187,12 +156,10 @@ var/list/department_radio_keys = list(
message = uppertext(message)
message += "[stutter(pick("!", "!!", "!!!"))]"
if(!stuttering && prob(15))
message = NewStutter(message,stunned)
message = stutter(message)
if (stuttering)
message = NewStutter(message,stunned)
if (slurring)
message = slur(message)
message = stutter(message)
/* //qw do not have beesease atm.
if(virus)
@@ -316,13 +283,6 @@ var/list/department_radio_keys = list(
var/list/V = view(message_range, T)
var/list/W = V
var/list/eavesdroppers = get_mobs_in_view(7, src)
for(var/mob/M in listening)
eavesdroppers.Remove(M)
for(var/mob/M in eavesdroppers)
if(M.stat || !M.client || istype(M, /mob/living/silicon/pai) || M == src)
eavesdroppers.Remove(M)
for (var/obj/O in ((W | contents)-used_radios))
W |= O
@@ -352,24 +312,17 @@ var/list/department_radio_keys = list(
var/list/heard_a = list() // understood us
var/list/heard_b = list() // didn't understand us
for (var/mob/M in listening) //My god this is to terrible and hacky - Erthilo
for (var/M in listening)
if(hascall(M,"say_understands"))
if (M:say_understands(src) && !is_speaking_skrell && !is_speaking_soghun && !is_speaking_tajaran) //This could probably be merged into say_understands(), but I'm too lazy
heard_a += M
else if(is_speaking_skrell && (M.skrell_talk_understand || M.universal_speak))
heard_a += M
else if(is_speaking_soghun && (M.soghun_talk_understand || M.universal_speak))
heard_a += M
else if(is_speaking_tajaran && (M.tajaran_talk_understand || M.universal_speak))
if (M:say_understands(src))
heard_a += M
else
heard_b += M
var/speech_bubble_test = say_test(message)
var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
var/rendered = null
if (length(heard_a))
var/message_a = say_quote(message,is_speaking_soghun,is_speaking_skrell,is_speaking_tajaran)
var/message_a = say_quote(message)
if (italics)
message_a = "<i>[message_a]</i>"
if (!istype(src, /mob/living/carbon/human))
@@ -382,17 +335,10 @@ var/list/department_radio_keys = list(
else
rendered = "<span class='game say'><span class='name'>[real_name]</span>[alt_name] <span class='message'>[message_a]</span></span>"
for (var/mob/M in heard_a)
M.show_message(rendered, 2)
M << speech_bubble
spawn(30) del(speech_bubble)
//spawn(30) del(speech_bubble)
/* for (var/M in heard_a)
for (var/M in heard_a)
if(hascall(M,"show_message"))
M:show_message(rendered, 2)
*/
if (length(heard_b))
var/message_b
@@ -400,17 +346,13 @@ var/list/department_radio_keys = list(
message_b = voice_message
else
message_b = stars(message)
message_b = say_quote(message_b,is_speaking_soghun,is_speaking_skrell,is_speaking_tajaran)
message_b = say_quote(message_b)
if (italics)
message_b = "<i>[message_b]</i>"
rendered = "<span class='game say'><span class='name'>[voice_name]</span> <span class='message'>[message_b]</span></span>"
for (var/mob/M in heard_b)
M.show_message(rendered, 2)
M << speech_bubble
spawn(30) del(speech_bubble)
for (var/M in heard_b)
if(hascall(M,"show_message"))
@@ -437,16 +379,9 @@ var/list/department_radio_keys = list(
del(B)
*/
if (length(eavesdroppers))
for (var/mob/M in eavesdroppers)
M << "\blue [src] speaks into their radio..."
M << speech_bubble
spawn(30) del(speech_bubble)
log_say("[name]/[key] : [message]")
/obj/effect/speech_bubble
var/mob/parent
var/mob/parent
+64 -30
View File
@@ -17,6 +17,7 @@
var/ioncheck[1]
var/icon/holo_icon//Default is assigned when AI is created.
var/obj/item/device/pda/ai/aiPDA = null
var/obj/item/device/multitool/aiMulti = null
//MALFUNCTION
var/datum/AI_Module/module_picker/malf_picker
@@ -69,6 +70,8 @@
aiPDA.ownjob = "AI"
aiPDA.name = name + " (" + aiPDA.ownjob + ")"
aiMulti = new(src)
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_call_shuttle,/mob/living/silicon/ai/proc/ai_camera_track, \
/mob/living/silicon/ai/proc/ai_camera_list, /mob/living/silicon/ai/proc/ai_network_change, \
@@ -101,7 +104,7 @@
/mob/living/silicon/ai/verb/pick_icon()
set category = "AI Commands"
set name = "Change AI Core Display"
set name = "Set AI Core Display"
if(stat || aiRestorePowerRoutine)
return
@@ -292,7 +295,7 @@
machine = null
src << browse(null, t1)
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"]))
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
@@ -325,15 +328,15 @@
statelaws()
if (href_list["track"])
var/mob/target = locate(href_list["track"])
var/mob/living/silicon/ai/A = locate(href_list["track2"])
var/mob/target = locate(href_list["track"]) in mob_list
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
if(A && target)
A.ai_actual_track(target)
return
else if (href_list["faketrack"])
var/mob/target = locate(href_list["track"])
var/mob/living/silicon/ai/A = locate(href_list["track2"])
var/mob/target = locate(href_list["track"]) in mob_list
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
if(A && target)
A.cameraFollow = target
@@ -426,25 +429,27 @@
/mob/living/silicon/ai/reset_view(atom/A)
if(current)
current.sd_SetLuminosity(0)
current.SetLuminosity(0)
if(istype(A,/obj/machinery/camera))
current = A
..()
if(istype(A,/obj/machinery/camera))
A.sd_SetLuminosity(camera_light_on * AI_CAMERA_LUMINOSITY)
if(camera_light_on) A.SetLuminosity(AI_CAMERA_LUMINOSITY)
else A.SetLuminosity(0)
/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)
src.cameraFollow = null
if (!C || stat == 2 || !C.status || C.network != network)
machine = null
reset_view(null)
if (!C || stat == 2 || !C.can_use())
//machine = null
//reset_view(null)
return 0
// ok, we're alive, camera is good and in our network...
machine = src
reset_view(C)
eyeobj.setLoc(get_turf(C))
//machine = src
return 1
/mob/living/silicon/ai/triggerAlarm(var/class, area/A, var/O, var/alarmsource)
@@ -468,7 +473,7 @@
C = O
L[A.name] = list(A, (C) ? C : O, list(alarmsource))
if (O)
if (C && C.status)
if (C && C.can_use())
src << "--- [class] alarm detected in [A.name]! (<A HREF=?src=\ref[src];switchcamera=\ref[C]>[C.c_tag]</A>)"
else if (CL && CL.len)
var/foo = 0
@@ -504,17 +509,17 @@
/mob/living/silicon/ai/cancel_camera()
set category = "AI Commands"
set name = "Cancel Camera View"
reset_view(null)
machine = null
//reset_view(null)
//machine = null
src.cameraFollow = null
//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead
//Addition by Mord_Sith to define AI's network change ability
/mob/living/silicon/ai/proc/ai_network_change()
set category = "AI Commands"
set name = "Change Camera Network"
reset_view(null)
set name = "Jump To Network"
machine = null
src.cameraFollow = null
var/cameralist[0]
@@ -523,8 +528,10 @@
usr << "You can't change your camera network because you are dead!"
return
for (var/obj/machinery/camera/C in Cameras)
if(!C.status)
var/mob/living/silicon/ai/U = usr
for (var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
if(C.network == "AI Satellite")
if (ticker.mode.name == "AI malfunction")
@@ -535,10 +542,17 @@
else
if(C.network != "CREED" && C.network != "thunder" && C.network != "RD" && C.network != "toxins" && C.network != "Prison")
cameralist[C.network] = C.network
network = input(usr, "Which network would you like to view?") as null|anything in cameralist
var/old_network = network
network = input(U, "Which network would you like to view?") as null|anything in cameralist
if(isnull(network))
network = initial(network) // If nothing is selected, default to SS13 (or the initial network)
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
if(C.network == network)
U.eyeobj.setLoc(get_turf(C))
break
src << "\blue Switched to [network] camera network."
//End of code by Mord_Sith
@@ -551,7 +565,7 @@
/mob/living/silicon/ai/proc/ai_statuschange()
set category = "AI Commands"
set name = "AI status"
set name = "AI Status"
if(usr.stat == 2)
usr <<"You cannot change your emotional status because you are dead!"
@@ -620,15 +634,35 @@
//Toggles the luminosity and applies it by re-entereing the camera.
/mob/living/silicon/ai/proc/toggle_camera_light()
set name = "Toggle camera light"
set name = "Toggle Camera Light"
set desc = "Toggles the light on the camera the AI is looking through."
set category = "AI Commands"
if(!current)
usr << "\red You are not looking through a camera right now."
return
camera_light_on = !camera_light_on
reset_view(current)
src << "Camera lights [camera_light_on ? "activated" : "deactivated"]."
if(!camera_light_on)
if(src.current)
src.current.SetLuminosity(0)
else
src.lightNearbyCamera()
#undef AI_CAMERA_LUMINOSITY
// Handled camera lighting, when toggled.
// It will get the nearest camera from the eyeobj, lighting it.
/mob/living/silicon/ai/proc/lightNearbyCamera()
if(camera_light_on && camera_light_on < world.timeofday)
if(src.current)
var/camera = near_range_camera(src.eyeobj)
if(camera && src.current != camera)
src.current.SetLuminosity(0)
src.current = camera
src.current.SetLuminosity(AI_CAMERA_LUMINOSITY)
else if(isnull(camera))
src.current.SetLuminosity(0)
src.current = null
camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds.
else
src.current = near_range_camera(src.eyeobj)
if(src.current) src.current.SetLuminosity(AI_CAMERA_LUMINOSITY)
@@ -4,6 +4,7 @@
icon_state = "ai-crash"
update_canmove()
src.eyeobj.setLoc(get_turf(src))
if(blind) blind.layer = 0
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
see_in_dark = 8
@@ -0,0 +1,134 @@
// CAMERA NET
//
// The datum containing all the chunks.
var/datum/cameranet/cameranet = new()
/datum/cameranet
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
var/list/cameras = list()
// The chunks of the map, mapping the areas that the cameras can see.
var/list/chunks = list()
var/ready = 0
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
return key in chunks
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z)
x &= ~0xf
y &= ~0xf
var/key = "[x],[y],[z]"
if(!(key in chunks))
chunks[key] = new /datum/camerachunk(null, x, y, z)
return chunks[key]
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
/datum/cameranet/proc/visibility(mob/aiEye/ai)
// 0xf = 15
var/x1 = max(0, ai.x - 16) & ~0xf
var/y1 = max(0, ai.y - 16) & ~0xf
var/x2 = min(world.maxx, ai.x + 16) & ~0xf
var/y2 = min(world.maxy, ai.y + 16) & ~0xf
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
visibleChunks += getCameraChunk(x, y, ai.z)
var/list/remove = ai.visibleCameraChunks - visibleChunks
var/list/add = visibleChunks - ai.visibleCameraChunks
for(var/datum/camerachunk/c in remove)
c.remove(ai)
for(var/datum/camerachunk/c in add)
c.add(ai)
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/cameranet/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/cameranet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
chunk.hasChanged()
// Removes a camera from a chunk.
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
// Used for Cyborg cameras. It is the same as "add" but named differently for easier readability
// and to allow the user know what it is for. Since portable cameras can be in ANY chunk, we have to
// all it to be added to all chunks. If the camera is disabled, it will instead remove.
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
else
majorChunkChange(c, 0)
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
/datum/cameranet/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - 16) & ~0xf
var/y1 = max(0, T.y - 16) & ~0xf
var/x2 = min(world.maxx, T.x + 16) & ~0xf
var/y2 = min(world.maxy, T.y + 16) & ~0xf
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, T.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
if(choice == 0)
// Remove the camera.
chunk.cameras -= c
else if(choice == 1)
// You can't have the same camera in the list twice.
chunk.cameras |= c
chunk.hasChanged()
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)
// 0xf = 15
var/turf/position = get_turf(target)
var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(position in chunk.visibleTurfs)
return 1
return 0
@@ -0,0 +1,135 @@
#define UPDATE_BUFFER 15
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the AI Eye to stream these chunks and know what it can and cannot see.
/datum/camerachunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/cameras = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
// Add an AI eye to the chunk, then update if changed.
/datum/camerachunk/proc/add(mob/aiEye/ai)
ai.visibleCameraChunks += src
if(ai.ai.client)
ai.ai.client.images += obscured
visible++
seenby += ai
if(changed && !updating)
update()
// Remove an AI eye from the chunk, then update if changed.
/datum/camerachunk/proc/remove(mob/aiEye/ai)
ai.visibleCameraChunks -= src
if(ai.ai.client)
ai.ai.client.images -= obscured
seenby -= ai
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/camerachunk/proc/visibilityChanged(turf/loc)
if(!(loc in visibleTurfs))
return
hasChanged()
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
// instead be flagged to update the next time an AI Eye moves near it.
/datum/camerachunk/proc/hasChanged(var/update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
/datum/camerachunk/proc/update()
var/list/newVisibleTurfs = list()
for(var/obj/machinery/camera/c in cameras)
if(!c.can_use())
continue
var/turf/pos = get_turf(c)
if(pos)
for(var/turf/t in range(7, pos))
if(t in turfs)
newVisibleTurfs += t
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
for(var/turf/t in visAdded)
if(t.obscured)
obscured -= t.obscured
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images -= t.obscured
for(var/turf/t in visRemoved)
if(t in obscuredTurfs)
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/mob/aiEye/m in seenby)
if(!m)
seenby -= m
if(m.ai.client)
m.ai.client.images += t.obscured
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/camerachunk/New(loc, x, y, z)
// 0xf = 15
x &= ~0xf
y &= ~0xf
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
cameras += c
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
turfs += t
for(var/obj/machinery/camera/c in cameras)
if(!c.can_use())
continue
var/turf/pos = get_turf(c)
if(pos)
for(var/turf/t in range(7, pos))
if(t in turfs)
visibleTurfs += t
obscuredTurfs = turfs - visibleTurfs
for(var/turf/t in obscuredTurfs)
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
#undef UPDATE_BUFFER
@@ -0,0 +1,114 @@
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/aiEye
name = "Inactive AI Eye"
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
density = 0
nodamage = 1 // You can't damage it.
// Movement code. Returns 0 to stop air movement from moving it.
/mob/aiEye/Move()
return 0
// Hide popout menu verbs
/mob/aiEye/examine()
set popup_menu = 0
set src = usr.contents
return 0
/mob/aiEye/pull()
set popup_menu = 0
set src = usr.contents
return 0
/mob/aiEye/point()
set popup_menu = 0
set src = usr.contents
return 0
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
/mob/aiEye/proc/setLoc(var/T)
T = get_turf(T)
loc = T
cameranet.visibility(src)
if(ai)
if(ai.client)
ai.client.eye = src
// AI MOVEMENT
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
var/mob/aiEye/eyeobj = new()
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/New()
..()
eyeobj.ai = src
spawn(5)
eyeobj.loc = src.loc
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
/mob/living/silicon/ai/Del()
eyeobj.ai = null
del(eyeobj) // No AI, no Eye
..()
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.
/client/AIMove(n, direct, var/mob/living/silicon/ai/user)
var/initial = initial(user.sprint)
var/max_sprint = 50
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
user.sprint = initial
for(var/i = 0; i < max(user.sprint, initial); i += 20)
user.eyeobj.setLoc(get_turf(get_step(user.eyeobj, direct)))
user.cooldown = world.timeofday + 5
if(user.acceleration)
user.sprint = min(user.sprint + 0.5, max_sprint)
else
user.sprint = initial
user.cameraFollow = null
src.eye = user.eyeobj
//user.machine = null //Uncomment this if it causes problems.
user.lightNearbyCamera()
// Return to the Core.
/mob/living/silicon/ai/verb/core()
set category = "AI Commands"
set name = "AI Core"
current = null
cameraFollow = null
machine = null
src.eyeobj.loc = src.loc
if(client && client.eye)
client.eye = src
for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
c.remove(eyeobj)
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
acceleration = !acceleration
usr << "Camera acceleration has been toggled [acceleration ? "on" : "off"]."
@@ -0,0 +1,51 @@
// CREDITS
/*
Initial code credit for this goes to Uristqwerty.
Debugging, functionality, all comments and porting by Giacom.
Everything about freelook (or what we can put in here) will be stored here.
WHAT IS THIS?
This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players.
The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and
cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it.
This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking,
the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Del().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.
HOW IT UPDATES
The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.
The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created.
One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area.
We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk
that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead
flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing
measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking
sight; for example, we don't update glass airlocks or floors.
WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
*/
@@ -0,0 +1,79 @@
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/turf
var/image/obscured
/turf/proc/visibilityChanged()
cameranet.updateVisibility(src)
/atom/proc/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.client.eye == AI.eyeobj)
AI.eyeobj.setLoc(src)
/*
/turf/simulated/Del()
visibilityChanged()
..()
/turf/simulated/New()
..()
visibilityChanged()
// STRUCTURES
/obj/structure/Del()
cameranet.updateVisibility(src)
..()
/obj/structure/New()
..()
cameranet.updateVisibility(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/update_nearby_tiles(need_rebuild)
. = ..(need_rebuild)
// Glass door glass = 1
// don't check then?
if(!glass)
cameranet.updateVisibility(src, 0)
*/
// ROBOT MOVEMENT
// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/robot/Move()
. = ..()
if(.)
if(src.camera)
cameranet.updatePortableCamera(src.camera)
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
cameranet.addCamera(src)
else
src.SetLuminosity(0)
cameranet.removeCamera(src)
/obj/machinery/camera/New()
..()
cameranet.cameras += src
cameranet.addCamera(src)
/obj/machinery/camera/Del()
cameranet.cameras -= src
cameranet.removeCamera(src)
..()
@@ -22,4 +22,5 @@
if(O)
O.mode = 1
O.emotion = "Neutral"
src.core()
return
@@ -6,4 +6,5 @@
if (client)
client.eye = loc
client.perspective = EYE_PERSPECTIVE
src.core()
return
+1 -15
View File
@@ -13,20 +13,6 @@
var/obj/machinery/camera/closest = null
var/atom/old = (user.current?user.current : user.loc)
if(istype(user.loc, /obj/item/clothing/suit/space/space_ninja))//To make ninja suit AI holograms work.
var/obj/item/clothing/suit/space/space_ninja/S = user.loc//Ease of use.
if(S.hologram)//If there is a hologram.
S.hologram.loc = get_step(S.hologram, direct)
S.hologram.dir = direct
return//Whatever the case, return since you can't move anyway.
if(user.client)//To make AI holograms work. They will relay directions as long as they are centered on the object.
var/obj/machinery/hologram/holopad/T = user.client.eye//Client eye centers on an object.
if(istype(T)&&T.hologram&&T.master==user)//If there is a hologram and its master is the user.
T.hologram.loc = get_step(T.hologram, direct)
T.hologram.dir = direct
return//Relay move and then return if that's the case.
if(!old) return
var/dx = 0
@@ -43,7 +29,7 @@
var/area/A = get_area(old)
var/list/old_types = dd_text2list("[A.type]", "/")
for(var/obj/machinery/camera/current in Cameras)
for(var/obj/machinery/camera/current in cameranet.cameras)
if(user.network != current.network) continue
if(!current.status) continue // ignore disabled cameras
@@ -198,6 +198,7 @@
var/mob/living/M = src.loc
var/count = 0
while(!istype(M, /mob/living))
if(!M || !M.loc) return 0 //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
M = M.loc
count++
if(count >= 6)
@@ -13,7 +13,6 @@
handle_regular_status_updates()
if(client)
// UpdateLuminosity()
handle_regular_hud_updates()
update_items()
if (src.stat != DEAD) //still using power
@@ -303,4 +302,4 @@
/mob/living/silicon/robot/update_canmove()
if(paralysis || stunned || weakened || buckled || lockcharge) canmove = 0
else canmove = 1
return canmove
return canmove
@@ -29,7 +29,7 @@
modtype = "Synd"
radio = new /obj/item/device/radio/borg(src)
if(!scrambledcodes)
if(!scrambledcodes && !camera)
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.network = "SS13"
@@ -63,6 +63,7 @@
if(BORG_WIRE_CAMERA)
if (!isnull(src.camera) && !scrambledcodes)
src.camera.status = 1
src.camera.deactivate(usr, 0) // Will kick anyone who is watching the Cyborg's camera.
src.interact(usr)
+5 -4
View File
@@ -26,9 +26,10 @@
robot_talk(message)
else if ((copytext(message, 1, 3) == ":h") || (copytext(message, 1, 3) == ":H"))
if(isAI(src)&&client)//For patching directly into AI holopads.
var/mob/living/silicon/ai/U = src
message = copytext(message, 3)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
holopad_talk(message)
U.holopad_talk(message)
else//Will not allow anyone by an active AI to use this function.
src << "This function is not available to you."
return
@@ -38,7 +39,7 @@
return ..(message)
//For holopads only. Usable by AI.
/mob/living/proc/holopad_talk(var/message)
/mob/living/silicon/ai/proc/holopad_talk(var/message)
log_say("[key_name(src)] : [message]")
@@ -47,8 +48,8 @@
if (!message)
return
var/obj/machinery/hologram/holopad/T = client.eye//Client eye centers on an object.
if(istype(T)&&T.hologram&&T.master==src)//If there is a hologram and its master is the user.
var/obj/machinery/hologram/holopad/T = locate(/obj/machinery/hologram/holopad) in src.eyeobj.loc
if(istype(T) && T.hologram && T.master==src)//If there is a hologram and its master is the user.
var/message_a = say_quote(message)
//Human-like, sorta, heard by those who understand humans.
@@ -14,6 +14,9 @@
/mob/living/silicon/proc/show_laws()
return
/mob/living/silicon/drop_item()
return
/mob/living/silicon/emp_act(severity)
switch(severity)
if(1)
@@ -80,7 +80,7 @@
emote_hear = list("barks", "woofs", "yaps","pants")
emote_see = list("shakes its head", "shivers")
desc = "It's a corgi."
src.sd_SetLuminosity(0)
SetLuminosity(0)
inventory_head.loc = src.loc
inventory_head = null
else
@@ -216,7 +216,7 @@
name = "Rudolph the Red-Nosed Corgi"
emote_hear = list("barks christmas songs", "yaps")
desc = "He has a very shiny nose."
src.sd_SetLuminosity(6)
SetLuminosity(6)
if(/obj/item/clothing/head/soft)
name = "Corgi Tech [real_name]"
speak = list("Needs a stamp!", "Request DENIED!", "Fill these out in triplicate!")
+31 -31
View File
@@ -26,9 +26,6 @@
usr.show_message(t, 1)
/atom/proc/relaymove()
return
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
if(!client) return
if (type)
@@ -75,6 +72,33 @@
M.show_message( message, 1, blind_message, 2)
//What the fuck is this code
/mob/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (user.intent != "harm")
if (istype(src.l_hand,/obj/item/latexballon) && src.l_hand:air_contents && is_sharp(W))
return src.l_hand.attackby(W)
if (istype(src.r_hand,/obj/item/latexballon) && src.r_hand:air_contents && is_sharp(W))
return src.r_hand.attackby(W)
var/shielded = 0
if (locate(/obj/item/weapon/grab, src))
var/mob/safe = null
if (istype(src.l_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = src.l_hand
if ((G.state == 3 && get_dir(src, user) == src.dir))
safe = G.affecting
if (istype(src.r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = src.r_hand
if ((G.state == 3 && get_dir(src, user) == src.dir))
safe = G.affecting
if (safe)
return safe.attackby(W, user)
if ((!( shielded ) || !( W.flags ) & 32))
spawn( 0 )
if (W)
W.attack(src, user)
return
return
/mob/proc/findname(msg)
for(var/mob/M in mob_list)
if (M.real_name == text("[]", msg))
@@ -505,11 +529,6 @@ var/list/slot_equipment_priority = list( \
// ..()
return
/mob/proc/UpdateLuminosity()
if(src.total_luminosity == src.last_luminosity) return 0//nothing to do here
src.last_luminosity = src.total_luminosity
sd_SetLuminosity(min(src.total_luminosity,7))//Current hardcode max at 7, should likely be a const somewhere else
return 1
/mob/MouseDrop(mob/M as mob)
..()
@@ -520,16 +539,6 @@ var/list/slot_equipment_priority = list( \
if(LinkBlocked(usr.loc,loc)) return
show_inv(usr)
/atom/movable
var/mob/pulledby = null
/atom/movable/verb/pull()
set name = "Pull"
set category = "IC"
set src in oview(1)
usr.start_pulling(src)
return
/mob/proc/stop_pulling()
if(pulling)
@@ -553,18 +562,6 @@ var/list/slot_equipment_priority = list( \
else
M.LAssailant = usr
/atom/verb/examine()
set name = "Examine"
set category = "IC"
set src in oview(12) //make it work from farther away
if (!( usr ))
return
usr << "That's \a [src]." //changed to "That's" from "This is" because "This is some metal sheets" sounds dumb compared to "That's some metal sheets" ~Carn
usr << desc
// *****RM
//usr << "[name]: Dn:[density] dir:[dir] cont:[contents] icon:[icon] is:[icon_state] loc:[loc]"
return
/mob/proc/can_use_hands()
if(handcuffed)
@@ -850,4 +847,7 @@ note dizziness decrements automatically in the mob's Life() proc.
for(var/file in args)
src << browse_rsc(file)
return 1
return 0
return 0
mob/proc/flash_weak_pain()
flick("weak_pain",pain)
+3 -11
View File
@@ -32,9 +32,6 @@
var/obj/screen/pressure = null
var/obj/screen/damageoverlay = null
var/total_luminosity = 0 //This controls luminosity for mobs, when you pick up lights and such this is edited. If you want the mob to use lights it must update its lum in its life proc or such. Note clamp this value around 7 or such to prevent massive light lag.
var/last_luminosity = 0
/*A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob.
A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such.
The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs).
@@ -66,7 +63,7 @@
var/ear_deaf = null //Carbon
var/ear_damage = null //Carbon
var/stuttering = null //Carbon
var/slurring = null //Carbon
var/slurring = null
var/real_name = null
// var/original_name = null //Original name is only used in ghost chat! Depracated, now used bb
var/blinded = null
@@ -85,7 +82,6 @@
var/eye_stat = null//Living, potentially Carbon
var/lastpuke = 0
var/unacidable = 0
var/flavor_text = ""
var/name_archive //For admin things like possession
@@ -126,11 +122,6 @@
var/seer = 0 //for cult//Carbon, probably Human
//skills
var/used_skillpoints = 0
var/skill_specialization = null
var/list/skills = null
var/obj/hud/hud_used = null
//var/list/organs = list( ) //moved to human.
@@ -228,6 +219,7 @@
var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE
var/robot_talk_understand = 0
var/alien_talk_understand = 0
var/skrell_talk_understand = 0
var/tajaran_talk_understand = 0
var/soghun_talk_understand = 0
var/skrell_talk_understand = 0
+38 -12
View File
@@ -7,9 +7,13 @@
var/atom/movable/structure = null // if the grab is not grabbing a mob
var/mob/assailant = null
var/state = 1.0
var/killing = 0.0
var/killing = 0.0 // 1 = about to kill, 2 = killing
var/kill_loc = null
var/allow_upgrade = 1.0
var/last_suffocate = 1.0
layer = 21
abstract = 1.0
item_state = "nothing"
@@ -94,7 +98,6 @@
for(var/obj/item/weapon/grab/G in affecting.grabbed_by)
if (G.state == 2)
allow_upgrade = 0
//Foreach goto(341)
if (allow_upgrade)
hud1.icon_state = "reinforce"
else
@@ -102,9 +105,15 @@
else
if (!( affecting.buckled ))
affecting.loc = assailant.loc
if ((killing && state == 3))
affecting.Stun(5)
affecting.Paralyse(3)
if ((killing == 2 && state == 3))
if(assailant.loc != kill_loc)
for(var/mob/O in viewers(assailant, null))
O.show_message(text("\red [] lost his tightened grip on []'s neck!", assailant, affecting), 1)
killing = 0
hud1.icon_state = "disarm/kill"
return
affecting.Weaken(3)
affecting.Stun(3) // It will hamper your voice, being choked and all.
affecting.losebreath = min(affecting.losebreath + 2, 3)
return
@@ -112,6 +121,8 @@
/obj/item/weapon/grab/proc/s_click(obj/screen/S as obj)
if (!affecting)
return
if(killing)
return
if (assailant.next_move > world.time)
return
if ((!( assailant.canmove ) || assailant.lying))
@@ -144,6 +155,9 @@
if ((!( assailant.canmove ) || assailant.lying))
del(src)
return
if(killing)
return
switch(S.id)
if(1.0)
if (state < 2)
@@ -196,9 +210,22 @@
hud1.icon_state = "disarm/kill"
hud1.name = "disarm/kill"
else
if (state >= 3)
killing = !( killing )
if (killing)
if (state >= 3 && !killing)
for(var/mob/O in viewers(assailant, null))
O.show_message(text("\red [] starts to tighten his grip on []'s neck!", assailant, affecting), 1)
hud1.icon_state = "disarm/kill1"
killing = 1
if(do_after(assailant, 50))
if(killing == 2)
return
if(!affecting)
del(src)
return
if ((!( assailant.canmove ) || assailant.lying))
del(src)
return
killing = 2
kill_loc = assailant.loc
for(var/mob/O in viewers(assailant, null))
O.show_message(text("\red [] has tightened his grip on []'s neck!", assailant, affecting), 1)
affecting.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>")
@@ -207,12 +234,11 @@
assailant.next_move = world.time + 10
affecting.losebreath += 1
hud1.icon_state = "disarm/kill1"
else
hud1.icon_state = "disarm/kill"
for(var/mob/O in viewers(assailant, null))
O.show_message(text("\red [] has loosened the grip on []'s neck!", assailant, affecting), 1)
else
O.show_message(text("\red [] was unable to tighten his grip on []'s neck!", assailant, affecting), 1)
killing = 0
hud1.icon_state = "disarm/kill"
return
+46 -47
View File
@@ -31,7 +31,7 @@
spawn(60)
spawn(30)
if(client)
if(!preferences.savefile_load(src, 0))
preferences.ShowChoices(src)
@@ -50,50 +50,49 @@
new_player_panel()
if(preferences.lobby_music)
Playmusic()
//PDA Resource Initialisation =======================================================>
/*
Quick note: local dream daemon instances don't seem to cache images right. Might be
a local problem with my machine but it's annoying nontheless.
*/
if(client)
//load the PDA iconset into the client
src << browse_rsc('icons/pda_icons/pda_atmos.png')
src << browse_rsc('icons/pda_icons/pda_back.png')
src << browse_rsc('icons/pda_icons/pda_bell.png')
src << browse_rsc('icons/pda_icons/pda_blank.png')
src << browse_rsc('icons/pda_icons/pda_boom.png')
src << browse_rsc('icons/pda_icons/pda_bucket.png')
src << browse_rsc('icons/pda_icons/pda_crate.png')
src << browse_rsc('icons/pda_icons/pda_cuffs.png')
src << browse_rsc('icons/pda_icons/pda_eject.png')
src << browse_rsc('icons/pda_icons/pda_exit.png')
src << browse_rsc('icons/pda_icons/pda_flashlight.png')
src << browse_rsc('icons/pda_icons/pda_honk.png')
src << browse_rsc('icons/pda_icons/pda_mail.png')
src << browse_rsc('icons/pda_icons/pda_medical.png')
src << browse_rsc('icons/pda_icons/pda_menu.png')
src << browse_rsc('icons/pda_icons/pda_mule.png')
src << browse_rsc('icons/pda_icons/pda_notes.png')
src << browse_rsc('icons/pda_icons/pda_power.png')
src << browse_rsc('icons/pda_icons/pda_rdoor.png')
src << browse_rsc('icons/pda_icons/pda_reagent.png')
src << browse_rsc('icons/pda_icons/pda_refresh.png')
src << browse_rsc('icons/pda_icons/pda_scanner.png')
src << browse_rsc('icons/pda_icons/pda_signaler.png')
src << browse_rsc('icons/pda_icons/pda_status.png')
//Loads icons for SpiderOS into client
src << browse_rsc('icons/spideros_icons/sos_1.png')
src << browse_rsc('icons/spideros_icons/sos_2.png')
src << browse_rsc('icons/spideros_icons/sos_3.png')
src << browse_rsc('icons/spideros_icons/sos_4.png')
src << browse_rsc('icons/spideros_icons/sos_5.png')
src << browse_rsc('icons/spideros_icons/sos_6.png')
src << browse_rsc('icons/spideros_icons/sos_7.png')
src << browse_rsc('icons/spideros_icons/sos_8.png')
src << browse_rsc('icons/spideros_icons/sos_9.png')
src << browse_rsc('icons/spideros_icons/sos_10.png')
src << browse_rsc('icons/spideros_icons/sos_11.png')
src << browse_rsc('icons/spideros_icons/sos_12.png')
src << browse_rsc('icons/spideros_icons/sos_13.png')
src << browse_rsc('icons/spideros_icons/sos_14.png')
//PDA Resource Initialisation =======================================================>
/*
Quick note: local dream daemon instances don't seem to cache images right. Might be
a local problem with my machine but it's annoying nontheless.
*/
//load the PDA iconset into the client
src << browse_rsc('icons/pda_icons/pda_atmos.png')
src << browse_rsc('icons/pda_icons/pda_back.png')
src << browse_rsc('icons/pda_icons/pda_bell.png')
src << browse_rsc('icons/pda_icons/pda_blank.png')
src << browse_rsc('icons/pda_icons/pda_boom.png')
src << browse_rsc('icons/pda_icons/pda_bucket.png')
src << browse_rsc('icons/pda_icons/pda_crate.png')
src << browse_rsc('icons/pda_icons/pda_cuffs.png')
src << browse_rsc('icons/pda_icons/pda_eject.png')
src << browse_rsc('icons/pda_icons/pda_exit.png')
src << browse_rsc('icons/pda_icons/pda_flashlight.png')
src << browse_rsc('icons/pda_icons/pda_honk.png')
src << browse_rsc('icons/pda_icons/pda_mail.png')
src << browse_rsc('icons/pda_icons/pda_medical.png')
src << browse_rsc('icons/pda_icons/pda_menu.png')
src << browse_rsc('icons/pda_icons/pda_mule.png')
src << browse_rsc('icons/pda_icons/pda_notes.png')
src << browse_rsc('icons/pda_icons/pda_power.png')
src << browse_rsc('icons/pda_icons/pda_rdoor.png')
src << browse_rsc('icons/pda_icons/pda_reagent.png')
src << browse_rsc('icons/pda_icons/pda_refresh.png')
src << browse_rsc('icons/pda_icons/pda_scanner.png')
src << browse_rsc('icons/pda_icons/pda_signaler.png')
src << browse_rsc('icons/pda_icons/pda_status.png')
//Loads icons for SpiderOS into client
src << browse_rsc('icons/spideros_icons/sos_1.png')
src << browse_rsc('icons/spideros_icons/sos_2.png')
src << browse_rsc('icons/spideros_icons/sos_3.png')
src << browse_rsc('icons/spideros_icons/sos_4.png')
src << browse_rsc('icons/spideros_icons/sos_5.png')
src << browse_rsc('icons/spideros_icons/sos_6.png')
src << browse_rsc('icons/spideros_icons/sos_7.png')
src << browse_rsc('icons/spideros_icons/sos_8.png')
src << browse_rsc('icons/spideros_icons/sos_9.png')
src << browse_rsc('icons/spideros_icons/sos_10.png')
src << browse_rsc('icons/spideros_icons/sos_11.png')
src << browse_rsc('icons/spideros_icons/sos_12.png')
src << browse_rsc('icons/spideros_icons/sos_13.png')
src << browse_rsc('icons/spideros_icons/sos_14.png')
//End PDA Resource Initialisation =====================================================>
+84 -1
View File
@@ -269,4 +269,87 @@
new_corgi << "<B>You are now a Corgi. Yap Yap!</B>"
spawn(0)//To prevent the proc from returning null.
del(src)
return
return
/mob/living/carbon/human/Animalize()
var/list/mobtypes = typesof(/mob/living/simple_animal)
var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
if(bad_animal(mobpath))
usr << "\red Sorry but this mob type is currently unavailable."
return
if(monkeyizing)
return
for(var/obj/item/W in src)
drop_from_inventory(W)
regenerate_icons()
monkeyizing = 1
canmove = 0
icon = null
invisibility = 101
for(var/t in organs)
del(t)
var/mob/new_mob = new mobpath(src.loc)
new_mob.key = key
new_mob.a_intent = "hurt"
new_mob.UI = UI
new_mob << "You suddenly feel more... animalistic."
spawn()
del(src)
return
/mob/proc/Animalize()
var/list/mobtypes = typesof(/mob/living/simple_animal)
var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
if(bad_animal(mobpath))
usr << "\red Sorry but this mob type is currently unavailable."
return
var/mob/new_mob = new mobpath(src.loc)
new_mob.key = key
new_mob.a_intent = "hurt"
new_mob.UI = UI
new_mob << "You feel more... animalistic"
del(src)
//Certain mob types either do not work, or have major problems and should now be allowed to be controlled by players.
/mob/proc/bad_animal(var/MP)
//Sanity, this should never happen.
if(!MP || !ispath(MP, /mob/living/simple_animal))
return 1
//It is impossible to pull up the player panel for mice
if(ispath(MP, /mob/living/simple_animal/mouse))
return 1
//Bears will auto-attack mobs, even if they're player controlled
if(ispath(MP, /mob/living/simple_animal/bear))
return 1
//Parrots are unfinished, they have no sprite, movement, ect...
else if(ispath(MP, /mob/living/simple_animal/parrot))
return 1
//Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning.
else if(ispath(MP, /mob/living/simple_animal/space_worm))
return 1
//No problems found!
else
return 0