Merge branch 'master' into upstream-merge-30079

This commit is contained in:
LetterJay
2017-09-06 09:24:23 -05:00
committed by GitHub
550 changed files with 13328 additions and 156749 deletions
+2
View File
@@ -31,6 +31,8 @@
if(M.client)
body += " played by <b>[M.client]</b> "
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
if(config.use_exp_tracking)
body += "\[<A href='?_src_=holder;getplaytimewindow=\ref[M]'>" + M.client.get_exp_living() + "</a>\]"
if(isnewplayer(M))
body += " <B>Hasn't Entered Game</B> "
@@ -1 +0,0 @@
garbage
+1
View File
@@ -61,6 +61,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
/client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/
/client/proc/cmd_admin_create_centcom_report,
/client/proc/cmd_change_command_name,
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
/client/proc/toggle_antag_hud, /*toggle display of the admin antag hud*/
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
/client/proc/customiseSNPC, /* Customise any interactive crewmembers in the world */
+10
View File
@@ -0,0 +1,10 @@
diff a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm (rejected hunks)
@@ -663,7 +664,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, AVerbsHideable())
if(!holder)
return
-
+
if(has_antag_hud())
toggle_antag_hud()
+18
View File
@@ -22,6 +22,24 @@
else if(href_list["stickyban"])
stickyban(href_list["stickyban"],href_list)
else if(href_list["getplaytimewindow"])
if(!check_rights(R_ADMIN))
return
var/mob/M = locate(href_list["getplaytimewindow"]) in GLOB.mob_list
if(!M)
to_chat(usr, "<span class='danger'>ERROR: Mob not found.</span>")
return
cmd_show_exp_panel(M.client)
else if(href_list["toggleexempt"])
if(!check_rights(R_ADMIN))
return
var/client/C = locate(href_list["toggleexempt"]) in GLOB.clients
if(!C)
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>")
return
toggle_exempt_status(C)
else if(href_list["makeAntag"])
if (!SSticker.mode)
to_chat(usr, "<span class='danger'>Not until the round starts!</span>")
-1
View File
@@ -352,7 +352,6 @@ GLOBAL_PROTECT(AdminProcCallCount)
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
/obj/item/reagent_containers/food = "FOOD",
/obj/item/reagent_containers = "REAGENT_CONTAINERS",
/obj/item/weapon = "WEAPON",
/obj/machinery/atmospherics = "ATMOS_MECH",
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
diff a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm (rejected hunks)
@@ -1246,7 +1246,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
to_chat(usr, "<span class='danger'>ERROR: Client not found.</span>")
return
- C.set_db_player_flags()
+ if(!C.set_db_player_flags())
+ to_chat(usr, "<span class='danger'>ERROR: Unable read player flags from database. Please check logs.</span>")
var/dbflags = C.prefs.db_flags
var/newstate = FALSE
if(dbflags & DB_FLAG_EXEMPT)
@@ -1254,6 +1255,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
else
newstate = TRUE
- message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]")
- log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
- C.update_flag_db(DB_FLAG_EXEMPT, newstate)
\ No newline at end of file
+ if(C.update_flag_db(DB_FLAG_EXEMPT, newstate))
+ to_chat(usr, "<span class='danger'>ERROR: Unable to update player flags. Please check logs.</span>")
+ else
+ message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]")
+ log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
\ No newline at end of file
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm (rejected hunks)
@@ -8,7 +8,7 @@
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 2
throw_range = 4
- flags = CONDUCT
+ flags_1 = CONDUCT_1
var/status = FALSE //0 - not readied //1 - bomb finished with welder
var/obj/item/device/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device
var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank
@@ -1,10 +0,0 @@
diff a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm (rejected hunks)
@@ -734,7 +734,7 @@
update_icon()
/obj/machinery/airalarm/deconstruct(disassembled = TRUE)
- if(!(flags & NODECONSTRUCT))
+ if(!(flags_1 & NODECONSTRUCT_1))
new /obj/item/stack/sheet/metal(loc, 2)
var/obj/item/I = new /obj/item/electronics/airalarm(loc)
if(!disassembled)
@@ -1,18 +0,0 @@
diff a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm (rejected hunks)
@@ -473,14 +473,14 @@
W.registered_name = H.real_name
W.update_label(W.registered_name, W.assignment)
- // The shielded hardsuit is already NODROP
+ // The shielded hardsuit is already NODROP_1
no_drops += H.get_item_by_slot(slot_gloves)
no_drops += H.get_item_by_slot(slot_shoes)
no_drops += H.get_item_by_slot(slot_w_uniform)
no_drops += H.get_item_by_slot(slot_ears)
for(var/i in no_drops)
var/obj/item/I = i
- I.flags |= NODROP
+ I.flags_1 |= NODROP_1
/datum/outfit/ctf/instagib
r_hand = /obj/item/gun/energy/laser/instakill
+5 -2
View File
@@ -46,10 +46,13 @@
create()
else
GLOB.poi_list |= src
LAZYADD(GLOB.mob_spawners[name], src)
/obj/effect/mob_spawn/Destroy()
GLOB.poi_list.Remove(src)
. = ..()
GLOB.poi_list -= src
var/list/spawners = GLOB.mob_spawners[name]
LAZYREMOVE(spawners, src)
return ..()
/obj/effect/mob_spawn/proc/special(mob/M)
return
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm (rejected hunks)
@@ -145,7 +145,7 @@
var/reason = ""
if(requestonly)
- reason = stripped_input("Reason:", name, "") as text|null
+ reason = stripped_input("Reason:", name, "")
if(isnull(reason) || ..())
return
+2 -1
View File
@@ -1,3 +1,4 @@
/* // Can't be bothered to maintain this, mostly just memes anyway.
/datum/supply_pack/misc/vidyacon
name = "Vidya-Con Surplus Crate"
cost = 3250
@@ -30,4 +31,4 @@ datum/supply_pack/misc/reenactor
/obj/item/clothing/under/officeruniform,/obj/item/clothing/head/naziofficer,/obj/item/clothing/suit/officercoat,
/obj/item/clothing/head/panzer,
/obj/item/clothing/suit/russofurcoat,/obj/item/clothing/head/russofurhat,/obj/item/clothing/under/soviet)
crate_name = "historical reanactor crate"
crate_name = "historical reanactor crate" */
+27 -28
View File
@@ -361,35 +361,34 @@ GLOBAL_LIST(external_rsc_urls)
holder.owner = null
GLOB.admins -= src
if (!GLOB.admins.len && SSticker.IsRoundInProgress()) //Only report this stuff if we are currently playing.
if(!GLOB.admins.len) //Apparently the admin logging out is no longer an admin at this point, so we have to check this towards 0 and not towards 1. Awell.
var/cheesy_message = pick(
"I have no admins online!",\
"I'm all alone... :(",\
"I'm feeling lonely. :(",\
"I'm so lonely. :(",\
"Why does nobody love me? :(",\
"I want a man. :(",\
"Where has everyone gone?",\
"I need a hug. :(",\
"Someone come hold me. :(",\
"I need someone on me :(",\
"What happened? Where has everyone gone?",\
"My nipples are so stiff, but Zelda ain't here. :(",\
"Leon senpai, play more Spessmans. :(",\
"If only Serdy were here...",\
"Panic bunker can't keep my love for you out.",\
"Cebu needs to Awoo herself back into my heart.",\
"I don't even have a Turry to snuggle viciously here.",\
"MOM, WHERE ARE YOU??? D:",\
"It's a beautiful day outside. Birds are singing, flowers are blooming. On days like this...kids like you...SHOULD BE BURNING IN HELL.",\
"Sometimes when I have sex, I think about putting an entire peanut butter and jelly sandwich in the VCR.",\
"Oh good, no-one around to watch me lick Goofball's nipples. :D",\
"I've replaced Beepsky with a fidget spinner, glory be autism abuse.",\
"i shure hop dere are no PRED arund!!!!",\
"NO PRED CAN eVER CATCH MI"\
)
var/cheesy_message = pick(
"I have no admins online!",\
"I'm all alone... :(",\
"I'm feeling lonely. :(",\
"I'm so lonely. :(",\
"Why does nobody love me? :(",\
"I want a man. :(",\
"Where has everyone gone?",\
"I need a hug. :(",\
"Someone come hold me. :(",\
"I need someone on me :(",\
"What happened? Where has everyone gone?",\
"My nipples are so stiff, but Zelda ain't here. :(",\
"Leon senpai, play more Spessmans. :(",\
"If only Serdy were here...",\
"Panic bunker can't keep my love for you out.",\
"Cebu needs to Awoo herself back into my heart.",\
"I don't even have a Turry to snuggle viciously here.",\
"MOM, WHERE ARE YOU??? D:",\
"It's a beautiful day outside. Birds are singing, flowers are blooming. On days like this...kids like you...SHOULD BE BURNING IN HELL.",\
"Sometimes when I have sex, I think about putting an entire peanut butter and jelly sandwich in the VCR.",\
"Oh good, no-one around to watch me lick Goofball's nipples. :D",\
"I've replaced Beepsky with a fidget spinner, glory be autism abuse.",\
"i shure hop dere are no PRED arund!!!!",\
"NO PRED CAN eVER CATCH MI"\
)
send2irc("Server", "[cheesy_message] (No admins online)")
send2irc("Server", "[cheesy_message] (No admins online)")
GLOB.ahelp_tickets.ClientLogout(src)
GLOB.directory -= ckey
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm (rejected hunks)
@@ -73,7 +73,7 @@
return
//Logs all hrefs, except chat pings
- if(href_list["proc"] != "ping")
+ if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2))
WRITE_FILE(GLOB.world_href_log, "<small>[time_stamp(show_ds = TRUE)] [src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]<br>")
// Admin PM
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
diff a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm (rejected hunks)
@@ -130,12 +130,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
menuoptions = list()
return
-/datum/preferences/vv_edit_var(var_name, var_value)
- var/static/list/banned_edits = list("exp")
- if(var_name in banned_edits)
- return FALSE
- return ..()
-
/datum/preferences/proc/ShowChoices(mob/user)
if(!user || !user.client)
return
@@ -1,10 +0,0 @@
diff a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm (rejected hunks)
@@ -193,7 +193,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
return 0
S.cd = "/"
- WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date)
+ WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date
//general preferences
WRITE_FILE(S["ooccolor"], ooccolor)
+2 -2
View File
@@ -9,7 +9,7 @@
avgping = MC_AVERAGE_SLOW(avgping, ping)
/client/proc/pingfromtime(time)
return ((world.time+world.tick_lag*world.tick_usage/100)-time)*100
return ((world.time+world.tick_lag*TICK_USAGE_REAL/100)-time)*100
/client/verb/display_ping(time as num)
set instant = TRUE
@@ -19,4 +19,4 @@
/client/verb/ping()
set name = "Ping"
set category = "OOC"
winset(src, null, "command=.display_ping+[world.time+world.tick_lag*world.tick_usage/100]")
winset(src, null, "command=.display_ping+[world.time+world.tick_lag*TICK_USAGE_REAL/100]")
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm (rejected hunks)
@@ -384,7 +384,7 @@
item_color = "black"
desc = "A pair of black shoes."
permeability_coefficient = 0.05
- flags = NOSLIP
+ flags_1 = NOSLIP_1
origin_tech = "syndicate=2"
resistance_flags = 0
pockets = /obj/item/storage/internal/pocket/shoes
+4 -3
View File
@@ -7,7 +7,7 @@
var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets
var/visor_flags = 0 //flags_1 that are added/removed when an item is adjusted up/down
var/visor_flags = 0 //flags that are added/removed when an item is adjusted up/down
var/visor_flags_inv = 0 //same as visor_flags, but for flags_inv
var/visor_flags_cover = 0 //same as above, but for flags_cover
//what to toggle when toggled with weldingvisortoggle()
@@ -193,7 +193,6 @@
var/invis_view = SEE_INVISIBLE_LIVING
var/invis_override = 0 //Override to allow glasses to set higher than normal see_invis
var/lighting_alpha
var/emagged = FALSE
var/list/icon/current = list() //the current hud icons
var/vision_correction = 0 //does wearing these glasses correct some of our vision defects?
strip_delay = 20
@@ -475,6 +474,8 @@ BLIND // can't see anything
permeability_coefficient = 0.01
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50, fire = 80, acid = 70)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
dynamic_hair_suffix = ""
dynamic_fhair_suffix = ""
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
@@ -783,7 +784,7 @@ BLIND // can't see anything
A.UpdateButtonIcon()
return TRUE
/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags_1
/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags
up = !up
flags_1 ^= visor_flags
flags_inv ^= visor_flags_inv
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm (rejected hunks)
@@ -494,7 +494,7 @@ BLIND // can't see anything
w_class = WEIGHT_CLASS_BULKY
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
- flags = STOPSPRESSUREDMAGE | THICKMATERIAL
+ flags_1 = STOPSPRESSUREDMAGE_1 | THICKMATERIAL_1
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals)
slowdown = 1
@@ -1,10 +0,0 @@
diff a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm (rejected hunks)
@@ -331,7 +331,7 @@
vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
darkness_view = 8
scan_reagents = 1
- flags = NODROP
+ flags_1 = NODROP_1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
/obj/item/clothing/glasses/godeye/attackby(obj/item/W as obj, mob/user as mob, params)
@@ -1,9 +0,0 @@
diff a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm (rejected hunks)
@@ -4,7 +4,6 @@
/obj/item/clothing/head/collectable
name = "collectable hat"
desc = "A rare collectable hat."
- dynamic_hair_suffix = "+detective"
/obj/item/clothing/head/collectable/petehat
-16
View File
@@ -1,16 +0,0 @@
diff a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm (rejected hunks)
@@ -250,7 +250,7 @@
name = "jester hat"
desc = "A hat with bells, to add some merriness to the suit."
icon_state = "jester_hat"
- dynamic_hair_suffix = "null"
+ dynamic_hair_suffix = ""
/obj/item/clothing/head/rice_hat
name = "rice hat"
@@ -302,4 +302,4 @@
name = "jester hat"
desc = "A hat with bells, to add some merriness to the suit."
icon_state = "jester_hat2"
- dynamic_hair_suffix = "null"
+ dynamic_hair_suffix = ""
+6 -5
View File
@@ -125,17 +125,18 @@
desc = "A pair of kitty ears. Meow!"
icon_state = "kitty"
color = "#999999"
dynamic_hair_suffix = ""
dynamic_hair_suffix = ""
dog_fashion = /datum/dog_fashion/head/kitty
/obj/item/clothing/head/kitty/equipped(mob/user, slot)
if(user && slot == slot_head)
/obj/item/clothing/head/kitty/equipped(mob/living/carbon/human/user, slot)
if(ishuman(user) && slot == slot_head)
update_icon(user)
user.update_inv_head() //Color might have been changed by update_icon.
..()
/obj/item/clothing/head/kitty/update_icon(mob/living/carbon/human/user)
if(istype(user))
if(ishuman(user))
add_atom_colour("#[user.hair_color]", FIXED_COLOUR_PRIORITY)
/obj/item/clothing/head/kitty/genuine
@@ -151,7 +152,7 @@
flags_inv = 0
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
brightness_on = 1 //luminosity when on
dynamic_hair_suffix = ""
dynamic_hair_suffix = ""
dog_fashion = /datum/dog_fashion/head/reindeer
@@ -57,6 +57,8 @@ Contains:
name = "officer's beret"
desc = "An armored beret commonly used by special operations officers. Uses advanced force field technology to protect the head from space."
icon_state = "beret_badge"
dynamic_hair_suffix = "+generic"
dynamic_fhair_suffix = "+generic"
flags_1 = STOPSPRESSUREDMAGE_1
flags_inv = 0
armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm (rejected hunks)
@@ -348,7 +348,7 @@
w_class = WEIGHT_CLASS_BULKY
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/gun/energy, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals/emergency_oxygen)
- flags = THICKMATERIAL
+ flags_1 = THICKMATERIAL_1
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm (rejected hunks)
@@ -18,7 +18,7 @@
w_class = WEIGHT_CLASS_BULKY
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
- flags = THICKMATERIAL
+ flags_1 = THICKMATERIAL_1
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 1
allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/pen, /obj/item/device/flashlight/pen, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray)
@@ -1,19 +0,0 @@
diff a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm (rejected hunks)
@@ -21,7 +21,7 @@
allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/extinguisher, /obj/item/crowbar)
slowdown = 1
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- flags = STOPSPRESSUREDMAGE | THICKMATERIAL
+ flags_1 = STOPSPRESSUREDMAGE_1 | THICKMATERIAL_1
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
@@ -124,7 +124,7 @@
w_class = WEIGHT_CLASS_BULKY
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- flags = THICKMATERIAL
+ flags_1 = THICKMATERIAL_1
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/device/geiger_counter)
slowdown = 1.5
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm (rejected hunks)
@@ -96,7 +96,7 @@
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
- if(RC.container_type & OPENCONTAINER)
+ if(RC.container_type & OPENCONTAINER_1)
for(var/datum/reagent/A in RC.reagents.reagent_list)
.[A.type] += A.volume
.[I.type] += 1
+2 -1
View File
@@ -16,4 +16,5 @@
//sound not longer matches the text, but an audible warning is probably good
/datum/round_event/radiation_storm/start()
SSweather.run_weather("radiation storm",ZLEVEL_STATION)
SSweather.run_weather("radiation storm",ZLEVEL_STATION)
make_maint_all_access()
-37
View File
@@ -69,43 +69,6 @@
return
/datum/spacevine_mutation/space_covering
name = "space protective"
hue = "#aa77aa"
quality = POSITIVE
/datum/spacevine_mutation/space_covering
var/static/list/coverable_turfs
/datum/spacevine_mutation/space_covering/New()
. = ..()
if(!coverable_turfs)
coverable_turfs = typecacheof(list(/turf/open/space)) - /turf/open/space/transit
/datum/spacevine_mutation/space_covering/on_grow(obj/structure/spacevine/holder)
process_mutation(holder)
/datum/spacevine_mutation/space_covering/process_mutation(obj/structure/spacevine/holder)
var/turf/T = get_turf(holder)
if(is_type_in_typecache(T, coverable_turfs))
var/currtype = T.type
T.ChangeTurf(/turf/open/floor/vines)
T.baseturf = currtype
/datum/spacevine_mutation/space_covering/on_death(obj/structure/spacevine/holder)
var/turf/T = get_turf(holder)
if(istype(T, /turf/open/floor/vines))
T.ChangeTurf(T.baseturf)
/datum/spacevine_mutation/bluespace
name = "bluespace"
hue = "#3333ff"
quality = MINOR_NEGATIVE
/datum/spacevine_mutation/bluespace/on_spread(obj/structure/spacevine/holder, turf/target)
if(holder.energy > 1 && !locate(/obj/structure/spacevine) in target)
holder.master.spawn_spacevine_piece(target, holder)
/datum/spacevine_mutation/light
name = "light"
hue = "#ffff00"
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/fields/turf_objects.dm b/code/modules/fields/turf_objects.dm (rejected hunks)
@@ -6,7 +6,7 @@
icon_state = null
alpha = 0
invisibility = INVISIBILITY_ABSTRACT
- flags = ABSTRACT|ON_BORDER
+ flags_1 = ABSTRACT_1|ON_BORDER_1
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/datum/proximity_monitor/advanced/parent = null
+2 -2
View File
@@ -759,7 +759,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
people += H
if(person) //Basic talk
var/image/speech_overlay = image('icons/mob/talk.dmi', person, "default0", layer = ABOVE_MOB_LAYER)
var/message = target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans())
var/message = target.compose_message(person,understood_language,pick(speak_messages),null,person.get_spans(),face_name = TRUE)
feedback_details += "Type: Talk, Source: [person.real_name], Message: [message]"
to_chat(target, message)
if(target.client)
@@ -771,7 +771,7 @@ GLOBAL_LIST_INIT(hallucinations_major, list(
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
humans += H
person = pick(humans)
var/message = target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans())
var/message = target.compose_message(person,understood_language,pick(radio_messages),"1459",person.get_spans(),face_name = TRUE)
feedback_details += "Type: Radio, Source: [person.real_name], Message: [message]"
to_chat(target, message)
qdel(src)
File diff suppressed because it is too large Load Diff
@@ -341,7 +341,7 @@
name = "soda can"
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
container_type = 0
container_type = NONE
spillable = FALSE
/obj/item/reagent_containers/food/drinks/soda_cans/attack(mob/M, mob/user)
@@ -1,10 +0,0 @@
diff a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm (rejected hunks)
@@ -357,7 +357,7 @@
/obj/item/reagent_containers/food/drinks/soda_cans/attack_self(mob/user)
if(!is_open_container())
to_chat(user, "You pull back the tab of \the [src] with a satisfying pop.") //Ahhhhhhhh
- container_type = OPENCONTAINER
+ container_type = OPENCONTAINER_1
playsound(src, "can_open", 50, 1)
spillable = TRUE
return
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm (rejected hunks)
@@ -4,7 +4,7 @@
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
volume = 50 //Sets the default container amount for all food items.
- container_type = INJECTABLE
+ container_type = INJECTABLE_1
resistance_flags = FLAMMABLE
var/foodtype = NONE
var/last_check_time
@@ -1,13 +0,0 @@
diff a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm (rejected hunks)
@@ -225,6 +225,11 @@
tastes = list("meat" = 1, "wheat" = 1)
foodtype = GRAIN
+/obj/item/weapon/reagent_containers/food/snacks/meat/slab/gorilla
+ name = "gorilla meat"
+ desc = "Much meatier than monkey meat."
+ list_reagents = list("nutriment" = 5, "vitamin" = 1)
+
/obj/item/weapon/reagent_containers/food/snacks/meat/rawbacon
name = "raw piece of bacon"
desc = "A raw piece of bacon."
@@ -1,10 +0,0 @@
diff a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm (rejected hunks)
@@ -15,7 +15,7 @@ insert ascii eagle on american flag background here
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
- container_type = OPENCONTAINER
+ container_type = OPENCONTAINER_1
var/obj/item/frying = null //What's being fried RIGHT NOW?
var/cook_time = 0
var/static/list/deepfry_blacklisted_items = typecacheof(list(
@@ -1,10 +0,0 @@
diff a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm (rejected hunks)
@@ -15,7 +15,7 @@
var/portion = 10
var/selected_drink
var/list/stored_food = list()
- container_type = OPENCONTAINER
+ container_type = OPENCONTAINER_1
var/obj/item/reagent_containers/mixer
/obj/machinery/food_cart/Initialize()
@@ -1,10 +0,0 @@
diff a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm (rejected hunks)
@@ -14,7 +14,7 @@
anchored = FALSE
use_power = NO_POWER_USE
layer = BELOW_OBJ_LAYER
- container_type = OPENCONTAINER
+ container_type = OPENCONTAINER_1
max_integrity = 300
var/list/product_types = list()
var/dispense_flavour = ICECREAM_VANILLA
-137
View File
@@ -1,137 +0,0 @@
diff a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm (rejected hunks)
@@ -166,135 +166,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
//Global chat procs
-//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
-// exporting it as text, and then parsing the base64 from that.
-// (This relies on byond automatically storing icons in savefiles as base64)
-/proc/icon2base64(icon/icon, iconKey = "misc")
- if (!isicon(icon))
- return FALSE
- WRITE_FILE(GLOB.iconCache[iconKey], icon)
- var/iconData = GLOB.iconCache.ExportText(iconKey)
- var/list/partial = splittext(iconData, "{")
- return replacetext(copytext(partial[2], 3, -5), "\n", "")
-
-/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving)
- if (!thing)
- return
- var/static/datum/callback/CB = CALLBACK(GLOBAL_PROC, .proc/send_asset)
-
- var/key
- var/icon/I = thing
- if (!target)
- return
- if (target == world)
- target = GLOB.clients
-
- var/list/targets
- if (!islist(target))
- targets = list(target)
- else
- targets = target
- if (!targets.len)
- return
- debug_usr("start")
- if (!isicon(I))
- debug_usr("not icon")
- if (isfile(thing)) //special snowflake
- debug_usr("file")
- var/name = sanitize_filename("bicon.[thing]")
- debug_usr("file:[name]")
- register_asset(name, thing)
- var/list/callbacks
- var/list/callback_args = list()
- for (var/thing2 in targets)
- callbacks += CB
- callback_args[++callback_args.len] = list(thing2, name, TRUE)
- callback_select(callbacks, callback_args, savereturns = FALSE)
- return "<img class='icon misc' src=\"[url_encode(name)]\">"
- debug_usr("not file")
- var/atom/A
- if (isnull(dir))
- dir = A.dir
- if (isnull(icon_state))
- icon_state = A.icon_state
- I = A.icon
- if (ishuman(thing)) // Shitty workaround for a BYOND issue.
- debug_usr("human")
- var/icon/temp = I
- I = icon()
- I.Insert(temp, dir = SOUTH)
- dir = SOUTH
- else
- debug_usr("icon")
- if (isnull(dir))
- dir = SOUTH
- if (isnull(icon_state))
- icon_state = ""
-
- I = icon(I, icon_state, dir, frame)
-
- key = sanitize_filename("bicon.[md5(icon2base64(I))].[icon_state].[dir].png")
- debug_usr("key:[key]")
- register_asset(key, I)
- var/list/callbacks = list()
- var/list/callback_args = list()
- for (var/thing2 in targets)
- callbacks += CB
- callback_args[++callback_args.len] = list(thing2, key, TRUE)
-
- callback_select(callbacks, callback_args, savereturns = FALSE)
- return "<img class='icon [icon_state]' src=\"[url_encode(key)]\">"
-
-/proc/icon2base64html(thing)
- if (!thing)
- return
- var/static/list/bicon_cache = list()
- if (isicon(thing))
- var/icon/I = thing
- var/icon_base64 = icon2base64(I)
-
- if (I.Height() > world.icon_size || I.Width() > world.icon_size)
- var/icon_md5 = md5(icon_base64)
- debug_admins(icon_md5)
- icon_base64 = bicon_cache[icon_md5]
- if (!icon_base64) // Doesn't exist yet, make it.
- I = icon(I)
- I.Scale(world.icon_size, world.icon_size)
- bicon_cache[icon_md5] = icon_base64 = icon2base64(I)
-
-
- return "<img class='icon misc' src='data:image/png;base64,[icon_base64]'>"
-
- // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
- var/atom/A = thing
- var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
-
-
- if (!bicon_cache[key]) // Doesn't exist, make it.
- var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
- if (ishuman(thing)) // Shitty workaround for a BYOND issue.
- var/icon/temp = I
- I = icon()
- I.Insert(temp, dir = SOUTH)
-
- if (I.Height() > world.icon_size || I.Width() > world.icon_size)
- I.Scale(world.icon_size, world.icon_size)
-
- bicon_cache[key] = icon2base64(I, key)
-
- return "<img class='icon [A.icon_state]' src='data:image/png;base64,[bicon_cache[key]]'>"
-
-//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs.
-/proc/costly_icon2html(thing, target)
- if (!thing)
- return
-
- if (isicon(thing))
- return icon2html(thing, target)
-
- var/icon/I = getFlatIcon(thing)
- return icon2html(I, target)
-
/proc/to_chat(target, message)
if(!target)
return
+18 -5
View File
@@ -25,7 +25,7 @@
/obj/structure/beebox
name = "apiary"
desc = "Dr Miles Manners is just your average wasp-themed super hero by day, but by night he becomes DR BEES!"
desc = "Dr. Miles Manners is just your average wasp-themed super hero by day, but by night he becomes DR. BEES!"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "beebox"
anchored = TRUE
@@ -45,9 +45,7 @@
/obj/structure/beebox/Destroy()
STOP_PROCESSING(SSobj, src)
bees.Cut()
bees = null
honeycombs.Cut()
honeycombs = null
queen_bee = null
return ..()
@@ -151,7 +149,7 @@
honey_frames += HF
else
to_chat(user, "<span class='warning'>There's no room for any more frames in the apiary!</span>")
return
if(istype(I, /obj/item/wrench))
if(default_unfasten_wrench(user, I, time = 20))
return
@@ -187,6 +185,9 @@
to_chat(user, "<span class='warning'>The queen bee disappeared! Disappearing bees have been in the news lately...</span>")
qdel(qb)
return
..()
/obj/structure/beebox/attack_hand(mob/user)
@@ -203,8 +204,10 @@
bees = TRUE
if(bees)
visible_message("<span class='danger'>[user] disturbs the bees!</span>")
else
visible_message("<span class='danger'>[user] disturbs the [name] to no effect!</span>")
else
var/option = alert(user, "What action do you wish to perform?","Apiary","Remove a Honey Frame","Remove the Queen Bee")
var/option = alert(user, "What action do you wish to perform?","Apiary","Remove a Honey Frame","Remove the Queen Bee", "Cancel")
if(!Adjacent(user))
return
switch(option)
@@ -244,3 +247,13 @@
QB.loc = get_turf(src)
visible_message("<span class='notice'>[user] removes the queen from the apiary.</span>")
queen_bee = null
/obj/structure/beebox/deconstruct(disassembled = TRUE)
new /obj/item/stack/sheet/mineral/wood (loc, 20)
for(var/mob/living/simple_animal/hostile/poison/bees/B in bees)
if(B.loc == src)
B.loc = get_turf(src)
for(var/obj/item/honey_frame/HF in honey_frames)
if(HF.loc == src)
HF.loc = get_turf(src)
qdel(src)
+1 -1
View File
@@ -113,7 +113,7 @@
/obj/item/reagent_containers/food/snacks/grown/cannabis/ultimate
seed = /obj/item/seeds/cannabis/ultimate
name = "omega cannibas leaf"
name = "omega cannabis leaf"
desc = "You feel dizzy looking at it. What the fuck?"
icon_state = "ocannabis"
volume = 420
+4 -2
View File
@@ -42,8 +42,10 @@
qdel(src)
/obj/item/seeds/kudzu/attack_self(mob/user)
plant(user)
to_chat(user, "<span class='notice'>You plant the kudzu. You monster.</span>")
user.visible_message("<span class='danger'>[user] begins throwing seeds on the ground...</span>")
if(do_after(user, 50, needhand = TRUE, target = user.drop_location(), progress = TRUE))
plant(user)
to_chat(user, "<span class='notice'>You plant the kudzu. You monster.</span>")
/obj/item/seeds/kudzu/get_analyzer_text()
var/text = ..()
+3 -1
View File
@@ -915,9 +915,11 @@
name = "soil"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "soil"
circuit = null
density = FALSE
use_power = NO_POWER_USE
unwrenchable = 0
flags_1 = NODECONSTRUCT_1
unwrenchable = FALSE
/obj/machinery/hydroponics/soil/update_icon_hoses()
return // Has no hoses
+279
View File
@@ -0,0 +1,279 @@
GLOBAL_LIST_EMPTY(exp_to_update)
GLOBAL_PROTECT(exp_to_update)
// Procs
/datum/job/proc/required_playtime_remaining(client/C)
if(!C)
return 0
if(!config.use_exp_tracking)
return 0
if(!exp_requirements || !exp_type)
return 0
if(!job_is_xp_locked(src.title))
return 0
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, FALSE, C.mob))
return 0
var/isexempt = C.prefs.db_flags & DB_FLAG_EXEMPT
if(isexempt)
return 0
var/my_exp = C.calc_exp_type(get_exp_req_type())
var/job_requirement = get_exp_req_amount()
if(my_exp >= job_requirement)
return 0
else
return (job_requirement - my_exp)
/datum/job/proc/get_exp_req_amount()
if(title in GLOB.command_positions)
if(config.use_exp_restrictions_heads_hours)
return config.use_exp_restrictions_heads_hours * 60
return exp_requirements
/datum/job/proc/get_exp_req_type()
if(title in GLOB.command_positions)
if(config.use_exp_restrictions_heads_department && exp_type_department)
return exp_type_department
return exp_type
/proc/job_is_xp_locked(jobtitle)
if(!config.use_exp_restrictions_heads && jobtitle in GLOB.command_positions)
return FALSE
if(!config.use_exp_restrictions_other && !(jobtitle in GLOB.command_positions))
return FALSE
return TRUE
/client/proc/calc_exp_type(exptype)
var/list/explist = prefs.exp.Copy()
var/amount = 0
var/list/typelist = GLOB.exp_jobsmap[exptype]
if(!typelist)
return -1
for(var/job in typelist["titles"])
if(job in explist)
amount += explist[job]
return amount
/client/proc/get_exp_report()
if(!config.use_exp_tracking)
return "Tracking is disabled in the server configuration file."
var/list/play_records = prefs.exp
if(!play_records.len)
set_exp_from_db()
play_records = prefs.exp
if(!play_records.len)
return "[key] has no records."
var/return_text = list()
return_text += "<UL>"
var/list/exp_data = list()
for(var/category in SSjob.name_occupations)
if(play_records[category])
exp_data[category] = text2num(play_records[category])
else
exp_data[category] = 0
for(var/category in GLOB.exp_specialmap)
if(play_records[category])
exp_data[category] = text2num(play_records[category])
else
exp_data[category] = 0
if(prefs.db_flags & DB_FLAG_EXEMPT)
return_text += "<LI>Exempt (all jobs auto-unlocked)</LI>"
for(var/dep in exp_data)
if(exp_data[dep] > 0)
if(exp_data[EXP_TYPE_LIVING] > 0)
var/percentage = num2text(round(exp_data[dep]/exp_data[EXP_TYPE_LIVING]*100))
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] ([percentage]%)</LI>"
else
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] </LI>"
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, mob))
return_text += "<LI>Admin (all jobs auto-unlocked)</LI>"
return_text += "</UL>"
var/list/jobs_locked = list()
var/list/jobs_unlocked = list()
for(var/datum/job/job in SSjob.occupations)
if(job.exp_requirements && job.exp_type)
if(!job_is_xp_locked(job.title))
continue
else if(!job.required_playtime_remaining(mob.client))
jobs_unlocked += job.title
else
var/xp_req = job.get_exp_req_amount()
jobs_locked += "[job.title] [get_exp_format(text2num(calc_exp_type(job.get_exp_req_type())))] / [get_exp_format(xp_req)] as [job.get_exp_req_type()])"
if(jobs_unlocked.len)
return_text += "<BR><BR>Jobs Unlocked:<UL><LI>"
return_text += jobs_unlocked.Join("</LI><LI>")
return_text += "</LI></UL>"
if(jobs_locked.len)
return_text += "<BR><BR>Jobs Not Unlocked:<UL><LI>"
return_text += jobs_locked.Join("</LI><LI>")
return_text += "</LI></UL>"
return return_text
/client/proc/get_exp_living()
if(!prefs.exp)
return "No data"
var/exp_living = text2num(prefs.exp[EXP_TYPE_LIVING])
return get_exp_format(exp_living)
/proc/get_exp_format(expnum)
if(expnum > 60)
return num2text(round(expnum / 60)) + "h"
else if(expnum > 0)
return num2text(expnum) + "m"
else
return "0h"
/datum/controller/subsystem/blackbox/proc/update_exp(mins, ann = FALSE)
if(!SSdbcore.Connect())
return -1
for(var/client/L in GLOB.clients)
if(L.is_afk())
continue
addtimer(CALLBACK(L,/client/proc/update_exp_list,mins,ann),10)
/datum/controller/subsystem/blackbox/proc/update_exp_db()
SSdbcore.MassInsert(format_table_name("role_time"),GLOB.exp_to_update,TRUE)
LAZYCLEARLIST(GLOB.exp_to_update)
//resets a client's exp to what was in the db.
/client/proc/set_exp_from_db()
if(!config.use_exp_tracking)
return -1
if(!SSdbcore.Connect())
return -1
var/datum/DBQuery/exp_read = SSdbcore.NewQuery("SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = '[sanitizeSQL(ckey)]'")
if(!exp_read.Execute())
return -1
var/list/play_records = list()
while(exp_read.NextRow())
play_records[exp_read.item[1]] = text2num(exp_read.item[2])
for(var/rtype in SSjob.name_occupations)
if(!play_records[rtype])
play_records[rtype] = 0
for(var/rtype in GLOB.exp_specialmap)
if(!play_records[rtype])
play_records[rtype] = 0
prefs.exp = play_records
//updates player db flags
/client/proc/update_flag_db(newflag, state = FALSE)
if(!SSdbcore.Connect())
return -1
if(!set_db_player_flags())
return -1
if((prefs.db_flags & newflag) && !state)
prefs.db_flags &= ~newflag
else
prefs.db_flags |= newflag
var/datum/DBQuery/flag_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET flags = '[prefs.db_flags]' WHERE ckey='[sanitizeSQL(ckey)]'")
if(!flag_update.Execute())
return -1
/client/proc/update_exp_list(minutes, announce_changes = FALSE)
if(!config.use_exp_tracking)
return -1
if(!SSdbcore.Connect())
return -1
var/datum/DBQuery/exp_read = SSdbcore.NewQuery("SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = '[sanitizeSQL(ckey)]'")
if(!exp_read.Execute())
return -1
var/list/play_records = list()
while(exp_read.NextRow())
play_records[exp_read.item[1]] = text2num(exp_read.item[2])
for(var/rtype in SSjob.name_occupations)
if(!play_records[rtype])
play_records[rtype] = 0
for(var/rtype in GLOB.exp_specialmap)
if(!play_records[rtype])
play_records[rtype] = 0
var/list/old_records = play_records.Copy()
if(isliving(mob))
if(mob.stat != DEAD)
var/rolefound = FALSE
play_records[EXP_TYPE_LIVING] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Living EXP!</span>")
if(mob.mind.assigned_role)
for(var/job in SSjob.name_occupations)
if(mob.mind.assigned_role == job)
rolefound = TRUE
play_records[job] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] [job] EXP!</span>")
if(!rolefound)
for(var/role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])
if(mob.mind.assigned_role == role)
rolefound = TRUE
play_records[role] += minutes
if(announce_changes)
to_chat(mob,"<span class='notice'>You got: [minutes] [role] EXP!</span>")
if(mob.mind.special_role && !mob.mind.var_edited)
var/trackedrole = mob.mind.special_role
var/gangrole = lookforgangrole(mob.mind.special_role)
if(gangrole)
trackedrole = gangrole
play_records[trackedrole] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] [trackedrole] EXP!</span>")
if(!rolefound)
play_records["Unknown"] += minutes
else
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Ghost EXP!</span>")
else if(isobserver(mob))
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Ghost EXP!</span>")
else if(minutes) //Let "refresh" checks go through
return
prefs.exp = play_records
for(var/jtype in play_records)
if(play_records[jtype] != old_records[jtype])
LAZYINITLIST(GLOB.exp_to_update)
GLOB.exp_to_update.Add(list(list(
"job" = "'[sanitizeSQL(jtype)]'",
"ckey" = "'[sanitizeSQL(ckey)]'",
"minutes" = play_records[jtype])))
addtimer(CALLBACK(SSblackbox,/datum/controller/subsystem/blackbox/proc/update_exp_db),20,TIMER_OVERRIDE|TIMER_UNIQUE)
//ALWAYS call this at beginning to any proc touching player flags, or your database admin will probably be mad
/client/proc/set_db_player_flags()
if(!SSdbcore.Connect())
return FALSE
var/datum/DBQuery/flags_read = SSdbcore.NewQuery("SELECT flags FROM [format_table_name("player")] WHERE ckey='[ckey]'")
if(!flags_read.Execute())
return FALSE
if(flags_read.NextRow())
prefs.db_flags = text2num(flags_read.item[1])
else if(isnull(prefs.db_flags))
prefs.db_flags = 0 //This PROBABLY won't happen, but better safe than sorry.
return TRUE
//Since each gang is tracked as a different antag type, records need to be generalized or you get up to 57 different possible records
/proc/lookforgangrole(rolecheck)
if(findtext(rolecheck,"Gangster"))
return "Gangster"
else if(findtext(rolecheck,"Gang Boss"))
return "Gang Boss"
else if(findtext(rolecheck,"Gang Lieutenant"))
return "Gang Lieutenant"
else
return FALSE
+108
View File
@@ -0,0 +1,108 @@
diff a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm (rejected hunks)
@@ -140,15 +140,12 @@ GLOBAL_PROTECT(exp_to_update)
//resets a client's exp to what was in the db.
/client/proc/set_exp_from_db()
if(!config.use_exp_tracking)
- return
+ return -1
if(!SSdbcore.Connect())
return -1
var/datum/DBQuery/exp_read = SSdbcore.NewQuery("SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = '[sanitizeSQL(ckey)]'")
if(!exp_read.Execute())
- var/err = exp_read.ErrorMsg()
- log_sql("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
- message_admins("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
- return
+ return -1
var/list/play_records = list()
while(exp_read.NextRow())
play_records[exp_read.item[1]] = text2num(exp_read.item[2])
@@ -172,42 +169,24 @@ GLOBAL_PROTECT(exp_to_update)
if(!set_db_player_flags())
return -1
- var/datum/DBQuery/flag_read = SSdbcore.NewQuery("SELECT flags FROM [format_table_name("player")] WHERE ckey='[sanitizeSQL(ckey)]'")
-
- if(!flag_read.Execute())
- var/err = flag_read.ErrorMsg()
- log_sql("SQL ERROR during player flags read. Error : \[[err]\]\n")
- message_admins("SQL ERROR during player flags read. Error : \[[err]\]\n")
- return
-
- var/playerflags = null
- if(flag_read.NextRow())
- playerflags = text2num(flag_read.item[1])
-
- if((playerflags & newflag) && !state)
+ if((prefs.db_flags & newflag) && !state)
prefs.db_flags &= ~newflag
else
prefs.db_flags |= newflag
var/datum/DBQuery/flag_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET flags = '[prefs.db_flags]' WHERE ckey='[sanitizeSQL(ckey)]'")
-
if(!flag_update.Execute())
- var/err = flag_update.ErrorMsg()
- log_sql("SQL ERROR during exp_exempt update. Error : \[[err]\]\n")
- message_admins("SQL ERROR during exp_exempt update. Error : \[[err]\]\n")
- return
+ return -1
+
/client/proc/update_exp_list(minutes, announce_changes = FALSE)
if(!config.use_exp_tracking)
- return
+ return -1
if(!SSdbcore.Connect())
return -1
var/datum/DBQuery/exp_read = SSdbcore.NewQuery("SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = '[sanitizeSQL(ckey)]'")
if(!exp_read.Execute())
- var/err = exp_read.ErrorMsg()
- log_sql("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
- message_admins("SQL ERROR during exp_update_client read. Error : \[[err]\]\n")
return -1
var/list/play_records = list()
while(exp_read.NextRow())
@@ -241,9 +220,13 @@ GLOBAL_PROTECT(exp_to_update)
if(announce_changes)
to_chat(mob,"<span class='notice'>You got: [minutes] [role] EXP!</span>")
if(mob.mind.special_role && !mob.mind.var_edited)
- play_records[mob.mind.special_role] += minutes
+ var/trackedrole = mob.mind.special_role
+ var/gangrole = lookforgangrole(mob.mind.special_role)
+ if(gangrole)
+ trackedrole = gangrole
+ play_records[trackedrole] += minutes
if(announce_changes)
- to_chat(src,"<span class='notice'>You got: [minutes] [mob.mind.special_role] EXP!</span>")
+ to_chat(src,"<span class='notice'>You got: [minutes] [trackedrole] EXP!</span>")
if(!rolefound)
play_records["Unknown"] += minutes
else
@@ -276,11 +259,21 @@ GLOBAL_PROTECT(exp_to_update)
var/datum/DBQuery/flags_read = SSdbcore.NewQuery("SELECT flags FROM [format_table_name("player")] WHERE ckey='[ckey]'")
if(!flags_read.Execute())
- var/err = flags_read.ErrorMsg()
- log_sql("SQL ERROR during player flags read. Error : \[[err]\]\n")
- message_admins("SQL ERROR during player flags read. Error : \[[err]\]\n")
return FALSE
if(flags_read.NextRow())
prefs.db_flags = text2num(flags_read.item[1])
+ else if(isnull(prefs.db_flags))
+ prefs.db_flags = 0 //This PROBABLY won't happen, but better safe than sorry.
return TRUE
+
+//Since each gang is tracked as a different antag type, records need to be generalized or you get up to 57 different possible records
+/proc/lookforgangrole(rolecheck)
+ if(findtext(rolecheck,"Gangster"))
+ return "Gangster"
+ else if(findtext(rolecheck,"Gang Boss"))
+ return "Gang Boss"
+ else if(findtext(rolecheck,"Gang Lieutenant"))
+ return "Gang Lieutenant"
+ else
+ return FALSE
\ No newline at end of file
+5
View File
@@ -13,6 +13,8 @@ Captain
selection_color = "#ccccff"
req_admin_notify = 1
minimal_player_age = 14
exp_requirements = 180
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/captain
@@ -64,6 +66,9 @@ Head of Personnel
selection_color = "#ddddff"
req_admin_notify = 1
minimal_player_age = 10
exp_requirements = 180
exp_type = EXP_TYPE_CREW
exp_type_department = EXP_TYPE_SUPPLY
outfit = /datum/outfit/job/hop
@@ -14,6 +14,9 @@ Chief Engineer
selection_color = "#ffeeaa"
req_admin_notify = 1
minimal_player_age = 7
exp_requirements = 180
exp_type = EXP_TYPE_CREW
exp_type_department = EXP_TYPE_ENGINEERING
outfit = /datum/outfit/job/ce
@@ -72,6 +75,8 @@ Station Engineer
spawn_positions = 5
supervisors = "the chief engineer"
selection_color = "#fff5cc"
exp_requirements = 60
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/engineer
@@ -127,6 +132,8 @@ Atmospheric Technician
spawn_positions = 2
supervisors = "the chief engineer"
selection_color = "#fff5cc"
exp_requirements = 60
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/atmos
+5
View File
@@ -43,6 +43,11 @@
var/outfit = null
var/exp_requirements = 0
var/exp_type = ""
var/exp_type_department = ""
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M)
+9
View File
@@ -14,6 +14,9 @@ Chief Medical Officer
selection_color = "#ffddf0"
req_admin_notify = 1
minimal_player_age = 7
exp_requirements = 180
exp_type = EXP_TYPE_CREW
exp_type_department = EXP_TYPE_MEDICAL
outfit = /datum/outfit/job/cmo
@@ -90,6 +93,8 @@ Chemist
spawn_positions = 2
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
exp_type = EXP_TYPE_CREW
exp_requirements = 60
outfit = /datum/outfit/job/chemist
@@ -124,6 +129,8 @@ Geneticist
spawn_positions = 2
supervisors = "the chief medical officer and research director"
selection_color = "#ffeef0"
exp_type = EXP_TYPE_CREW
exp_requirements = 60
outfit = /datum/outfit/job/geneticist
@@ -158,6 +165,8 @@ Virologist
spawn_positions = 1
supervisors = "the chief medical officer"
selection_color = "#ffeef0"
exp_type = EXP_TYPE_CREW
exp_requirements = 60
outfit = /datum/outfit/job/virologist
+7
View File
@@ -14,6 +14,9 @@ Research Director
selection_color = "#ffddff"
req_admin_notify = 1
minimal_player_age = 7
exp_type_department = EXP_TYPE_SCIENCE
exp_requirements = 180
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/rd
@@ -68,6 +71,8 @@ Scientist
spawn_positions = 3
supervisors = "the research director"
selection_color = "#ffeeff"
exp_requirements = 60
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/scientist
@@ -101,6 +106,8 @@ Roboticist
spawn_positions = 2
supervisors = "research director"
selection_color = "#ffeeff"
exp_requirements = 60
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/roboticist
+9
View File
@@ -20,6 +20,9 @@ Head of Security
selection_color = "#ffdddd"
req_admin_notify = 1
minimal_player_age = 14
exp_requirements = 300
exp_type = EXP_TYPE_CREW
exp_type_department = EXP_TYPE_SECURITY
outfit = /datum/outfit/job/hos
@@ -71,6 +74,8 @@ Warden
supervisors = "the head of security"
selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 300
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/warden
@@ -121,6 +126,8 @@ Detective
supervisors = "the head of security"
selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 300
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/detective
@@ -169,6 +176,8 @@ Security Officer
supervisors = "the head of security, and the head of your assigned department (if applicable)"
selection_color = "#ffeeee"
minimal_player_age = 7
exp_requirements = 300
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/security
+4
View File
@@ -12,6 +12,8 @@ AI
supervisors = "your laws"
req_admin_notify = 1
minimal_player_age = 30
exp_requirements = 180
exp_type = EXP_TYPE_CREW
/datum/job/ai/equip(mob/living/carbon/human/H)
return H.AIize(FALSE)
@@ -44,6 +46,8 @@ Cyborg
supervisors = "your laws and the AI" //Nodrak
selection_color = "#ddffdd"
minimal_player_age = 21
exp_requirements = 120
exp_type = EXP_TYPE_CREW
/datum/job/cyborg/equip(mob/living/carbon/human/H)
return H.Robotize(FALSE, FALSE)
+20
View File
@@ -59,6 +59,26 @@ GLOBAL_LIST_INIT(nonhuman_positions, list(
"Cyborg",
"pAI"))
GLOBAL_LIST_INIT(exp_jobsmap, list(
EXP_TYPE_CREW = list("titles" = command_positions | engineering_positions | medical_positions | science_positions | supply_positions | security_positions | civilian_positions | list("AI","Cyborg")), // crew positions
EXP_TYPE_COMMAND = list("titles" = command_positions),
EXP_TYPE_ENGINEERING = list("titles" = engineering_positions),
EXP_TYPE_MEDICAL = list("titles" = medical_positions),
EXP_TYPE_SCIENCE = list("titles" = science_positions),
EXP_TYPE_SUPPLY = list("titles" = supply_positions),
EXP_TYPE_SECURITY = list("titles" = security_positions),
EXP_TYPE_SILICON = list("titles" = list("AI","Cyborg")),
EXP_TYPE_SERVICE = list("titles" = civilian_positions),
))
GLOBAL_LIST_INIT(exp_specialmap, list(
EXP_TYPE_LIVING = list(), // all living mobs
EXP_TYPE_ANTAG = list(),
EXP_TYPE_SPECIAL = list("Lifebringer","Ash Walker","Exile","Servant Golem","Free Golem","Hermit","Translocated Vet","Escaped Prisoner","Hotel Staff","SuperFriend","Space Syndicate","Ancient Crew","Space Doctor","Space Bartender","Beach Bum","Skeleton","Zombie","Space Bar Patron","Lavaland Syndicate","Ghost Role"), // Ghost roles
EXP_TYPE_GHOST = list() // dead people, observers
))
GLOBAL_PROTECT(exp_jobsmap)
GLOBAL_PROTECT(exp_specialmap)
/proc/guest_jobbans(job)
return ((job in GLOB.command_positions) || (job in GLOB.nonhuman_positions) || (job in GLOB.security_positions))
+18
View File
@@ -49,3 +49,21 @@
/obj/effect/baseturf_helper/lava_land/surface
name = "lavaland baseturf editor"
baseturf = /turf/open/lava/smooth/lava_land_surface
//Contains the list of planetary z-levels defined by the planet_z helper.
GLOBAL_LIST_EMPTY(z_is_planet)
/obj/effect/mapping_helpers/planet_z //adds the map it is on to the z_is_planet list
name = "planet z helper"
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "syndballoon"
layer = POINT_LAYER
/obj/effect/mapping_helpers/planet_z/Initialize()
. = ..()
var/turf/T = get_turf(src)
if(!turf_z_is_planet(T))
GLOB.z_is_planet["[T.z]"] = list()
qdel(src)
@@ -1,19 +0,0 @@
diff a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm (rejected hunks)
@@ -62,7 +62,7 @@
/obj/item/pickaxe/drill/cyborg
name = "cyborg mining drill"
desc = "An integrated electric mining drill."
- flags = NODROP
+ flags_1 = NODROP_1
/obj/item/pickaxe/drill/diamonddrill
name = "diamond-tipped mining drill"
@@ -72,7 +72,7 @@
desc = "Yours is the drill that will pierce the heavens!"
/obj/item/pickaxe/drill/cyborg/diamond //This is the BORG version!
- name = "diamond-tipped cyborg mining drill" //To inherit the NODROP flag, and easier to change borg specific drill mechanics.
+ name = "diamond-tipped cyborg mining drill" //To inherit the NODROP_1 flag, and easier to change borg specific drill mechanics.
icon_state = "diamonddrill"
digspeed = 7
@@ -1,35 +0,0 @@
diff a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm (rejected hunks)
@@ -167,7 +167,7 @@
pixel_y = -32
/obj/item/device/gps/computer/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/wrench) && !(flags&NODECONSTRUCT))
+ if(istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1))
playsound(src.loc, W.usesound, 50, 1)
user.visible_message("<span class='warning'>[user] disassembles the gps.</span>", \
"<span class='notice'>You start to disassemble the gps...</span>", "You hear clanking and banging noises.")
@@ -198,7 +198,7 @@
light_color = "#DDFFD3"
max_n_of_items = 10
pixel_y = -4
- flags = NODECONSTRUCT
+ flags_1 = NODECONSTRUCT_1
var/empty = FALSE
/obj/machinery/smartfridge/survival_pod/Initialize(mapload)
@@ -237,13 +237,13 @@
CanAtmosPass = ATMOS_PASS_NO
/obj/structure/fans/deconstruct()
- if(!(flags & NODECONSTRUCT))
+ if(!(flags_1 & NODECONSTRUCT_1))
if(buildstacktype)
new buildstacktype(loc,buildstackamount)
qdel(src)
/obj/structure/fans/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/wrench) && !(flags&NODECONSTRUCT))
+ if(istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1))
playsound(src.loc, W.usesound, 50, 1)
user.visible_message("<span class='warning'>[user] disassembles the fan.</span>", \
"<span class='notice'>You start to disassemble the fan...</span>", "You hear clanking and banging noises.")
@@ -1,4 +1,7 @@
/mob/dead/new_player/Login()
if(config.use_exp_tracking)
client.set_exp_from_db()
client.set_db_player_flags()
if(!mind)
mind = new /datum/mind(key)
mind.active = 1
@@ -0,0 +1,9 @@
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
@@ -307,6 +307,8 @@
return 0
if(!job.player_old_enough(src.client))
return 0
if(job.required_playtime_remaining(client))
return 0
if(config.enforce_human_authority && !client.prefs.pref_species.qualifies_for_rank(rank, client.prefs.features))
return 0
return 1
@@ -96,6 +96,20 @@
icon = 'icons/mob/mam_bodyparts.dmi'
extra = 1
/datum/sprite_accessory/tails/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
extra = 1
extra_color_src = MUTCOLORS2
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/tails_animated/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
extra = 1
extra_color_src = MUTCOLORS2
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/ears/lab
name = "Dog, Floppy"
icon_state = "lab"
@@ -119,6 +133,33 @@
color_src = 0
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/ears/human/otie
name = "Otusian"
icon_state = "otie"
hasinner= 1
/datum/sprite_accessory/tails/human/otie
name = "Otusian"
icon_state = "otie"
/datum/sprite_accessory/tails_animated/human/otie
name = "Otusian"
icon_state = "otie"
/datum/sprite_accessory/ears/human/skunk
name = "skunk"
icon_state = "skunk"
/datum/sprite_accessory/tails/human/skunk
name = "skunk"
icon_state = "skunk"
color_src = 0
/datum/sprite_accessory/tails_animated/human/skunk
name = "skunk"
icon_state = "skunk"
color_src = 0
/datum/sprite_accessory/tails/human/shark
name = "Shark"
icon_state = "shark"
@@ -198,6 +239,16 @@
**************** Snouts *******************
*******************************************/
/datum/sprite_accessory/snouts/none
name = "None"
icon_state = "none"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/snouts/bird
name = "Beak"
icon_state = "bird"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/snouts/lcanid
name = "Fox, Long"
icon_state = "lcanid"
@@ -347,6 +398,31 @@
icon_state = "husky"
extra = 1
/datum/sprite_accessory/mam_ears/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
extra = 1
/datum/sprite_accessory/mam_tails/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
/datum/sprite_accessory/mam_tails_animated/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
/datum/sprite_accessory/mam_tails/kitsune
name = "Kitsune"
icon_state = "kitsune"
extra = 1
extra_color_src = MUTCOLORS2
/datum/sprite_accessory/mam_tails_animated/kitsune
name = "Kitsune"
icon_state = "kitsune"
extra = 1
extra_color_src = MUTCOLORS2
/datum/sprite_accessory/mam_ears/lab
name = "Dog, Long"
icon_state = "lab"
@@ -386,6 +462,22 @@
name = "Otusian"
icon_state = "otie"
/datum/sprite_accessory/mam_ears/skunk
name = "skunk"
icon_state = "skunk"
/datum/sprite_accessory/mam_tails/skunk
name = "skunk"
icon_state = "skunk"
color_src = 0
extra = 1
/datum/sprite_accessory/mam_tails_animated/skunk
name = "skunk"
icon_state = "skunk"
color_src = 0
extra = 1
/datum/sprite_accessory/mam_tails/shark
name = "Shark"
icon_state = "shark"
@@ -396,17 +488,6 @@
icon_state = "shark"
color_src = 0
/datum/sprite_accessory/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
// ckeys_allowed = list("rubyflamewing")
/datum/sprite_accessory/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
/datum/sprite_accessory/mam_tails/shepherd
name = "Shepherd"
icon_state = "shepherd"
@@ -445,31 +526,18 @@
name = "Wolf"
icon_state = "wolf"
/datum/sprite_accessory/mam_tails/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra = 1
/datum/sprite_accessory/mam_tails_animated/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra = 1
/datum/sprite_accessory/mam_ears/guilmon
name = "Guilmon"
icon_state = "guilmon"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/mam_tails/rabbit
name = "Rabbit"
icon_state = "rabbit"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/mam_tails_animated/rabbit
name = "Rabbit"
icon_state = "rabbit"
/datum/sprite_accessory/mam_ears/rabbit
name = "Rabbit"
icon_state = "rabbit"
hasinner= 1
icon = 'icons/mob/mam_bodyparts.dmi'
/******************************************
************ Body Markings ****************
@@ -586,20 +654,14 @@
color_src = MUTCOLORS2
gender_specific = 1
/datum/sprite_accessory/mam_body_markings/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra = 1
extra2 = 1
icon = 'icons/mob/mam_body_markings.dmi'
/datum/sprite_accessory/mam_body_markings/xeno
/datum/sprite_accessory/mam_body_markings/xeno
name = "Xeno"
icon_state = "xeno"
color_src = MUTCOLORS2
extra_color_src = MUTCOLORS3
gender_specific = 1
/******************************************
************ Taur Bodies ******************
*******************************************/
@@ -711,7 +773,6 @@
icon = 'icons/mob/xeno_parts_greyscale.dmi'
//Xeno Caste Heads
//unused as of October 3, 2016
/datum/sprite_accessory/xeno_head
icon = 'icons/mob/xeno_parts_greyscale.dmi'
@@ -739,17 +800,67 @@
icon_state = "warrior"
icon = 'icons/mob/xeno_parts_greyscale.dmi'
// *** Snooooow flaaaaake ***
/datum/sprite_accessory/mam_body_markings/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra_color_src = MUTCOLORS2
extra2_color_src = MUTCOLORS3
gender_specific = 1
/datum/sprite_accessory/mam_tails/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra = 1
/datum/sprite_accessory/mam_tails_animated/guilmon
name = "Guilmon"
icon_state = "guilmon"
extra = 1
/datum/sprite_accessory/mam_ears/guilmon
name = "Guilmon"
icon_state = "guilmon"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
// ckeys_allowed = list("rubyflamewing")
/datum/sprite_accessory/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
/*
//Slimecoon Parts
/datum/sprite_accessory/slimecoon_ears
icon = 'icons/mob/exotic_bodyparts.dmi'
name = "Slimecoon Ears"
icon_state = "slimecoon"
/datum/sprite_accessory/slimecoon_tail
icon = 'icons/mob/exotic_bodyparts.dmi'
name = "Slimecoon Tail"
icon_state = "slimecoon"
/datum/sprite_accessory/slimecoon_snout
icon = 'icons/mob/exotic_bodyparts.dmi'
name = "Hunter"
icon_state = "slimecoon" */
//Till I get my snowflake only ckey lock, these are locked-locked :D
/datum/sprite_accessory/mam_ears/sabresune
name = "sabresune"
icon_state = "sabresune"
extra = 1
extra_color_src = MUTCOLORS3
locked = TRUE
/datum/sprite_accessory/mam_tails/sabresune
name = "sabresune"
icon_state = "sabresune"
extra = 1
locked = TRUE
/datum/sprite_accessory/mam_tails_animated/sabresune
name = "sabresune"
icon_state = "sabresune"
extra = 1
/datum/sprite_accessory/mam_body_markings/sabresune
name = "Sabresune"
icon_state = "sabresune"
color_src = MUTCOLORS2
extra = 0
extra2 = 0
locked = TRUE
*/
+15 -1
View File
@@ -52,11 +52,14 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
// Used for displaying in ghost chat, without changing the actual name
// of the mob
var/deadchat_name
var/datum/spawners_menu/spawners_menu
/mob/dead/observer/Initialize()
set_invisibility(GLOB.observer_default_invisibility)
verbs += /mob/dead/observer/proc/dead_tele
verbs += list(
/mob/dead/observer/proc/dead_tele,
/mob/dead/observer/proc/open_spawners_menu)
if(icon_state in GLOB.ghost_forms_with_directions_list)
ghostimage_default = image(src.icon,src,src.icon_state + "_nodir")
@@ -149,6 +152,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
QDEL_NULL(ghostimage_simple)
updateallghostimages()
QDEL_NULL(spawners_menu)
return ..()
/mob/dead/CanPass(atom/movable/mover, turf/target)
@@ -816,3 +821,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(message)
to_chat(G, message)
GLOB.observer_default_invisibility = amount
/mob/dead/observer/proc/open_spawners_menu()
set name = "Mob spawners menu"
set desc = "See all currently available ghost spawners"
set category = "Ghost"
if(!spawners_menu)
spawners_menu = new(src)
spawners_menu.ui_interact(src)
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm (rejected hunks)
@@ -167,7 +167,7 @@
if(iscarbon(src))
var/mob/living/carbon/C = src
for(var/obj/item/bloodcrawl/BC in C)
- BC.flags = null
+ BC.flags_1 = null
qdel(BC)
qdel(src.holder)
src.holder = null
@@ -1,19 +0,0 @@
diff a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm (rejected hunks)
@@ -213,7 +213,7 @@
if(href_list["internal"])
var/slot = text2num(href_list["internal"])
var/obj/item/ITEM = get_item_by_slot(slot)
- if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.flags & MASKINTERNALS))
+ if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.flags_1 & MASKINTERNALS_1))
visible_message("<span class='danger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>", \
"<span class='userdanger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>")
if(do_mob(usr, src, POCKET_STRIP_DELAY))
@@ -221,7 +221,7 @@
internal = null
update_internals_hud_icon(0)
else if(ITEM && istype(ITEM, /obj/item/tank))
- if((wear_mask && (wear_mask.flags & MASKINTERNALS)) || getorganslot("breathing_tube"))
+ if((wear_mask && (wear_mask.flags_1 & MASKINTERNALS_1)) || getorganslot("breathing_tube"))
internal = ITEM
update_internals_hud_icon(1)
@@ -255,6 +255,8 @@
else if(check_zone(M.zone_selected) == "head")
M.visible_message("<span class='notice'>[M] gives [src] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>")
if(dna && dna.species && (("tail_lizard" in dna.species.mutant_bodyparts) || (dna.features["tail_human"] != "None") || ("mam_tail" in dna.species.mutant_bodyparts)))
emote("wag") //lewd
else
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
@@ -613,7 +613,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
//Check for dresscode violations
if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/syndi) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi))
threatcount += 3
threatcount += 6
//Check for nonhuman scum
if(dna && dna.species.id && !(dna.species.id in list("human" , "lizard", "mammal", "avian", "aquatic", "insect")))
@@ -1,91 +0,0 @@
diff a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm (rejected hunks)
@@ -141,42 +141,42 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
dat += "<table>"
for(var/i in 1 to held_items.len)
var/obj/item/I = get_item_for_held_index(i)
- dat += "<tr><td><B>[get_held_index_name(i)]:</B></td><td><A href='?src=\ref[src];item=[slot_hands];hand_index=[i]'>[(I && !(I.flags & ABSTRACT)) ? I : "<font color=grey>Empty</font>"]</a></td></tr>"
+ dat += "<tr><td><B>[get_held_index_name(i)]:</B></td><td><A href='?src=\ref[src];item=[slot_hands];hand_index=[i]'>[(I && !(I.flags_1 & ABSTRACT_1)) ? I : "<font color=grey>Empty</font>"]</a></td></tr>"
dat += "<tr><td>&nbsp;</td></tr>"
- dat += "<tr><td><B>Back:</B></td><td><A href='?src=\ref[src];item=[slot_back]'>[(back && !(back.flags&ABSTRACT)) ? back : "<font color=grey>Empty</font>"]</A>"
+ dat += "<tr><td><B>Back:</B></td><td><A href='?src=\ref[src];item=[slot_back]'>[(back && !(back.flags_1&ABSTRACT_1)) ? back : "<font color=grey>Empty</font>"]</A>"
if(has_breathable_mask && istype(back, /obj/item/tank))
dat += "&nbsp;<A href='?src=\ref[src];internal=[slot_back]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
dat += "</td></tr><tr><td>&nbsp;</td></tr>"
- dat += "<tr><td><B>Head:</B></td><td><A href='?src=\ref[src];item=[slot_head]'>[(head && !(head.flags&ABSTRACT)) ? head : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Head:</B></td><td><A href='?src=\ref[src];item=[slot_head]'>[(head && !(head.flags_1&ABSTRACT_1)) ? head : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_wear_mask in obscured)
dat += "<tr><td><font color=grey><B>Mask:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Mask:</B></td><td><A href='?src=\ref[src];item=[slot_wear_mask]'>[(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Mask:</B></td><td><A href='?src=\ref[src];item=[slot_wear_mask]'>[(wear_mask && !(wear_mask.flags_1&ABSTRACT_1)) ? wear_mask : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_neck in obscured)
dat += "<tr><td><font color=grey><B>Neck:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Neck:</B></td><td><A href='?src=\ref[src];item=[slot_neck]'>[(wear_neck && !(wear_neck.flags&ABSTRACT)) ? wear_neck : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Neck:</B></td><td><A href='?src=\ref[src];item=[slot_neck]'>[(wear_neck && !(wear_neck.flags_1&ABSTRACT_1)) ? wear_neck : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_glasses in obscured)
dat += "<tr><td><font color=grey><B>Eyes:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Eyes:</B></td><td><A href='?src=\ref[src];item=[slot_glasses]'>[(glasses && !(glasses.flags&ABSTRACT)) ? glasses : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Eyes:</B></td><td><A href='?src=\ref[src];item=[slot_glasses]'>[(glasses && !(glasses.flags_1&ABSTRACT_1)) ? glasses : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_ears in obscured)
dat += "<tr><td><font color=grey><B>Ears:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Ears:</B></td><td><A href='?src=\ref[src];item=[slot_ears]'>[(ears && !(ears.flags&ABSTRACT)) ? ears : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Ears:</B></td><td><A href='?src=\ref[src];item=[slot_ears]'>[(ears && !(ears.flags_1&ABSTRACT_1)) ? ears : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td>&nbsp;</td></tr>"
- dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=\ref[src];item=[slot_wear_suit]'>[(wear_suit && !(wear_suit.flags&ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=\ref[src];item=[slot_wear_suit]'>[(wear_suit && !(wear_suit.flags_1&ABSTRACT_1)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
if(wear_suit)
- dat += "<tr><td>&nbsp;&#8627;<B>Suit Storage:</B></td><td><A href='?src=\ref[src];item=[slot_s_store]'>[(s_store && !(s_store.flags&ABSTRACT)) ? s_store : "<font color=grey>Empty</font>"]</A>"
+ dat += "<tr><td>&nbsp;&#8627;<B>Suit Storage:</B></td><td><A href='?src=\ref[src];item=[slot_s_store]'>[(s_store && !(s_store.flags_1&ABSTRACT_1)) ? s_store : "<font color=grey>Empty</font>"]</A>"
if(has_breathable_mask && istype(s_store, /obj/item/tank))
dat += "&nbsp;<A href='?src=\ref[src];internal=[slot_s_store]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
dat += "</td></tr>"
@@ -186,30 +186,30 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
if(slot_shoes in obscured)
dat += "<tr><td><font color=grey><B>Shoes:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=\ref[src];item=[slot_shoes]'>[(shoes && !(shoes.flags&ABSTRACT)) ? shoes : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=\ref[src];item=[slot_shoes]'>[(shoes && !(shoes.flags_1&ABSTRACT_1)) ? shoes : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_gloves in obscured)
dat += "<tr><td><font color=grey><B>Gloves:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Gloves:</B></td><td><A href='?src=\ref[src];item=[slot_gloves]'>[(gloves && !(gloves.flags&ABSTRACT)) ? gloves : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Gloves:</B></td><td><A href='?src=\ref[src];item=[slot_gloves]'>[(gloves && !(gloves.flags_1&ABSTRACT_1)) ? gloves : "<font color=grey>Empty</font>"]</A></td></tr>"
if(slot_w_uniform in obscured)
dat += "<tr><td><font color=grey><B>Uniform:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
- dat += "<tr><td><B>Uniform:</B></td><td><A href='?src=\ref[src];item=[slot_w_uniform]'>[(w_uniform && !(w_uniform.flags&ABSTRACT)) ? w_uniform : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td><B>Uniform:</B></td><td><A href='?src=\ref[src];item=[slot_w_uniform]'>[(w_uniform && !(w_uniform.flags_1&ABSTRACT_1)) ? w_uniform : "<font color=grey>Empty</font>"]</A></td></tr>"
if((w_uniform == null && !(dna && dna.species.nojumpsuit)) || (slot_w_uniform in obscured))
dat += "<tr><td><font color=grey>&nbsp;&#8627;<B>Pockets:</B></font></td></tr>"
dat += "<tr><td><font color=grey>&nbsp;&#8627;<B>ID:</B></font></td></tr>"
dat += "<tr><td><font color=grey>&nbsp;&#8627;<B>Belt:</B></font></td></tr>"
else
- dat += "<tr><td>&nbsp;&#8627;<B>Belt:</B></td><td><A href='?src=\ref[src];item=[slot_belt]'>[(belt && !(belt.flags&ABSTRACT)) ? belt : "<font color=grey>Empty</font>"]</A>"
+ dat += "<tr><td>&nbsp;&#8627;<B>Belt:</B></td><td><A href='?src=\ref[src];item=[slot_belt]'>[(belt && !(belt.flags_1&ABSTRACT_1)) ? belt : "<font color=grey>Empty</font>"]</A>"
if(has_breathable_mask && istype(belt, /obj/item/tank))
dat += "&nbsp;<A href='?src=\ref[src];internal=[slot_belt]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
dat += "</td></tr>"
- dat += "<tr><td>&nbsp;&#8627;<B>Pockets:</B></td><td><A href='?src=\ref[src];pockets=left'>[(l_store && !(l_store.flags&ABSTRACT)) ? "Left (Full)" : "<font color=grey>Left (Empty)</font>"]</A>"
- dat += "&nbsp;<A href='?src=\ref[src];pockets=right'>[(r_store && !(r_store.flags&ABSTRACT)) ? "Right (Full)" : "<font color=grey>Right (Empty)</font>"]</A></td></tr>"
- dat += "<tr><td>&nbsp;&#8627;<B>ID:</B></td><td><A href='?src=\ref[src];item=[slot_wear_id]'>[(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "<font color=grey>Empty</font>"]</A></td></tr>"
+ dat += "<tr><td>&nbsp;&#8627;<B>Pockets:</B></td><td><A href='?src=\ref[src];pockets=left'>[(l_store && !(l_store.flags_1&ABSTRACT_1)) ? "Left (Full)" : "<font color=grey>Left (Empty)</font>"]</A>"
+ dat += "&nbsp;<A href='?src=\ref[src];pockets=right'>[(r_store && !(r_store.flags_1&ABSTRACT_1)) ? "Right (Full)" : "<font color=grey>Right (Empty)</font>"]</A></td></tr>"
+ dat += "<tr><td>&nbsp;&#8627;<B>ID:</B></td><td><A href='?src=\ref[src];item=[slot_wear_id]'>[(wear_id && !(wear_id.flags_1&ABSTRACT_1)) ? wear_id : "<font color=grey>Empty</font>"]</A></td></tr>"
if(handcuffed)
dat += "<tr><td><B>Handcuffed:</B> <A href='?src=\ref[src];item=[slot_handcuffed]'>Remove</A></td></tr>"
@@ -143,19 +143,19 @@
var/protection = (prot["head"] + prot["arms"] + prot["feet"] + prot["legs"] + prot["groin"] + prot["chest"] + prot["hands"])/7
return protection
/mob/living/carbon/human/can_use_guns(var/obj/item/G)
/mob/living/carbon/human/can_use_guns(obj/item/G)
. = ..()
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
if(src.dna.check_mutation(HULK))
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
return 0
return FALSE
if(NOGUNS in src.dna.species.species_traits)
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
return 0
return FALSE
if(mind)
if(mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
return 0
return FALSE
return .
@@ -87,17 +87,28 @@
/// SNPC voice handling
/mob/living/carbon/human/interactive/proc/loadVoice()
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
S["knownStrings"] >> 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 = list()
json = json_decode(file2text(json_file))
knownStrings = json["knownStrings"]
if(isnull(knownStrings))
knownStrings = list()
/mob/living/carbon/human/interactive/proc/saveVoice()
if(voice_saved)
return
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
WRITE_FILE(S["knownStrings"], knownStrings)
var/json_file = file("data/npc_saves/snpc.json")
var/list/file_data = list()
file_data["knownStrings"] = knownStrings
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
//botPool funcs
/mob/living/carbon/human/interactive/proc/takeDelegate(mob/living/carbon/human/interactive/from,doReset=TRUE)
@@ -147,7 +147,7 @@
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
if(!. || !I)
return
if(index && dna.species.mutanthands)
if(index && !QDELETED(src) && dna.species.mutanthands) //hand freed, fill with claws, skip if we're getting deleted.
put_in_hand(new dna.species.mutanthands(), index)
if(I == wear_suit)
if(s_store && invdrop)
@@ -57,6 +57,8 @@
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
if((wear_suit && (wear_suit.flags_1 & STOPSPRESSUREDMAGE_1)) && (head && (head.flags_1 & STOPSPRESSUREDMAGE_1)))
return ONE_ATMOSPHERE
if(ismob(loc))
return ONE_ATMOSPHERE
else
return pressure
@@ -242,6 +244,9 @@
if(dna && (RESISTCOLD in dna.species.species_traits))
return 1
if(ismob(loc))
return 1 //because lazy and being inside somemone insulates you from space
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
var/thermal_protection_flags = get_cold_protection_flags(temperature)
@@ -9,6 +9,8 @@
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
roundstart = 1
liked_food = MEAT | FRIED
disliked_food = TOXIC
/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -24,12 +26,14 @@
say_mod = "chirps"
default_color = "BCAC9B"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings")
mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
default_features = list("snout" = "Sharp", "wings" = "None", "taur" = "None", "mam_body_markings" = "Hawk")
attack_verb = "peck"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
roundstart = 1
liked_food = MEAT | FRUIT
disliked_food = TOXIC
/datum/species/avian/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -44,12 +48,14 @@
id = "aquatic"
default_color = "BCAC9B"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears")
mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears", "taur")
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF","mam_tail" = "shark", "mam_body_markings" = "None", "mam_ears" = "None")
attack_verb = "bite"
attack_sound = 'sound/weapons/bite.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
roundstart = 1
liked_food = MEAT
disliked_food = TOXIC
/datum/species/aquatic/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -64,12 +70,14 @@
id = "insect"
default_color = "BCAC9B"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail")
mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail", "taur")
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_body_markings" = "moth", "mam_tail" = "None", "mam_ears" = "None")
attack_verb = "flutter" //wat?
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
roundstart = 1
liked_food = MEAT | FRUIT
disliked_food = TOXIC
/datum/species/insect/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
@@ -98,6 +106,7 @@
exotic_bloodtype = "L"
damage_overlay_type = "xeno"
roundstart = 1
liked_food = MEAT
//Praise the Omnissiah, A challange worthy of my skills - HS
@@ -10,7 +10,7 @@
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
toxic_food = NONE
liked_food = NONE
liked_food = MEAT
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
if(regenerate_limbs)
+12 -6
View File
@@ -95,24 +95,30 @@
if(I == head)
head = null
head_update(I)
if(!QDELETED(src))
head_update(I)
else if(I == back)
back = null
update_inv_back()
if(!QDELETED(src))
update_inv_back()
else if(I == wear_mask)
wear_mask = null
wear_mask_update(I, toggle_off = 1)
if(!QDELETED(src))
wear_mask_update(I, toggle_off = 1)
if(I == wear_neck)
wear_neck = null
update_inv_neck(I)
if(!QDELETED(src))
update_inv_neck(I)
else if(I == handcuffed)
handcuffed = null
if(buckled && buckled.buckle_requires_restraints)
buckled.unbuckle_mob(src)
update_handcuffed()
if(!QDELETED(src))
update_handcuffed()
else if(I == legcuffed)
legcuffed = null
update_inv_legcuffed()
if(!QDELETED(src))
update_inv_legcuffed()
//handle stuff to update when a mob equips/unequips a mask.
/mob/living/proc/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
+2
View File
@@ -48,6 +48,8 @@
return
if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
return
if(istype(loc, /obj/item/device/dogborg/sleeper))
return
if(ismob(loc))
return
var/datum/gas_mixture/environment
@@ -1,19 +0,0 @@
diff a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm (rejected hunks)
@@ -153,7 +153,7 @@
if(!locate(/obj/item) in held_items)
best_force = 0
- if(restrained() || blacklistItems[pickupTarget] || (pickupTarget && (pickupTarget.flags & NODROP)))
+ if(restrained() || blacklistItems[pickupTarget] || (pickupTarget && (pickupTarget.flags_1 & NODROP_1)))
pickupTarget = null
if(!resisting && pickupTarget)
@@ -274,7 +274,7 @@
// check if target has a weapon
var/obj/item/W
for(var/obj/item/I in target.held_items)
- if(!(I.flags & ABSTRACT))
+ if(!(I.flags_1 & ABSTRACT_1))
W = I
break
@@ -140,8 +140,8 @@
return 0
return 1
/mob/living/carbon/monkey/can_use_guns(var/obj/item/G)
return 1
/mob/living/carbon/monkey/can_use_guns(obj/item/G)
return TRUE
/mob/living/carbon/monkey/angry
aggressive = TRUE
+32 -24
View File
@@ -24,7 +24,7 @@
..()
//These have to be after the parent new to ensure that the monkey
//bodyparts are actually created before we try to equip things to
//bodyparts are actually created before we try to equip things to
//those slots
if(relic_hat)
equip_to_slot_or_del(new relic_hat, slot_head)
@@ -42,32 +42,40 @@
..()
/mob/living/carbon/monkey/punpun/proc/Read_Memory()
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
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 = 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/savefile/S = new /savefile("data/npc_saves/Punpun.sav")
var/json_file = file("data/npc_saves/Punpun.json")
var/list/file_data = list()
if(gibbed)
WRITE_FILE(S["ancestor_name"], null)
WRITE_FILE(S["ancestor_chain"], 1)
WRITE_FILE(S["relic_hat"], null)
WRITE_FILE(S["relic_mask"], null)
return
file_data["ancestor_name"] = null
file_data["ancestor_chain"] = null
file_data["relic_hat"] = null
file_data["relic_mask"] = null
if(dead)
WRITE_FILE(S["ancestor_name"], ancestor_name)
WRITE_FILE(S["ancestor_chain"], ancestor_chain + 1)
if(!ancestor_name) //new monkey name this round
WRITE_FILE(S["ancestor_name"], name)
if(head)
WRITE_FILE(S["relic_hat"], head.type)
else
WRITE_FILE(S["relic_hat"], null)
if(wear_mask)
WRITE_FILE(S["relic_mask"], wear_mask.type)
else
WRITE_FILE(S["relic_mask"], null)
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
fdel(json_file)
WRITE_FILE(json_file, json_encode(json_file))
if(!dead)
memory_saved = 1
+4 -4
View File
@@ -241,7 +241,7 @@
return 1
/mob/living/proc/InCritical()
return (health < 0 && health > -100 && stat == UNCONSCIOUS)
return (health < HEALTH_THRESHOLD_CRIT && health > HEALTH_THRESHOLD_DEAD && stat == UNCONSCIOUS)
//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
//affects them once clothing is factored in. ~Errorage
@@ -798,11 +798,11 @@
else
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
/mob/living/proc/can_use_guns(var/obj/item/G)
/mob/living/proc/can_use_guns(obj/item/G)
if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
return 0
return 1
return FALSE
return TRUE
/mob/living/carbon/proc/update_stamina()
if(staminaloss)
-10
View File
@@ -1,10 +0,0 @@
diff a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm (rejected hunks)
@@ -793,7 +793,7 @@
else
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
-/mob/living/proc/can_use_guns(var/obj/item/weapon/gun/G)
+/mob/living/proc/can_use_guns(var/obj/item/weapon/G)
if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
return 0
+8 -10
View File
@@ -67,17 +67,15 @@
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
var/dtype = BRUTE
var/volume = I.get_volume_by_throwforce_and_or_w_class()
if(istype(I, /obj/item/weapon)) //If the item is a weapon...
var/obj/item/W = I
dtype = W.damtype
dtype = I.damtype
if (W.throwforce > 0) //If the weapon's throwforce is greater than zero...
if (W.throwhitsound) //...and throwhitsound is defined...
playsound(loc, W.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
else if(W.hitsound) //Otherwise, if the weapon's hitsound is defined...
playsound(loc, W.hitsound, volume, 1, -1) //...play the weapon's hitsound.
else if(!W.throwhitsound) //Otherwise, if throwhitsound isn't defined...
playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
if (I.throwhitsound) //...and throwhitsound is defined...
playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
playsound(loc, I.hitsound, volume, 1, -1) //...play the weapon's hitsound.
else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
playsound(loc, 'sound/weapons/genhit.ogg', volume, 1, -1)//...play genhit.ogg
@@ -1,10 +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)
@@ -121,7 +121,7 @@
if(I.loc != src)
I.forceMove(src)
modules += I
- I.flags |= NODROP
+ I.flags_1 |= NODROP_1
I.mouse_opacity = MOUSE_OPACITY_OPAQUE
if(nonstandard)
added_modules += I
+5 -5
View File
@@ -36,11 +36,11 @@
var/d_hud = DATA_HUD_DIAGNOSTIC //There is only one kind of diag hud
var/law_change_counter = 0
var/obj/machinery/camera/builtInCamera = null
var/updating = FALSE //portable camera camerachunk update
var/obj/machinery/camera/builtInCamera = null
var/updating = FALSE //portable camera camerachunk update
/mob/living/silicon/Initialize()
. = ..()
. = ..()
GLOB.silicon_mobs += src
var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
diag_hud.add_to_hud(src)
@@ -56,7 +56,7 @@
/mob/living/silicon/Destroy()
radio = null
aicamera = null
QDEL_NULL(builtInCamera)
QDEL_NULL(builtInCamera)
GLOB.silicon_mobs -= src
return ..()
@@ -310,7 +310,7 @@
else //For department channels, if any, given by the internal radio.
for(var/key in GLOB.department_radio_keys)
if(GLOB.department_radio_keys[key] == Autochan)
radiomod = key
radiomod = ":" + key
break
to_chat(src, "<span class='notice'>Automatic announcements [Autochan == "None" ? "will not use the radio." : "set to [Autochan]."]</span>")
@@ -28,3 +28,6 @@
. = ..()
var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
/mob/living/simple_animal/butterfly/bee_friendly()
return TRUE //treaty signed at the Beeneeva convention
@@ -113,14 +113,22 @@
..()
/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
S["family"] >> 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 = 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/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
var/json_file = file("data/npc_saves/Runtime.json")
family = list()
if(!dead)
for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
@@ -130,7 +138,8 @@
family[C.type] += 1
else
family[C.type] = 1
WRITE_FILE(S["family"], family)
fdel(json_file)
WRITE_FILE(json_file, json_encode(family))
memory_saved = 1
/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
@@ -328,33 +328,44 @@
..()
/mob/living/simple_animal/pet/dog/corgi/Ian/proc/Read_Memory()
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
S["age"] >> age
S["record_age"] >> record_age
S["saved_head"] >> 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 = 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))
record_age = 1
if(saved_head)
place_on_head(new saved_head)
/mob/living/simple_animal/pet/dog/corgi/Ian/proc/Write_Memory(dead)
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
var/json_file = file("data/npc_saves/Ian.json")
var/list/file_data = list()
if(!dead)
WRITE_FILE(S["age"], age + 1)
file_data["age"] = age + 1
if((age + 1) > record_age)
WRITE_FILE(S["record_age"], record_age + 1)
file_data["record_age"] = record_age + 1
if(inventory_head)
WRITE_FILE(S["saved_head"], inventory_head.type)
file_data["saved_head"] = inventory_head.type
else
WRITE_FILE(S["age"], 0)
WRITE_FILE(S["saved_head"], null)
file_data["age"] = 0
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()
..()
@@ -0,0 +1,17 @@
/mob/living/simple_animal/hostile/jungle
vision_range = 5
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = NONE
a_intent = INTENT_HARM
see_in_dark = 4
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
mob_size = MOB_SIZE_LARGE
@@ -0,0 +1,263 @@
#define PLAYER_HOP_DELAY 25
//Huge, carnivorous toads that spit an immobilizing toxin at its victims before leaping onto them.
//It has no melee attack, and its damage comes from the toxin in its bubbles and its crushing leap.
//Its eyes will turn red to signal an imminent attack!
/mob/living/simple_animal/hostile/jungle/leaper
name = "leaper"
desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth."
icon = 'icons/mob/jungle/leaper.dmi'
icon_state = "leaper"
icon_living = "leaper"
icon_dead = "leaper_dead"
maxHealth = 300
health = 300
ranged = TRUE
projectiletype = /obj/item/projectile/leaper
projectilesound = 'sound/weapons/pierce.ogg'
ranged_cooldown_time = 30
pixel_x = -16
layer = LARGE_MOB_LAYER
speed = 10
stat_attack = 1
robust_searching = 1
var/hopping = FALSE
var/hop_cooldown = 0 //Strictly for player controlled leapers
var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead
/obj/item/projectile/leaper
name = "leaper bubble"
icon_state = "leaper"
knockdown = 50
damage = 0
range = 7
hitsound = 'sound/effects/snap.ogg'
nondirectional_sprite = TRUE
impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact
/obj/item/projectile/leaper/on_hit(atom/target, blocked = FALSE)
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.reagents.add_reagent("leaper_venom", 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
L.adjustHealth(25)
/obj/item/projectile/leaper/on_range()
var/turf/T = get_turf(src)
..()
new /obj/structure/leaper_bubble(T)
/obj/effect/temp_visual/leaper_projectile_impact
name = "leaper bubble"
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper_bubble_pop"
layer = ABOVE_ALL_MOB_LAYER
duration = 3
/obj/effect/temp_visual/leaper_projectile_impact/Initialize()
. = ..()
new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src))
/obj/effect/decal/cleanable/leaper_sludge
name = "leaper sludge"
desc = "A small pool of sludge, containing trace amounts of leaper venom."
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "tomato_floor1"
/obj/structure/leaper_bubble
name = "leaper bubble"
desc = "A floating bubble containing leaper venom. The contents are under a surprising amount of pressure."
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper"
max_integrity = 10
density = FALSE
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
return ..()
/obj/structure/leaper_bubble/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
if(!istype(L, /mob/living/simple_animal/hostile/jungle/leaper))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
L.Knockdown(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.reagents.add_reagent("leaper_venom", 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
qdel(src)
return ..()
/datum/reagent/toxin/leaper_venom
name = "Leaper venom"
id = "leaper_venom"
description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
color = "#801E28" // rgb: 128, 30, 40
toxpwr = 0
taste_description = "french cuisine"
taste_mult = 1.3
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/M)
if(volume >= 10)
M.adjustToxLoss(5, 0)
..()
/obj/effect/temp_visual/leaper_crush
name = "grim tidings"
desc = "Incoming leaper!"
icon = 'icons/effects/96x96.dmi'
icon_state = "lily_pad"
layer = BELOW_MOB_LAYER
pixel_x = -32
pixel_y = -32
duration = 30
/mob/living/simple_animal/hostile/jungle/leaper/Initialize()
. = ..()
verbs -= /mob/living/verb/pulled
/mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A)
face_atom(A)
target = A
if(!isturf(loc))
return
if(next_move > world.time)
return
if(hopping)
return
if(isliving(A))
var/mob/living/L = A
if(L.incapacitated())
BellyFlop()
return
if(hop_cooldown <= world.time)
Hop(player_hop = TRUE)
/mob/living/simple_animal/hostile/jungle/leaper/AttackingTarget()
if(isliving(target))
return
return ..()
/mob/living/simple_animal/hostile/jungle/leaper/handle_automated_action()
if(hopping || projectile_ready)
return
. = ..()
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
BellyFlop()
return
if(!hopping)
Hop()
/mob/living/simple_animal/hostile/jungle/leaper/Life()
. = ..()
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(prob(33) && !ckey)
ranged_cooldown = 0 //Keeps em on their toes instead of a constant rotation
..()
/mob/living/simple_animal/hostile/jungle/leaper/OpenFire()
face_atom(target)
if(ranged_cooldown <= world.time)
if(ckey)
if(hopping)
return
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return //No stunlocking. Hop on them after you stun them, you donk.
if(AIStatus == AI_ON && !projectile_ready && !ckey)
return
. = ..(target)
projectile_ready = FALSE
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/proc/Hop(player_hop = FALSE)
if(z != target.z)
return
hopping = TRUE
density = FALSE
pass_flags |= PASSMOB
notransform = TRUE
var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z)
if(player_hop)
new_turf = get_turf(target)
hop_cooldown = world.time + PLAYER_HOP_DELAY
if(AIStatus == AI_ON && ranged_cooldown <= world.time)
projectile_ready = TRUE
update_icons()
throw_at(new_turf, max(3,get_dist(src,new_turf)), 1, src, FALSE, callback = CALLBACK(src, .FinishHop))
/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop()
density = TRUE
notransform = FALSE
pass_flags &= ~PASSMOB
hopping = FALSE
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, 1)
if(target && AIStatus == AI_ON && projectile_ready && !ckey)
face_atom(target)
addtimer(CALLBACK(src, .proc/OpenFire, target), 5)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlop()
var/turf/new_turf = get_turf(target)
hopping = TRUE
notransform = TRUE
new /obj/effect/temp_visual/leaper_crush(new_turf)
addtimer(CALLBACK(src, .proc/BellyFlopHop, new_turf), 30)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlopHop(turf/T)
density = FALSE
throw_at(T, get_dist(src,T),1,src, FALSE, callback = CALLBACK(src, .proc/Crush))
/mob/living/simple_animal/hostile/jungle/leaper/proc/Crush()
hopping = FALSE
density = TRUE
notransform = FALSE
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
L.adjustBruteLoss(35)
if(!QDELETED(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at(throwtarget, 3, 1)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
if(ckey)//Lessens ability to chain stun as a player
ranged_cooldown = ranged_cooldown_time + world.time
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/Goto()
return
/mob/living/simple_animal/hostile/jungle/leaper/throw_impact()
return
/mob/living/simple_animal/hostile/jungle/leaper/update_icons()
. = ..()
if(stat)
icon_state = "leaper_dead"
return
if(ranged_cooldown <= world.time)
if(AIStatus == AI_ON && projectile_ready || ckey)
icon_state = "leaper_alert"
return
icon_state = "leaper"
#undef PLAYER_HOP_DELAY
@@ -0,0 +1,65 @@
//Large and powerful, but timid. It won't engage anything above 50 health, or anything without legcuffs.
//It can fire fleshy snares that legcuff anyone that it hits, making them look especially tasty to the arachnid.
/mob/living/simple_animal/hostile/jungle/mega_arachnid
name = "mega arachnid"
desc = "Though physically imposing, it prefers to ambush its prey, and it will only engage with an already crippled opponent."
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "arachnid"
icon_living = "arachnid"
icon_dead = "arachnid_dead"
melee_damage_lower = 30
melee_damage_upper = 30
maxHealth = 300
health = 300
speed = 1
ranged = 1
pixel_x = -16
move_to_delay = 10
aggro_vision_range = 9
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_time = 60
projectiletype = /obj/item/projectile/mega_arachnid
projectilesound = 'sound/weapons/pierce.ogg'
alpha = 50
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
..()
if(target && ranged_cooldown > world.time && iscarbon(target))
var/mob/living/carbon/C = target
if(!C.legcuffed && C.health < 50)
retreat_distance = 9
minimum_distance = 9
alpha = 125
return
retreat_distance = 0
minimum_distance = 0
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Aggro()
..()
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/LoseAggro()
..()
alpha = 50
/obj/item/projectile/mega_arachnid
name = "flesh snare"
nodamage = 1
damage = 0
icon_state = "tentacle_end"
/obj/item/projectile/mega_arachnid/on_hit(atom/target, blocked = FALSE)
if(iscarbon(target) && blocked < 100)
var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target))
B.Crossed(target)
..()
/obj/item/restraints/legcuffs/beartrap/mega_arachnid
name = "fleshy restraints"
desc = "Used by mega arachnids to immobilize their prey."
flags_1 = DROPDEL_1
icon_state = "tentacle_end"
icon = 'icons/obj/projectiles.dmi'
@@ -0,0 +1,224 @@
#define MOOK_ATTACK_NEUTRAL 0
#define MOOK_ATTACK_WARMUP 1
#define MOOK_ATTACK_ACTIVE 2
#define MOOK_ATTACK_RECOVERY 3
#define ATTACK_INTERMISSION_TIME 5
//Fragile but highly aggressive wanderers that pose a large threat in numbers.
//They'll attempt to leap at their target from afar using their hatchets.
/mob/living/simple_animal/hostile/jungle/mook
name = "wanderer"
desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent."
icon = 'icons/mob/jungle/mook.dmi'
icon_state = "mook"
icon_living = "mook"
icon_dead = "mook_dead"
pixel_x = -16
maxHealth = 45
health = 45
melee_damage_lower = 30
melee_damage_upper = 30
pixel_y = -8
ranged = TRUE
ranged_cooldown_time = 10
pass_flags = LETPASSTHROW
robust_searching = TRUE
stat_attack = UNCONSCIOUS
attack_sound = 'sound/weapons/rapierhit.ogg'
death_sound = 'sound/voice/mook_death.ogg'
aggro_vision_range = 15 //A little more aggressive once in combat to balance out their really low HP
var/attack_state = MOOK_ATTACK_NEUTRAL
var/struck_target_leap = FALSE
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
var/mob/living/simple_animal/hostile/jungle/mook/M = O
if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing)
return TRUE
return ..()
/mob/living/simple_animal/hostile/jungle/mook/death()
desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist
return ..()
/mob/living/simple_animal/hostile/jungle/mook/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && attack_state == MOOK_ATTACK_NEUTRAL)
var/mob/living/L = target
if(L.incapacitated())
WarmupAttack(forced_slash_combo = TRUE)
return
WarmupAttack()
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Goto()
if(attack_state != MOOK_ATTACK_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Move()
if(attack_state == MOOK_ATTACK_WARMUP || attack_state == MOOK_ATTACK_RECOVERY)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/proc/WarmupAttack(forced_slash_combo = FALSE)
if(attack_state == MOOK_ATTACK_NEUTRAL && target)
attack_state = MOOK_ATTACK_WARMUP
walk(src,0)
update_icons()
if(prob(50) && get_dist(src,target) <= 3 || forced_slash_combo)
addtimer(CALLBACK(src, .proc/SlashCombo), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/LeapAttack), ATTACK_INTERMISSION_TIME + rand(0,3))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashCombo()
if(attack_state == MOOK_ATTACK_WARMUP && !stat)
attack_state = MOOK_ATTACK_ACTIVE
update_icons()
SlashAttack()
addtimer(CALLBACK(src, .proc/SlashAttack), 3)
addtimer(CALLBACK(src, .proc/SlashAttack), 6)
addtimer(CALLBACK(src, .proc/AttackRecovery), 9)
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashAttack()
if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE)
melee_damage_lower = 15
melee_damage_upper = 15
var/mob_direction = get_dir(src,target)
if(get_dist(src,target) > 1)
step(src,mob_direction)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && isliving(target))
var/mob/living/L = target
L.attack_animal(src)
return
var/swing_turf = get_step(src,mob_direction)
new /obj/effect/temp_visual/kinetic_blast(swing_turf)
playsound(src, 'sound/weapons/slashmiss.ogg', 50, 1)
/mob/living/simple_animal/hostile/jungle/mook/proc/LeapAttack()
if(target && !stat && attack_state == MOOK_ATTACK_WARMUP)
attack_state = MOOK_ATTACK_ACTIVE
density = FALSE
melee_damage_lower = 30
melee_damage_upper = 30
update_icons()
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1)
playsound(src, 'sound/voice/mook_leap_yell.ogg', 100, 1)
var/target_turf = get_turf(target)
throw_at(target_turf, 7, 1, src, FALSE, callback = CALLBACK(src, .proc/AttackRecovery))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/AttackRecovery()
if(attack_state == MOOK_ATTACK_ACTIVE && !stat)
attack_state = MOOK_ATTACK_RECOVERY
density = TRUE
face_atom(target)
if(!struck_target_leap)
update_icons()
struck_target_leap = FALSE
if(prob(40))
attack_state = MOOK_ATTACK_NEUTRAL
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated() && L.stat != DEAD)
addtimer(CALLBACK(src, .proc/WarmupAttack, TRUE), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/WarmupAttack), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/ResetNeutral), ATTACK_INTERMISSION_TIME)
/mob/living/simple_animal/hostile/jungle/mook/proc/ResetNeutral()
if(attack_state == MOOK_ATTACK_RECOVERY)
attack_state = MOOK_ATTACK_NEUTRAL
ranged_cooldown = world.time + ranged_cooldown_time
update_icons()
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/mook/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
if(isliving(hit_atom) && attack_state == MOOK_ATTACK_ACTIVE)
var/mob/living/L = hit_atom
if(CanAttack(L))
L.attack_animal(src)
struck_target_leap = TRUE
density = TRUE
update_icons()
var/mook_under_us = FALSE
for(var/A in get_turf(src))
if(struck_target_leap && mook_under_us)
break
if(A == src)
continue
if(isliving(A))
var/mob/living/ML = A
if(!struck_target_leap && CanAttack(ML))//Check if some joker is attempting to use rest to evade us
struck_target_leap = TRUE
ML.attack_animal(src)
density = TRUE
struck_target_leap = TRUE
update_icons()
continue
if(istype(ML, /mob/living/simple_animal/hostile/jungle/mook) && !mook_under_us)//If we land on the same tile as another mook, spread out so we don't stack our sprite on the same tile
var/mob/living/simple_animal/hostile/jungle/mook/M = ML
if(!M.stat)
mook_under_us = TRUE
var/anydir = pick(GLOB.cardinals)
Move(get_step(src, anydir), anydir)
continue
/mob/living/simple_animal/hostile/jungle/mook/handle_automated_action()
if(attack_state)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/OpenFire()
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/mook/update_icons()
. = ..()
if(!stat)
switch(attack_state)
if(MOOK_ATTACK_NEUTRAL)
icon_state = "mook"
if(MOOK_ATTACK_WARMUP)
icon_state = "mook_warmup"
if(MOOK_ATTACK_ACTIVE)
if(!density)
icon_state = "mook_leap"
return
if(struck_target_leap)
icon_state = "mook_strike"
return
icon_state = "mook_slash_combo"
if(MOOK_ATTACK_RECOVERY)
icon_state = "mook"
/obj/effect/temp_visual/mook_dust
name = "dust"
desc = "it's just a dust cloud!"
icon = 'icons/mob/jungle/mook.dmi'
icon_state = "mook_leap_cloud"
layer = BELOW_MOB_LAYER
pixel_x = -16
pixel_y = -16
duration = 10
#undef MOOK_ATTACK_NEUTRAL
#undef MOOK_ATTACK_WARMUP
#undef MOOK_ATTACK_ACTIVE
#undef MOOK_ATTACK_RECOVERY
#undef ATTACK_INTERMISSION_TIME
@@ -0,0 +1,244 @@
#define SEEDLING_STATE_NEUTRAL 0
#define SEEDLING_STATE_WARMUP 1
#define SEEDLING_STATE_ACTIVE 2
#define SEEDLING_STATE_RECOVERY 3
//A plant rooted in the ground that forfeits its melee attack in favor of ranged barrages.
//It will fire flurries of solar energy, and occasionally charge up a powerful blast that makes it vulnerable to attack.
/mob/living/simple_animal/hostile/jungle/seedling
name = "seedling"
desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon, and it will not die until its hidden vital organs are sliced out. \
The concentrated streams of energy it sometimes produces require its full attention, attacking it during this time will prevent it from finishing its attack."
icon = 'icons/mob/jungle/seedling.dmi'
icon_state = "seedling"
icon_living = "seedling"
icon_dead = "seedling_dead"
maxHealth = 100
health = 100
melee_damage_lower = 30
melee_damage_upper = 30
pixel_x = -16
pixel_y = -14
minimum_distance = 3
move_to_delay = 20
vision_range = 9
aggro_vision_range = 15
ranged = TRUE
ranged_cooldown_time = 10
projectiletype = /obj/item/projectile/seedling
projectilesound = 'sound/weapons/pierce.ogg'
robust_searching = TRUE
stat_attack = UNCONSCIOUS
anchored = TRUE
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
var/solar_beam_identifier = 0
/obj/item/projectile/seedling
name = "solar energy"
icon_state = "seedling"
damage = 10
damage_type = BURN
light_range = 2
flag = "energy"
light_color = LIGHT_COLOR_YELLOW
hitsound = 'sound/weapons/sear.ogg'
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
nondirectional_sprite = TRUE
/obj/item/projectile/seedling/Collide(atom/A)//Stops seedlings from destroying other jungle mobs through FF
if(isliving(A))
var/mob/living/L = A
if("jungle" in L.faction)
return FALSE
return ..()
/obj/effect/temp_visual/solarbeam_killsat
name = "beam of solar energy"
icon_state = "solar_beam"
icon = 'icons/effects/beam.dmi'
layer = LIGHTING_LAYER
duration = 5
randomdir = FALSE
/datum/status_effect/seedling_beam_indicator
id = "seedling beam indicator"
duration = 30
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
tick_interval = 1
var/obj/screen/seedling/seedling_screen_object
var/atom/target
/datum/status_effect/seedling_beam_indicator/on_creation(mob/living/new_owner, target_plant)
. = ..()
if(.)
target = target_plant
tick()
/datum/status_effect/seedling_beam_indicator/on_apply()
if(owner.client)
seedling_screen_object = new /obj/screen/seedling()
owner.client.screen += seedling_screen_object
tick()
return ..()
/datum/status_effect/seedling_beam_indicator/Destroy()
if(owner)
if(owner.client)
owner.client.screen -= seedling_screen_object
return ..()
/datum/status_effect/seedling_beam_indicator/tick()
var/target_angle = Get_Angle(owner, target)
var/matrix/final = matrix()
final.Turn(target_angle)
seedling_screen_object.transform = final
/obj/screen/seedling
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling_beam_indicator"
screen_loc = "CENTER:-16,CENTER:-16"
/mob/living/simple_animal/hostile/jungle/seedling/Goto()
if(combatant_state != SEEDLING_STATE_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && combatant_state == SEEDLING_STATE_NEUTRAL)
OpenFire(target)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/OpenFire()
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/seedling/proc/WarmupAttack()
if(combatant_state == SEEDLING_STATE_NEUTRAL)
combatant_state = SEEDLING_STATE_WARMUP
walk(src,0)
update_icons()
var/target_dist = get_dist(src,target)
var/living_target_check = isliving(target)
if(living_target_check)
if(target_dist > 7)//Offscreen check
SolarBeamStartup(target)
return
if(get_dist(src,target) >= 4 && prob(40))
SolarBeamStartup(target)
return
addtimer(CALLBACK(src, .proc/Volley), 5)
/mob/living/simple_animal/hostile/jungle/seedling/proc/SolarBeamStartup(mob/living/living_target)//It's more like requiem than final spark
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
living_target.apply_status_effect(/datum/status_effect/seedling_beam_indicator, src)
beam_debuff_target = living_target
playsound(src,'sound/effects/seedling_chargeup.ogg', 100, 0)
if(get_dist(src,living_target) > 7)
playsound(living_target,'sound/effects/seedling_chargeup.ogg', 100, 0)
solar_beam_identifier = world.time
addtimer(CALLBACK(src, .proc/Beamu, living_target, solar_beam_identifier), 35)
/mob/living/simple_animal/hostile/jungle/seedling/proc/Beamu(mob/living/living_target, beam_id = 0)
if(combatant_state == SEEDLING_STATE_ACTIVE && living_target && beam_id == solar_beam_identifier)
if(living_target.z == z)
update_icons()
var/obj/effect/temp_visual/solarbeam_killsat/S = new (get_turf(src))
var/matrix/starting = matrix()
starting.Scale(1,32)
starting.Translate(0,520)
S.transform = starting
var/obj/effect/temp_visual/solarbeam_killsat/K = new (get_turf(living_target))
var/matrix/final = matrix()
final.Scale(1,32)
final.Translate(0,512)
K.transform = final
living_target.adjustFireLoss(30)
living_target.adjust_fire_stacks(0.2)//Just here for the showmanship
living_target.IgniteMob()
playsound(living_target,'sound/weapons/sear.ogg', 50, 1)
addtimer(CALLBACK(src, .proc/AttackRecovery), 5)
return
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/proc/Volley()
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
update_icons()
var/datum/callback/cb = CALLBACK(src, .proc/InaccurateShot)
for(var/i in 1 to 13)
addtimer(cb, i)
addtimer(CALLBACK(src, .proc/AttackRecovery), 14)
/mob/living/simple_animal/hostile/jungle/seedling/proc/InaccurateShot()
if(!QDELETED(target) && combatant_state == SEEDLING_STATE_ACTIVE && !stat)
if(get_dist(src,target) <= 3)//If they're close enough just aim straight at them so we don't miss at point blank ranges
Shoot(target)
return
var/turf/our_turf = get_turf(src)
var/obj/item/projectile/seedling/readied_shot = new /obj/item/projectile/seedling(our_turf)
readied_shot.current = our_turf
readied_shot.starting = our_turf
readied_shot.firer = src
readied_shot.original = target
readied_shot.yo = target.y - our_turf.y + rand(-1,1)
readied_shot.xo = target.x - our_turf.x + rand(-1,1)
readied_shot.fire()
playsound(src, projectilesound, 100, 1)
/mob/living/simple_animal/hostile/jungle/seedling/proc/AttackRecovery()
if(combatant_state == SEEDLING_STATE_ACTIVE)
combatant_state = SEEDLING_STATE_RECOVERY
update_icons()
ranged_cooldown = world.time + ranged_cooldown_time
if(target)
face_atom(target)
addtimer(CALLBACK(src, .proc/ResetNeutral), 10)
/mob/living/simple_animal/hostile/jungle/seedling/proc/ResetNeutral()
combatant_state = SEEDLING_STATE_NEUTRAL
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/seedling/adjustHealth()
. = ..()
if(combatant_state == SEEDLING_STATE_ACTIVE && beam_debuff_target)
beam_debuff_target.remove_status_effect(/datum/status_effect/seedling_beam_indicator)
beam_debuff_target = null
solar_beam_identifier = 0
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/update_icons()
. = ..()
if(!stat)
switch(combatant_state)
if(SEEDLING_STATE_NEUTRAL)
icon_state = "seedling"
if(SEEDLING_STATE_WARMUP)
icon_state = "seedling_charging"
if(SEEDLING_STATE_ACTIVE)
icon_state = "seedling_fire"
if(SEEDLING_STATE_RECOVERY)
icon_state = "seedling"
/mob/living/simple_animal/hostile/jungle/seedling/GiveTarget()
if(target)
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)//So it doesn't 180 and blast you in the face while it's firing at someone else
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/LoseTarget()
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)
return
return ..()
#undef SEEDLING_STATE_NEUTRAL
#undef SEEDLING_STATE_WARMUP
#undef SEEDLING_STATE_ACTIVE
#undef SEEDLING_STATE_RECOVERY
@@ -1,833 +0,0 @@
/mob/living/simple_animal/hostile/jungle
vision_range = 5
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
see_in_dark = 4
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
mob_size = MOB_SIZE_LARGE
//Mega arachnid
/mob/living/simple_animal/hostile/jungle/mega_arachnid
name = "mega arachnid"
desc = "Though physically imposing, it prefers to ambush its prey, and it will only engage with an already crippled opponent."
melee_damage_lower = 30
melee_damage_upper = 30
maxHealth = 300
health = 300
speed = 1
ranged = 1
pixel_x = -16
move_to_delay = 10
aggro_vision_range = 9
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_time = 60
projectiletype = /obj/item/projectile/mega_arachnid
projectilesound = 'sound/weapons/pierce.ogg'
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "arachnid"
icon_living = "arachnid"
icon_dead = "dead_purple"
alpha = 50
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
..()
if(target && ranged_cooldown > world.time && iscarbon(target))
var/mob/living/carbon/C = target
if(!C.legcuffed && C.health < 50)
retreat_distance = 9
minimum_distance = 9
alpha = 125
return
retreat_distance = 0
minimum_distance = 0
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Aggro()
..()
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/LoseAggro()
..()
alpha = 50
/obj/item/projectile/mega_arachnid
name = "flesh snare"
nodamage = 1
damage = 0
icon_state = "tentacle_end"
/obj/item/projectile/mega_arachnid/on_hit(atom/target, blocked = FALSE)
if(iscarbon(target) && blocked < 100)
var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target))
B.Crossed(target)
..()
/obj/item/restraints/legcuffs/beartrap/mega_arachnid
name = "fleshy restraints"
desc = "Used by mega arachnids to immobilize their prey."
flags_1 = DROPDEL_1
icon_state = "tentacle_end"
icon = 'icons/obj/projectiles.dmi'
////Leaper////
#define PLAYER_HOP_DELAY 25
/mob/living/simple_animal/hostile/jungle/leaper
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
maxHealth = 300
health = 300
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
see_in_dark = 4
ranged = TRUE
projectiletype = /obj/item/projectile/leaper
projectilesound = 'sound/weapons/pierce.ogg'
ranged_cooldown_time = 30
pixel_x = -16
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "leaper"
icon_living = "leaper"
icon_dead = "leaper_dead"
layer = LARGE_MOB_LAYER
name = "leaper"
desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth."
speed = 10
stat_attack = 1
robust_searching = 1
var/hopping = FALSE
var/hop_cooldown = 0 //Strictly for player controlled leapers
var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead
/obj/item/projectile/leaper
name = "leaper bubble"
icon_state = "leaper"
knockdown = 50
damage = 0
range = 7
hitsound = 'sound/effects/snap.ogg'
nondirectional_sprite = TRUE
impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact
/obj/item/projectile/leaper/on_hit(atom/target, blocked = FALSE)
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.reagents.add_reagent("leaper_venom", 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
L.adjustHealth(25)
/obj/item/projectile/leaper/on_range()
var/turf/T = get_turf(src)
..()
new /obj/structure/leaper_bubble(T)
/obj/effect/temp_visual/leaper_projectile_impact
name = "leaper bubble"
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper_bubble_pop"
layer = ABOVE_ALL_MOB_LAYER
duration = 3
/obj/effect/temp_visual/leaper_projectile_impact/Initialize()
. = ..()
new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src))
/obj/effect/decal/cleanable/leaper_sludge
name = "leaper sludge"
desc = "A small pool of sludge, containing trace amounts of leaper venom"
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "tomato_floor1"
/obj/structure/leaper_bubble
name = "leaper bubble"
desc = "A floating bubble containing leaper venom, the contents are under a surprising amount of pressure."
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper"
max_integrity = 10
density = FALSE
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
return ..()
/obj/structure/leaper_bubble/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
if(!istype(L, /mob/living/simple_animal/hostile/jungle/leaper))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
L.Knockdown(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.reagents.add_reagent("leaper_venom", 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
qdel(src)
return ..()
/datum/reagent/toxin/leaper_venom
name = "Leaper venom"
id = "leaper_venom"
description = "A toxin spat out by leapers that while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
color = "#801E28" // rgb: 128, 30, 40
toxpwr = 0
taste_description = "french cuisine"
taste_mult = 1.3
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/M)
if(volume >= 10)
M.adjustToxLoss(5, 0)
..()
/obj/effect/temp_visual/leaper_crush
name = "Grim tidings"
desc = "Incoming leaper!"
icon = 'icons/effects/96x96.dmi'
icon_state = "lily_pad"
layer = BELOW_MOB_LAYER
pixel_x = -32
pixel_y = -32
duration = 30
/mob/living/simple_animal/hostile/jungle/leaper/Initialize()
. = ..()
verbs -= /mob/living/verb/pulled
/mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A)
face_atom(A)
target = A
if(!isturf(loc))
return
if(next_move > world.time)
return
if(hopping)
return
if(isliving(A))
var/mob/living/L = A
if(L.incapacitated())
BellyFlop()
return
if(hop_cooldown <= world.time)
Hop(player_hop = TRUE)
/mob/living/simple_animal/hostile/jungle/leaper/AttackingTarget()
if(isliving(target))
return
return ..()
/mob/living/simple_animal/hostile/jungle/leaper/handle_automated_action()
if(hopping || projectile_ready)
return
. = ..()
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
BellyFlop()
return
if(!hopping)
Hop()
/mob/living/simple_animal/hostile/jungle/leaper/Life()
. = ..()
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(prob(33) && !ckey)
ranged_cooldown = 0 //Keeps em on their toes instead of a constant rotation
..()
/mob/living/simple_animal/hostile/jungle/leaper/OpenFire()
face_atom(target)
if(ranged_cooldown <= world.time)
if(ckey)
if(hopping)
return
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return //No stunlocking. Hop on them after you stun them, you donk.
if(AIStatus == AI_ON && !projectile_ready && !ckey)
return
. = ..(target)
projectile_ready = FALSE
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/proc/Hop(player_hop = FALSE)
if(z != target.z)
return
hopping = TRUE
density = FALSE
pass_flags |= PASSMOB
notransform = TRUE
var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z)
if(player_hop)
new_turf = get_turf(target)
hop_cooldown = world.time + PLAYER_HOP_DELAY
if(AIStatus == AI_ON && ranged_cooldown <= world.time)
projectile_ready = TRUE
update_icons()
throw_at(new_turf, max(3,get_dist(src,new_turf)), 1, src, FALSE, callback = CALLBACK(src, .FinishHop))
/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop()
density = TRUE
notransform = FALSE
pass_flags &= ~PASSMOB
hopping = FALSE
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, 1)
if(target && AIStatus == AI_ON && projectile_ready && !ckey)
face_atom(target)
addtimer(CALLBACK(src, .proc/OpenFire, target), 5)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlop()
var/turf/new_turf = get_turf(target)
hopping = TRUE
notransform = TRUE
new /obj/effect/temp_visual/leaper_crush(new_turf)
addtimer(CALLBACK(src, .proc/BellyFlopHop, new_turf), 30)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlopHop(turf/T)
density = FALSE
throw_at(T, get_dist(src,T),1,src, FALSE, callback = CALLBACK(src, .proc/Crush))
/mob/living/simple_animal/hostile/jungle/leaper/proc/Crush()
hopping = FALSE
density = TRUE
notransform = FALSE
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
L.adjustBruteLoss(35)
if(!QDELETED(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at(throwtarget, 3, 1)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
if(ckey)//Lessens ability to chain stun as a player
ranged_cooldown = ranged_cooldown_time + world.time
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/Goto()
return
/mob/living/simple_animal/hostile/jungle/leaper/throw_impact()
return
/mob/living/simple_animal/hostile/jungle/leaper/update_icons()
. = ..()
if(stat)
icon_state = "leaper_dead"
return
if(ranged_cooldown <= world.time)
if(AIStatus == AI_ON && projectile_ready || ckey)
icon_state = "leaper_alert"
return
icon_state = "leaper"
#undef PLAYER_HOP_DELAY
////JUNGLE MOOK////
#define MOOK_ATTACK_NEUTRAL 0
#define MOOK_ATTACK_WARMUP 1
#define MOOK_ATTACK_ACTIVE 2
#define MOOK_ATTACK_RECOVERY 3
#define ATTACK_INTERMISSION_TIME 5
/mob/living/simple_animal/hostile/jungle/mook
name = "wanderer"
desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent."
maxHealth = 45
health = 45
melee_damage_lower = 30
melee_damage_upper = 30
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "mook"
icon_living = "mook"
icon_dead = "mook_dead"
pixel_x = -16
pixel_y = -8
ranged = TRUE
ranged_cooldown_time = 10
pass_flags = LETPASSTHROW
robust_searching = TRUE
stat_attack = UNCONSCIOUS
attack_sound = 'sound/weapons/rapierhit.ogg'
death_sound = 'sound/voice/mook_death.ogg'
aggro_vision_range = 15 //A little more aggressive once in combat to balance out their really low HP
var/attack_state = MOOK_ATTACK_NEUTRAL
var/struck_target_leap = FALSE
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
var/mob/living/simple_animal/hostile/jungle/mook/M = O
if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing)
return TRUE
return ..()
/mob/living/simple_animal/hostile/jungle/mook/death()
desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist
return ..()
/mob/living/simple_animal/hostile/jungle/mook/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && attack_state == MOOK_ATTACK_NEUTRAL)
var/mob/living/L = target
if(L.incapacitated())
WarmupAttack(forced_slash_combo = TRUE)
return
WarmupAttack()
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Goto()
if(attack_state != MOOK_ATTACK_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Move()
if(attack_state == MOOK_ATTACK_WARMUP || attack_state == MOOK_ATTACK_RECOVERY)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/proc/WarmupAttack(forced_slash_combo = FALSE)
if(attack_state == MOOK_ATTACK_NEUTRAL && target)
attack_state = MOOK_ATTACK_WARMUP
walk(src,0)
update_icons()
if(prob(50) && get_dist(src,target) <= 3 || forced_slash_combo)
addtimer(CALLBACK(src, .proc/SlashCombo), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/LeapAttack), ATTACK_INTERMISSION_TIME + rand(0,3))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashCombo()
if(attack_state == MOOK_ATTACK_WARMUP && !stat)
attack_state = MOOK_ATTACK_ACTIVE
update_icons()
SlashAttack()
addtimer(CALLBACK(src, .proc/SlashAttack), 3)
addtimer(CALLBACK(src, .proc/SlashAttack), 6)
addtimer(CALLBACK(src, .proc/AttackRecovery), 9)
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashAttack()
if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE)
melee_damage_lower = 15
melee_damage_upper = 15
var/mob_direction = get_dir(src,target)
if(get_dist(src,target) > 1)
step(src,mob_direction)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && isliving(target))
var/mob/living/L = target
L.attack_animal(src)
return
var/swing_turf = get_step(src,mob_direction)
new /obj/effect/temp_visual/kinetic_blast(swing_turf)
playsound(src, 'sound/weapons/slashmiss.ogg', 50, 1)
/mob/living/simple_animal/hostile/jungle/mook/proc/LeapAttack()
if(target && !stat && attack_state == MOOK_ATTACK_WARMUP)
attack_state = MOOK_ATTACK_ACTIVE
density = FALSE
melee_damage_lower = 30
melee_damage_upper = 30
update_icons()
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1)
playsound(src, 'sound/voice/mook_leap_yell.ogg', 100, 1)
var/target_turf = get_turf(target)
throw_at(target_turf, 7, 1, src, FALSE, callback = CALLBACK(src, .proc/AttackRecovery))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/AttackRecovery()
if(attack_state == MOOK_ATTACK_ACTIVE && !stat)
attack_state = MOOK_ATTACK_RECOVERY
density = TRUE
face_atom(target)
if(!struck_target_leap)
update_icons()
struck_target_leap = FALSE
if(prob(40))
attack_state = MOOK_ATTACK_NEUTRAL
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated() && L.stat != DEAD)
addtimer(CALLBACK(src, .proc/WarmupAttack, TRUE), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/WarmupAttack), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/ResetNeutral), ATTACK_INTERMISSION_TIME)
/mob/living/simple_animal/hostile/jungle/mook/proc/ResetNeutral()
if(attack_state == MOOK_ATTACK_RECOVERY)
attack_state = MOOK_ATTACK_NEUTRAL
ranged_cooldown = world.time + ranged_cooldown_time
update_icons()
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/mook/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
if(isliving(hit_atom) && attack_state == MOOK_ATTACK_ACTIVE)
var/mob/living/L = hit_atom
if(CanAttack(L))
L.attack_animal(src)
struck_target_leap = TRUE
density = TRUE
update_icons()
var/mook_under_us = FALSE
for(var/A in get_turf(src))
if(struck_target_leap && mook_under_us)
break
if(A == src)
continue
if(isliving(A))
var/mob/living/ML = A
if(!struck_target_leap && CanAttack(ML))//Check if some joker is attempting to use rest to evade us
struck_target_leap = TRUE
ML.attack_animal(src)
density = TRUE
struck_target_leap = TRUE
update_icons()
continue
if(istype(ML, /mob/living/simple_animal/hostile/jungle/mook) && !mook_under_us)//If we land on the same tile as another mook, spread out so we don't stack our sprite on the same tile
var/mob/living/simple_animal/hostile/jungle/mook/M = ML
if(!M.stat)
mook_under_us = TRUE
var/anydir = pick(GLOB.cardinals)
Move(get_step(src, anydir), anydir)
continue
/mob/living/simple_animal/hostile/jungle/mook/handle_automated_action()
if(attack_state)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/OpenFire()
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/mook/update_icons()
. = ..()
if(!stat)
switch(attack_state)
if(MOOK_ATTACK_NEUTRAL)
icon_state = "mook"
if(MOOK_ATTACK_WARMUP)
icon_state = "mook_warmup"
if(MOOK_ATTACK_ACTIVE)
if(!density)
icon_state = "mook_leap"
return
if(struck_target_leap)
icon_state = "mook_strike"
return
icon_state = "mook_slash_combo"
if(MOOK_ATTACK_RECOVERY)
icon_state = "mook"
/obj/effect/temp_visual/mook_dust
name = "dust"
desc = "it's just a dust cloud!"
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "mook_leap_cloud"
layer = BELOW_MOB_LAYER
pixel_x = -16
pixel_y = -16
duration = 10
#undef MOOK_ATTACK_NEUTRAL
#undef MOOK_ATTACK_WARMUP
#undef MOOK_ATTACK_ACTIVE
#undef MOOK_ATTACK_RECOVERY
#undef ATTACK_INTERMISSION_TIME
////Jungle Seedling////
#define SEEDLING_STATE_NEUTRAL 0
#define SEEDLING_STATE_WARMUP 1
#define SEEDLING_STATE_ACTIVE 2
#define SEEDLING_STATE_RECOVERY 3
/mob/living/simple_animal/hostile/jungle/seedling
name = "seedling"
desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon, and it will not die until its hidden vital organs are sliced out. \
The concentrated streams of energy it sometimes produces require its full attention, attacking it during this time will prevent it from finishing its attack."
maxHealth = 100
health = 100
melee_damage_lower = 30
melee_damage_upper = 30
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling"
icon_living = "seedling"
icon_dead = "seedling_dead"
pixel_x = -16
pixel_y = -14
minimum_distance = 3
move_to_delay = 20
vision_range = 9
aggro_vision_range = 15
ranged = TRUE
ranged_cooldown_time = 10
projectiletype = /obj/item/projectile/seedling
projectilesound = 'sound/weapons/pierce.ogg'
robust_searching = TRUE
stat_attack = UNCONSCIOUS
anchored = TRUE
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
var/solar_beam_identifier = 0
/obj/item/projectile/seedling
name = "solar energy"
icon_state = "seedling"
damage = 10
damage_type = BURN
light_range = 2
flag = "energy"
light_color = LIGHT_COLOR_YELLOW
hitsound = 'sound/weapons/sear.ogg'
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
nondirectional_sprite = TRUE
/obj/item/projectile/seedling/Collide(atom/A)//Stops seedlings from destroying other jungle mobs through FF
if(isliving(A))
var/mob/living/L = A
if("jungle" in L.faction)
return FALSE
return ..()
/obj/effect/temp_visual/solarbeam_killsat
name = "beam of solar energy"
icon_state = "solar_beam"
icon = 'icons/effects/beam.dmi'
layer = LIGHTING_LAYER
duration = 5
randomdir = FALSE
/datum/status_effect/seedling_beam_indicator
id = "seedling beam indicator"
duration = 30
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
tick_interval = 1
var/obj/screen/seedling/seedling_screen_object
var/atom/target
/datum/status_effect/seedling_beam_indicator/on_creation(mob/living/new_owner, target_plant)
. = ..()
if(.)
target = target_plant
tick()
/datum/status_effect/seedling_beam_indicator/on_apply()
if(owner.client)
seedling_screen_object = new /obj/screen/seedling()
owner.client.screen += seedling_screen_object
tick()
return ..()
/datum/status_effect/seedling_beam_indicator/Destroy()
if(owner)
if(owner.client)
owner.client.screen -= seedling_screen_object
return ..()
/datum/status_effect/seedling_beam_indicator/tick()
var/target_angle = Get_Angle(owner, target)
var/matrix/final = matrix()
final.Turn(target_angle)
seedling_screen_object.transform = final
/obj/screen/seedling
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling_beam_indicator"
screen_loc = "CENTER:-16,CENTER:-16"
/mob/living/simple_animal/hostile/jungle/seedling/Goto()
if(combatant_state != SEEDLING_STATE_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && combatant_state == SEEDLING_STATE_NEUTRAL)
OpenFire(target)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/OpenFire()
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/seedling/proc/WarmupAttack()
if(combatant_state == SEEDLING_STATE_NEUTRAL)
combatant_state = SEEDLING_STATE_WARMUP
walk(src,0)
update_icons()
var/target_dist = get_dist(src,target)
var/living_target_check = isliving(target)
if(living_target_check)
if(target_dist > 7)//Offscreen check
SolarBeamStartup(target)
return
if(get_dist(src,target) >= 4 && prob(40))
SolarBeamStartup(target)
return
addtimer(CALLBACK(src, .proc/Volley), 5)
/mob/living/simple_animal/hostile/jungle/seedling/proc/SolarBeamStartup(mob/living/living_target)//It's more like requiem than final spark
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
living_target.apply_status_effect(/datum/status_effect/seedling_beam_indicator, src)
beam_debuff_target = living_target
playsound(src,'sound/effects/seedling_chargeup.ogg', 100, 0)
if(get_dist(src,living_target) > 7)
playsound(living_target,'sound/effects/seedling_chargeup.ogg', 100, 0)
solar_beam_identifier = world.time
addtimer(CALLBACK(src, .proc/Beamu, living_target, solar_beam_identifier), 35)
/mob/living/simple_animal/hostile/jungle/seedling/proc/Beamu(mob/living/living_target, beam_id = 0)
if(combatant_state == SEEDLING_STATE_ACTIVE && living_target && beam_id == solar_beam_identifier)
if(living_target.z == z)
update_icons()
var/obj/effect/temp_visual/solarbeam_killsat/S = new (get_turf(src))
var/matrix/starting = matrix()
starting.Scale(1,32)
starting.Translate(0,520)
S.transform = starting
var/obj/effect/temp_visual/solarbeam_killsat/K = new (get_turf(living_target))
var/matrix/final = matrix()
final.Scale(1,32)
final.Translate(0,512)
K.transform = final
living_target.adjustFireLoss(30)
living_target.adjust_fire_stacks(0.2)//Just here for the showmanship
living_target.IgniteMob()
playsound(living_target,'sound/weapons/sear.ogg', 50, 1)
addtimer(CALLBACK(src, .proc/AttackRecovery), 5)
return
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/proc/Volley()
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
update_icons()
var/datum/callback/cb = CALLBACK(src, .proc/InaccurateShot)
for(var/i in 1 to 13)
addtimer(cb, i)
addtimer(CALLBACK(src, .proc/AttackRecovery), 14)
/mob/living/simple_animal/hostile/jungle/seedling/proc/InaccurateShot()
if(!QDELETED(target) && combatant_state == SEEDLING_STATE_ACTIVE && !stat)
if(get_dist(src,target) <= 3)//If they're close enough just aim straight at them so we don't miss at point blank ranges
Shoot(target)
return
var/turf/our_turf = get_turf(src)
var/obj/item/projectile/seedling/readied_shot = new /obj/item/projectile/seedling(our_turf)
readied_shot.current = our_turf
readied_shot.starting = our_turf
readied_shot.firer = src
readied_shot.original = target
readied_shot.yo = target.y - our_turf.y + rand(-1,1)
readied_shot.xo = target.x - our_turf.x + rand(-1,1)
readied_shot.fire()
playsound(src, projectilesound, 100, 1)
/mob/living/simple_animal/hostile/jungle/seedling/proc/AttackRecovery()
if(combatant_state == SEEDLING_STATE_ACTIVE)
combatant_state = SEEDLING_STATE_RECOVERY
update_icons()
ranged_cooldown = world.time + ranged_cooldown_time
if(target)
face_atom(target)
addtimer(CALLBACK(src, .proc/ResetNeutral), 10)
/mob/living/simple_animal/hostile/jungle/seedling/proc/ResetNeutral()
combatant_state = SEEDLING_STATE_NEUTRAL
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/seedling/adjustHealth()
. = ..()
if(combatant_state == SEEDLING_STATE_ACTIVE && beam_debuff_target)
beam_debuff_target.remove_status_effect(/datum/status_effect/seedling_beam_indicator)
beam_debuff_target = null
solar_beam_identifier = 0
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/update_icons()
. = ..()
if(!stat)
switch(combatant_state)
if(SEEDLING_STATE_NEUTRAL)
icon_state = "seedling"
if(SEEDLING_STATE_WARMUP)
icon_state = "seedling_charging"
if(SEEDLING_STATE_ACTIVE)
icon_state = "seedling_fire"
if(SEEDLING_STATE_RECOVERY)
icon_state = "seedling"
/mob/living/simple_animal/hostile/jungle/seedling/GiveTarget()
if(target)
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)//So it doesn't 180 and blast you in the face while it's firing at someone else
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/LoseTarget()
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)
return
return ..()
#undef SEEDLING_STATE_NEUTRAL
#undef SEEDLING_STATE_WARMUP
#undef SEEDLING_STATE_ACTIVE
#undef SEEDLING_STATE_RECOVERY
@@ -1,10 +0,0 @@
diff a/code/modules/mob/living/simple_animal/hostile/jungle_mobs.dm b/code/modules/mob/living/simple_animal/hostile/jungle_mobs.dm (rejected hunks)
@@ -80,7 +80,7 @@
/obj/item/restraints/legcuffs/beartrap/mega_arachnid
name = "fleshy restraints"
desc = "Used by mega arachnids to immobilize their prey."
- flags = DROPDEL
+ flags_1 = DROPDEL_1
icon_state = "tentacle_end"
icon = 'icons/obj/projectiles.dmi'
@@ -277,19 +277,29 @@ Difficulty: Very Hard
WriteMemory()
/obj/machinery/smartfridge/black_box/proc/WriteMemory()
var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav")
var/json_file = file("data/npc_saves/Blackbox.json")
stored_items = list()
for(var/obj/O in (contents-component_parts))
stored_items += O.type
WRITE_FILE(S["stored_items"], stored_items)
var/list/file_data = list()
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/savefile/S = new /savefile("data/npc_saves/Blackbox.sav")
S["stored_items"] >> stored_items
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 = list()
json = json_decode(file2text(json_file))
stored_items = json["data"]
if(isnull(stored_items))
stored_items = list()
+26 -12
View File
@@ -296,7 +296,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
@@ -924,22 +924,36 @@
..(gibbed)
/mob/living/simple_animal/parrot/Poly/proc/Read_Memory()
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
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 = 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()
var/savefile/S = new /savefile("data/npc_saves/Poly.sav")
var/json_file = file("data/npc_saves/Poly.json")
var/list/file_data = list()
if(islist(speech_buffer))
WRITE_FILE(S["phrases"], speech_buffer)
WRITE_FILE(S["roundssurvived"], rounds_survived)
WRITE_FILE(S["longestsurvival"], longest_survival)
WRITE_FILE(S["longestdeathstreak"], longest_deathstreak)
file_data["phrases"] = speech_buffer
file_data["roundssurvived"] = rounds_survived
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

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