Merge remote-tracking branch 'refs/remotes/Citadel-Station-13/master' into crewobjectivesandmiscreants
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
diff a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm (rejected hunks)
|
||||
@@ -1,5 +1,6 @@
|
||||
/mob/dead/new_player/Login()
|
||||
- client.update_exp_client(0, 0)
|
||||
+ if(config.use_exp_tracking)
|
||||
+ client.update_exp_client(0, 0)
|
||||
if(!mind)
|
||||
mind = new /datum/mind(key)
|
||||
mind.active = 1
|
||||
@@ -329,6 +329,9 @@
|
||||
if(SSshuttle.arrivals.damaged && config.arrivals_shuttle_require_safe_latejoin)
|
||||
src << alert("The arrivals shuttle is currently malfunctioning! You cannot join.")
|
||||
return FALSE
|
||||
|
||||
if(config.arrivals_shuttle_require_undocked)
|
||||
SSshuttle.arrivals.RequireUndocked(src)
|
||||
arrivals_docked = SSshuttle.arrivals.mode != SHUTTLE_CALL
|
||||
|
||||
//Remove the player from the join queue if he was in one and reset the timer
|
||||
@@ -394,12 +397,7 @@
|
||||
|
||||
|
||||
/mob/dead/new_player/proc/LateChoices()
|
||||
var/mills = world.time - SSticker.round_start_time // 1/10 of a second, not real milliseconds but whatever
|
||||
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
|
||||
var/mins = (mills % 36000) / 600
|
||||
var/hours = mills / 36000
|
||||
|
||||
var/dat = "<div class='notice'>Round Duration: [round(hours)]h [round(mins)]m</div>"
|
||||
var/dat = "<div class='notice'>Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]</div>"
|
||||
|
||||
if(SSshuttle.emergency)
|
||||
switch(SSshuttle.emergency.mode)
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
to_chat(src, "<span class='danger'>Invalid vote data</span>")
|
||||
return 0
|
||||
|
||||
//lets add the vote, first we generate a insert statement.
|
||||
//lets add the vote, first we generate an insert statement.
|
||||
|
||||
var/sqlrowlist = ""
|
||||
for (var/vote in numberedvotelist)
|
||||
|
||||
@@ -1,100 +1,84 @@
|
||||
|
||||
//The mob should have a gender you want before running this proc. Will run fine without H
|
||||
/datum/preferences/proc/random_character(gender_override)
|
||||
if(gender_override)
|
||||
gender = gender_override
|
||||
else
|
||||
gender = pick(MALE,FEMALE)
|
||||
skin_tone = random_skin_tone()
|
||||
hair_style = random_hair_style(gender)
|
||||
facial_hair_style = random_facial_hair_style(gender)
|
||||
hair_color = random_short_color()
|
||||
facial_hair_color = hair_color
|
||||
eye_color = random_eye_color()
|
||||
if(!pref_species)
|
||||
var/rando_race = pick(config.roundstart_races)
|
||||
pref_species = new rando_race()
|
||||
features = random_features()
|
||||
age = rand(AGE_MIN,AGE_MAX)
|
||||
|
||||
/datum/preferences/proc/update_preview_icon(nude = 0)
|
||||
var/wide_icon = 0
|
||||
var/stamp_x = 0
|
||||
var/stamp_y = 1
|
||||
if(features["taur"] != "None")
|
||||
wide_icon = 1
|
||||
// Silicons only need a very basic preview since there is no customization for them.
|
||||
if(job_engsec_high)
|
||||
switch(job_engsec_high)
|
||||
if(AI_JF)
|
||||
preview_icon = icon('icons/mob/AI.dmi', "AI", SOUTH)
|
||||
preview_icon.Scale(64, 64)
|
||||
return
|
||||
if(CYBORG)
|
||||
preview_icon = icon('icons/mob/robots.dmi', "robot", SOUTH)
|
||||
preview_icon.Scale(64, 64)
|
||||
return
|
||||
|
||||
// Set up the dummy for its photoshoot
|
||||
var/mob/living/carbon/human/dummy/mannequin = new()
|
||||
copy_to(mannequin)
|
||||
|
||||
// Determine what job is marked as 'High' priority, and dress them up as such.
|
||||
var/datum/job/previewJob
|
||||
var/highRankFlag = job_civilian_high | job_medsci_high | job_engsec_high
|
||||
|
||||
if(job_civilian_low & ASSISTANT)
|
||||
previewJob = SSjob.GetJob("Assistant")
|
||||
else if(highRankFlag)
|
||||
var/highDeptFlag
|
||||
if(job_civilian_high)
|
||||
highDeptFlag = CIVILIAN
|
||||
else if(job_medsci_high)
|
||||
highDeptFlag = MEDSCI
|
||||
else if(job_engsec_high)
|
||||
highDeptFlag = ENGSEC
|
||||
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job.flag == highRankFlag && job.department_flag == highDeptFlag)
|
||||
previewJob = job
|
||||
break
|
||||
|
||||
if(previewJob && !nude)
|
||||
mannequin.job = previewJob.title
|
||||
previewJob.equip(mannequin, TRUE)
|
||||
mannequin.update_body()
|
||||
CHECK_TICK
|
||||
preview_icon = icon('icons/effects/effects.dmi', "nothing")
|
||||
preview_icon.Scale((112), (32))
|
||||
CHECK_TICK
|
||||
mannequin.setDir(NORTH)
|
||||
|
||||
var/icon/stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
if(wide_icon)
|
||||
stamp_x = 16
|
||||
else
|
||||
stamp_x = 32
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, stamp_x, stamp_y)
|
||||
CHECK_TICK
|
||||
mannequin.setDir(WEST)
|
||||
stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
if(wide_icon)
|
||||
stamp_x = 48
|
||||
else
|
||||
stamp_x = 64
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, stamp_x, stamp_y)
|
||||
CHECK_TICK
|
||||
mannequin.setDir(SOUTH)
|
||||
stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
if(wide_icon)
|
||||
stamp_x = -15
|
||||
else
|
||||
stamp_x = 1
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, stamp_x, stamp_y)
|
||||
CHECK_TICK
|
||||
preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser.
|
||||
CHECK_TICK
|
||||
qdel(mannequin)
|
||||
//The mob should have a gender you want before running this proc. Will run fine without H
|
||||
/datum/preferences/proc/random_character(gender_override)
|
||||
if(gender_override)
|
||||
gender = gender_override
|
||||
else
|
||||
gender = pick(MALE,FEMALE)
|
||||
underwear = random_underwear(gender)
|
||||
undershirt = random_undershirt(gender)
|
||||
socks = random_socks()
|
||||
skin_tone = random_skin_tone()
|
||||
hair_style = random_hair_style(gender)
|
||||
facial_hair_style = random_facial_hair_style(gender)
|
||||
hair_color = random_short_color()
|
||||
facial_hair_color = hair_color
|
||||
eye_color = random_eye_color()
|
||||
if(!pref_species)
|
||||
var/rando_race = pick(config.roundstart_races)
|
||||
pref_species = new rando_race()
|
||||
features = random_features()
|
||||
age = rand(AGE_MIN,AGE_MAX)
|
||||
|
||||
/datum/preferences/proc/update_preview_icon(nude = 0)
|
||||
// Silicons only need a very basic preview since there is no customization for them.
|
||||
if(job_engsec_high)
|
||||
switch(job_engsec_high)
|
||||
if(AI_JF)
|
||||
preview_icon = icon('icons/mob/ai.dmi', "AI", SOUTH)
|
||||
preview_icon.Scale(64, 64)
|
||||
return
|
||||
if(CYBORG)
|
||||
preview_icon = icon('icons/mob/robots.dmi', "robot", SOUTH)
|
||||
preview_icon.Scale(64, 64)
|
||||
return
|
||||
|
||||
// Set up the dummy for its photoshoot
|
||||
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
|
||||
copy_to(mannequin)
|
||||
|
||||
// Determine what job is marked as 'High' priority, and dress them up as such.
|
||||
var/datum/job/previewJob
|
||||
var/highRankFlag = job_civilian_high | job_medsci_high | job_engsec_high
|
||||
|
||||
if(job_civilian_low & ASSISTANT)
|
||||
previewJob = SSjob.GetJob("Assistant")
|
||||
else if(highRankFlag)
|
||||
var/highDeptFlag
|
||||
if(job_civilian_high)
|
||||
highDeptFlag = CIVILIAN
|
||||
else if(job_medsci_high)
|
||||
highDeptFlag = MEDSCI
|
||||
else if(job_engsec_high)
|
||||
highDeptFlag = ENGSEC
|
||||
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job.flag == highRankFlag && job.department_flag == highDeptFlag)
|
||||
previewJob = job
|
||||
break
|
||||
|
||||
if(previewJob && !nude)
|
||||
mannequin.job = previewJob.title
|
||||
previewJob.equip(mannequin, TRUE)
|
||||
CHECK_TICK
|
||||
preview_icon = icon('icons/effects/effects.dmi', "nothing")
|
||||
preview_icon.Scale(48+32, 16+32)
|
||||
CHECK_TICK
|
||||
mannequin.setDir(NORTH)
|
||||
|
||||
var/icon/stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17)
|
||||
CHECK_TICK
|
||||
mannequin.setDir(WEST)
|
||||
stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9)
|
||||
CHECK_TICK
|
||||
mannequin.setDir(SOUTH)
|
||||
stamp = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1)
|
||||
CHECK_TICK
|
||||
preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser.
|
||||
CHECK_TICK
|
||||
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
|
||||
|
||||
@@ -711,9 +711,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
update_icon()
|
||||
|
||||
/mob/dead/observer/canUseTopic(atom/movable/AM,be_close = FALSE)
|
||||
if(check_rights(R_ADMIN, 0))
|
||||
return 1
|
||||
return
|
||||
return IsAdminGhost(usr)
|
||||
|
||||
/mob/dead/observer/is_literate()
|
||||
return 1
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
var/obj/item/organ/brain/brain = null //The actual brain
|
||||
var/datum/ai_laws/laws = new()
|
||||
var/force_replace_ai_name = FALSE
|
||||
var/overrides_aicore_laws = FALSE // Whether the laws on the MMI, if any, override possible pre-existing laws loaded on the AI core.
|
||||
|
||||
/obj/item/device/mmi/update_icon()
|
||||
if(brain)
|
||||
@@ -203,8 +204,9 @@
|
||||
name = "Syndicate Man-Machine Interface"
|
||||
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs and AIs created with it."
|
||||
origin_tech = "biotech=4;programming=4;syndicate=2"
|
||||
overrides_aicore_laws = TRUE
|
||||
|
||||
/obj/item/device/mmi/syndie/New()
|
||||
..()
|
||||
/obj/item/device/mmi/syndie/Initialize()
|
||||
. = ..()
|
||||
laws = new /datum/ai_laws/syndicate_override()
|
||||
radio.on = 0
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
create_internal_organs()
|
||||
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/brain/alien
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/Initialize()
|
||||
AddAbility(new/obj/effect/proc_holder/alien/evolve(null))
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/drone/create_internal_organs()
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
#define MAX_ALIEN_LEAP_DIST 7
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/proc/leap_at(atom/A)
|
||||
if(pounce_cooldown > world.time)
|
||||
to_chat(src, "<span class='alertalien'>You are too fatigued to pounce right now!</span>")
|
||||
if(!canmove || leaping)
|
||||
return
|
||||
|
||||
if(leaping || stat || buckled || lying)
|
||||
if(pounce_cooldown > world.time)
|
||||
to_chat(src, "<span class='alertalien'>You are too fatigued to pounce right now!</span>")
|
||||
return
|
||||
|
||||
if(!has_gravity() || !A.has_gravity())
|
||||
@@ -66,6 +66,7 @@
|
||||
if(!leaping)
|
||||
return ..()
|
||||
|
||||
pounce_cooldown = world.time + pounce_cooldown_time
|
||||
if(A)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
@@ -83,7 +84,6 @@
|
||||
Knockdown(40, 1, 1)
|
||||
|
||||
toggle_leap(0)
|
||||
pounce_cooldown = world.time + pounce_cooldown_time
|
||||
else if(A.density && !A.CanPass(src))
|
||||
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='alertalien'>[src] smashes into [A]!</span>")
|
||||
Knockdown(40, 1, 1)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src))
|
||||
AddAbility(new /obj/effect/proc_holder/alien/royal/praetorian/evolve())
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/royal/praetorian/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/alien/plasmavessel/large
|
||||
@@ -48,4 +48,4 @@
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='notice'>We already have an alive queen.</span>")
|
||||
return 0
|
||||
return 0
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/Initialize()
|
||||
AddAbility(new /obj/effect/proc_holder/alien/sneak)
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/alien/plasmavessel
|
||||
@@ -18,4 +18,4 @@
|
||||
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/movement_delay()
|
||||
. = ..()
|
||||
. = ..()
|
||||
@@ -18,12 +18,13 @@
|
||||
var/drooling = 0 //For Neruotoxic spit overlays
|
||||
bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien,
|
||||
/obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien)
|
||||
devourable = TRUE
|
||||
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/humanoid/Initialize()
|
||||
AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null))
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/movement_delay()
|
||||
. = ..()
|
||||
@@ -42,7 +43,7 @@
|
||||
<HR>"}
|
||||
for(var/i in 1 to held_items.len)
|
||||
var/obj/item/I = get_item_for_held_index(i)
|
||||
dat += "<BR><B>[get_held_index_name(i)]:</B><A href='?src=\ref[src];item=[slot_hands];hand_index=[i]'>[(I && !(I.flags_1 & ABSTRACT_1)) ? I : "<font color=grey>Empty</font>"]</a>"
|
||||
dat += "<BR><B>[get_held_index_name(i)]:</B><A href='?src=\ref[src];item=[slot_hands];hand_index=[i]'>[(I && !(I.flags_1 & ABSTRACT_1)) ? I : "<font color=grey>Empty</font>"]</a>"
|
||||
dat += "<BR><A href='?src=\ref[src];pouches=1'>Empty Pouches</A>"
|
||||
|
||||
if(handcuffed)
|
||||
@@ -120,4 +121,4 @@
|
||||
/mob/living/carbon/alien/humanoid/check_breath(datum/gas_mixture/breath)
|
||||
if(breath && breath.total_moles() > 0 && !sneaking)
|
||||
playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5)
|
||||
..()
|
||||
..()
|
||||
@@ -4,7 +4,7 @@
|
||||
icon_state = "larva0"
|
||||
pass_flags = PASSTABLE | PASSMOB
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
density = FALSE
|
||||
density = FALSE
|
||||
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
AddAbility(new/obj/effect/proc_holder/alien/hide(null))
|
||||
AddAbility(new/obj/effect/proc_holder/alien/larva_evolve(null))
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/larva/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny
|
||||
@@ -65,4 +65,4 @@
|
||||
|
||||
/mob/living/carbon/alien/larva/stripPanelEquip(obj/item/what, mob/who)
|
||||
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return
|
||||
return
|
||||
@@ -297,11 +297,14 @@
|
||||
|
||||
|
||||
/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
|
||||
if(I.being_removed)
|
||||
to_chat(src, "<span class='warning'>You're already attempting to remove [I]!</span>")
|
||||
return
|
||||
I.being_removed = TRUE
|
||||
breakouttime = I.breakouttime
|
||||
var/displaytime = breakouttime / 600
|
||||
if(!cuff_break)
|
||||
visible_message("<span class='warning'>[src] attempts to remove [I]!</span>")
|
||||
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [displaytime] minutes and you need to stand still.)</span>")
|
||||
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)</span>")
|
||||
if(do_after(src, breakouttime, 0, target = src))
|
||||
clear_cuffs(I, cuff_break)
|
||||
else
|
||||
@@ -318,6 +321,7 @@
|
||||
|
||||
else if(cuff_break == INSTANT_CUFFBREAK)
|
||||
clear_cuffs(I, cuff_break)
|
||||
I.being_removed = FALSE
|
||||
|
||||
/mob/living/carbon/proc/uncuff()
|
||||
if (handcuffed)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
/mob/living/carbon/human/dummy
|
||||
real_name = "Test Dummy"
|
||||
status_flags = GODMODE|CANPUSH
|
||||
var/in_use = FALSE
|
||||
|
||||
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
|
||||
/mob/living/carbon/human/dummy/Destroy()
|
||||
in_use = FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/dummy/Life()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
QDEL_LIST(contents)
|
||||
cut_overlays(TRUE)
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||
|
||||
/proc/generate_or_wait_for_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return new /mob/living/carbon/human/dummy
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotkey]
|
||||
if(istype(D))
|
||||
UNTIL(!D.in_use)
|
||||
else
|
||||
pass()
|
||||
if(QDELETED(D))
|
||||
D = new
|
||||
GLOB.human_dummy_list[slotkey] = D
|
||||
D.in_use = TRUE
|
||||
return D
|
||||
|
||||
/proc/unset_busy_human_dummy(slotnumber)
|
||||
if(!slotnumber)
|
||||
return
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
||||
if(istype(D))
|
||||
D.wipe_state()
|
||||
D.in_use = FALSE
|
||||
@@ -5,15 +5,6 @@
|
||||
icon = 'icons/mob/human.dmi'
|
||||
icon_state = "caucasian_m"
|
||||
|
||||
/mob/living/carbon/human/dummy
|
||||
real_name = "Test Dummy"
|
||||
status_flags = GODMODE|CANPUSH
|
||||
|
||||
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
|
||||
/mob/living/carbon/human/dummy/Life()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/Initialize()
|
||||
verbs += /mob/living/proc/mob_sleep
|
||||
verbs += /mob/living/proc/lay_down
|
||||
@@ -244,7 +235,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
|
||||
return
|
||||
var/time_taken = I.embedded_unsafe_removal_time*I.w_class
|
||||
usr.visible_message("<span class='warning'>[usr] attempts to remove [I] from their [L.name].</span>","<span class='notice'>You attempt to remove [I] from your [L.name]... (It will take [time_taken/10] seconds.)</span>")
|
||||
usr.visible_message("<span class='warning'>[usr] attempts to remove [I] from their [L.name].</span>","<span class='notice'>You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
||||
if(do_after(usr, time_taken, needhand = 1, target = src))
|
||||
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
|
||||
return
|
||||
|
||||
@@ -87,12 +87,16 @@
|
||||
/// SNPC voice handling
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/loadVoice()
|
||||
var/json_file = file("data/npc_saves/snpc.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
knownStrings = json["knownStrings"]
|
||||
if(fexists("data/npc_saves/snpc.sav"))
|
||||
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
|
||||
S["knownStrings"] >> knownStrings
|
||||
fdel(S)
|
||||
else
|
||||
var/json_file = file("data/npc_saves/snpc.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
knownStrings = json["knownStrings"]
|
||||
if(isnull(knownStrings))
|
||||
knownStrings = list()
|
||||
|
||||
@@ -1618,4 +1622,4 @@
|
||||
TRAITS |= TRAIT_ROBUST
|
||||
TRAITS |= TRAIT_SMART
|
||||
faction += "bot_power"
|
||||
. = ..()
|
||||
. = ..()
|
||||
@@ -236,6 +236,10 @@
|
||||
/mob/living/carbon/human/head_update(obj/item/I, forced)
|
||||
if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || forced)
|
||||
update_hair()
|
||||
else
|
||||
var/obj/item/clothing/C = I
|
||||
if(istype(C) && C.dynamic_hair_suffix)
|
||||
update_hair()
|
||||
if(I.flags_inv & HIDEEYES || forced)
|
||||
update_inv_glasses()
|
||||
if(I.flags_inv & HIDEEARS || forced)
|
||||
|
||||
@@ -111,6 +111,10 @@
|
||||
randname += " [pick(GLOB.last_names)]"
|
||||
|
||||
return randname
|
||||
|
||||
//Called when cloning, copies some vars that should be kept
|
||||
/datum/species/proc/copy_properties_from(datum/species/old_species)
|
||||
return
|
||||
|
||||
|
||||
//Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced.
|
||||
@@ -1437,7 +1441,7 @@
|
||||
H.adjust_blurriness(10)
|
||||
|
||||
if(prob(I.force + ((100 - H.health)/2)) && H != user)
|
||||
SSticker.mode.remove_revolutionary(H.mind)
|
||||
SSticker.mode.remove_revolutionary(H.mind, FALSE, user)
|
||||
|
||||
if(bloody) //Apply blood
|
||||
if(H.wear_mask)
|
||||
@@ -1721,4 +1725,4 @@
|
||||
|
||||
#undef COLD_DAMAGE_LEVEL_1
|
||||
#undef COLD_DAMAGE_LEVEL_2
|
||||
#undef COLD_DAMAGE_LEVEL_3
|
||||
#undef COLD_DAMAGE_LEVEL_3
|
||||
@@ -2,8 +2,10 @@
|
||||
name = "Abductor"
|
||||
id = "abductor"
|
||||
say_mod = "gibbers"
|
||||
sexes = 0
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOBREATH,VIRUSIMMUNE,NOGUNS,NOHUNGER)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
var/scientist = 0 // vars to not pollute spieces list with castes
|
||||
var/team = 1
|
||||
var/scientist = FALSE // vars to not pollute spieces list with castes
|
||||
|
||||
/datum/species/abductor/copy_properties_from(datum/species/abductor/old_species)
|
||||
scientist = old_species.scientist
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
if(H.dna && H.dna.species &&((H.dna.features["wings"] != "Angel") && ("wings" in H.dna.species.mutant_bodyparts)))
|
||||
H.dna.features["wings"] = "Angel"
|
||||
H.update_body()
|
||||
if(ishuman(H)&& !fly)
|
||||
if(ishuman(H) && !fly)
|
||||
fly = new
|
||||
fly.Grant(H)
|
||||
|
||||
|
||||
/datum/species/angel/on_species_loss(mob/living/carbon/human/H)
|
||||
if(fly)
|
||||
fly.Remove(H)
|
||||
@@ -66,7 +65,7 @@
|
||||
/datum/action/innate/flight
|
||||
name = "Toggle Flight"
|
||||
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_STUN
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "flight"
|
||||
|
||||
/datum/action/innate/flight/Activate()
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
name = "Plasteel Golem"
|
||||
id = "plasteel golem"
|
||||
fixed_mut_color = "bbb"
|
||||
stunmod = 0.40
|
||||
stunmod = 0.4
|
||||
punchdamagelow = 12
|
||||
punchdamagehigh = 21
|
||||
punchstunthreshold = 18 //still 40% stun chance
|
||||
@@ -436,6 +436,7 @@
|
||||
name = "Unstable Teleport"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "jaunt"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
var/cooldown = 150
|
||||
var/last_teleport = 0
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
exotic_blood = "slimejelly"
|
||||
damage_overlay_type = ""
|
||||
var/datum/action/innate/regenerate_limbs/regenerate_limbs
|
||||
toxic_food = NONE
|
||||
liked_food = MEAT
|
||||
|
||||
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
|
||||
@@ -60,6 +59,7 @@
|
||||
name = "Regenerate Limbs"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimeheal"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/regenerate_limbs/IsAvailable()
|
||||
@@ -128,7 +128,7 @@
|
||||
/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
..()
|
||||
if(ishuman(C))
|
||||
/* slime_split = new
|
||||
/* slime_split = new
|
||||
slime_split.Grant(C)
|
||||
swap_body = new
|
||||
swap_body.Grant(C) */
|
||||
@@ -140,6 +140,10 @@
|
||||
|
||||
C.faction |= "slime"
|
||||
|
||||
//If you're cloned you get your body pool back
|
||||
/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
|
||||
bodies = old_species.bodies
|
||||
|
||||
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
if(prob(5))
|
||||
@@ -154,6 +158,7 @@
|
||||
name = "Split Body"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimesplit"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/split_body/IsAvailable()
|
||||
@@ -220,6 +225,7 @@
|
||||
name = "Swap Body"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimeswap"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/swap_body/Activate()
|
||||
@@ -326,4 +332,4 @@
|
||||
M.transfer_to(dupe)
|
||||
dupe.visible_message("<span class='notice'>[dupe] blinks and looks \
|
||||
around.</span>",
|
||||
"<span class='notice'>...and move this one instead.</span>")
|
||||
"<span class='notice'>...and move this one instead.</span>")
|
||||
@@ -30,7 +30,7 @@
|
||||
burnmod = 1.5
|
||||
blacklisted = TRUE
|
||||
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform, slot_s_store)
|
||||
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER,NO_UNDERWEAR,NOHUNGER)
|
||||
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOGUNS,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NODISMEMBER,NO_UNDERWEAR,NOHUNGER,NO_DNA_COPY,NOTRANSSTING)
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/nightmare
|
||||
var/obj/effect/proc_holder/spell/targeted/shadowwalk/shadowwalk
|
||||
|
||||
|
||||
@@ -1,121 +1,121 @@
|
||||
/datum/species/synth
|
||||
name = "Synth" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
species_traits = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER) //all of these + whatever we inherit from the real species
|
||||
dangerous_existence = 1
|
||||
blacklisted = 1
|
||||
meat = null
|
||||
damage_overlay_type = "synth"
|
||||
limbs_id = "synth"
|
||||
var/list/initial_species_traits = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER) //for getting these values back for assume_disguise()
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchdamagelow = 10
|
||||
punchdamagehigh = 19
|
||||
punchstunthreshold = 14 //about 50% chance to stun
|
||||
disguise_fail_health = 50
|
||||
|
||||
/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
assume_disguise(old_species, H)
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "synthflesh")
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
sexes = S.sexes
|
||||
species_traits = initial_species_traits.Copy()
|
||||
species_traits.Add(S.species_traits)
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
species_traits = initial_species_traits.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
limbs_id = "synth"
|
||||
use_skintones = 0
|
||||
sexes = 0
|
||||
fixed_mut_color = ""
|
||||
hair_color = ""
|
||||
|
||||
for(var/X in H.bodyparts) //propagates the damage_overlay changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
H.update_body_parts() //to update limb icon cache with the new damage overlays
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/get_spans()
|
||||
if(fake_species)
|
||||
return fake_species.get_spans()
|
||||
return list()
|
||||
|
||||
|
||||
/datum/species/synth/handle_speech(message, mob/living/carbon/human/H)
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
return fake_species.handle_speech(message,H)
|
||||
else
|
||||
return ..()
|
||||
else
|
||||
/datum/species/synth
|
||||
name = "Synth" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
species_traits = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER) //all of these + whatever we inherit from the real species
|
||||
dangerous_existence = 1
|
||||
blacklisted = 1
|
||||
meat = null
|
||||
damage_overlay_type = "synth"
|
||||
limbs_id = "synth"
|
||||
var/list/initial_species_traits = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER,NO_DNA_COPY) //for getting these values back for assume_disguise()
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchdamagelow = 10
|
||||
punchdamagehigh = 19
|
||||
punchstunthreshold = 14 //about 50% chance to stun
|
||||
disguise_fail_health = 50
|
||||
|
||||
/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
assume_disguise(old_species, H)
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "synthflesh")
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
sexes = S.sexes
|
||||
species_traits = initial_species_traits.Copy()
|
||||
species_traits.Add(S.species_traits)
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
species_traits = initial_species_traits.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
limbs_id = "synth"
|
||||
use_skintones = 0
|
||||
sexes = 0
|
||||
fixed_mut_color = ""
|
||||
hair_color = ""
|
||||
|
||||
for(var/X in H.bodyparts) //propagates the damage_overlay changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
H.update_body_parts() //to update limb icon cache with the new damage overlays
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/get_spans()
|
||||
if(fake_species)
|
||||
return fake_species.get_spans()
|
||||
return list()
|
||||
|
||||
|
||||
/datum/species/synth/handle_speech(message, mob/living/carbon/human/H)
|
||||
if(H.health > disguise_fail_health)
|
||||
if(fake_species)
|
||||
return fake_species.handle_speech(message,H)
|
||||
else
|
||||
return ..()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define REGENERATION_DELAY 60 // After taking damage, how long it takes for automatic regeneration to begin
|
||||
|
||||
/datum/species/zombie
|
||||
// 1spooky
|
||||
name = "High Functioning Zombie"
|
||||
@@ -6,7 +8,7 @@
|
||||
sexes = 0
|
||||
blacklisted = 1
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
|
||||
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOBLOOD,RADIMMUNE,NOZOMBIE,EASYDISMEMBER,EASYLIMBATTACHMENT)
|
||||
species_traits = list(NOBREATH,RESISTCOLD,RESISTPRESSURE,NOBLOOD,RADIMMUNE,NOZOMBIE,EASYDISMEMBER,EASYLIMBATTACHMENT,NOTRANSSTING)
|
||||
mutant_organs = list(/obj/item/organ/tongue/zombie)
|
||||
var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg')
|
||||
disliked_food = NONE
|
||||
@@ -20,14 +22,21 @@
|
||||
armor = 20 // 120 damage to KO a zombie, which kills it
|
||||
speedmod = 2
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
|
||||
var/regen_cooldown = 0
|
||||
|
||||
/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount)
|
||||
. = min(2, amount)
|
||||
|
||||
/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(.)
|
||||
regen_cooldown = world.time + REGENERATION_DELAY
|
||||
|
||||
/datum/species/zombie/infectious/spec_life(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW
|
||||
C.heal_overall_damage(4,4)
|
||||
if(regen_cooldown < world.time)
|
||||
C.heal_overall_damage(4,4)
|
||||
if(prob(4))
|
||||
playsound(C, pick(spooks), 50, TRUE, 10)
|
||||
if(C.InCritical())
|
||||
@@ -56,3 +65,5 @@
|
||||
sexes = 0
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
|
||||
mutant_organs = list(/obj/item/organ/tongue/zombie)
|
||||
|
||||
#undef REGENERATION_DELAY
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
emote("collapse")
|
||||
Knockdown(200)
|
||||
to_chat(src, "<span class='danger'>You feel weak.</span>")
|
||||
if(radiation > 30 && prob((radiation - 30) * (radiation - 30) * 0.00002))
|
||||
if(radiation > 30 && prob((radiation - 30) * (radiation - 30) * 0.0002))
|
||||
gorillize()
|
||||
return
|
||||
switch(radiation)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/ancestor_chain = 1
|
||||
var/relic_hat //Note: these two are paths
|
||||
var/relic_mask
|
||||
var/memory_saved = 0
|
||||
var/memory_saved = FALSE
|
||||
var/list/pet_monkey_names = list("Pun Pun", "Bubbles", "Mojo", "George", "Darwin", "Aldo", "Caeser", "Kanzi", "Kong", "Terk", "Grodd", "Mala", "Bojangles", "Coco", "Able", "Baker", "Scatter", "Norbit", "Travis")
|
||||
var/list/rare_pet_monkey_names = list("Professor Bobo", "Deempisi's Revenge", "Furious George", "King Louie", "Dr. Zaius", "Jimmy Rustles", "Dinner", "Lanky")
|
||||
|
||||
@@ -32,25 +32,33 @@
|
||||
equip_to_slot_or_del(new relic_mask, slot_wear_mask)
|
||||
|
||||
/mob/living/carbon/monkey/punpun/Life()
|
||||
if(SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory(0)
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory(FALSE, FALSE)
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
|
||||
/mob/living/carbon/monkey/punpun/death(gibbed)
|
||||
if(!memory_saved || gibbed)
|
||||
Write_Memory(1,gibbed)
|
||||
if(!memory_saved)
|
||||
Write_Memory(TRUE, gibbed)
|
||||
..()
|
||||
|
||||
/mob/living/carbon/monkey/punpun/proc/Read_Memory()
|
||||
var/json_file = file("data/npc_saves/Punpun.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
ancestor_name = json["ancestor_name"]
|
||||
ancestor_chain = json["ancestor_chain"]
|
||||
relic_hat = json["relic_hat"]
|
||||
relic_mask = json["relic_hat"]
|
||||
if(fexists("data/npc_saves/Punpun.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Punpun.sav")
|
||||
S["ancestor_name"] >> ancestor_name
|
||||
S["ancestor_chain"] >> ancestor_chain
|
||||
S["relic_hat"] >> relic_hat
|
||||
S["relic_mask"] >> relic_mask
|
||||
fdel("data/npc_saves/Punpun.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Punpun.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
ancestor_name = json["ancestor_name"]
|
||||
ancestor_chain = json["ancestor_chain"]
|
||||
relic_hat = json["relic_hat"]
|
||||
relic_mask = json["relic_hat"]
|
||||
|
||||
/mob/living/carbon/monkey/punpun/proc/Write_Memory(dead, gibbed)
|
||||
var/json_file = file("data/npc_saves/Punpun.json")
|
||||
@@ -60,14 +68,10 @@
|
||||
file_data["ancestor_chain"] = null
|
||||
file_data["relic_hat"] = null
|
||||
file_data["relic_mask"] = null
|
||||
if(dead)
|
||||
file_data["ancestor_name"] = ancestor_name
|
||||
file_data["ancestor_chain"] = ancestor_chain + 1
|
||||
file_data["relic_hat"] = head ? head.type : null
|
||||
file_data["relic_mask"] = wear_mask ? wear_mask.type : null
|
||||
if(!ancestor_name)
|
||||
file_data["ancestor_name"] = name
|
||||
else
|
||||
file_data["ancestor_name"] = ancestor_name ? ancestor_name : name
|
||||
file_data["ancestor_chain"] = dead ? ancestor_chain + 1 : ancestor_chain
|
||||
file_data["relic_hat"] = head ? head.type : null
|
||||
file_data["relic_mask"] = wear_mask ? wear_mask.type : null
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
if(!dead)
|
||||
memory_saved = 1
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
@@ -544,11 +544,14 @@
|
||||
if(!force_moving)
|
||||
..(pressure_difference, direction, pressure_resistance_prob_delta)
|
||||
|
||||
/mob/living/proc/can_resist()
|
||||
return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE))
|
||||
|
||||
/mob/living/verb/resist()
|
||||
set name = "Resist"
|
||||
set category = "IC"
|
||||
|
||||
if(!isliving(src) || next_move > world.time || incapacitated(ignore_restraints = 1))
|
||||
if(!can_resist())
|
||||
return
|
||||
changeNext_move(CLICK_CD_RESIST)
|
||||
|
||||
@@ -709,30 +712,24 @@
|
||||
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life().
|
||||
|
||||
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
|
||||
var/loc_temp = T0C
|
||||
if(istype(loc, /obj/mecha))
|
||||
var/obj/mecha/M = loc
|
||||
loc_temp = M.return_temperature()
|
||||
|
||||
else if(istype(loc, /obj/structure/transit_tube_pod))
|
||||
loc_temp = environment.temperature
|
||||
|
||||
var/loc_temp = environment ? environment.temperature : T0C
|
||||
if(isobj(loc))
|
||||
var/obj/oloc = loc
|
||||
var/obj_temp = oloc.return_temperature()
|
||||
if(obj_temp != null)
|
||||
loc_temp = obj_temp
|
||||
/* if(ismob(loc))
|
||||
var/mob/living/mloc = loc
|
||||
var/mob_temp = mloc.return_temperature()
|
||||
if(mloc == DEAD)
|
||||
loc_temp = get_turf(loc) //wew
|
||||
else
|
||||
loc_temp = mob_temp
|
||||
*/
|
||||
//just gunna ommit this for now, it's on the 'to figgur out' list.
|
||||
else if(isspaceturf(get_turf(src)))
|
||||
var/turf/heat_turf = get_turf(src)
|
||||
loc_temp = heat_turf.temperature
|
||||
|
||||
else if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
|
||||
var/obj/machinery/atmospherics/components/unary/cryo_cell/C = loc
|
||||
var/datum/gas_mixture/G = C.AIR1
|
||||
|
||||
if(G.total_moles() < 10)
|
||||
loc_temp = environment.temperature
|
||||
else
|
||||
loc_temp = G.temperature
|
||||
|
||||
else
|
||||
loc_temp = environment.temperature
|
||||
|
||||
return loc_temp
|
||||
|
||||
/mob/living/proc/get_standard_pixel_x_offset(lying = 0)
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
/mob/living/silicon/ai/verb/pick_icon()
|
||||
set category = "AI Commands"
|
||||
set name = "Set AI Core Display"
|
||||
if(stat || aiRestorePowerRoutine)
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
//if(icon_state == initial(icon_state))
|
||||
@@ -308,16 +308,15 @@
|
||||
onclose(src, "airoster")
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_call_shuttle()
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = src
|
||||
if(AI.control_disabled)
|
||||
to_chat(usr, "Wireless control is disabled!")
|
||||
return
|
||||
if(control_disabled)
|
||||
to_chat(usr, "<span class='warning'>Wireless control is disabled!</span>")
|
||||
return
|
||||
|
||||
var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text
|
||||
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
if(trim(reason))
|
||||
SSshuttle.requestEvac(src, reason)
|
||||
|
||||
@@ -335,8 +334,8 @@
|
||||
set name = "Toggle Floor Bolts"
|
||||
if(!isturf(loc)) // if their location isn't a turf
|
||||
return // stop
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
anchored = !anchored // Toggles the anchor
|
||||
|
||||
to_chat(src, "<b>You are now [anchored ? "" : "un"]anchored.</b>")
|
||||
@@ -347,21 +346,16 @@
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_cancel_call()
|
||||
set category = "Malfunction"
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = src
|
||||
if(AI.control_disabled)
|
||||
to_chat(src, "Wireless control is disabled!")
|
||||
return
|
||||
if(control_disabled)
|
||||
to_chat(src, "<span class='warning'>Wireless control is disabled!</span>")
|
||||
return
|
||||
SSshuttle.cancelEvac(src)
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/restrained(ignore_grab)
|
||||
. = 0
|
||||
|
||||
/mob/living/silicon/ai/Topic(href, href_list)
|
||||
if(usr != src)
|
||||
if(usr != src || incapacitated())
|
||||
return
|
||||
..()
|
||||
if (href_list["mach_close"])
|
||||
@@ -385,11 +379,10 @@
|
||||
//Carn: holopad requests
|
||||
if(href_list["jumptoholopad"])
|
||||
var/obj/machinery/holopad/H = locate(href_list["jumptoholopad"])
|
||||
if(stat == CONSCIOUS)
|
||||
if(H)
|
||||
H.attack_ai(src) //may as well recycle
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Unable to locate the holopad.</span>")
|
||||
if(H)
|
||||
H.attack_ai(src) //may as well recycle
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Unable to locate the holopad.</span>")
|
||||
if(href_list["track"])
|
||||
var/string = href_list["track"]
|
||||
trackable_mobs()
|
||||
@@ -434,9 +427,6 @@
|
||||
if(!GLOB.cameranet.checkCameraVis(M))
|
||||
to_chat(src, "<span class='warning'>Exosuit is no longer near active cameras.</span>")
|
||||
return
|
||||
if(lacks_power())
|
||||
to_chat(src, "<span class='warning'>You're depowered!</span>")
|
||||
return
|
||||
if(!isturf(loc))
|
||||
to_chat(src, "<span class='warning'>You aren't in your core!</span>")
|
||||
return
|
||||
@@ -449,8 +439,8 @@
|
||||
if(!tracking)
|
||||
cameraFollow = null
|
||||
|
||||
if (!C || stat == DEAD) //C.can_use())
|
||||
return 0
|
||||
if (!C)
|
||||
return FALSE
|
||||
|
||||
if(!src.eyeobj)
|
||||
view_core()
|
||||
@@ -459,17 +449,17 @@
|
||||
eyeobj.setLoc(get_turf(C))
|
||||
//machine = src
|
||||
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/ai/proc/botcall()
|
||||
set category = "AI Commands"
|
||||
set name = "Access Robot Control"
|
||||
set desc = "Wirelessly control various automatic robots."
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
if(control_disabled)
|
||||
to_chat(src, "Wireless communication is disabled.")
|
||||
to_chat(src, "<span class='warning'>Wireless control is disabled.</span>")
|
||||
return
|
||||
var/turf/ai_current_turf = get_turf(src)
|
||||
var/ai_Zlevel = ai_current_turf.z
|
||||
@@ -522,8 +512,6 @@
|
||||
/mob/living/silicon/ai/triggerAlarm(class, area/A, O, obj/alarmsource)
|
||||
if(alarmsource.z != z)
|
||||
return
|
||||
if (stat == 2)
|
||||
return 1
|
||||
var/list/L = alarms[class]
|
||||
for (var/I in L)
|
||||
if (I == A.name)
|
||||
@@ -585,8 +573,8 @@
|
||||
cameraFollow = null
|
||||
var/cameralist[0]
|
||||
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
var/mob/living/silicon/ai/U = usr
|
||||
|
||||
@@ -629,8 +617,8 @@
|
||||
set category = "AI Commands"
|
||||
set name = "AI Status"
|
||||
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow")
|
||||
var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
|
||||
for (var/M in GLOB.ai_status_displays) //change status of displays
|
||||
@@ -652,8 +640,8 @@
|
||||
set desc = "Change the default hologram available to AI to something else."
|
||||
set category = "AI Commands"
|
||||
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
var/input
|
||||
switch(alert("Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?",,"Crew Member","Unique","Animal"))
|
||||
if("Crew Member")
|
||||
@@ -729,9 +717,6 @@
|
||||
apc.malfvacate()
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light()
|
||||
if(stat != CONSCIOUS)
|
||||
return
|
||||
|
||||
camera_light_on = !camera_light_on
|
||||
|
||||
if (!camera_light_on)
|
||||
@@ -755,7 +740,7 @@
|
||||
var/list/obj/machinery/camera/visible = list()
|
||||
for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
|
||||
for (var/obj/machinery/camera/C in CC.cameras)
|
||||
if (!C.can_use() || get_dist(C, eyeobj) > 7)
|
||||
if (!C.can_use() || get_dist(C, eyeobj) > 7 || !C.internal_light)
|
||||
continue
|
||||
visible |= C
|
||||
|
||||
@@ -774,8 +759,8 @@
|
||||
set desc = "Allows you to change settings of your radio."
|
||||
set category = "AI Commands"
|
||||
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
to_chat(src, "Accessing Subspace Transceiver control...")
|
||||
if (radio)
|
||||
@@ -790,8 +775,8 @@
|
||||
set desc = "Modify the default radio setting for your automatic announcements."
|
||||
set category = "AI Commands"
|
||||
|
||||
if(stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
set_autosay()
|
||||
|
||||
/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
|
||||
@@ -818,17 +803,22 @@
|
||||
/mob/living/silicon/ai/can_buckle()
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close = 0)
|
||||
if(stat)
|
||||
return
|
||||
/mob/living/silicon/ai/incapacitated()
|
||||
if(aiRestorePowerRoutine)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close = FALSE)
|
||||
if(control_disabled || incapacitated())
|
||||
return FALSE
|
||||
if(be_close && !in_range(M, src))
|
||||
return
|
||||
return FALSE
|
||||
//stop AIs from leaving windows open and using then after they lose vision
|
||||
//apc_override is needed here because AIs use their own APC when powerless
|
||||
//get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera
|
||||
if(M && GLOB.cameranet && !GLOB.cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
|
||||
return
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
raw_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
|
||||
@@ -931,8 +921,10 @@
|
||||
set category = "AI Commands"
|
||||
set name = "Deploy to Shell"
|
||||
|
||||
if(stat || lacks_power() || control_disabled)
|
||||
to_chat(src, "<span class='danger'>Wireless networking module is offline.</span>")
|
||||
if(incapacitated())
|
||||
return
|
||||
if(control_disabled)
|
||||
to_chat(src, "<span class='warning'>Wireless networking module is offline.</span>")
|
||||
return
|
||||
|
||||
var/list/possible = list()
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
diff a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm (rejected hunks)
|
||||
@@ -35,9 +35,9 @@
|
||||
if(nuking)
|
||||
set_security_level("red")
|
||||
nuking = FALSE
|
||||
- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
|
||||
+ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
|
||||
P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
|
||||
- P.nuke_warning = FALSE
|
||||
+ P.alert = FALSE
|
||||
|
||||
if(doomsday_device)
|
||||
doomsday_device.timing = FALSE
|
||||
@@ -114,9 +114,6 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
//to_chat(world, "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]")
|
||||
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
@@ -161,4 +158,4 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
|
||||
if(cameranet.chunkGenerated(x, y, z))
|
||||
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
|
||||
usr.client.debug_variables(chunk)
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -106,8 +106,8 @@
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
return !config.silent_ai
|
||||
|
||||
/mob/living/silicon/ai/radio(message, message_mode, list/spans, language)
|
||||
if(!radio_enabled || aiRestorePowerRoutine || stat) //AI cannot speak if radio is disabled (via intellicard) or depowered.
|
||||
if(incapacitated())
|
||||
return FALSE
|
||||
if(!radio_enabled) //AI cannot speak if radio is disabled (via intellicard) or depowered.
|
||||
to_chat(src, "<span class='danger'>Your radio transmitter is offline!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
..()
|
||||
|
||||
/mob/living/silicon/ai/get_message_mode(message)
|
||||
@@ -71,8 +73,8 @@
|
||||
set desc = "Display a list of vocal words to announce to the crew."
|
||||
set category = "AI Commands"
|
||||
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.<BR> \
|
||||
<UL><LI>You can also click on the word to preview it.</LI>\
|
||||
@@ -95,7 +97,7 @@
|
||||
/mob/living/silicon/ai/proc/announcement()
|
||||
var/static/announcing_vox = 0 // Stores the time of the last announcement
|
||||
if(announcing_vox > world.time)
|
||||
to_chat(src, "<span class='notice'>Please wait [round((announcing_vox - world.time) / 10)] seconds.</span>")
|
||||
to_chat(src, "<span class='notice'>Please wait [DisplayTimeText(announcing_vox - world.time)].</span>")
|
||||
return
|
||||
|
||||
var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text
|
||||
@@ -105,11 +107,11 @@
|
||||
if(!message || announcing_vox > world.time)
|
||||
return
|
||||
|
||||
if(stat != CONSCIOUS)
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
if(control_disabled)
|
||||
to_chat(src, "<span class='notice'>Wireless interface disabled, unable to interact with announcement PA.</span>")
|
||||
to_chat(src, "<span class='warning'>Wireless interface disabled, unable to interact with announcement PA.</span>")
|
||||
return
|
||||
|
||||
var/list/words = splittext(trim(message), " ")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/mob/living/silicon/Login()
|
||||
if(mind && SSticker.mode)
|
||||
SSticker.mode.remove_cultist(mind, 0, 0)
|
||||
SSticker.mode.remove_revolutionary(mind, 0)
|
||||
SSticker.mode.remove_revolutionary(mind, TRUE)
|
||||
..()
|
||||
|
||||
@@ -127,11 +127,11 @@
|
||||
if("buy")
|
||||
if(subscreen == 1)
|
||||
var/target = href_list["buy"]
|
||||
if(available_software.Find(target))
|
||||
if(available_software.Find(target) && !software.Find(target))
|
||||
var/cost = src.available_software[target]
|
||||
if(ram >= cost)
|
||||
ram -= cost
|
||||
software.Add(target)
|
||||
ram -= cost
|
||||
else
|
||||
temp = "Insufficient RAM available."
|
||||
else
|
||||
@@ -248,6 +248,7 @@
|
||||
medHUD = !medHUD
|
||||
if(medHUD)
|
||||
add_med_hud()
|
||||
|
||||
else
|
||||
var/datum/atom_hud/med = GLOB.huds[med_hud]
|
||||
med.remove_hud_from(src)
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
/mob/living/silicon/robot/Login()
|
||||
..()
|
||||
regenerate_icons()
|
||||
show_laws(0)
|
||||
if(mind)
|
||||
SSticker.mode.remove_revolutionary(mind)
|
||||
/mob/living/silicon/robot/Login()
|
||||
..()
|
||||
regenerate_icons()
|
||||
show_laws(0)
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
builtInCamera = new (src)
|
||||
builtInCamera.c_tag = real_name
|
||||
builtInCamera.network = list("SS13")
|
||||
builtInCamera.internal_light = FALSE
|
||||
if(wires.is_cut(WIRE_CAMERA))
|
||||
builtInCamera.status = 0
|
||||
module = new /obj/item/robot_module(src)
|
||||
|
||||
@@ -307,6 +307,7 @@
|
||||
/obj/item/device/analyzer,
|
||||
/obj/item/device/assembly/signaler/cyborg,
|
||||
/obj/item/areaeditor/blueprints/cyborg,
|
||||
/obj/item/device/electroadaptive_pseudocircuit,
|
||||
/obj/item/stack/sheet/metal/cyborg,
|
||||
/obj/item/stack/sheet/glass/cyborg,
|
||||
/obj/item/stack/sheet/rglass/cyborg,
|
||||
@@ -679,4 +680,4 @@
|
||||
/datum/robot_energy_storage/beacon
|
||||
max_energy = 30
|
||||
recharge_rate = 1
|
||||
name = "Marker Beacon Storage"
|
||||
name = "Marker Beacon Storage"
|
||||
@@ -1,19 +0,0 @@
|
||||
diff a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm (rejected hunks)
|
||||
@@ -519,7 +519,7 @@
|
||||
/obj/item/weapon/gun/ballistic/revolver/grenadelauncher/cyborg,
|
||||
/obj/item/weapon/card/emag,
|
||||
/obj/item/weapon/crowbar/cyborg,
|
||||
- /obj/item/weapon/pinpointer/syndicate/cyborg)
|
||||
+ /obj/item/weapon/pinpointer/syndicate_cyborg)
|
||||
|
||||
ratvar_modules = list(
|
||||
/obj/item/clockwork/slab/cyborg/security,
|
||||
@@ -545,7 +545,7 @@
|
||||
/obj/item/roller/robo,
|
||||
/obj/item/weapon/card/emag,
|
||||
/obj/item/weapon/crowbar/cyborg,
|
||||
- /obj/item/weapon/pinpointer/syndicate/cyborg,
|
||||
+ /obj/item/weapon/pinpointer/syndicate_cyborg,
|
||||
/obj/item/stack/medical/gauze/cyborg,
|
||||
/obj/item/weapon/gun/medbeam)
|
||||
ratvar_modules = list(
|
||||
@@ -856,6 +856,7 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
bot_name = name
|
||||
name = paicard.pai.name
|
||||
faction = user.faction.Copy()
|
||||
language_holder = paicard.pai.language_holder.copy(src)
|
||||
add_logs(user, paicard.pai, "uploaded to [bot_name],")
|
||||
return 1
|
||||
else
|
||||
|
||||
@@ -432,7 +432,6 @@
|
||||
return
|
||||
if(on)
|
||||
var/speed = (wires.is_cut(WIRE_MOTOR1) ? 0 : 1) + (wires.is_cut(WIRE_MOTOR2) ? 0 : 2)
|
||||
//to_chat(world, "speed: [speed]")
|
||||
var/num_steps = 0
|
||||
switch(speed)
|
||||
if(0)
|
||||
@@ -474,8 +473,6 @@
|
||||
path -= next
|
||||
return
|
||||
if(isturf(next))
|
||||
//to_chat(world, "at ([x],[y]) moving to ([next.x],[next.y])")
|
||||
|
||||
if(bloodiness)
|
||||
var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
|
||||
if(blood_DNA && blood_DNA.len)
|
||||
@@ -497,7 +494,6 @@
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(cell) cell.use(1)
|
||||
if(moved && oldloc!=loc) // successful move
|
||||
//to_chat(world, "Successful move.")
|
||||
blockcount = 0
|
||||
path -= loc
|
||||
|
||||
@@ -508,7 +504,6 @@
|
||||
|
||||
else // failed to move
|
||||
|
||||
//to_chat(world, "Unable to move.")
|
||||
blockcount++
|
||||
mode = BOT_BLOCKED
|
||||
if(blockcount == 3)
|
||||
@@ -528,16 +523,13 @@
|
||||
return
|
||||
else
|
||||
buzz(ANNOYED)
|
||||
//to_chat(world, "Bad turf.")
|
||||
mode = BOT_NAV
|
||||
return
|
||||
else
|
||||
//to_chat(world, "No path.")
|
||||
mode = BOT_NAV
|
||||
return
|
||||
|
||||
if(BOT_NAV) // calculate new path
|
||||
//to_chat(world, "Calc new path.")
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
spawn(0)
|
||||
calc_path()
|
||||
|
||||
@@ -65,10 +65,9 @@
|
||||
/mob/living/simple_animal/bot/secbot/Initialize()
|
||||
. = ..()
|
||||
icon_state = "secbot[on]"
|
||||
spawn(3)
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
//SECHUD
|
||||
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
@@ -225,21 +224,25 @@ Auto Patrol: []"},
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
|
||||
spawn(60)
|
||||
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_handcuffed()
|
||||
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
back_to_idle()
|
||||
addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C)
|
||||
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_handcuffed()
|
||||
playsound(src, "law", 50, 0)
|
||||
back_to_idle()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/update_onsprite()
|
||||
icon_state = "secbot[on]"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
|
||||
var/judgement_criteria = judgement_criteria()
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
icon_state = "secbot-c"
|
||||
spawn(2)
|
||||
icon_state = "secbot[on]"
|
||||
addtimer(CALLBACK(src, .proc/update_onsprite), 2)
|
||||
var/threat = 5
|
||||
if(ishuman(C))
|
||||
C.stuttering = 5
|
||||
@@ -352,15 +355,13 @@ Auto Patrol: []"},
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
|
||||
anchored = FALSE
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
|
||||
@@ -385,8 +386,7 @@ Auto Patrol: []"},
|
||||
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() // ensure bot quickly responds to a perp
|
||||
INVOKE_ASYNC(src, .proc/handle_automated_action)
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
var/mob/living/simple_animal/mouse/movement_target
|
||||
gold_core_spawnable = 2
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Initialize()
|
||||
. = ..()
|
||||
@@ -84,7 +85,7 @@
|
||||
var/list/family = list()//var restored from savefile, has count of each child type
|
||||
var/list/children = list()//Actual mob instances of children
|
||||
var/cats_deployed = 0
|
||||
var/memory_saved = 0
|
||||
var/memory_saved = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/Initialize()
|
||||
if(prob(5))
|
||||
@@ -99,6 +100,7 @@
|
||||
Deploy_The_Cats()
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory()
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/make_babies()
|
||||
@@ -109,21 +111,26 @@
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/death()
|
||||
if(!memory_saved)
|
||||
Write_Memory(1)
|
||||
Write_Memory(TRUE)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
family = json["family"]
|
||||
if(fexists("data/npc_saves/Runtime.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
|
||||
S["family"] >> family
|
||||
fdel("data/npc_saves/Runtime.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
family = json["family"]
|
||||
if(isnull(family))
|
||||
family = list()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
|
||||
var/json_file = file("data/npc_saves/Runtime.json")
|
||||
var/list/file_data = list()
|
||||
family = list()
|
||||
if(!dead)
|
||||
for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
|
||||
@@ -133,9 +140,9 @@
|
||||
family[C.type] += 1
|
||||
else
|
||||
family[C.type] = 1
|
||||
file_data["family"] = family
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(family))
|
||||
memory_saved = 1
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
|
||||
cats_deployed = 1
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
speak_chance = 1
|
||||
turns_per_move = 10
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
//Corgis and pugs are now under one dog subtype
|
||||
|
||||
@@ -291,7 +292,7 @@
|
||||
gold_core_spawnable = 0
|
||||
var/age = 0
|
||||
var/record_age = 1
|
||||
var/memory_saved = 0
|
||||
var/memory_saved = FALSE
|
||||
var/saved_head //path
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/Initialize()
|
||||
@@ -307,7 +308,7 @@
|
||||
P.real_name = "Ian"
|
||||
P.gender = MALE
|
||||
P.desc = "It's the HoP's beloved corgi puppy."
|
||||
Write_Memory(0)
|
||||
Write_Memory(FALSE)
|
||||
qdel(src)
|
||||
else if(age == record_age)
|
||||
icon_state = "old_corgi"
|
||||
@@ -317,24 +318,31 @@
|
||||
turns_per_move = 20
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
|
||||
if(SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory(0)
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory(FALSE)
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/death()
|
||||
if(!memory_saved)
|
||||
Write_Memory(1)
|
||||
Write_Memory(TRUE)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/proc/Read_Memory()
|
||||
var/json_file = file("data/npc_saves/Ian.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
age = json["age"]
|
||||
record_age = json["record_age"]
|
||||
saved_head = json["saved_head"]
|
||||
if(fexists("data/npc_saves/Ian.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
|
||||
S["age"] >> age
|
||||
S["record_age"] >> record_age
|
||||
S["saved_head"] >> saved_head
|
||||
fdel("data/npc_saves/Ian.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Ian.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
age = json["age"]
|
||||
record_age = json["record_age"]
|
||||
saved_head = json["saved_head"]
|
||||
if(isnull(age))
|
||||
age = 0
|
||||
if(isnull(record_age))
|
||||
@@ -349,14 +357,18 @@
|
||||
file_data["age"] = age + 1
|
||||
if((age + 1) > record_age)
|
||||
file_data["record_age"] = record_age + 1
|
||||
else
|
||||
file_data["record_age"] = record_age
|
||||
if(inventory_head)
|
||||
file_data["saved_head"] = inventory_head.type
|
||||
else
|
||||
file_data["saved_head"] = null
|
||||
else
|
||||
file_data["age"] = 0
|
||||
file_data["record_age"] = record_age
|
||||
file_data["saved_head"] = null
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
memory_saved = 1
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
|
||||
..()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/udder/udder = null
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
|
||||
udder = new()
|
||||
@@ -119,6 +120,7 @@
|
||||
gold_core_spawnable = 2
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/cow/Initialize()
|
||||
udder = new()
|
||||
@@ -251,6 +253,7 @@
|
||||
gold_core_spawnable = 2
|
||||
var/static/chicken_count = 0
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/chicken/Initialize()
|
||||
. = ..()
|
||||
@@ -275,7 +278,6 @@
|
||||
user.drop_item()
|
||||
qdel(O)
|
||||
eggsleft += rand(1, 4)
|
||||
//to_chat(world, eggsleft)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
|
||||
else
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
devourable = TRUE
|
||||
var/mob/living/simple_animal/mouse/movement_target
|
||||
var/turns_since_scan = 0
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/fox/Life()
|
||||
//MICE!
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
/mob/living/simple_animal/mouse/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, list('sound/effects/mousesqueek.ogg'=1), 100)
|
||||
if(!body_color)
|
||||
body_color = pick( list("brown","gray","white") )
|
||||
icon_state = "mouse_[body_color]"
|
||||
@@ -58,7 +59,6 @@
|
||||
if(!stat)
|
||||
var/mob/M = AM
|
||||
to_chat(M, "<span class='notice'>[icon2html(src, M)] Squeek!</span>")
|
||||
playsound(src, 'sound/effects/mousesqueek.ogg', 100, 1)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_action()
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
speak_chance = 1
|
||||
turns_per_move = 10
|
||||
icon = 'icons/mob/penguins.dmi'
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/penguin/emperor
|
||||
name = "Emperor penguin"
|
||||
|
||||
@@ -159,7 +159,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
|
||||
resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5)
|
||||
stat(null, "Summoner Health: [resulthealth]%")
|
||||
if(cooldown >= world.time)
|
||||
stat(null, "Manifest/Recall Cooldown Remaining: [max(round((cooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
stat(null, "Manifest/Recall Cooldown Remaining: [DisplayTimeText(cooldown - world.time)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range
|
||||
. = ..()
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(stealthcooldown >= world.time)
|
||||
stat(null, "Stealth Cooldown Remaining: [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
stat(null, "Stealth Cooldown Remaining: [DisplayTimeText(stealthcooldown - world.time)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget()
|
||||
. = ..()
|
||||
@@ -79,7 +79,7 @@
|
||||
updatestealthalert()
|
||||
toggle = TRUE
|
||||
else if(!forced)
|
||||
to_chat(src, "<span class='danger'><B>You cannot yet enter stealth, wait another [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds!</span></B>")
|
||||
to_chat(src, "<span class='danger'><B>You cannot yet enter stealth, wait another [DisplayTimeText(stealthcooldown - world.time)]!</span></B>")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/proc/updatestealthalert()
|
||||
if(stealthcooldown <= world.time)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(bomb_cooldown >= world.time)
|
||||
stat(null, "Bomb Cooldown Remaining: [max(round((bomb_cooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
stat(null, "Bomb Cooldown Remaining: [DisplayTimeText(bomb_cooldown - world.time)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/bomb/AttackingTarget()
|
||||
. = ..()
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(beacon_cooldown >= world.time)
|
||||
stat(null, "Beacon Cooldown Remaining: [max(round((beacon_cooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
stat(null, "Beacon Cooldown Remaining: [DisplayTimeText(beacon_cooldown - world.time)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
|
||||
. = ..()
|
||||
if(toggle && iscarbon(target))
|
||||
if(. && toggle && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.adjustBruteLoss(-5)
|
||||
C.adjustFireLoss(-5)
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
gold_core_spawnable = 0
|
||||
death_sound = 'sound/voice/hiss6.ogg'
|
||||
deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..."
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/drone
|
||||
name = "alien drone"
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
faction = list("russian")
|
||||
gold_core_spawnable = 1
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
//SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!!
|
||||
/mob/living/simple_animal/hostile/bear/Hudson
|
||||
|
||||
@@ -128,11 +128,12 @@
|
||||
if(istype(target, /obj/machinery/hydroponics))
|
||||
var/obj/machinery/hydroponics/Hydro = target
|
||||
pollinate(Hydro)
|
||||
else if(target == beehome)
|
||||
var/obj/structure/beebox/BB = target
|
||||
loc = BB
|
||||
target = null
|
||||
wanted_objects -= typecacheof(/obj/structure/beebox) //so we don't attack beeboxes when not going home
|
||||
else if(istype(target, /obj/structure/beebox))
|
||||
if(target == beehome)
|
||||
var/obj/structure/beebox/BB = target
|
||||
forceMove(BB)
|
||||
target = null
|
||||
wanted_objects -= typecacheof(/obj/structure/beebox) //so we don't attack beeboxes when not going home
|
||||
return //no don't attack the goddamm box
|
||||
else
|
||||
. = ..()
|
||||
@@ -186,7 +187,7 @@
|
||||
if(loc == beehome)
|
||||
idle = min(100, ++idle)
|
||||
if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
|
||||
loc = get_turf(beehome)
|
||||
forceMove(get_turf(beehome))
|
||||
else
|
||||
idle = max(0, --idle)
|
||||
if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME))
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
harm_intent_damage = 8
|
||||
obj_damage = 50
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
if(L.reagents)
|
||||
L.reagents.add_reagent(poison_type, poison_per_bite)
|
||||
|
||||
|
||||
|
||||
//basic spider mob, these generally guard nests
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider
|
||||
name = "giant spider"
|
||||
@@ -104,6 +102,64 @@
|
||||
poison_per_bite = 5
|
||||
move_to_delay = 5
|
||||
|
||||
//vipers are the rare variant of the hunter, no IMMEDIATE damage but so much poison medical care will be needed fast.
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper
|
||||
name = "viper"
|
||||
desc = "Furry and black, it makes you shudder to look at it. This one has effervescent purple eyes."
|
||||
icon_state = "viper"
|
||||
icon_living = "viper"
|
||||
icon_dead = "viper_dead"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 1
|
||||
poison_per_bite = 12
|
||||
move_to_delay = 4
|
||||
poison_type = "venom" //all in venom, glass cannon. you bite 5 times and they are DEFINITELY dead, but 40 health and you are extremely obvious. Ambush, maybe?
|
||||
speed = 1
|
||||
|
||||
//tarantulas are really tanky, regenerating (maybe), hulky monster but are also extremely slow, so.
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/tarantula
|
||||
name = "tarantula"
|
||||
desc = "Furry and black, it makes you shudder to look at it. This one has abyssal red eyes."
|
||||
icon_state = "tarantula"
|
||||
icon_living = "tarantula"
|
||||
icon_dead = "tarantula_dead"
|
||||
maxHealth = 300 // woah nelly
|
||||
health = 300
|
||||
melee_damage_lower = 35
|
||||
melee_damage_upper = 40
|
||||
poison_per_bite = 0
|
||||
move_to_delay = 8
|
||||
speed = 7
|
||||
status_flags = NONE
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/tarantula/movement_delay()
|
||||
var/turf/T = get_turf(src)
|
||||
if(locate(/obj/structure/spider/stickyweb) in T)
|
||||
speed = 2
|
||||
else
|
||||
speed = 7
|
||||
. = ..()
|
||||
|
||||
//midwives are the queen of the spiders, can send messages to all them and web faster. That rare round where you get a queen spider and turn your 'for honor' players into 'r6siege' players will be a fun one.
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife
|
||||
name = "midwife"
|
||||
desc = "Furry and black, it makes you shudder to look at it. This one has scintillating green eyes."
|
||||
icon_state = "midwife"
|
||||
icon_living = "midwife"
|
||||
icon_dead = "midwife_dead"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
var/datum/action/innate/spider/comm/letmetalkpls
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Initialize()
|
||||
. = ..()
|
||||
letmetalkpls = new
|
||||
letmetalkpls.Grant(src)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
|
||||
name = "giant ice spider"
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
@@ -296,6 +352,39 @@
|
||||
busy = SPIDER_IDLE
|
||||
stop_automated_movement = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/Login()
|
||||
. = ..()
|
||||
GLOB.spidermobs[src] = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
|
||||
GLOB.spidermobs -= src
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/spider/comm
|
||||
name = "Command"
|
||||
button_icon_state = "cult_comms"
|
||||
|
||||
/datum/action/innate/spider/comm/IsAvailable()
|
||||
if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/spider/comm/Trigger()
|
||||
var/input = stripped_input(usr, "Input a message for your legions to follow.", "Command", "")
|
||||
if(QDELETED(src) || !input || !IsAvailable())
|
||||
return FALSE
|
||||
spider_command(usr, input)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/spider/comm/proc/spider_command(mob/living/user, message)
|
||||
if(!message)
|
||||
return
|
||||
var/my_message
|
||||
my_message = "<FONT size = 3><b>COMMAND FROM SPIDER QUEEN:</b> [message]</FONT>"
|
||||
for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
|
||||
to_chat(M, my_message)
|
||||
log_talk(user, "SPIDERCOMMAND: [key_name(user)] : [message]",LOGSAY)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/handle_temperature_damage()
|
||||
if(bodytemperature < minbodytemp)
|
||||
adjustBruteLoss(20)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
melee_damage_upper = 18
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, CLONE = 0, STAMINA = 0, OXY = 1.5)
|
||||
obj_damage = 20
|
||||
environment_smash = 2
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
attacktext = "pummels"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
dextrous = TRUE
|
||||
@@ -32,7 +32,11 @@
|
||||
stat_attack = UNCONSCIOUS
|
||||
minbodytemp = 270
|
||||
maxbodytemp = 350
|
||||
unique_name = TRUE
|
||||
var/list/gorilla_overlays[GORILLA_TOTAL_LAYERS]
|
||||
var/oogas = 0
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
// Gorillas like to dismember limbs from unconcious mobs.
|
||||
// Returns null when the target is not an unconcious carbon mob; a list of limbs (possibly empty) otherwise.
|
||||
@@ -49,6 +53,8 @@
|
||||
return parts
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/AttackingTarget()
|
||||
if(client)
|
||||
oogaooga()
|
||||
var/list/parts = target_bodyparts(target)
|
||||
if(parts)
|
||||
if(!parts.len)
|
||||
@@ -61,7 +67,7 @@
|
||||
var/mob/living/L = target
|
||||
if(prob(80))
|
||||
var/atom/throw_target = get_edge_target_turf(L, dir)
|
||||
L.throw_at(throw_target, rand(1,2), 7, src)
|
||||
L.throw_at(throw_target, rand(1,2), 7, src)
|
||||
else
|
||||
L.Knockdown(20)
|
||||
visible_message("<span class='danger'>[src] knocks [L] down!</span>")
|
||||
@@ -70,8 +76,30 @@
|
||||
var/list/parts = target_bodyparts(target)
|
||||
return ..() && !istype(the_target, /mob/living/carbon/monkey) && (!parts || parts.len > 3)
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/CanSmashTurfs(turf/T)
|
||||
return iswallturf(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/gib(no_brain)
|
||||
if(!no_brain)
|
||||
var/mob/living/brain/B = new(drop_location())
|
||||
B.name = real_name
|
||||
B.real_name = real_name
|
||||
if(mind)
|
||||
mind.transfer_to(B)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/handle_automated_speech(override)
|
||||
if(speak_chance && (override || prob(speak_chance)))
|
||||
playsound(src, "sound/creatures/gorilla.ogg", 200)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/can_use_guns(obj/item/G)
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
return FALSE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/gorilla/proc/oogaooga()
|
||||
oogas++
|
||||
if(oogas >= rand(2,6))
|
||||
playsound(src, "sound/creatures/gorilla.ogg", 200)
|
||||
oogas = 0
|
||||
|
||||
@@ -228,6 +228,9 @@
|
||||
if(!target || !CanAttack(target))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(ismob(target.loc))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(target in possible_targets)
|
||||
if(target.z != z)
|
||||
LoseTarget()
|
||||
@@ -366,23 +369,26 @@
|
||||
P.original = targeted_atom
|
||||
P.fire()
|
||||
return P
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/CanSmashTurfs(turf/T)
|
||||
return iswallturf(T) || ismineralturf(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
|
||||
if(environment_smash)
|
||||
EscapeConfinement()
|
||||
for(var/dir in GLOB.cardinals)
|
||||
var/turf/T = get_step(targets_from, dir)
|
||||
if(iswallturf(T) || ismineralturf(T))
|
||||
if(CanSmashTurfs(T))
|
||||
if(T.Adjacent(targets_from))
|
||||
T.attack_animal(src)
|
||||
for(var/a in T)
|
||||
var/atom/A = a
|
||||
if(!A.Adjacent(targets_from))
|
||||
continue
|
||||
if(is_type_in_typecache(A, environment_target_typecache))
|
||||
if(is_type_in_typecache(A, environment_target_typecache) && !A.IsObscured())
|
||||
A.attack_animal(src)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/EscapeConfinement()
|
||||
if(buckled)
|
||||
buckled.attack_animal(src)
|
||||
|
||||
@@ -250,7 +250,7 @@ Difficulty: Very Hard
|
||||
use_power = NO_POWER_USE
|
||||
var/memory_saved = FALSE
|
||||
var/list/stored_items = list()
|
||||
var/static/list/blacklist = typecacheof(list(/obj/item/spellbook))
|
||||
var/list/blacklist = list()
|
||||
|
||||
/obj/machinery/smartfridge/black_box/update_icon()
|
||||
return
|
||||
@@ -258,7 +258,8 @@ Difficulty: Very Hard
|
||||
/obj/machinery/smartfridge/black_box/accept_check(obj/item/O)
|
||||
if(!istype(O))
|
||||
return FALSE
|
||||
if(is_type_in_typecache(O, blacklist))
|
||||
if(blacklist[O])
|
||||
visible_message("<span class='boldwarning'>[src] ripples as it rejects [O]. The device will not accept items that have been removed from it.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -275,6 +276,7 @@ Difficulty: Very Hard
|
||||
..()
|
||||
if(!memory_saved && SSticker.current_state == GAME_STATE_FINISHED)
|
||||
WriteMemory()
|
||||
memory_saved = TRUE
|
||||
|
||||
/obj/machinery/smartfridge/black_box/proc/WriteMemory()
|
||||
var/json_file = file("data/npc_saves/Blackbox.json")
|
||||
@@ -286,15 +288,18 @@ Difficulty: Very Hard
|
||||
file_data["data"] = stored_items
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
memory_saved = TRUE
|
||||
|
||||
/obj/machinery/smartfridge/black_box/proc/ReadMemory()
|
||||
var/json_file = file("data/npc_saves/Blackbox.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
stored_items = json["data"]
|
||||
if(fexists("data/npc_saves/Blackbox.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav")
|
||||
S["stored_items"] >> stored_items
|
||||
fdel("data/npc_saves/Blackbox.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Blackbox.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
stored_items = json["data"]
|
||||
if(isnull(stored_items))
|
||||
stored_items = list()
|
||||
|
||||
@@ -304,7 +309,8 @@ Difficulty: Very Hard
|
||||
//in it's own proc to avoid issues with items that nolonger exist in the code base.
|
||||
//try catch doesn't always prevent byond runtimes from halting a proc,
|
||||
/obj/machinery/smartfridge/black_box/proc/create_item(item_type)
|
||||
new item_type(src)
|
||||
var/obj/O = new item_type(src)
|
||||
blacklist[O] = TRUE
|
||||
|
||||
/obj/machinery/smartfridge/black_box/Destroy(force = FALSE)
|
||||
if(force)
|
||||
|
||||
@@ -60,6 +60,7 @@ Difficulty: Medium
|
||||
score_type = DRAKE_SCORE
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
|
||||
. = ..()
|
||||
@@ -352,9 +353,9 @@ Difficulty: Medium
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/proc/flight(negative)
|
||||
if(negative)
|
||||
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT*0.10, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
else
|
||||
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT*0.10, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
sleep(3)
|
||||
icon_state = "swoop"
|
||||
if(negative)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon
|
||||
vore_active = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
|
||||
// Create and register 'stomachs'
|
||||
var/datum/belly/megafauna/dragon/maw/maw = new(src)
|
||||
var/datum/belly/megafauna/dragon/gullet/gullet = new(src)
|
||||
var/datum/belly/megafauna/dragon/gut/gut = new(src)
|
||||
for(var/datum/belly/X in list(maw, gullet, gut))
|
||||
vore_organs[X.name] = X
|
||||
// Connect 'stomachs' together
|
||||
maw.transferlocation = gullet
|
||||
gullet.transferlocation = gut
|
||||
vore_selected = maw.name // NPC eats into maw
|
||||
return ..()
|
||||
|
||||
/datum/belly/megafauna/dragon
|
||||
human_prey_swallow_time = 50 // maybe enough to switch targets if distracted
|
||||
nonhuman_prey_swallow_time = 50
|
||||
|
||||
/datum/belly/megafauna/dragon/maw
|
||||
name = "maw"
|
||||
inside_flavor = "The maw of the dreaded Ash drake closes around you, engulfing you into a swelteringly hot, disgusting enviroment. The acidic saliva tingles over your form while that tongue pushes you further back...towards the dark gullet beyond."
|
||||
vore_verb = "scoop"
|
||||
vore_sound = 'sound/vore/pred/taurswallow.ogg'
|
||||
swallow_time = 20
|
||||
escapechance = 25
|
||||
// From above, will transfer into gullet
|
||||
transferchance = 25
|
||||
autotransferchance = 66
|
||||
autotransferwait = 200
|
||||
|
||||
/datum/belly/megafauna/dragon/gullet
|
||||
name = "gullet"
|
||||
inside_flavor = "A ripple of muscle and arching of the tongue pushes you down like any other food. No choice in the matter, you're simply consumed. The dark ambiance of the outside world is replaced with working, wet flesh. Your only light being what you brought with you."
|
||||
swallow_time = 60 // costs extra time to eat directly to here
|
||||
escapechance = 5
|
||||
// From above, will transfer into gut
|
||||
transferchance = 25
|
||||
autotransferchance = 50
|
||||
autotransferwait = 200
|
||||
|
||||
/datum/belly/megafauna/dragon/gut
|
||||
name = "stomach"
|
||||
vore_capacity = 5 //I doubt this many people will actually last in the gut, but...
|
||||
inside_flavor = "With a rush of burning ichor greeting you, you're introduced to the Drake's stomach. Wrinkled walls greedily grind against you, acidic slimes working into your body as you become fuel and nutriton for a superior predator. All that's left is your body's willingness to resist your destiny."
|
||||
digest_mode = DM_DRAGON
|
||||
digest_burn = 5
|
||||
swallow_time = 100 // costs extra time to eat directly to here
|
||||
escapechance = 0
|
||||
@@ -60,7 +60,7 @@
|
||||
else
|
||||
var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
if(C && crusher_loot)
|
||||
if(C.total_damage >= maxHealth * 0.60) //if you do at least 60% of its health with the crusher, you'll get the item
|
||||
if(C.total_damage >= maxHealth * 0.6) //if you do at least 60% of its health with the crusher, you'll get the item
|
||||
spawn_crusher_loot()
|
||||
if(!admin_spawned)
|
||||
SSblackbox.set_details("megafauna_kills","[initial(name)]")
|
||||
@@ -89,11 +89,15 @@
|
||||
. = ..()
|
||||
if(. && isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat != DEAD)
|
||||
if(!client && ranged && ranged_cooldown <= world.time)
|
||||
OpenFire()
|
||||
if(L.stat >= SOFT_CRIT)
|
||||
if(vore_active == TRUE && L.devourable == TRUE)
|
||||
dragon_feeding(src,L)
|
||||
else if(L.stat == DEAD)
|
||||
devour(L)
|
||||
else
|
||||
devour(L)
|
||||
if(L.stat != DEAD)
|
||||
if(!client && ranged && ranged_cooldown <= world.time)
|
||||
OpenFire()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
|
||||
if(!L)
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
var/pre_attack = 0
|
||||
var/pre_attack_icon = "Goliath_preattack"
|
||||
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide)
|
||||
no_vore = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
|
||||
. = ..()
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
cap_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
|
||||
UpdateMushroomCap()
|
||||
health = maxHealth
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //Possibility to flee from a fight just to make it more visually interesting
|
||||
if(!retreat_distance && prob(33))
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
minimum_distance = 5
|
||||
icon_state = "stickmanranged"
|
||||
icon_living = "stickmanranged"
|
||||
casingtype = /obj/item/ammo_casing/c45nostamina
|
||||
casingtype = /obj/item/ammo_casing/c45/nostamina
|
||||
projectilesound = 'sound/misc/bang.ogg'
|
||||
loot = list(/obj/item/gun/ballistic/automatic/pistol/stickman)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
minimum_distance = 5
|
||||
icon_state = "syndicateranged"
|
||||
icon_living = "syndicateranged"
|
||||
casingtype = /obj/item/ammo_casing/c45nostamina
|
||||
casingtype = /obj/item/ammo_casing/c45/nostamina
|
||||
projectilesound = 'sound/weapons/gunshot_smg.ogg'
|
||||
loot = list(/obj/effect/gibspawner/human)
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
movement_type = FLYING
|
||||
gold_core_spawnable = 2
|
||||
devourable = TRUE
|
||||
no_vore = FALSE
|
||||
|
||||
var/parrot_damage_upper = 10
|
||||
var/parrot_state = PARROT_WANDER //Hunt for a perch when created
|
||||
@@ -296,7 +297,7 @@
|
||||
else
|
||||
parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
|
||||
drop_held_item(0)
|
||||
if(!stat && M.a_intent == INTENT_HELP)
|
||||
if(stat != DEAD && M.a_intent == INTENT_HELP)
|
||||
handle_automated_speech(1) //assured speak/emote
|
||||
return
|
||||
|
||||
@@ -872,7 +873,7 @@
|
||||
speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE")
|
||||
gold_core_spawnable = 0
|
||||
speak_chance = 3
|
||||
var/memory_saved = 0
|
||||
var/memory_saved = FALSE
|
||||
var/rounds_survived = 0
|
||||
var/longest_survival = 0
|
||||
var/longest_deathstreak = 0
|
||||
@@ -903,50 +904,62 @@
|
||||
rounds_survived = max(++rounds_survived,1)
|
||||
if(rounds_survived > longest_survival)
|
||||
longest_survival = rounds_survived
|
||||
Write_Memory()
|
||||
Write_Memory(FALSE)
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/death(gibbed)
|
||||
if(!memory_saved)
|
||||
var/go_ghost = 0
|
||||
if(rounds_survived == longest_survival || rounds_survived == longest_deathstreak || prob(0.666))
|
||||
go_ghost = 1
|
||||
rounds_survived = min(--rounds_survived,0)
|
||||
if(rounds_survived < longest_deathstreak)
|
||||
longest_deathstreak = rounds_survived
|
||||
Write_Memory()
|
||||
if(go_ghost)
|
||||
var/mob/living/simple_animal/parrot/Poly/ghost/G = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(G)
|
||||
else
|
||||
G.key = key
|
||||
Write_Memory(TRUE)
|
||||
if(rounds_survived == longest_survival || rounds_survived == longest_deathstreak || prob(0.666))
|
||||
var/mob/living/simple_animal/parrot/Poly/ghost/G = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(G)
|
||||
else
|
||||
G.key = key
|
||||
..(gibbed)
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/proc/Read_Memory()
|
||||
var/json_file = file("data/npc_saves/Poly.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = list()
|
||||
json = json_decode(file2text(json_file))
|
||||
speech_buffer = json["phrases"]
|
||||
rounds_survived = json["roundssurvived"]
|
||||
longest_survival = json["longestsurvival"]
|
||||
longest_deathstreak = json["longestdeathstreak"]
|
||||
if(fexists("data/npc_saves/Poly.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/Poly.sav")
|
||||
S["phrases"] >> speech_buffer
|
||||
S["roundssurvived"] >> rounds_survived
|
||||
S["longestsurvival"] >> longest_survival
|
||||
S["longestdeathstreak"] >> longest_deathstreak
|
||||
fdel("data/npc_saves/Poly.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/Poly.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
speech_buffer = json["phrases"]
|
||||
rounds_survived = json["roundssurvived"]
|
||||
longest_survival = json["longestsurvival"]
|
||||
longest_deathstreak = json["longestdeathstreak"]
|
||||
if(!islist(speech_buffer))
|
||||
speech_buffer = list()
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/proc/Write_Memory()
|
||||
/mob/living/simple_animal/parrot/Poly/proc/Write_Memory(dead)
|
||||
var/json_file = file("data/npc_saves/Poly.json")
|
||||
var/list/file_data = list()
|
||||
if(islist(speech_buffer))
|
||||
file_data["phrases"] = speech_buffer
|
||||
file_data["roundssurvived"] = rounds_survived
|
||||
file_data["longestsurvival"] = longest_survival
|
||||
file_data["longestdeathstreak"] = longest_deathstreak
|
||||
if(dead)
|
||||
file_data["roundssurvived"] = min(rounds_survived - 1, 0)
|
||||
file_data["longestsurvival"] = longest_survival
|
||||
if(rounds_survived - 1 < longest_deathstreak)
|
||||
file_data["longestdeathstreak"] = rounds_survived - 1
|
||||
else
|
||||
file_data["longestdeathstreak"] = longest_deathstreak
|
||||
else
|
||||
file_data["roundssurvived"] = rounds_survived + 1
|
||||
if(rounds_survived + 1 > longest_survival)
|
||||
file_data["longestsurvival"] = rounds_survived + 1
|
||||
else
|
||||
file_data["longestsurvival"] = longest_survival
|
||||
file_data["longestdeathstreak"] = longest_deathstreak
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
memory_saved = 1
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/ghost
|
||||
name = "The Ghost of Poly"
|
||||
@@ -958,8 +971,8 @@
|
||||
butcher_results = list(/obj/item/ectoplasm = 1)
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/ghost/Initialize()
|
||||
memory_saved = 1 //At this point nothing is saved
|
||||
..()
|
||||
memory_saved = TRUE //At this point nothing is saved
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/parrot/Poly/ghost/handle_automated_speech()
|
||||
if(ismob(loc))
|
||||
@@ -983,4 +996,4 @@
|
||||
loc = H
|
||||
H.ContractDisease(P)
|
||||
parrot_interest = null
|
||||
H.visible_message("<span class='danger'>[src] dive bombs into [H]'s chest and vanishes!</span>", "<span class='userdanger'>[src] dive bombs into your chest, vanishing! This can't be good!</span>")
|
||||
H.visible_message("<span class='danger'>[src] dive bombs into [H]'s chest and vanishes!</span>", "<span class='userdanger'>[src] dive bombs into your chest, vanishing! This can't be good!</span>")
|
||||
@@ -85,6 +85,8 @@
|
||||
//domestication
|
||||
var/tame = 0
|
||||
|
||||
no_vore = TRUE
|
||||
|
||||
/mob/living/simple_animal/Initialize()
|
||||
. = ..()
|
||||
GLOB.simple_animals += src
|
||||
@@ -95,6 +97,9 @@
|
||||
real_name = name
|
||||
if(!loc)
|
||||
stack_trace("Simple animal being instantiated in nullspace")
|
||||
if(vore_active)
|
||||
init_belly()
|
||||
verbs |= /mob/living/proc/animal_nom
|
||||
|
||||
|
||||
/mob/living/simple_animal/Login()
|
||||
@@ -228,7 +233,6 @@
|
||||
if( abs(areatemp - bodytemperature) > 40 )
|
||||
var/diff = areatemp - bodytemperature
|
||||
diff = diff / 5
|
||||
//to_chat(world, "changed from [bodytemperature] by [diff] to [bodytemperature + diff]")
|
||||
bodytemperature += diff
|
||||
|
||||
if(!environment_is_safe(environment))
|
||||
|
||||
@@ -2,3 +2,101 @@
|
||||
// List of targets excluded (for now) from being eaten by this mob.
|
||||
var/list/prey_exclusions = list()
|
||||
devourable = FALSE //insurance because who knows.
|
||||
var/vore_active = FALSE // If vore behavior is enabled for this mob
|
||||
|
||||
var/vore_default_mode = DM_DIGEST // Default bellymode (DM_DIGEST, DM_HOLD, DM_ABSORB)
|
||||
var/vore_digest_chance = 25 // Chance to switch to digest mode if resisted
|
||||
var/vore_escape_chance = 25 // Chance of resisting out of mob
|
||||
|
||||
var/vore_stomach_name // The name for the first belly if not "stomach"
|
||||
var/vore_stomach_flavor // The flavortext for the first belly if not the default
|
||||
|
||||
var/vore_fullness = 0 // How "full" the belly is (controls icons)
|
||||
|
||||
|
||||
// Release belly contents beforey being gc'd!
|
||||
/mob/living/simple_animal/Destroy()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
B.release_all_contents() // When your stomach is empty
|
||||
prey_excludes.Cut()
|
||||
. = ..()
|
||||
|
||||
|
||||
// Update fullness based on size & quantity of belly contents
|
||||
/mob/living/simple_animal/proc/update_fullness(var/atom/movable/M)
|
||||
var/new_fullness = 0
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if (!(M in B.internal_contents))
|
||||
return FALSE // Nothing's inside
|
||||
new_fullness += M
|
||||
|
||||
vore_fullness = new_fullness
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/swallow_check()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if(vore_active)
|
||||
update_fullness()
|
||||
if(!vore_fullness)
|
||||
// Nothing
|
||||
return
|
||||
else
|
||||
addtimer(CALLBACK(src, .proc/swallow_mob), B.swallow_time)
|
||||
|
||||
/mob/living/simple_animal/proc/swallow_mob()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
for(var/mob/living/M in B.internal_contents)
|
||||
B.transfer_contents(M, B.transferlocation)
|
||||
|
||||
|
||||
/mob/living/simple_animal/death()
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
B.release_all_contents() // When your stomach is empty
|
||||
..() // then you have my permission to die.
|
||||
|
||||
// Simple animals have only one belly. This creates it (if it isn't already set up)
|
||||
/mob/living/simple_animal/proc/init_belly()
|
||||
if(vore_organs.len)
|
||||
return
|
||||
if(no_vore) //If it can't vore, let's not give it a stomach.
|
||||
return
|
||||
|
||||
var/datum/belly/B = new /datum/belly(src)
|
||||
B.immutable = TRUE
|
||||
B.name = vore_stomach_name ? vore_stomach_name : "stomach"
|
||||
B.inside_flavor = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
|
||||
B.digest_mode = vore_default_mode
|
||||
B.escapable = vore_escape_chance > 0
|
||||
B.escapechance = vore_escape_chance
|
||||
B.digestchance = vore_digest_chance
|
||||
B.human_prey_swallow_time = swallowTime
|
||||
B.nonhuman_prey_swallow_time = swallowTime
|
||||
B.vore_verb = "swallow"
|
||||
// TODO - Customizable per mob
|
||||
B.emote_lists[DM_HOLD] = list( // We need more that aren't repetitive. I suck at endo. -Ace
|
||||
"The insides knead at you gently for a moment.",
|
||||
"The guts glorp wetly around you as some air shifts.",
|
||||
"The predator takes a deep breath and sighs, shifting you somewhat.",
|
||||
"The stomach squeezes you tight for a moment, then relaxes harmlessly.",
|
||||
"The predator's calm breathing and thumping heartbeat pulses around you.",
|
||||
"The warm walls kneads harmlessly against you.",
|
||||
"The liquids churn around you, though there doesn't seem to be much effect.",
|
||||
"The sound of bodily movements drown out everything for a moment.",
|
||||
"The predator's movements gently force you into a different position.")
|
||||
B.emote_lists[DM_DIGEST] = list(
|
||||
"The burning acids eat away at your form.",
|
||||
"The muscular stomach flesh grinds harshly against you.",
|
||||
"The caustic air stings your chest when you try to breathe.",
|
||||
"The slimy guts squeeze inward to help the digestive juices soften you up.",
|
||||
"The onslaught against your body doesn't seem to be letting up; you're food now.",
|
||||
"The predator's body ripples and crushes against you as digestive enzymes pull you apart.",
|
||||
"The juices pooling beneath you sizzle against your sore skin.",
|
||||
"The churning walls slowly pulverize you into meaty nutrients.",
|
||||
"The stomach glorps and gurgles as it tries to work you into slop.")
|
||||
src.vore_organs[B.name] = B
|
||||
src.vore_selected = B.name
|
||||
|
||||
@@ -225,7 +225,9 @@
|
||||
var/mob/living/L = mob
|
||||
switch(L.incorporeal_move)
|
||||
if(INCORPOREAL_MOVE_BASIC)
|
||||
L.loc = get_step(L, direct)
|
||||
var/T = get_step(L,direct)
|
||||
if(T)
|
||||
L.loc = T
|
||||
L.setDir(direct)
|
||||
if(INCORPOREAL_MOVE_SHADOW)
|
||||
if(prob(50))
|
||||
@@ -254,31 +256,36 @@
|
||||
return
|
||||
else
|
||||
return
|
||||
L.loc = locate(locx,locy,mobloc.z)
|
||||
var/limit = 2//For only two trailing shadows.
|
||||
for(var/turf/T in getline(mobloc, L.loc))
|
||||
new /obj/effect/temp_visual/dir_setting/ninja/shadow(T, L.dir)
|
||||
limit--
|
||||
if(limit<=0)
|
||||
break
|
||||
var/target = locate(locx,locy,mobloc.z)
|
||||
if(target)
|
||||
L.loc = target
|
||||
var/limit = 2//For only two trailing shadows.
|
||||
for(var/turf/T in getline(mobloc, L.loc))
|
||||
new /obj/effect/temp_visual/dir_setting/ninja/shadow(T, L.dir)
|
||||
limit--
|
||||
if(limit<=0)
|
||||
break
|
||||
else
|
||||
new /obj/effect/temp_visual/dir_setting/ninja/shadow(mobloc, L.dir)
|
||||
L.loc = get_step(L, direct)
|
||||
var/T = get_step(L,direct)
|
||||
if(T)
|
||||
L.loc = T
|
||||
L.setDir(direct)
|
||||
if(INCORPOREAL_MOVE_JAUNT) //Incorporeal move, but blocked by holy-watered tiles and salt piles.
|
||||
var/turf/open/floor/stepTurf = get_step(L, direct)
|
||||
for(var/obj/effect/decal/cleanable/salt/S in stepTurf)
|
||||
to_chat(L, "<span class='warning'>[S] bars your passage!</span>")
|
||||
if(isrevenant(L))
|
||||
var/mob/living/simple_animal/revenant/R = L
|
||||
R.reveal(20)
|
||||
R.stun(20)
|
||||
return
|
||||
if(stepTurf.flags_1 & NOJAUNT_1)
|
||||
to_chat(L, "<span class='warning'>Holy energies block your path.</span>")
|
||||
else
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
if(stepTurf)
|
||||
for(var/obj/effect/decal/cleanable/salt/S in stepTurf)
|
||||
to_chat(L, "<span class='warning'>[S] bars your passage!</span>")
|
||||
if(isrevenant(L))
|
||||
var/mob/living/simple_animal/revenant/R = L
|
||||
R.reveal(20)
|
||||
R.stun(20)
|
||||
return
|
||||
if(stepTurf.flags_1 & NOJAUNT_1)
|
||||
to_chat(L, "<span class='warning'>Holy energies block your path.</span>")
|
||||
else
|
||||
L.loc = get_step(L, direct)
|
||||
L.setDir(direct)
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user