mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-11 15:14:27 +01:00
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:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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 =====================================================>
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user