Merge pull request #4522 from VOREStation/upstream-merge-5735

[MIRROR] Merges AI Branch into Master
This commit is contained in:
Spades
2019-02-23 11:20:37 -05:00
committed by GitHub
581 changed files with 24399 additions and 31654 deletions

View File

@@ -22,9 +22,6 @@ mob/proc/airflow_stun()
mob/living/silicon/airflow_stun() mob/living/silicon/airflow_stun()
return return
mob/living/simple_animal/slime/airflow_stun()
return
mob/living/carbon/human/airflow_stun() mob/living/carbon/human/airflow_stun()
if(shoes && (shoes.item_flags & NOSLIP)) if(shoes && (shoes.item_flags & NOSLIP))
to_chat(src, "<span class='notice'>Air suddenly rushes past you!</span>") to_chat(src, "<span class='notice'>Air suddenly rushes past you!</span>")

View File

@@ -58,7 +58,10 @@ What is the naming convention for planes or layers?
#define ATMOS_LAYER 2.4 // Pipe-like atmos machinery that goes on the floor, like filters. #define ATMOS_LAYER 2.4 // Pipe-like atmos machinery that goes on the floor, like filters.
#define ABOVE_UTILITY 2.5 // Above stuff like pipes and wires #define ABOVE_UTILITY 2.5 // Above stuff like pipes and wires
#define TURF_PLANE -45 // Turfs themselves, most flooring #define TURF_PLANE -45 // Turfs themselves, most flooring
#define ABOVE_TURF_LAYER 2.1 // Snow and wallmounted/floormounted equipment #define WATER_FLOOR_LAYER 2.0 // The 'bottom' of water tiles.
#define UNDERWATER_LAYER 2.5 // Anything on this layer will render under the water layer.
#define WATER_LAYER 3.0 // Layer for water overlays.
#define ABOVE_TURF_LAYER 3.1 // Snow and wallmounted/floormounted equipment
#define DECAL_PLANE -44 // Permanent decals #define DECAL_PLANE -44 // Permanent decals
#define DIRTY_PLANE -43 // Nonpermanent decals #define DIRTY_PLANE -43 // Nonpermanent decals
#define BLOOD_PLANE -42 // Blood is really dirty, but we can do special stuff if we separate it #define BLOOD_PLANE -42 // Blood is really dirty, but we can do special stuff if we separate it

View File

@@ -302,4 +302,4 @@ var/global/list/##LIST_NAME = list();\
#define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units. #define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units.
#define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT #define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT

View File

@@ -27,6 +27,9 @@
#define BORGXRAY 0x4 #define BORGXRAY 0x4
#define BORGMATERIAL 8 #define BORGMATERIAL 8
#define STANCE_ATTACK 11 // Backwards compatability
#define STANCE_ATTACKING 12 // Ditto
/*
#define STANCE_IDLE 1 // Looking for targets if hostile. Does idle wandering. #define STANCE_IDLE 1 // Looking for targets if hostile. Does idle wandering.
#define STANCE_ALERT 2 // Bears #define STANCE_ALERT 2 // Bears
#define STANCE_ATTACK 3 // Attempting to get into attack position #define STANCE_ATTACK 3 // Attempting to get into attack position
@@ -34,6 +37,20 @@
#define STANCE_TIRED 5 // Bears #define STANCE_TIRED 5 // Bears
#define STANCE_FOLLOW 6 // Following somone #define STANCE_FOLLOW 6 // Following somone
#define STANCE_BUSY 7 // Do nothing on life ticks (Other code is running) #define STANCE_BUSY 7 // Do nothing on life ticks (Other code is running)
*/
#define STANCE_SLEEP 0 // Doing (almost) nothing, to save on CPU because nobody is around to notice or the mob died.
#define STANCE_IDLE 1 // The more or less default state. Wanders around, looks for baddies, and spouts one-liners.
#define STANCE_ALERT 2 // A baddie is visible but not too close, and essentially we tell them to go away or die.
#define STANCE_APPROACH 3 // Attempting to get into range to attack them.
#define STANCE_FIGHT 4 // Actually fighting, with melee or ranged.
#define STANCE_BLINDFIGHT 5 // Fighting something that cannot be seen by the mob, from invisibility or out of sight.
#define STANCE_REPOSITION 6 // Relocating to a better position while in combat. Also used when moving away from a danger like grenades.
#define STANCE_MOVE 7 // Similar to above but for out of combat. If a baddie is seen, they'll cancel and fight them.
#define STANCE_FOLLOW 8 // Following somone, without trying to murder them.
#define STANCE_FLEE 9 // Run away from the target because they're too spooky/we're dying/some other reason.
#define STANCE_DISABLED 10 // Used when the holder is afflicted with certain status effects, such as stuns or confusion.
#define STANCES_COMBAT list(STANCE_ALERT, STANCE_APPROACH, STANCE_FIGHT, STANCE_BLINDFIGHT, STANCE_REPOSITION)
#define LEFT 0x1 #define LEFT 0x1
#define RIGHT 0x2 #define RIGHT 0x2
@@ -279,11 +296,34 @@
#define SA_ROBOTIC 3 #define SA_ROBOTIC 3
#define SA_HUMANOID 4 #define SA_HUMANOID 4
// More refined version of SA_* ""intelligence"" seperators.
// Now includes bitflags, so to target two classes you just do 'MOB_CLASS_ANIMAL|MOB_CLASS_HUMANOID'
#define MOB_CLASS_NONE 0 // Default value, and used to invert for _ALL.
#define MOB_CLASS_PLANT 1 // Unused at the moment.
#define MOB_CLASS_ANIMAL 2 // Animals and beasts like spiders, saviks, and bears.
#define MOB_CLASS_HUMANOID 4 // Non-robotic humanoids, including /simple_mob and /carbon/humans and their alien variants.
#define MOB_CLASS_SYNTHETIC 8 // Silicons, mechanical simple mobs, FBPs, and anything else that would pass is_synthetic()
#define MOB_CLASS_SLIME 16 // Everyone's favorite xenobiology specimen (and maybe prometheans?).
#define MOB_CLASS_ABERRATION 32 // Weird shit.
#define MOB_CLASS_DEMONIC 64 // Cult stuff.
#define MOB_CLASS_BOSS 128 // Future megafauna hopefully someday.
#define MOB_CLASS_ILLUSION 256 // Fake mobs, e.g. Technomancer illusions.
#define MOB_CLASS_PHOTONIC 512 // Holographic mobs like holocarp, similar to _ILLUSION, but that make no attempt to hide their true nature.
#define MOB_CLASS_ALL (~MOB_CLASS_NONE)
// For slime commanding. Higher numbers allow for more actions. // For slime commanding. Higher numbers allow for more actions.
#define SLIME_COMMAND_OBEY 1 // When disciplined. #define SLIME_COMMAND_OBEY 1 // When disciplined.
#define SLIME_COMMAND_FACTION 2 // When in the same 'faction'. #define SLIME_COMMAND_FACTION 2 // When in the same 'faction'.
#define SLIME_COMMAND_FRIEND 3 // When befriended with a slime friendship agent. #define SLIME_COMMAND_FRIEND 3 // When befriended with a slime friendship agent.
// Threshold for mobs being able to damage things like airlocks or reinforced glass windows.
// If the damage is below this, nothing will happen besides a message saying that the attack was ineffective.
// Generally, this was not a define but was commonly set to 10, however 10 may be too low now since simple_mobs now attack twice as fast,
// at half damage compared to the old mob system, meaning mobs who could hurt structures may not be able to now, so now it is 5.
#define STRUCTURE_MIN_DAMAGE_THRESHOLD 5
//Vision flags, for dealing with plane visibility //Vision flags, for dealing with plane visibility
#define VIS_FULLBRIGHT 1 #define VIS_FULLBRIGHT 1
#define VIS_LIGHTING 2 #define VIS_LIGHTING 2

View File

@@ -60,6 +60,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_OVERLAY -6 #define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_XENOARCH -20 #define INIT_ORDER_XENOARCH -20
#define INIT_ORDER_CIRCUIT -21 #define INIT_ORDER_CIRCUIT -21
#define INIT_ORDER_AI -22
// Subsystem fire priority, from lowest to highest priority // Subsystem fire priority, from lowest to highest priority
@@ -67,6 +68,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_SHUTTLES 5 #define FIRE_PRIORITY_SHUTTLES 5
#define FIRE_PRIORITY_ORBIT 8 #define FIRE_PRIORITY_ORBIT 8
#define FIRE_PRIORITY_VOTE 9 #define FIRE_PRIORITY_VOTE 9
#define FIRE_PRIORITY_AI 10
#define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_AIRFLOW 30 #define FIRE_PRIORITY_AIRFLOW 30
#define FIRE_PRIORITY_AIR 35 #define FIRE_PRIORITY_AIR 35

View File

@@ -1,4 +1,8 @@
GLOBAL_LIST_EMPTY(all_observable_events) GLOBAL_LIST_EMPTY(error_last_seen)
GLOBAL_LIST_EMPTY(error_cooldown)
GLOBAL_DATUM_INIT(all_observable_events, /datum/all_observable_events, new) // This is a datum. It is not a list.
GLOBAL_DATUM_INIT(destroyed_event, /decl/observ/destroyed, new())
GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks. GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks.

View File

@@ -2,4 +2,4 @@ GLOBAL_LIST_EMPTY(admins) //all clients whom are admins
GLOBAL_PROTECT(admins) GLOBAL_PROTECT(admins)
GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb. GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb.
GLOBAL_LIST_EMPTY(stealthminID) GLOBAL_LIST_EMPTY(stealthminID)
GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client

View File

@@ -239,4 +239,4 @@ var/round_start_time = 0
else else
day = "[truncate ? "day" : "1 day"]" day = "[truncate ? "day" : "1 day"]"
return "[day][hour][minute][second]" return "[day][hour][minute][second]"

View File

@@ -501,7 +501,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M) moblist.Add(M)
for(var/mob/new_player/M in sortmob) for(var/mob/new_player/M in sortmob)
moblist.Add(M) moblist.Add(M)
for(var/mob/living/simple_animal/M in sortmob) for(var/mob/living/simple_mob/M in sortmob)
moblist.Add(M) moblist.Add(M)
// for(var/mob/living/silicon/hivebot/M in sortmob) // for(var/mob/living/silicon/hivebot/M in sortmob)
// mob_list.Add(M) // mob_list.Add(M)

View File

@@ -10,7 +10,7 @@
#define isalien(A) istype(A, /mob/living/carbon/alien) #define isalien(A) istype(A, /mob/living/carbon/alien)
#define isanimal(A) istype(A, /mob/living/simple_animal) #define isanimal(A) istype(A, /mob/living/simple_mob)
#define isairlock(A) istype(A, /obj/machinery/door/airlock) #define isairlock(A) istype(A, /obj/machinery/door/airlock)
@@ -18,7 +18,7 @@
#define iscarbon(A) istype(A, /mob/living/carbon) #define iscarbon(A) istype(A, /mob/living/carbon)
#define iscorgi(A) istype(A, /mob/living/simple_animal/corgi) #define iscorgi(A) istype(A, /mob/living/simple_mob/animal/passive/dog/corgi)
#define isEye(A) istype(A, /mob/observer/eye) #define isEye(A) istype(A, /mob/observer/eye)
@@ -26,7 +26,7 @@
#define isliving(A) istype(A, /mob/living) #define isliving(A) istype(A, /mob/living)
#define ismouse(A) istype(A, /mob/living/simple_animal/mouse) #define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse)
#define isnewplayer(A) istype(A, /mob/new_player) #define isnewplayer(A) istype(A, /mob/new_player)
@@ -42,11 +42,11 @@
#define isvoice(A) istype(A, /mob/living/voice) #define isvoice(A) istype(A, /mob/living/voice)
#define isslime(A) istype(A, /mob/living/simple_animal/slime) #define isslime(A) istype(A, /mob/living/simple_mob/slime)
#define isbot(A) istype(A, /mob/living/bot) #define isbot(A) istype(A, /mob/living/bot)
#define isxeno(A) istype(A, /mob/living/simple_animal/xeno) #define isxeno(A) istype(A, /mob/living/simple_mob/animal/space/alien)
#define isopenspace(A) istype(A, /turf/simulated/open) #define isopenspace(A) istype(A, /turf/simulated/open)

View File

@@ -98,7 +98,7 @@
/obj/screen/fullscreen/flash /obj/screen/fullscreen/flash
icon = 'icons/mob/screen1.dmi' icon = 'icons/mob/screen1.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH" screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash" icon_state = "flash_static"
/obj/screen/fullscreen/flash/noise /obj/screen/fullscreen/flash/noise
icon_state = "noise" icon_state = "noise"

View File

@@ -316,8 +316,6 @@ datum/hud/New(mob/owner)
mymob.instantiate_hud(src) mymob.instantiate_hud(src)
else if(isalien(mymob)) else if(isalien(mymob))
larva_hud() larva_hud()
else if(isslime(mymob))
slime_hud()
else if(isAI(mymob)) else if(isAI(mymob))
ai_hud() ai_hud()
else if(isobserver(mymob)) else if(isobserver(mymob))

View File

@@ -23,7 +23,7 @@
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay) mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
mymob.client.screen += mymob.client.void mymob.client.screen += mymob.client.void
/*
/datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi') /datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
src.adding = list() src.adding = list()
@@ -92,23 +92,20 @@
mymob.client.screen += mymob.client.void mymob.client.screen += mymob.client.void
return return
*/
/mob/living/simple_animal/construct/instantiate_hud(var/datum/hud/HUD)
..(HUD)
// HUD.construct_hud() //Archaic. // HUD.construct_hud() //Archaic.
/* /*
/datum/hud/proc/construct_hud() /datum/hud/proc/construct_hud()
var/constructtype var/constructtype
if(istype(mymob,/mob/living/simple_animal/construct/armoured) || istype(mymob,/mob/living/simple_animal/construct/behemoth)) if(istype(mymob,/mob/living/simple_mob/construct/armoured) || istype(mymob,/mob/living/simple_mob/construct/behemoth))
constructtype = "juggernaut" constructtype = "juggernaut"
else if(istype(mymob,/mob/living/simple_animal/construct/builder)) else if(istype(mymob,/mob/living/simple_mob/construct/builder))
constructtype = "artificer" constructtype = "artificer"
else if(istype(mymob,/mob/living/simple_animal/construct/wraith)) else if(istype(mymob,/mob/living/simple_mob/construct/wraith))
constructtype = "wraith" constructtype = "wraith"
else if(istype(mymob,/mob/living/simple_animal/construct/harvester)) else if(istype(mymob,/mob/living/simple_mob/construct/harvester))
constructtype = "harvester" constructtype = "harvester"
if(constructtype) if(constructtype)

View File

@@ -1,15 +1,15 @@
/obj/screen/proc/Click_vr(location, control, params) /obj/screen/proc/Click_vr(location, control, params) //VORESTATION AI TEMPORARY REMOVAL
if(!usr) return 1 if(!usr) return 1
switch(name) switch(name)
//Shadekin //Shadekin
if("darkness") if("darkness")
var/mob/living/simple_animal/shadekin/sk = usr var/mob/living/simple_mob/shadekin/sk = usr
var/turf/T = get_turf(sk) var/turf/T = get_turf(sk)
var/darkness = round(1 - T.get_lumcount(),0.1) var/darkness = round(1 - T.get_lumcount(),0.1)
to_chat(usr,"<span class='notice'><b>Darkness:</b> [darkness]</span>") to_chat(usr,"<span class='notice'><b>Darkness:</b> [darkness]</span>")
if("energy") if("energy")
var/mob/living/simple_animal/shadekin/sk = usr var/mob/living/simple_mob/shadekin/sk = usr
to_chat(usr,"<span class='notice'><b>Energy:</b> [sk.energy] ([sk.dark_gains])</span>") to_chat(usr,"<span class='notice'><b>Energy:</b> [sk.energy] ([sk.dark_gains])</span>")

View File

@@ -60,7 +60,7 @@ avoid code duplication. This includes items that may sometimes act as a standard
// Same as above but actually does useful things. // Same as above but actually does useful things.
// W is the item being used in the attack, if any. modifier is if the attack should be longer or shorter than usual, for whatever reason. // W is the item being used in the attack, if any. modifier is if the attack should be longer or shorter than usual, for whatever reason.
/mob/living/get_attack_speed(var/obj/item/W) /mob/living/get_attack_speed(var/obj/item/W)
var/speed = DEFAULT_ATTACK_COOLDOWN var/speed = base_attack_cooldown
if(W && istype(W)) if(W && istype(W))
speed = W.attackspeed speed = W.attackspeed
for(var/datum/modifier/M in modifiers) for(var/datum/modifier/M in modifiers)

View File

@@ -68,58 +68,3 @@
*/ */
/mob/new_player/ClickOn() /mob/new_player/ClickOn()
return return
/*
Animals
*/
/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity)
if(!(. = ..()))
return
setClickCooldown(get_attack_speed())
if(has_hands && istype(A,/obj) && a_intent != I_HURT)
var/obj/O = A
return O.attack_hand(src)
switch(a_intent)
if(I_HELP)
if(isliving(A))
custom_emote(1,"[pick(friendly)] [A]!")
if(I_HURT)
if(prob(spattack_prob))
if(spattack_min_range <= 1)
SpecialAtkTarget()
else if(melee_damage_upper == 0 && istype(A,/mob/living))
custom_emote(1,"[pick(friendly)] [A]!")
else
DoPunch(A)
if(I_GRAB)
if(has_hands)
A.attack_hand(src)
if(I_DISARM)
if(has_hands)
A.attack_hand(src)
/mob/living/simple_animal/RangedAttack(var/atom/A)
setClickCooldown(get_attack_speed())
var/distance = get_dist(src, A)
if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range))
target_mob = A
SpecialAtkTarget()
target_mob = null
return
if(ranged && distance <= shoot_range)
target_mob = A
ShootTarget(A)
target_mob = null

View File

@@ -11,7 +11,7 @@
var/datum/controller/process/alarm/alarm_manager var/datum/controller/process/alarm/alarm_manager
/datum/controller/process/alarm /datum/controller/process/alarm
var/list/datum/alarm/all_handlers var/list/datum/alarm/all_handlers = list()
/datum/controller/process/alarm/setup() /datum/controller/process/alarm/setup()
name = "alarm" name = "alarm"

View File

@@ -40,7 +40,7 @@
// We are being killed. Least we can do is deregister all those events we registered // We are being killed. Least we can do is deregister all those events we registered
/datum/controller/process/scheduler/onKill() /datum/controller/process/scheduler/onKill()
for(var/st in scheduled_tasks) for(var/st in scheduled_tasks)
destroyed_event.unregister(st, src) GLOB.destroyed_event.unregister(st, src)
/datum/controller/process/scheduler/statProcess() /datum/controller/process/scheduler/statProcess()
..() ..()
@@ -148,7 +148,7 @@
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) /datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
src.source = source src.source = source
destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed) GLOB.destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args) ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
/datum/scheduled_task/source/Destroy() /datum/scheduled_task/source/Destroy()

View File

@@ -0,0 +1,36 @@
SUBSYSTEM_DEF(ai)
name = "AI"
init_order = INIT_ORDER_AI
priority = FIRE_PRIORITY_AI
wait = 5 // This gets run twice a second, however this is technically two loops in one, with the second loop being run every four iterations.
flags = SS_NO_INIT|SS_TICKER
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/processing = list()
var/list/currentrun = list()
/datum/controller/subsystem/ai/stat_entry(msg_prefix)
var/list/msg = list(msg_prefix)
msg += "P:[processing.len]"
..(msg.Join())
/datum/controller/subsystem/ai/fire(resumed = 0)
if (!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
// var/mob/living/L = currentrun[currentrun.len]
var/datum/ai_holder/A = currentrun[currentrun.len]
--currentrun.len
if(!A || QDELETED(A)) // Doesn't exist or won't exist soon.
continue
if(times_fired % 4 == 0 && A.holder.stat != DEAD)
A.handle_strategicals()
if(A.holder.stat != DEAD) // The /TG/ version checks stat twice, presumably in-case processing somehow got the mob killed in that instant.
A.handle_tactics()
if(MC_TICK_CHECK)
return

View File

@@ -1,373 +1,373 @@
SUBSYSTEM_DEF(vote) SUBSYSTEM_DEF(vote)
name = "Vote" name = "Vote"
wait = 10 wait = 10
priority = FIRE_PRIORITY_VOTE priority = FIRE_PRIORITY_VOTE
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
flags = SS_KEEP_TIMING | SS_NO_INIT flags = SS_KEEP_TIMING | SS_NO_INIT
var/list/round_voters = list() var/list/round_voters = list()
//Current vote //Current vote
var/initiator var/initiator
var/started_time var/started_time
var/time_remaining var/time_remaining
var/duration var/duration
var/mode var/mode
var/question var/question
var/list/choices = list() var/list/choices = list()
var/list/gamemode_names = list() var/list/gamemode_names = list()
var/list/voted = list() var/list/voted = list()
var/list/current_votes = list() var/list/current_votes = list()
var/list/additional_text = list() var/list/additional_text = list()
/datum/controller/subsystem/vote/fire(resumed) /datum/controller/subsystem/vote/fire(resumed)
if(mode) if(mode)
time_remaining = round((started_time + duration - world.time)/10) time_remaining = round((started_time + duration - world.time)/10)
if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP) if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP)
to_chat(world, "<b>Gamemode vote aborted: Game has already started.</b>") to_chat(world, "<b>Gamemode vote aborted: Game has already started.</b>")
reset() reset()
return return
if(time_remaining <= 0) if(time_remaining <= 0)
result() result()
reset() reset()
/datum/controller/subsystem/vote/proc/autotransfer() /datum/controller/subsystem/vote/proc/autotransfer()
initiate_vote(VOTE_CREW_TRANSFER, "the server", 1) initiate_vote(VOTE_CREW_TRANSFER, "the server", 1)
log_debug("The server has called a crew transfer vote.") log_debug("The server has called a crew transfer vote.")
/datum/controller/subsystem/vote/proc/autogamemode() /datum/controller/subsystem/vote/proc/autogamemode()
initiate_vote(VOTE_GAMEMODE, "the server", 1) initiate_vote(VOTE_GAMEMODE, "the server", 1)
log_debug("The server has called a gamemode vote.") log_debug("The server has called a gamemode vote.")
/datum/controller/subsystem/vote/proc/reset() /datum/controller/subsystem/vote/proc/reset()
initiator = null initiator = null
started_time = null started_time = null
duration = null duration = null
time_remaining = null time_remaining = null
mode = null mode = null
question = null question = null
choices.Cut() choices.Cut()
voted.Cut() voted.Cut()
current_votes.Cut() current_votes.Cut()
additional_text.Cut() additional_text.Cut()
/datum/controller/subsystem/vote/proc/get_result() // Get the highest number of votes /datum/controller/subsystem/vote/proc/get_result() // Get the highest number of votes
var/greatest_votes = 0 var/greatest_votes = 0
var/total_votes = 0 var/total_votes = 0
for(var/option in choices) for(var/option in choices)
var/votes = choices[option] var/votes = choices[option]
total_votes += votes total_votes += votes
if(votes > greatest_votes) if(votes > greatest_votes)
greatest_votes = votes greatest_votes = votes
if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote
var/non_voters = (clients.len - total_votes) var/non_voters = (clients.len - total_votes)
if(non_voters > 0) if(non_voters > 0)
if(mode == VOTE_RESTART) if(mode == VOTE_RESTART)
choices["Continue Playing"] += non_voters choices["Continue Playing"] += non_voters
if(choices["Continue Playing"] >= greatest_votes) if(choices["Continue Playing"] >= greatest_votes)
greatest_votes = choices["Continue Playing"] greatest_votes = choices["Continue Playing"]
else if(mode == VOTE_GAMEMODE) else if(mode == VOTE_GAMEMODE)
if(master_mode in choices) if(master_mode in choices)
choices[master_mode] += non_voters choices[master_mode] += non_voters
if(choices[master_mode] >= greatest_votes) if(choices[master_mode] >= greatest_votes)
greatest_votes = choices[master_mode] greatest_votes = choices[master_mode]
else if(mode == VOTE_CREW_TRANSFER) else if(mode == VOTE_CREW_TRANSFER)
var/factor = 0.5 var/factor = 0.5
switch(world.time / (10 * 60)) // minutes switch(world.time / (10 * 60)) // minutes
if(0 to 60) if(0 to 60)
factor = 0.5 factor = 0.5
if(61 to 120) if(61 to 120)
factor = 0.8 factor = 0.8
if(121 to 240) if(121 to 240)
factor = 1 factor = 1
if(241 to 300) if(241 to 300)
factor = 1.2 factor = 1.2
else else
factor = 1.4 factor = 1.4
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor) choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
world << "<font color='purple'>Crew Transfer Factor: [factor]</font>" world << "<font color='purple'>Crew Transfer Factor: [factor]</font>"
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"]) greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
. = list() // Get all options with that many votes and return them in a list . = list() // Get all options with that many votes and return them in a list
if(greatest_votes) if(greatest_votes)
for(var/option in choices) for(var/option in choices)
if(choices[option] == greatest_votes) if(choices[option] == greatest_votes)
. += option . += option
/datum/controller/subsystem/vote/proc/announce_result() /datum/controller/subsystem/vote/proc/announce_result()
var/list/winners = get_result() var/list/winners = get_result()
var/text var/text
if(winners.len > 0) if(winners.len > 0)
if(winners.len > 1) if(winners.len > 1)
if(mode != VOTE_GAMEMODE || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes if(mode != VOTE_GAMEMODE || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
text = "<b>Vote Tied Between:</b>\n" text = "<b>Vote Tied Between:</b>\n"
for(var/option in winners) for(var/option in winners)
text += "\t[option]\n" text += "\t[option]\n"
. = pick(winners) . = pick(winners)
for(var/key in current_votes) for(var/key in current_votes)
if(choices[current_votes[key]] == .) if(choices[current_votes[key]] == .)
round_voters += key // Keep track of who voted for the winning round. round_voters += key // Keep track of who voted for the winning round.
if(mode != VOTE_GAMEMODE || . == "Extended" || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes if(mode != VOTE_GAMEMODE || . == "Extended" || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes
text += "<b>Vote Result: [mode == VOTE_GAMEMODE ? gamemode_names[.] : .]</b>" text += "<b>Vote Result: [mode == VOTE_GAMEMODE ? gamemode_names[.] : .]</b>"
else else
text += "<b>The vote has ended.</b>" text += "<b>The vote has ended.</b>"
else else
text += "<b>Vote Result: Inconclusive - No Votes!</b>" text += "<b>Vote Result: Inconclusive - No Votes!</b>"
if(mode == VOTE_ADD_ANTAGONIST) if(mode == VOTE_ADD_ANTAGONIST)
antag_add_failed = 1 antag_add_failed = 1
log_vote(text) log_vote(text)
to_chat(world, "<font color='purple'>[text]</font>") to_chat(world, "<font color='purple'>[text]</font>")
/datum/controller/subsystem/vote/proc/result() /datum/controller/subsystem/vote/proc/result()
. = announce_result() . = announce_result()
var/restart = 0 var/restart = 0
if(.) if(.)
switch(mode) switch(mode)
if(VOTE_RESTART) if(VOTE_RESTART)
if(. == "Restart Round") if(. == "Restart Round")
restart = 1 restart = 1
if(VOTE_GAMEMODE) if(VOTE_GAMEMODE)
if(master_mode != .) if(master_mode != .)
world.save_mode(.) world.save_mode(.)
if(ticker && ticker.mode) if(ticker && ticker.mode)
restart = 1 restart = 1
else else
master_mode = . master_mode = .
if(VOTE_CREW_TRANSFER) if(VOTE_CREW_TRANSFER)
if(. == "Initiate Crew Transfer") if(. == "Initiate Crew Transfer")
init_shift_change(null, 1) init_shift_change(null, 1)
if(VOTE_ADD_ANTAGONIST) if(VOTE_ADD_ANTAGONIST)
if(isnull(.) || . == "None") if(isnull(.) || . == "None")
antag_add_failed = 1 antag_add_failed = 1
else else
additional_antag_types |= antag_names_to_ids[.] additional_antag_types |= antag_names_to_ids[.]
if(mode == VOTE_GAMEMODE) //fire this even if the vote fails. if(mode == VOTE_GAMEMODE) //fire this even if the vote fails.
if(!round_progressing) if(!round_progressing)
round_progressing = 1 round_progressing = 1
world << "<font color='red'><b>The round will start soon.</b></font>" world << "<font color='red'><b>The round will start soon.</b></font>"
if(restart) if(restart)
world << "World restarting due to vote..." world << "World restarting due to vote..."
feedback_set_details("end_error", "restart vote") feedback_set_details("end_error", "restart vote")
if(blackbox) if(blackbox)
blackbox.save_all_data_to_sql() blackbox.save_all_data_to_sql()
sleep(50) sleep(50)
log_game("Rebooting due to restart vote") log_game("Rebooting due to restart vote")
world.Reboot() world.Reboot()
/datum/controller/subsystem/vote/proc/submit_vote(ckey, newVote) /datum/controller/subsystem/vote/proc/submit_vote(ckey, newVote)
if(mode) if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder) if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return return
if(current_votes[ckey]) if(current_votes[ckey])
choices[choices[current_votes[ckey]]]-- choices[choices[current_votes[ckey]]]--
if(newVote && newVote >= 1 && newVote <= choices.len) if(newVote && newVote >= 1 && newVote <= choices.len)
choices[choices[newVote]]++ choices[choices[newVote]]++
current_votes[ckey] = newVote current_votes[ckey] = newVote
else else
current_votes[ckey] = null current_votes[ckey] = null
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, automatic = FALSE, time = config.vote_period) /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, automatic = FALSE, time = config.vote_period)
if(!mode) if(!mode)
if(started_time != null && !(check_rights(R_ADMIN) || automatic)) if(started_time != null && !(check_rights(R_ADMIN) || automatic))
var/next_allowed_time = (started_time + config.vote_delay) var/next_allowed_time = (started_time + config.vote_delay)
if(next_allowed_time > world.time) if(next_allowed_time > world.time)
return 0 return 0
reset() reset()
switch(vote_type) switch(vote_type)
if(VOTE_RESTART) if(VOTE_RESTART)
choices.Add("Restart Round", "Continue Playing") choices.Add("Restart Round", "Continue Playing")
if(VOTE_GAMEMODE) if(VOTE_GAMEMODE)
if(ticker.current_state >= GAME_STATE_SETTING_UP) if(ticker.current_state >= GAME_STATE_SETTING_UP)
return 0 return 0
choices.Add(config.votable_modes) choices.Add(config.votable_modes)
for(var/F in choices) for(var/F in choices)
var/datum/game_mode/M = gamemode_cache[F] var/datum/game_mode/M = gamemode_cache[F]
if(!M) if(!M)
continue continue
gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works
additional_text.Add("<td align = 'center'>[M.required_players]</td>") additional_text.Add("<td align = 'center'>[M.required_players]</td>")
gamemode_names["secret"] = "Secret" gamemode_names["secret"] = "Secret"
if(VOTE_CREW_TRANSFER) if(VOTE_CREW_TRANSFER)
if(!check_rights(R_ADMIN|R_MOD, 0)) // The gods care not for the affairs of the mortals if(!check_rights(R_ADMIN|R_MOD, 0)) // The gods care not for the affairs of the mortals
if(get_security_level() == "red" || get_security_level() == "delta") if(get_security_level() == "red" || get_security_level() == "delta")
initiator_key << "The current alert status is too high to call for a crew transfer!" initiator_key << "The current alert status is too high to call for a crew transfer!"
return 0 return 0
if(ticker.current_state <= GAME_STATE_SETTING_UP) if(ticker.current_state <= GAME_STATE_SETTING_UP)
initiator_key << "The crew transfer button has been disabled!" initiator_key << "The crew transfer button has been disabled!"
return 0 return 0
question = "End the shift?" question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round") choices.Add("Initiate Crew Transfer", "Continue The Round")
if(VOTE_ADD_ANTAGONIST) if(VOTE_ADD_ANTAGONIST)
if(!config.allow_extra_antags || ticker.current_state >= GAME_STATE_SETTING_UP) if(!config.allow_extra_antags || ticker.current_state >= GAME_STATE_SETTING_UP)
return 0 return 0
for(var/antag_type in all_antag_types) for(var/antag_type in all_antag_types)
var/datum/antagonist/antag = all_antag_types[antag_type] var/datum/antagonist/antag = all_antag_types[antag_type]
if(!(antag.id in additional_antag_types) && antag.is_votable()) if(!(antag.id in additional_antag_types) && antag.is_votable())
choices.Add(antag.role_text) choices.Add(antag.role_text)
choices.Add("None") choices.Add("None")
if(VOTE_CUSTOM) if(VOTE_CUSTOM)
question = sanitizeSafe(input(usr, "What is the vote for?") as text|null) question = sanitizeSafe(input(usr, "What is the vote for?") as text|null)
if(!question) if(!question)
return 0 return 0
for(var/i = 1 to 10) for(var/i = 1 to 10)
var/option = capitalize(sanitize(input(usr, "Please enter an option or hit cancel to finish") as text|null)) var/option = capitalize(sanitize(input(usr, "Please enter an option or hit cancel to finish") as text|null))
if(!option || mode || !usr.client) if(!option || mode || !usr.client)
break break
choices.Add(option) choices.Add(option)
else else
return 0 return 0
mode = vote_type mode = vote_type
initiator = initiator_key initiator = initiator_key
started_time = world.time started_time = world.time
duration = time duration = time
var/text = "[capitalize(mode)] vote started by [initiator]." var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == VOTE_CUSTOM) if(mode == VOTE_CUSTOM)
text += "\n[question]" text += "\n[question]"
log_vote(text) log_vote(text)
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period / 10] seconds to vote.</font>" world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period / 10] seconds to vote.</font>"
if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM) if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM)
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
if(mode == VOTE_GAMEMODE && round_progressing) if(mode == VOTE_GAMEMODE && round_progressing)
round_progressing = 0 round_progressing = 0
world << "<font color='red'><b>Round start has been delayed.</b></font>" world << "<font color='red'><b>Round start has been delayed.</b></font>"
time_remaining = round(config.vote_period / 10) time_remaining = round(config.vote_period / 10)
return 1 return 1
return 0 return 0
/datum/controller/subsystem/vote/proc/interface(var/client/C) /datum/controller/subsystem/vote/proc/interface(var/client/C)
if(!istype(C)) if(!istype(C))
return return
var/admin = FALSE var/admin = FALSE
if(C.holder) if(C.holder)
if(C.holder.rights & R_ADMIN) if(C.holder.rights & R_ADMIN)
admin = TRUE admin = TRUE
. = "<html><head><title>Voting Panel</title></head><body>" . = "<html><head><title>Voting Panel</title></head><body>"
if(mode) if(mode)
if(question) if(question)
. += "<h2>Vote: '[question]'</h2>" . += "<h2>Vote: '[question]'</h2>"
else else
. += "<h2>Vote: [capitalize(mode)]</h2>" . += "<h2>Vote: [capitalize(mode)]</h2>"
. += "Time Left: [time_remaining] s<hr>" . += "Time Left: [time_remaining] s<hr>"
. += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>" . += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>"
if(mode == VOTE_GAMEMODE) if(mode == VOTE_GAMEMODE)
.+= "<td align = 'center'><b>Minimum Players</b></td></tr>" .+= "<td align = 'center'><b>Minimum Players</b></td></tr>"
for(var/i = 1 to choices.len) for(var/i = 1 to choices.len)
var/votes = choices[choices[i]] var/votes = choices[choices[i]]
if(!votes) if(!votes)
votes = 0 votes = 0
. += "<tr>" . += "<tr>"
var/thisVote = (current_votes[C.ckey] == i) var/thisVote = (current_votes[C.ckey] == i)
if(mode == VOTE_GAMEMODE) if(mode == VOTE_GAMEMODE)
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>" . += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
else else
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[choices[i]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>" . += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[choices[i]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
if (additional_text.len >= i) if (additional_text.len >= i)
. += additional_text[i] . += additional_text[i]
. += "</tr>" . += "</tr>"
. += "<tr><td><a href='?src=\ref[src];vote=unvote'>Unvote</a></td></tr>" . += "<tr><td><a href='?src=\ref[src];vote=unvote'>Unvote</a></td></tr>"
. += "</table><hr>" . += "</table><hr>"
if(admin) if(admin)
. += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) " . += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) "
else else
. += "<h2>Start a vote:</h2><hr><ul><li>" . += "<h2>Start a vote:</h2><hr><ul><li>"
if(admin || config.allow_vote_restart) if(admin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>" . += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
else else
. += "<font color='grey'>Restart (Disallowed)</font>" . += "<font color='grey'>Restart (Disallowed)</font>"
. += "</li><li>" . += "</li><li>"
if(admin || config.allow_vote_restart) if(admin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>" . += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>"
else else
. += "<font color='grey'>Crew Transfer (Disallowed)</font>" . += "<font color='grey'>Crew Transfer (Disallowed)</font>"
if(admin) if(admin)
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart ? "Allowed" : "Disallowed"]</a>)" . += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>" . += "</li><li>"
if(admin || config.allow_vote_mode) if(admin || config.allow_vote_mode)
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>" . += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
else else
. += "<font color='grey'>GameMode (Disallowed)</font>" . += "<font color='grey'>GameMode (Disallowed)</font>"
if(admin) if(admin)
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode ? "Allowed" : "Disallowed"]</a>)" . += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>" . += "</li><li>"
if(!antag_add_failed && config.allow_extra_antags) if(!antag_add_failed && config.allow_extra_antags)
. += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>" . += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>"
else else
. += "<font color='grey'>Add Antagonist (Disallowed)</font>" . += "<font color='grey'>Add Antagonist (Disallowed)</font>"
. += "</li>" . += "</li>"
if(admin) if(admin)
. += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>" . += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>"
. += "</ul><hr>" . += "</ul><hr>"
. += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>" . += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>"
/datum/controller/subsystem/vote/Topic(href, href_list[]) /datum/controller/subsystem/vote/Topic(href, href_list[])
if(!usr || !usr.client) if(!usr || !usr.client)
return return
switch(href_list["vote"]) switch(href_list["vote"])
if("close") if("close")
usr << browse(null, "window=vote") usr << browse(null, "window=vote")
return return
if("cancel") if("cancel")
if(usr.client.holder) if(usr.client.holder)
reset() reset()
if("toggle_restart") if("toggle_restart")
if(usr.client.holder) if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart config.allow_vote_restart = !config.allow_vote_restart
if("toggle_gamemode") if("toggle_gamemode")
if(usr.client.holder) if(usr.client.holder)
config.allow_vote_mode = !config.allow_vote_mode config.allow_vote_mode = !config.allow_vote_mode
if(VOTE_RESTART) if(VOTE_RESTART)
if(config.allow_vote_restart || usr.client.holder) if(config.allow_vote_restart || usr.client.holder)
initiate_vote(VOTE_RESTART, usr.key) initiate_vote(VOTE_RESTART, usr.key)
if(VOTE_GAMEMODE) if(VOTE_GAMEMODE)
if(config.allow_vote_mode || usr.client.holder) if(config.allow_vote_mode || usr.client.holder)
initiate_vote(VOTE_GAMEMODE, usr.key) initiate_vote(VOTE_GAMEMODE, usr.key)
if(VOTE_CREW_TRANSFER) if(VOTE_CREW_TRANSFER)
if(config.allow_vote_restart || usr.client.holder) if(config.allow_vote_restart || usr.client.holder)
initiate_vote(VOTE_CREW_TRANSFER, usr.key) initiate_vote(VOTE_CREW_TRANSFER, usr.key)
if(VOTE_ADD_ANTAGONIST) if(VOTE_ADD_ANTAGONIST)
if(config.allow_extra_antags || usr.client.holder) if(config.allow_extra_antags || usr.client.holder)
initiate_vote(VOTE_ADD_ANTAGONIST, usr.key) initiate_vote(VOTE_ADD_ANTAGONIST, usr.key)
if(VOTE_CUSTOM) if(VOTE_CUSTOM)
if(usr.client.holder) if(usr.client.holder)
initiate_vote(VOTE_CUSTOM, usr.key) initiate_vote(VOTE_CUSTOM, usr.key)
if("unvote") if("unvote")
submit_vote(usr.ckey, null) submit_vote(usr.ckey, null)
else else
var/t = round(text2num(href_list["vote"])) var/t = round(text2num(href_list["vote"]))
if(t) // It starts from 1, so there's no problem if(t) // It starts from 1, so there's no problem
submit_vote(usr.ckey, t) submit_vote(usr.ckey, t)
usr.client.vote() usr.client.vote()
/client/verb/vote() /client/verb/vote()
set category = "OOC" set category = "OOC"
set name = "Vote" set name = "Vote"
if(SSvote) if(SSvote)
src << browse(SSvote.interface(src), "window=vote;size=500x[300 + SSvote.choices.len * 25]") src << browse(SSvote.interface(src), "window=vote;size=500x[300 + SSvote.choices.len * 25]")

View File

@@ -106,6 +106,13 @@
check_bans = list("AI", "Cyborg", "Syndicate") check_bans = list("AI", "Cyborg", "Syndicate")
cutoff_number = 1 cutoff_number = 1
/datum/ghost_query/borer
role_name = "Cortical Borer"
question = "A cortical borer has just been created on the facility. Would you like to play as them?"
be_special_flag = BE_ALIEN
check_bans = list("Syndicate", "Borer")
cutoff_number = 1
// Surface stuff. // Surface stuff.
/datum/ghost_query/lost_drone /datum/ghost_query/lost_drone
role_name = "Lost Drone" role_name = "Lost Drone"

View File

@@ -502,7 +502,7 @@
if(!mind.assigned_role) mind.assigned_role = USELESS_JOB //defualt //VOREStation Edit - Visitor not Assistant if(!mind.assigned_role) mind.assigned_role = USELESS_JOB //defualt //VOREStation Edit - Visitor not Assistant
//slime //slime
/mob/living/simple_animal/slime/mind_initialize() /mob/living/simple_mob/slime/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "slime" mind.assigned_role = "slime"
@@ -527,29 +527,30 @@
mind.special_role = "" mind.special_role = ""
//Animals //Animals
/mob/living/simple_animal/mind_initialize() /mob/living/simple_mob/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Animal" mind.assigned_role = "Simple Mob"
/mob/living/simple_animal/corgi/mind_initialize() /mob/living/simple_mob/animal/passive/dog/corgi/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Corgi" mind.assigned_role = "Corgi"
/mob/living/simple_animal/shade/mind_initialize() /mob/living/simple_mob/construct/shade/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Shade" mind.assigned_role = "Shade"
mind.special_role = "Cultist"
/mob/living/simple_animal/construct/builder/mind_initialize() /mob/living/simple_mob/construct/artificer/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Artificer" mind.assigned_role = "Artificer"
mind.special_role = "Cultist" mind.special_role = "Cultist"
/mob/living/simple_animal/construct/wraith/mind_initialize() /mob/living/simple_mob/construct/wraith/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Wraith" mind.assigned_role = "Wraith"
mind.special_role = "Cultist" mind.special_role = "Cultist"
/mob/living/simple_animal/construct/armoured/mind_initialize() /mob/living/simple_mob/construct/juggernaut/mind_initialize()
. = ..() . = ..()
mind.assigned_role = "Juggernaut" mind.assigned_role = "Juggernaut"
mind.special_role = "Cultist" mind.special_role = "Cultist"

View File

@@ -1,7 +1,6 @@
/**************** /****************
* Debug Support * * Debug Support *
****************/ ****************/
var/datum/all_observable_events/all_observable_events = new()
/datum/all_observable_events /datum/all_observable_events
var/list/events var/list/events

View File

@@ -5,11 +5,10 @@
// //
// Arguments that the called proc should expect: // Arguments that the called proc should expect:
// /datum/destroyed_instance: The instance that was destroyed. // /datum/destroyed_instance: The instance that was destroyed.
var/decl/observ/destroyed/destroyed_event = new()
/decl/observ/destroyed /decl/observ/destroyed
name = "Destroyed" name = "Destroyed"
/datum/Destroy() /datum/Destroy()
destroyed_event.raise_event(src) GLOB.destroyed_event.raise_event(src)
. = ..() . = ..()

View File

@@ -63,7 +63,7 @@
var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call.
/decl/observ/New() /decl/observ/New()
all_observable_events.events += src GLOB.all_observable_events.events += src
. = ..() . = ..()
/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call)

View File

@@ -1,6 +1,6 @@
var/list/global_listen_count = list() GLOBAL_LIST_EMPTY(global_listen_count)
var/list/event_sources_count = list() GLOBAL_LIST_EMPTY(event_sources_count)
var/list/event_listen_count = list() GLOBAL_LIST_EMPTY(event_listen_count)
/decl/observ/destroyed/raise_event() /decl/observ/destroyed/raise_event()
. = ..() . = ..()
@@ -8,39 +8,39 @@ var/list/event_listen_count = list()
return return
var/source = args[1] var/source = args[1]
if(global_listen_count[source]) if(GLOB.global_listen_count[source])
cleanup_global_listener(source, global_listen_count[source]) cleanup_global_listener(source, GLOB.global_listen_count[source])
if(event_sources_count[source]) if(GLOB.event_sources_count[source])
cleanup_source_listeners(source, event_sources_count[source]) cleanup_source_listeners(source, GLOB.event_sources_count[source])
if(event_listen_count[source]) if(GLOB.event_listen_count[source])
cleanup_event_listener(source, event_listen_count[source]) cleanup_event_listener(source, GLOB.event_listen_count[source])
/decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call) /decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call)
. = ..() . = ..()
if(.) if(.)
event_sources_count[event_source] += 1 GLOB.event_sources_count[event_source] += 1
event_listen_count[listener] += 1 GLOB.event_listen_count[listener] += 1
/decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call) /decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call)
. = ..() . = ..()
if(.) if(.)
event_sources_count[event_source] -= 1 GLOB.event_sources_count[event_source] -= 1
event_listen_count[listener] -= 1 GLOB.event_listen_count[listener] -= 1
/decl/observ/register_global(var/datum/listener, var/proc_call) /decl/observ/register_global(var/datum/listener, var/proc_call)
. = ..() . = ..()
if(.) if(.)
global_listen_count[listener] += 1 GLOB.global_listen_count[listener] += 1
/decl/observ/unregister_global(var/datum/listener, var/proc_call) /decl/observ/unregister_global(var/datum/listener, var/proc_call)
. = ..() . = ..()
if(.) if(.)
global_listen_count[listener] -= 1 GLOB.global_listen_count[listener] -= 1
/decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count) /decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count)
global_listen_count -= listener GLOB.global_listen_count -= listener
for(var/entry in all_observable_events.events) for(var/entry in GLOB.all_observable_events.events)
var/decl/observ/event = entry var/decl/observ/event = entry
if(event.unregister_global(listener)) if(event.unregister_global(listener))
log_debug("[event] - [listener] was deleted while still registered to global events.") log_debug("[event] - [listener] was deleted while still registered to global events.")
@@ -48,8 +48,8 @@ var/list/event_listen_count = list()
return return
/decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count) /decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count)
event_sources_count -= event_source GLOB.event_sources_count -= event_source
for(var/entry in all_observable_events.events) for(var/entry in GLOB.all_observable_events.events)
var/decl/observ/event = entry var/decl/observ/event = entry
var/proc_owners = event.event_sources[event_source] var/proc_owners = event.event_sources[event_source]
if(proc_owners) if(proc_owners)
@@ -60,11 +60,11 @@ var/list/event_listen_count = list()
return return
/decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count) /decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count)
event_listen_count -= listener GLOB.event_listen_count -= listener
for(var/entry in all_observable_events.events) for(var/entry in GLOB.all_observable_events.events)
var/decl/observ/event = entry var/decl/observ/event = entry
for(var/event_source in event.event_sources) for(var/event_source in event.event_sources)
if(event.unregister(event_source, listener)) if(event.unregister(event_source, listener))
log_debug("[event] - [listener] was deleted while still listening to [event_source].") log_debug("[event] - [listener] was deleted while still listening to [event_source].")
if(!(--listener_count)) if(!(--listener_count))
return return

View File

@@ -22,7 +22,7 @@
containername = "EXTREMELY Dangerous Predator crate" containername = "EXTREMELY Dangerous Predator crate"
access = access_xenobiology access = access_xenobiology
contraband = 1 contraband = 1
/*
/datum/supply_pack/sci/otie /datum/supply_pack/sci/otie
name = "VARMAcorp adoptable reject (Dangerous!)" name = "VARMAcorp adoptable reject (Dangerous!)"
cost = 100 cost = 100
@@ -35,4 +35,5 @@
cost = 200 cost = 200
containertype = /obj/structure/largecrate/animal/otie/phoron containertype = /obj/structure/largecrate/animal/otie/phoron
containername = "VARMAcorp adaptive beta subject (Experimental)" containername = "VARMAcorp adaptive beta subject (Experimental)"
access = access_xenobiology access = access_xenobiology
*/ //VORESTATION AI TEMPORARY REMOVAL. Oties commented out cuz broke.

View File

@@ -1,4 +1,4 @@
/datum/supply_pack/security/guardbeast /*/datum/supply_pack/security/guardbeast //VORESTATION AI TEMPORARY REMOVAL
name = "VARMAcorp autoNOMous security solution" name = "VARMAcorp autoNOMous security solution"
cost = 150 cost = 150
containertype = /obj/structure/largecrate/animal/guardbeast containertype = /obj/structure/largecrate/animal/guardbeast
@@ -15,6 +15,7 @@
access = list( access = list(
access_security, access_security,
access_xenobiology) access_xenobiology)
*/
/datum/supply_pack/security/biosuit /datum/supply_pack/security/biosuit
contains = list( contains = list(

View File

@@ -5,7 +5,7 @@ var/datum/antagonist/borer/borers
role_type = BE_ALIEN role_type = BE_ALIEN
role_text = "Cortical Borer" role_text = "Cortical Borer"
role_text_plural = "Cortical Borers" role_text_plural = "Cortical Borers"
mob_path = /mob/living/simple_animal/borer mob_path = /mob/living/simple_mob/animal/borer
bantype = "Borer" bantype = "Borer"
welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with :x." welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with :x."
antag_indicator = "brainworm" antag_indicator = "brainworm"
@@ -40,7 +40,7 @@ var/datum/antagonist/borer/borers
player.objectives += new /datum/objective/escape() player.objectives += new /datum/objective/escape()
/datum/antagonist/borer/place_mob(var/mob/living/mob) /datum/antagonist/borer/place_mob(var/mob/living/mob)
var/mob/living/simple_animal/borer/borer = mob var/mob/living/simple_mob/animal/borer/borer = mob
if(istype(borer)) if(istype(borer))
var/mob/living/carbon/human/host var/mob/living/carbon/human/host
for(var/mob/living/carbon/human/H in mob_list) for(var/mob/living/carbon/human/H in mob_list)

View File

@@ -111,12 +111,12 @@ var/datum/antagonist/cultist/cult
. = ..() . = ..()
if(.) if(.)
player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back."
if(player.current && !istype(player.current, /mob/living/simple_animal/construct)) if(player.current && !istype(player.current, /mob/living/simple_mob/construct))
player.current.add_language(LANGUAGE_CULT) player.current.add_language(LANGUAGE_CULT)
/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) /datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
. = ..() . = ..()
if(. && player.current && !istype(player.current, /mob/living/simple_animal/construct)) if(. && player.current && !istype(player.current, /mob/living/simple_mob/construct))
player.current.remove_language(LANGUAGE_CULT) player.current.remove_language(LANGUAGE_CULT)
/datum/antagonist/cultist/can_become_antag(var/datum/mind/player) /datum/antagonist/cultist/can_become_antag(var/datum/mind/player)

View File

@@ -476,14 +476,14 @@ proc/findNullRod(var/atom/target)
/obj/item/weapon/spell/construct/run_checks() /obj/item/weapon/spell/construct/run_checks()
if(owner) if(owner)
if((iscultist(owner) || istype(owner, /mob/living/simple_animal/construct)) && (world.time >= (last_castcheck + cooldown))) //Are they a cultist or a construct, and has the cooldown time passed? if((iscultist(owner) || istype(owner, /mob/living/simple_mob/construct)) && (world.time >= (last_castcheck + cooldown))) //Are they a cultist or a construct, and has the cooldown time passed?
last_castcheck = world.time last_castcheck = world.time
return 1 return 1
return 0 return 0
/obj/item/weapon/spell/construct/pay_energy(var/amount) /obj/item/weapon/spell/construct/pay_energy(var/amount)
if(owner) if(owner)
if(istype(owner, /mob/living/simple_animal/construct)) if(istype(owner, /mob/living/simple_mob/construct))
return 1 return 1
if(iscultist(owner) && pay_blood(amount)) if(iscultist(owner) && pay_blood(amount))
return 1 return 1
@@ -607,7 +607,7 @@ proc/findNullRod(var/atom/target)
name = "sphere of agony" name = "sphere of agony"
desc = "Call forth a portal to a dimension of naught but pain at your target." desc = "Call forth a portal to a dimension of naught but pain at your target."
spawner_type = /obj/effect/temporary_effect/pulsar/agonizing_sphere spawner_type = /obj/effect/temporary_effect/pulse/agonizing_sphere
/obj/item/weapon/spell/construct/spawner/agonizing_sphere/on_ranged_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/construct/spawner/agonizing_sphere/on_ranged_cast(atom/hit_atom, mob/user)
if(within_range(hit_atom) && pay_energy(10)) if(within_range(hit_atom) && pay_energy(10))
@@ -619,7 +619,7 @@ proc/findNullRod(var/atom/target)
var/mob/living/L = hit_atom var/mob/living/L = hit_atom
L.add_modifier(/datum/modifier/agonize, 10 SECONDS) L.add_modifier(/datum/modifier/agonize, 10 SECONDS)
/obj/effect/temporary_effect/pulsar/agonizing_sphere /obj/effect/temporary_effect/pulse/agonizing_sphere
name = "agonizing sphere" name = "agonizing sphere"
desc = "A portal to some hellish place. Its screams wrack your body with pain.." desc = "A portal to some hellish place. Its screams wrack your body with pain.."
icon_state = "red_static_sphere" icon_state = "red_static_sphere"
@@ -628,19 +628,15 @@ proc/findNullRod(var/atom/target)
light_power = 5 light_power = 5
light_color = "#FF0000" light_color = "#FF0000"
pulses_remaining = 10 pulses_remaining = 10
pulse_delay = 1 SECOND
/obj/effect/temporary_effect/pulsar/agonizing_sphere/pulse_loop() /obj/effect/temporary_effect/pulse/agonizing_sphere/on_pulse()
while(pulses_remaining) for(var/mob/living/L in view(4,src))
sleep(1 SECONDS) if(!iscultist(L) && !istype(L, /mob/living/simple_mob/construct))
spawn() L.add_modifier(/datum/modifier/agonize, 2 SECONDS)
for(var/mob/living/L in view(4,src)) if(L.isSynthetic())
if(!iscultist(L) && !istype(L, /mob/living/simple_animal/construct)) to_chat(L, "<span class='cult'>Your chassis warps as the [src] pulses!</span>")
L.add_modifier(/datum/modifier/agonize, 2 SECONDS) L.adjustFireLoss(4)
if(L.isSynthetic())
to_chat(L, "<span class='cult'>Your chassis warps as the [src] pulses!</span>")
L.adjustFireLoss(4)
pulses_remaining--
qdel(src)
//Artificer Heal //Artificer Heal
@@ -659,7 +655,7 @@ proc/findNullRod(var/atom/target)
L.add_modifier(/datum/modifier/mend_occult, 150) L.add_modifier(/datum/modifier/mend_occult, 150)
qdel(src) qdel(src)
//Juggernaut + Behemoth Slam //Juggernaut Slam
/obj/item/weapon/spell/construct/slam /obj/item/weapon/spell/construct/slam
name = "slam" name = "slam"
desc = "Empower your FIST, to send an opponent flying." desc = "Empower your FIST, to send an opponent flying."
@@ -672,8 +668,8 @@ proc/findNullRod(var/atom/target)
/obj/item/weapon/spell/construct/slam/on_melee_cast(atom/hit_atom, mob/living/user, def_zone) /obj/item/weapon/spell/construct/slam/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
var/attack_message = "slams" var/attack_message = "slams"
if(istype(user, /mob/living/simple_animal)) if(istype(user, /mob/living/simple_mob))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = user
attack_message = pick(S.attacktext) attack_message = pick(S.attacktext)
if(isliving(hit_atom)) if(isliving(hit_atom))
var/mob/living/L = hit_atom var/mob/living/L = hit_atom

View File

@@ -14,7 +14,7 @@
return return
/obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone) /obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone)
if(iscultist(user) && !istype(user, /mob/living/simple_animal/construct)) if(iscultist(user) && !istype(user, /mob/living/simple_mob/construct))
return ..() return ..()
var/zone = (user.hand ? "l_arm":"r_arm") var/zone = (user.hand ? "l_arm":"r_arm")
@@ -25,7 +25,7 @@
//random amount of damage between half of the blade's force and the full force of the blade. //random amount of damage between half of the blade's force and the full force of the blade.
user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1) user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1)
user.Weaken(5) user.Weaken(5)
else if(!istype(user, /mob/living/simple_animal/construct)) else if(!istype(user, /mob/living/simple_mob/construct))
to_chat(user, "<span class='danger'>An inexplicable force rips through you, tearing the sword from your grasp!</span>") to_chat(user, "<span class='danger'>An inexplicable force rips through you, tearing the sword from your grasp!</span>")
else else
to_chat(user, "<span class='critical'>The blade hisses, forcing itself from your manipulators. \The [src] will only allow mortals to wield it against foes, not kin.</span>") to_chat(user, "<span class='critical'>The blade hisses, forcing itself from your manipulators. \The [src] will only allow mortals to wield it against foes, not kin.</span>")
@@ -39,10 +39,10 @@
return 1 return 1
/obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) /obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob)
if(!iscultist(user) && !istype(user, /mob/living/simple_animal/construct)) if(!iscultist(user) && !istype(user, /mob/living/simple_mob/construct))
to_chat(user, "<span class='warning'>An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.</span>") to_chat(user, "<span class='warning'>An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.</span>")
user.make_dizzy(120) user.make_dizzy(120)
if(istype(user, /mob/living/simple_animal/construct)) if(istype(user, /mob/living/simple_mob/construct))
to_chat(user, "<span class='warning'>\The [src] hisses, as it is discontent with your acquisition of it. It would be wise to return it to a worthy mortal quickly.</span>") to_chat(user, "<span class='warning'>\The [src] hisses, as it is discontent with your acquisition of it. It would be wise to return it to a worthy mortal quickly.</span>")
/obj/item/clothing/head/culthood /obj/item/clothing/head/culthood

View File

@@ -108,18 +108,18 @@
light_range=5 light_range=5
light_color="#ff0000" light_color="#ff0000"
spawnable=list( spawnable=list(
/mob/living/simple_animal/hostile/scarybat, /mob/living/simple_mob/animal/space/bats,
/mob/living/simple_animal/hostile/creature/vore, /mob/living/simple_mob/creature,
/mob/living/simple_animal/hostile/faithless /mob/living/simple_mob/faithless
) // Vorestation Edit )
/obj/effect/gateway/active/cult /obj/effect/gateway/active/cult
light_range=5 light_range=5
light_color="#ff0000" light_color="#ff0000"
spawnable=list( spawnable=list(
/mob/living/simple_animal/hostile/scarybat/cult, /mob/living/simple_mob/animal/space/bats/cult,
/mob/living/simple_animal/hostile/creature/cult, /mob/living/simple_mob/creature/cult,
/mob/living/simple_animal/hostile/faithless/cult /mob/living/simple_mob/faithless/cult
) )
/obj/effect/gateway/active/cult/cultify() /obj/effect/gateway/active/cult/cultify()

View File

@@ -16,7 +16,7 @@
/mob/living/cultify() /mob/living/cultify()
if(iscultist(src) && client) if(iscultist(src) && client)
var/mob/living/simple_animal/construct/harvester/C = new(get_turf(src)) var/mob/living/simple_mob/construct/harvester/C = new(get_turf(src))
mind.transfer_to(C) mind.transfer_to(C)
C << "<span class='sinister'>The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.<br>Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.<br>You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.</span>" C << "<span class='sinister'>The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.<br>Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.<br>You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.</span>"
dust() dust()

View File

@@ -1,242 +1,246 @@
/obj/item/device/soulstone/cultify() /////////////////////////
return // Soulstone
/////////////////////////
/obj/item/device/soulstone
name = "Soul Stone Shard" /obj/item/device/soulstone
icon = 'icons/obj/wizard.dmi' name = "Soul Stone Shard"
icon_state = "soulstone" icon = 'icons/obj/wizard.dmi'
item_state = "electronic" icon_state = "soulstone"
desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'. The shard still flickers with a fraction of the full artefacts power." item_state = "electronic"
w_class = ITEMSIZE_SMALL desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'. The shard still flickers with a fraction of the full artefacts power."
slot_flags = SLOT_BELT w_class = ITEMSIZE_SMALL
origin_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 4) slot_flags = SLOT_BELT
var/imprinted = "empty" origin_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 4)
var/possible_constructs = list("Juggernaut","Wraith","Artificer","Harvester") var/imprinted = "empty"
var/possible_constructs = list("Juggernaut","Wraith","Artificer","Harvester")
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/device/soulstone/cultify()
/obj/item/device/soulstone/attack(mob/living/carbon/human/M as mob, mob/user as mob) return
if(!istype(M, /mob/living/carbon/human))//If target is not a human.
return ..() //////////////////////////////Capturing////////////////////////////////////////////////////////
if(istype(M, /mob/living/carbon/human/dummy))
return..() /obj/item/device/soulstone/attack(mob/living/carbon/human/M as mob, mob/user as mob)
if(jobban_isbanned(M, "cultist")) if(!istype(M, /mob/living/carbon/human))//If target is not a human.
user << "<span class='warning'>This person's soul is too corrupt and cannot be captured!</span>" return ..()
return..() if(istype(M, /mob/living/carbon/human/dummy))
return..()
if(M.has_brain_worms()) //Borer stuff - RR if(jobban_isbanned(M, "cultist"))
user << "<span class='warning'>This being is corrupted by an alien intelligence and cannot be soul trapped.</span>" user << "<span class='warning'>This person's soul is too corrupt and cannot be captured!</span>"
return..() return..()
add_attack_logs(user,M,"Soulstone'd with [src.name]") if(M.has_brain_worms()) //Borer stuff - RR
transfer_soul("VICTIM", M, user) user << "<span class='warning'>This being is corrupted by an alien intelligence and cannot be soul trapped.</span>"
return return..()
add_attack_logs(user,M,"Soulstone'd with [src.name]")
///////////////////Options for using captured souls/////////////////////////////////////// transfer_soul("VICTIM", M, user)
return
/obj/item/device/soulstone/attack_self(mob/user)
if (!in_range(src, user))
return ///////////////////Options for using captured souls///////////////////////////////////////
user.set_machine(src)
var/dat = "<TT><B>Soul Stone</B><BR>" /obj/item/device/soulstone/attack_self(mob/user)
for(var/mob/living/simple_animal/shade/A in src) if (!in_range(src, user))
dat += "Captured Soul: [A.name]<br>" return
dat += {"<A href='byond://?src=\ref[src];choice=Summon'>Summon Shade</A>"} user.set_machine(src)
dat += "<br>" var/dat = "<TT><B>Soul Stone</B><BR>"
dat += {"<a href='byond://?src=\ref[src];choice=Close'> Close</a>"} for(var/mob/living/simple_mob/construct/shade/A in src)
user << browse(dat, "window=aicard") dat += "Captured Soul: [A.name]<br>"
onclose(user, "aicard") dat += {"<A href='byond://?src=\ref[src];choice=Summon'>Summon Shade</A>"}
return dat += "<br>"
dat += {"<a href='byond://?src=\ref[src];choice=Close'> Close</a>"}
user << browse(dat, "window=aicard")
onclose(user, "aicard")
return
/obj/item/device/soulstone/Topic(href, href_list)
var/mob/U = usr
if (!in_range(src, U)||U.machine!=src)
U << browse(null, "window=aicard")
U.unset_machine() /obj/item/device/soulstone/Topic(href, href_list)
return var/mob/U = usr
if (!in_range(src, U)||U.machine!=src)
add_fingerprint(U) U << browse(null, "window=aicard")
U.set_machine(src) U.unset_machine()
return
switch(href_list["choice"])//Now we switch based on choice.
if ("Close") add_fingerprint(U)
U << browse(null, "window=aicard") U.set_machine(src)
U.unset_machine()
return switch(href_list["choice"])//Now we switch based on choice.
if ("Close")
if ("Summon") U << browse(null, "window=aicard")
for(var/mob/living/simple_animal/shade/A in src) U.unset_machine()
A.status_flags &= ~GODMODE return
A.canmove = 1
A << "<b>You have been released from your prison, but you are still bound to [U.name]'s will. Help them suceed in their goals at all costs.</b>" if ("Summon")
A.forceMove(U.loc) for(var/mob/living/simple_mob/construct/shade/A in src)
A.cancel_camera() A.status_flags &= ~GODMODE
src.icon_state = "soulstone" A.canmove = 1
attack_self(U) A << "<b>You have been released from your prison, but you are still bound to [U.name]'s will. Help them suceed in their goals at all costs.</b>"
A.forceMove(U.loc)
///////////////////////////Transferring to constructs///////////////////////////////////////////////////// A.cancel_camera()
/obj/structure/constructshell src.icon_state = "soulstone"
name = "empty shell" attack_self(U)
icon = 'icons/obj/wizard.dmi'
icon_state = "construct" ///////////////////////////Transferring to constructs/////////////////////////////////////////////////////
desc = "A wicked machine used by those skilled in magical arts. It is inactive." /obj/structure/constructshell
name = "empty shell"
/obj/structure/constructshell/cultify() icon = 'icons/obj/wizard.dmi'
return icon_state = "construct"
desc = "A wicked machine used by those skilled in magical arts. It is inactive."
/obj/structure/constructshell/cult
icon_state = "construct-cult" /obj/structure/constructshell/cultify()
desc = "This eerie contraption looks like it would come alive if supplied with a missing ingredient." return
/obj/structure/constructshell/attackby(obj/item/O as obj, mob/user as mob) /obj/structure/constructshell/cult
if(istype(O, /obj/item/device/soulstone)) icon_state = "construct-cult"
var/obj/item/device/soulstone/S = O; desc = "This eerie contraption looks like it would come alive if supplied with a missing ingredient."
S.transfer_soul("CONSTRUCT",src,user)
/obj/structure/constructshell/attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/device/soulstone))
////////////////////////////Proc for moving soul in and out off stone////////////////////////////////////// var/obj/item/device/soulstone/S = O;
/obj/item/device/soulstone/proc/transfer_human(var/mob/living/carbon/human/T,var/mob/U) S.transfer_soul("CONSTRUCT",src,user)
if(!istype(T))
return;
if(src.imprinted != "empty") ////////////////////////////Proc for moving soul in and out off stone//////////////////////////////////////
U << "<span class='danger'>Capture failed!</span>: The soul stone has already been imprinted with [src.imprinted]'s mind!" /obj/item/device/soulstone/proc/transfer_human(var/mob/living/carbon/human/T,var/mob/U)
return if(!istype(T))
if ((T.health + T.halloss) > config.health_threshold_crit && T.stat != DEAD) return;
U << "<span class='danger'>Capture failed!</span>: Kill or maim the victim first!" if(src.imprinted != "empty")
return U << "<span class='danger'>Capture failed!</span>: The soul stone has already been imprinted with [src.imprinted]'s mind!"
if(T.client == null) return
U << "<span class='danger'>Capture failed!</span>: The soul has already fled it's mortal frame." if ((T.health + T.halloss) > config.health_threshold_crit && T.stat != DEAD)
return U << "<span class='danger'>Capture failed!</span>: Kill or maim the victim first!"
if(src.contents.len) return
U << "<span class='danger'>Capture failed!</span>: The soul stone is full! Use or free an existing soul to make room." if(T.client == null)
return U << "<span class='danger'>Capture failed!</span>: The soul has already fled it's mortal frame."
return
for(var/obj/item/W in T) if(src.contents.len)
T.drop_from_inventory(W) U << "<span class='danger'>Capture failed!</span>: The soul stone is full! Use or free an existing soul to make room."
return
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
T.invisibility = 101 for(var/obj/item/W in T)
T.drop_from_inventory(W)
var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc )
animation.icon_state = "blank" new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
animation.icon = 'icons/mob/mob.dmi' T.invisibility = 101
animation.master = T
flick("dust-h", animation) var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc )
qdel(animation) animation.icon_state = "blank"
animation.icon = 'icons/mob/mob.dmi'
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade( T.loc ) animation.master = T
S.forceMove(src) //put shade in stone flick("dust-h", animation)
S.status_flags |= GODMODE //So they won't die inside the stone somehow qdel(animation)
S.canmove = 0//Can't move out of the soul stone
S.name = "Shade of [T.real_name]" var/mob/living/simple_mob/construct/shade/S = new /mob/living/simple_mob/construct/shade( T.loc )
S.real_name = "Shade of [T.real_name]" S.forceMove(src) //put shade in stone
S.icon = T.icon S.status_flags |= GODMODE //So they won't die inside the stone somehow
S.icon_state = T.icon_state S.canmove = 0//Can't move out of the soul stone
S.overlays = T.overlays S.name = "Shade of [T.real_name]"
S.color = rgb(254,0,0) S.real_name = "Shade of [T.real_name]"
S.alpha = 127 S.icon = T.icon
if (T.client) S.icon_state = T.icon_state
T.client.mob = S S.overlays = T.overlays
S.cancel_camera() S.color = rgb(254,0,0)
S.alpha = 127
if (T.client)
src.icon_state = "soulstone2" T.client.mob = S
src.name = "Soul Stone: [S.real_name]" S.cancel_camera()
to_chat(S, "Your soul has been captured! You are now bound to [U.name]'s will, help them suceed in their goals at all costs.")
to_chat(U, "<span class='notice'>Capture successful!</span> : [T.real_name]'s soul has been ripped from their body and stored within the soul stone.")
to_chat(U, "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls.") src.icon_state = "soulstone2"
src.imprinted = "[S.name]" src.name = "Soul Stone: [S.real_name]"
qdel(T) to_chat(S, "Your soul has been captured! You are now bound to [U.name]'s will, help them suceed in their goals at all costs.")
to_chat(U, "<span class='notice'>Capture successful!</span> : [T.real_name]'s soul has been ripped from their body and stored within the soul stone.")
/obj/item/device/soulstone/proc/transfer_shade(var/mob/living/simple_animal/shade/T,var/mob/U) to_chat(U, "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls.")
if(!istype(T)) src.imprinted = "[S.name]"
return; qdel(T)
if (T.stat == DEAD)
to_chat(U, "<span class='danger'>Capture failed!</span>: The shade has already been banished!") /obj/item/device/soulstone/proc/transfer_shade(var/mob/living/simple_mob/construct/shade/T,var/mob/U)
return if(!istype(T))
if(src.contents.len) return;
to_chat(U, "<span class='danger'>Capture failed!</span>: The soul stone is full! Use or free an existing soul to make room.") if (T.stat == DEAD)
return to_chat(U, "<span class='danger'>Capture failed!</span>: The shade has already been banished!")
if(T.name != src.imprinted) return
to_chat(U, "<span class='danger'>Capture failed!</span>: The soul stone has already been imprinted with [src.imprinted]'s mind!") if(src.contents.len)
return to_chat(U, "<span class='danger'>Capture failed!</span>: The soul stone is full! Use or free an existing soul to make room.")
return
T.forceMove(src) //put shade in stone if(T.name != src.imprinted)
T.status_flags |= GODMODE to_chat(U, "<span class='danger'>Capture failed!</span>: The soul stone has already been imprinted with [src.imprinted]'s mind!")
T.canmove = 0 return
T.health = T.getMaxHealth()
src.icon_state = "soulstone2" T.forceMove(src) //put shade in stone
T.status_flags |= GODMODE
to_chat(T, "Your soul has been recaptured by the soul stone, its arcane energies are reknitting your ethereal form") T.canmove = 0
to_chat(U, "<span class='notice'>Capture successful!</span> : [T.name]'s has been recaptured and stored within the soul stone.") T.health = T.getMaxHealth()
src.icon_state = "soulstone2"
/obj/item/device/soulstone/proc/transfer_construct(var/obj/structure/constructshell/T,var/mob/U)
var/mob/living/simple_animal/shade/A = locate() in src to_chat(T, "Your soul has been recaptured by the soul stone, its arcane energies are reknitting your ethereal form")
if(!A) to_chat(U, "<span class='notice'>Capture successful!</span> : [T.name]'s has been recaptured and stored within the soul stone.")
to_chat(U,"<span class='danger'>Capture failed!</span>: The soul stone is empty! Go kill someone!")
return; /obj/item/device/soulstone/proc/transfer_construct(var/obj/structure/constructshell/T,var/mob/U)
var/construct_class = input(U, "Please choose which type of construct you wish to create.") as null|anything in possible_constructs var/mob/living/simple_mob/construct/shade/A = locate() in src
switch(construct_class) if(!A)
if("Juggernaut") to_chat(U,"<span class='danger'>Capture failed!</span>: The soul stone is empty! Go kill someone!")
var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) return;
Z.key = A.key var/construct_class = input(U, "Please choose which type of construct you wish to create.") as null|anything in possible_constructs
if(iscultist(U)) switch(construct_class)
cult.add_antagonist(Z.mind) if("Juggernaut")
qdel(T) var/mob/living/simple_mob/construct/juggernaut/Z = new /mob/living/simple_mob/construct/juggernaut (get_turf(T.loc))
to_chat(Z,"<B>You are playing a Juggernaut. Though slow, you can withstand extreme punishment, and rip apart enemies and walls alike.</B>") Z.key = A.key
to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>") if(iscultist(U))
Z.cancel_camera() cult.add_antagonist(Z.mind)
qdel(src) qdel(T)
if("Wraith") to_chat(Z,"<B>You are playing a Juggernaut. Though slow, you can withstand extreme punishment, and rip apart enemies and walls alike.</B>")
var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>")
Z.key = A.key Z.cancel_camera()
if(iscultist(U)) qdel(src)
cult.add_antagonist(Z.mind) if("Wraith")
qdel(T) var/mob/living/simple_mob/construct/wraith/Z = new /mob/living/simple_mob/construct/wraith (get_turf(T.loc))
to_chat(Z,"<B>You are playing a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</B>") Z.key = A.key
to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>") if(iscultist(U))
Z.cancel_camera() cult.add_antagonist(Z.mind)
qdel(src) qdel(T)
if("Artificer") to_chat(Z,"<B>You are playing a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</B>")
var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>")
Z.key = A.key Z.cancel_camera()
if(iscultist(U)) qdel(src)
cult.add_antagonist(Z.mind) if("Artificer")
qdel(T) var/mob/living/simple_mob/construct/artificer/Z = new /mob/living/simple_mob/construct/artificer (get_turf(T.loc))
to_chat(Z,"<B>You are playing an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, repair allied constructs (by clicking on them), and even create new constructs</B>") Z.key = A.key
to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>") if(iscultist(U))
Z.cancel_camera() cult.add_antagonist(Z.mind)
qdel(src) qdel(T)
if("Harvester") to_chat(Z,"<B>You are playing an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, repair allied constructs (by clicking on them), and even create new constructs</B>")
var/mob/living/simple_animal/construct/harvester/Z = new /mob/living/simple_animal/construct/harvester (get_turf(T.loc)) to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>")
Z.key = A.key Z.cancel_camera()
if(iscultist(U)) qdel(src)
cult.add_antagonist(Z.mind) if("Harvester")
qdel(T) var/mob/living/simple_mob/construct/harvester/Z = new /mob/living/simple_mob/construct/harvester (get_turf(T.loc))
to_chat(Z,"<B>You are playing a Harvester. You are relatively weak, but your physical frailty is made up for by your ranged abilities.</B>") Z.key = A.key
to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>") if(iscultist(U))
Z.cancel_camera() cult.add_antagonist(Z.mind)
qdel(src) qdel(T)
if("Behemoth") to_chat(Z,"<B>You are playing a Harvester. You are relatively weak, but your physical frailty is made up for by your ranged abilities.</B>")
var/mob/living/simple_animal/construct/behemoth/Z = new /mob/living/simple_animal/construct/behemoth (get_turf(T.loc)) to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>")
Z.key = A.key Z.cancel_camera()
if(iscultist(U)) qdel(src)
cult.add_antagonist(Z.mind) if("Behemoth")
qdel(T) var/mob/living/simple_mob/construct/juggernaut/behemoth/Z = new /mob/living/simple_mob/construct/juggernaut/behemoth (get_turf(T.loc))
to_chat(Z,"<B>You are playing a Behemoth. You are incredibly slow, though your slowness is made up for by the fact your shell is far larger than any of your bretheren. You are the Unstoppable Force, and Immovable Object.</B>") Z.key = A.key
to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>") if(iscultist(U))
Z.cancel_camera() cult.add_antagonist(Z.mind)
qdel(src) qdel(T)
to_chat(Z,"<B>You are playing a Behemoth. You are incredibly slow, though your slowness is made up for by the fact your shell is far larger than any of your bretheren. You are the Unstoppable Force, and Immovable Object.</B>")
/obj/item/device/soulstone/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob) to_chat(Z,"<B>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</B>")
switch(choice) Z.cancel_camera()
if("VICTIM") qdel(src)
transfer_human(target,U)
if("SHADE") /obj/item/device/soulstone/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob)
transfer_shade(target,U) switch(choice)
if("CONSTRUCT") if("VICTIM")
transfer_construct(target,U) transfer_human(target,U)
if("SHADE")
transfer_shade(target,U)
if("CONSTRUCT")
transfer_construct(target,U)

View File

@@ -206,7 +206,7 @@ var/hadevent = 0
/proc/carp_migration() // -- Darem /proc/carp_migration() // -- Darem
for(var/obj/effect/landmark/C in landmarks_list) for(var/obj/effect/landmark/C in landmarks_list)
if(C.name == "carpspawn") if(C.name == "carpspawn")
new /mob/living/simple_animal/hostile/carp(C.loc) new /mob/living/simple_mob/animal/space/carp(C.loc)
//sleep(100) //sleep(100)
spawn(rand(300, 600)) //Delayed announcements to keep the crew on their toes. spawn(rand(300, 600)) //Delayed announcements to keep the crew on their toes.
command_announcement.Announce("Unknown biological entities have been detected near \the [station_name()], please stand-by.", "Lifesign Alert", new_sound = 'sound/AI/commandreport.ogg') command_announcement.Announce("Unknown biological entities have been detected near \the [station_name()], please stand-by.", "Lifesign Alert", new_sound = 'sound/AI/commandreport.ogg')

View File

@@ -4,12 +4,12 @@
for(var/turf/simulated/floor/T in orange(1,xmas)) for(var/turf/simulated/floor/T in orange(1,xmas))
for(var/i=1,i<=rand(1,5),i++) for(var/i=1,i<=rand(1,5),i++)
new /obj/item/weapon/a_gift(T) new /obj/item/weapon/a_gift(T)
//for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) //for(var/mob/living/simple_mob/corgi/Ian/Ian in mob_list)
// Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian)) // Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
/proc/ChristmasEvent() /proc/ChristmasEvent()
for(var/obj/structure/flora/tree/pine/xmas in world) for(var/obj/structure/flora/tree/pine/xmas in world)
var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc) var/mob/living/simple_mob/animal/space/tree/evil_tree = new /mob/living/simple_mob/animal/space/tree(xmas.loc)
evil_tree.icon_state = xmas.icon_state evil_tree.icon_state = xmas.icon_state
evil_tree.icon_living = evil_tree.icon_state evil_tree.icon_living = evil_tree.icon_state
evil_tree.icon_dead = evil_tree.icon_state evil_tree.icon_dead = evil_tree.icon_state

View File

@@ -808,7 +808,7 @@ datum/objective/heist/salvage
/datum/objective/borer_survive/check_completion() /datum/objective/borer_survive/check_completion()
if(owner) if(owner)
var/mob/living/simple_animal/borer/B = owner var/mob/living/simple_mob/animal/borer/B = owner
if(istype(B) && B.stat < 2 && B.host && B.host.stat < 2) return 1 if(istype(B) && B.stat < 2 && B.host && B.host.stat < 2) return 1
return 0 return 0
@@ -817,7 +817,7 @@ datum/objective/heist/salvage
/datum/objective/borer_reproduce/check_completion() /datum/objective/borer_reproduce/check_completion()
if(owner && owner.current) if(owner && owner.current)
var/mob/living/simple_animal/borer/B = owner.current var/mob/living/simple_mob/animal/borer/B = owner.current
if(istype(B) && B.has_reproduced) return 1 if(istype(B) && B.has_reproduced) return 1
return 0 return 0

View File

@@ -1,258 +0,0 @@
//An AI-controlled 'companion' for the Technomancer. It's tough, strong, and can also use spells.
/mob/living/simple_animal/technomancer_golem
name = "G.O.L.E.M."
desc = "A rather unusual looking synthetic."
icon = 'icons/mob/mob.dmi'
icon_state = "technomancer_golem"
health = 250
maxHealth = 250
stop_automated_movement = 1
wander = 0
response_help = "pets"
response_disarm = "pushes away"
response_harm = "punches"
harm_intent_damage = 3
heat_damage_per_tick = 0
cold_damage_per_tick = 0
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
unsuitable_atoms_damage = 0
speed = 0
melee_damage_lower = 30 // It has a built in esword.
melee_damage_upper = 30
attack_sound = 'sound/weapons/blade1.ogg'
attacktext = list("slashed")
friendly = "hugs"
resistance = 0
melee_miss_chance = 0
var/obj/item/weapon/technomancer_core/golem/core = null
var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells
var/mob/living/master = null
var/list/known_spells = list(
"beam" = /obj/item/weapon/spell/projectile/beam,
"chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning,
"force missile" = /obj/item/weapon/spell/projectile/force_missile,
"ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt,
"lightning" = /obj/item/weapon/spell/projectile/lightning,
"blink" = /obj/item/weapon/spell/blink,
"dispel" = /obj/item/weapon/spell/dispel,
"oxygenate" = /obj/item/weapon/spell/oxygenate,
"mend life" = /obj/item/weapon/spell/modifier/mend_life,
"mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic,
"mend organs" = /obj/item/weapon/spell/mend_organs,
"purify" = /obj/item/weapon/spell/modifier/purify,
"resurrect" = /obj/item/weapon/spell/resurrect,
"passwall" = /obj/item/weapon/spell/passwall,
"repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles,
"corona" = /obj/item/weapon/spell/modifier/corona,
"haste" = /obj/item/weapon/spell/modifier/haste
)
// Holds the overlays, when idle or attacking.
var/image/sword_image = null
var/image/spell_image = null
// These contain icon_states for each frame of an attack animation, which is swapped in and out manually, because BYOND.
// They are assoc lists, to hold the frame duration and the frame icon_state in one list.
var/list/spell_pre_attack_states = list(
"golem_spell_attack_1" = 1,
"golem_spell_attack_2" = 2,
"golem_spell_attack_3" = 2
)
var/list/spell_post_attack_states = list(
"golem_spell_attack_4" = 2,
"golem_spell_attack_5" = 3,
"golem_spell_attack_6" = 3
)
var/list/sword_pre_attack_states = list(
"golem_sword_attack_1" = 1,
"golem_sword_attack_2" = 5
)
var/list/sword_post_attack_states = list(
"golem_sword_attack_3" = 1,
"golem_sword_attack_4" = 3
)
/mob/living/simple_animal/technomancer_golem/New()
..()
core = new(src)
sword_image = image(icon, src, "golem_sword")
spell_image = image(icon, src, "golem_spell")
update_icon()
/mob/living/simple_animal/technomancer_golem/Destroy()
qdel(core)
qdel(sword_image)
qdel(spell_image)
return ..()
/mob/living/simple_animal/technomancer_golem/unref_spell()
active_spell = null
return ..()
/mob/living/simple_animal/hostile/hivebot/death()
..()
visible_message("\The [src] disintegrates!")
new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
qdel(src)
/mob/living/simple_animal/technomancer_golem/update_icon()
overlays.Cut()
overlays += sword_image
overlays += spell_image
update_modifier_visuals()
// Unfortunately, BYOND does not let you flick() images or other overlays, so we need to do this in a terrible way.
/atom/proc/manual_flick(var/list/frames, var/image/I, var/reset_to = null)
// Swap in and out each frame manually.
for(var/frame in frames)
overlays -= I
I.icon_state = frame
overlays += I
sleep(frames[frame])
if(reset_to)
// One more time to reset it to what it was before.
overlays -= I
I.icon_state = reset_to
overlays += I
/mob/living/simple_animal/technomancer_golem/proc/spellcast_pre_animation()
setClickCooldown(5)
manual_flick(spell_pre_attack_states, spell_image, reset_to = "golem_spell_attack_3")
/mob/living/simple_animal/technomancer_golem/proc/spellcast_post_animation()
setClickCooldown(8)
manual_flick(spell_post_attack_states, spell_image, reset_to = "golem_spell")
/mob/living/simple_animal/technomancer_golem/proc/sword_pre_animation()
setClickCooldown(6)
manual_flick(sword_pre_attack_states, sword_image)
/mob/living/simple_animal/technomancer_golem/proc/sword_post_animation()
setClickCooldown(3)
manual_flick(sword_post_attack_states, sword_image, reset_to = "golem_sword")
/mob/living/simple_animal/technomancer_golem/DoPunch(var/atom/A)
sword_pre_animation()
. = ..() // This does the actual attack and will check adjacency again.
sword_post_animation()
/mob/living/simple_animal/technomancer_golem/isSynthetic()
return TRUE // So Mend Synthetic will work on them.
/mob/living/simple_animal/technomancer_golem/speech_bubble_appearance()
return "synthetic_evil"
/mob/living/simple_animal/technomancer_golem/place_spell_in_hand(var/path)
if(!path || !ispath(path))
return 0
if(active_spell)
qdel(active_spell) // Get rid of our old spell.
var/obj/item/weapon/spell/S = new path(src)
active_spell = S
/mob/living/simple_animal/technomancer_golem/verb/test_giving_spells()
var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells
if(choice)
place_spell_in_hand(known_spells[choice])
else
qdel(active_spell)
// Used to cast spells.
/mob/living/simple_animal/technomancer_golem/RangedAttack(var/atom/A, var/params)
if(active_spell)
spellcast_pre_animation()
if(active_spell.cast_methods & CAST_RANGED)
active_spell.on_ranged_cast(A, src)
spellcast_post_animation()
/mob/living/simple_animal/technomancer_golem/UnarmedAttack(var/atom/A, var/proximity)
if(proximity)
if(active_spell)
spellcast_pre_animation()
if(!Adjacent(A)) // Need to check again since they might've moved while 'warming up'.
spellcast_post_animation()
return
var/effective_cooldown = round(active_spell.cooldown * core.cooldown_modifier, 5)
if(active_spell.cast_methods & CAST_MELEE)
active_spell.on_melee_cast(A, src)
else if(active_spell.cast_methods & CAST_RANGED)
active_spell.on_ranged_cast(A, src)
spellcast_post_animation()
src.setClickCooldown(effective_cooldown)
else
..()
/mob/living/simple_animal/technomancer_golem/get_technomancer_core()
return core
/mob/living/simple_animal/technomancer_golem/proc/bind_to_mob(mob/user)
if(!user || master)
return
master = user
name = "[master]'s [initial(name)]"
/mob/living/simple_animal/technomancer_golem/examine(mob/user)
..()
if(user.mind && technomancers.is_antagonist(user.mind))
user << "Your pride and joy. It's a very special synthetic robot, capable of using functions similar to you, and you built it \
yourself! It'll always stand by your side, ready to help you out. You have no idea what GOLEM stands for, however..."
/mob/living/simple_animal/technomancer_golem/Life()
..()
handle_ai()
// This is where the real spaghetti begins.
/mob/living/simple_animal/technomancer_golem/proc/handle_ai()
if(!master)
return
if(get_dist(src, master) > 6 || src.z != master.z)
targeted_blink(master)
// Give our allies buffs and heals.
for(var/mob/living/L in view(src))
if(L in friends)
support_friend(L)
return
/mob/living/simple_animal/technomancer_golem/proc/support_friend(var/mob/living/L)
if(L.getBruteLoss() >= 10 || L.getFireLoss() >= 10)
if(L.isSynthetic() && !L.has_modifier_of_type(/datum/modifier/technomancer/mend_synthetic))
place_spell_in_hand(known_spells["mend synthetic"])
targeted_blink(L)
UnarmedAttack(L, 1)
else if(!L.has_modifier_of_type(/datum/modifier/technomancer/mend_life))
place_spell_in_hand(known_spells["mend life"])
targeted_blink(L)
UnarmedAttack(L, 1)
return
// Give them repel missiles if they lack it.
if(!L.has_modifier_of_type(/datum/modifier/technomancer/repel_missiles))
place_spell_in_hand(known_spells["repel missiles"])
RangedAttack(L)
return
/mob/living/simple_animal/technomancer_golem/proc/targeted_blink(var/atom/target)
var/datum/effect/effect/system/spark_spread/spark_system = new()
spark_system.set_up(5, 0, get_turf(src))
spark_system.start()
src.visible_message("<span class='notice'>\The [src] vanishes!</span>")
src.forceMove(get_turf(target))
return

View File

@@ -130,7 +130,7 @@
for(var/mob/living/L in summoned_mobs) for(var/mob/living/L in summoned_mobs)
summoned_mobs -= L summoned_mobs -= L
qdel(L) qdel(L)
for(var/mob/living/simple_animal/ward/ward in wards_in_use) for(var/mob/living/ward in wards_in_use)
wards_in_use -= ward wards_in_use -= ward
qdel(ward) qdel(ward)

View File

@@ -1,12 +1,17 @@
//Returns 1 if the turf is dense, or if there's dense objects on it, unless told to ignore them. //Returns 1 if the turf is dense, or if there's dense objects/mobs on it, unless told to ignore them.
/turf/proc/check_density(var/ignore_objs = 0) /turf/proc/check_density(var/ignore_objs = FALSE, var/ignore_mobs = FALSE)
if(density) if(density)
return 1 return TRUE
if(!ignore_objs) if(!ignore_objs || !ignore_mobs)
for(var/atom/movable/stuff in contents) for(var/atom/movable/stuff in contents)
if(stuff.density) if(stuff.density)
return 1 if(ignore_objs && isobj(stuff))
return 0 continue
else if(ignore_mobs && isliving(stuff)) // Ghosts aren't dense but keeping this limited to living type will probably save headaches in the future.
continue
else
return TRUE
return FALSE
// Used to distinguish friend from foe. // Used to distinguish friend from foe.
/obj/item/weapon/spell/proc/is_ally(var/mob/living/L) /obj/item/weapon/spell/proc/is_ally(var/mob/living/L)
@@ -14,9 +19,9 @@
return 1 return 1
if(L.mind && technomancers.is_antagonist(L.mind)) // This should be done better since we might want opposing technomancers later. if(L.mind && technomancers.is_antagonist(L.mind)) // This should be done better since we might want opposing technomancers later.
return 1 return 1
if(istype(L, /mob/living/simple_animal/hostile)) // Mind controlled simple mobs count as allies too. if(istype(L, /mob/living/simple_mob)) // Mind controlled simple mobs count as allies too.
var/mob/living/simple_animal/SA = L var/mob/living/simple_mob/SM = L
if(owner in SA.friends) if(owner in SM.friends)
return 1 return 1
return 0 return 0

View File

@@ -16,12 +16,12 @@
/obj/item/weapon/spell/abjuration/on_ranged_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/abjuration/on_ranged_cast(atom/hit_atom, mob/user)
if(istype(hit_atom, /mob/living) && pay_energy(500) && within_range(hit_atom)) if(istype(hit_atom, /mob/living) && pay_energy(500) && within_range(hit_atom))
var/mob/living/L = hit_atom var/mob/living/L = hit_atom
var/mob/living/simple_animal/SA = null var/mob/living/simple_mob/SM = null
//Bit of a roundabout typecheck, in order to test for two variables from two different mob types in one line. //Bit of a roundabout typecheck, in order to test for two variables from two different mob types in one line.
if(istype(L, /mob/living/simple_animal)) if(istype(L, /mob/living/simple_mob))
SA = L SM = L
if(L.summoned || (SA && SA.supernatural) ) if(L.summoned || (SM && SM.supernatural) )
if(L.client) // Player-controlled mobs are immune to being killed by this. if(L.client) // Player-controlled mobs are immune to being killed by this.
user << "<span class='warning'>\The [L] resists your attempt to banish it!</span>" user << "<span class='warning'>\The [L] resists your attempt to banish it!</span>"
L << "<span class='warning'>\The [user] tried to teleport you far away, but failed.</span>" L << "<span class='warning'>\The [user] tried to teleport you far away, but failed.</span>"
@@ -29,8 +29,8 @@
else else
visible_message("<span class='notice'>\The [L] vanishes!</span>") visible_message("<span class='notice'>\The [L] vanishes!</span>")
qdel(L) qdel(L)
else if(istype(L, /mob/living/simple_animal/construct)) else if(istype(L, /mob/living/simple_mob/construct))
var/mob/living/simple_animal/construct/evil = L var/mob/living/simple_mob/construct/evil = L
evil << "<span class='danger'>\The [user]'s abjuration purges your form!</span>" evil << "<span class='danger'>\The [user]'s abjuration purges your form!</span>"
evil.purge = 3 evil.purge = 3
adjust_instability(5) adjust_instability(5)

View File

@@ -120,7 +120,7 @@
for(var/mob/living/carbon/human/H in nearby_mobs) //Heal our apprentices for(var/mob/living/carbon/human/H in nearby_mobs) //Heal our apprentices
if(H.mind && technomancers.is_antagonist(H.mind)) if(H.mind && technomancers.is_antagonist(H.mind))
mobs_to_heal |= H mobs_to_heal |= H
for(var/mob/living/simple_animal/hostile/SAH in nearby_mobs) //Heal our controlled mobs for(var/mob/living/simple_mob/hostile/SAH in nearby_mobs) //Heal our controlled mobs
if(owner in SAH.friends) if(owner in SAH.friends)
mobs_to_heal |= SAH mobs_to_heal |= SAH
else else

View File

@@ -21,91 +21,68 @@
aspect = ASPECT_BIOMED //Not sure if this should be something else. aspect = ASPECT_BIOMED //Not sure if this should be something else.
var/image/control_overlay = null var/image/control_overlay = null
var/list/controlled_mobs = list() var/list/controlled_mobs = list()
var/list/allowed_mobs = list( var/allowed_mob_classes = MOB_CLASS_ANIMAL|MOB_CLASS_SYNTHETIC
/mob/living/bot,
/mob/living/simple_animal/cat,
/mob/living/simple_animal/chick,
/mob/living/simple_animal/chicken,
/mob/living/simple_animal/corgi,
/mob/living/simple_animal/cow,
/mob/living/simple_animal/crab,
/mob/living/simple_animal/lizard,
/mob/living/simple_animal/mouse,
/mob/living/simple_animal/parrot,
/mob/living/simple_animal/slime,
// /mob/living/simple_animal/adultslime,
/mob/living/simple_animal/tindalos,
/mob/living/simple_animal/yithian,
/mob/living/simple_animal/hostile/scarybat,
/mob/living/simple_animal/hostile/viscerator,
/mob/living/simple_animal/hostile/malf_drone,
/mob/living/simple_animal/hostile/giant_spider,
/mob/living/simple_animal/hostile/hivebot,
/mob/living/simple_animal/retaliate/diyaab, //Doubt these will get used but might as well,
/mob/living/simple_animal/hostile/savik,
/mob/living/simple_animal/hostile/shantak
)
//This unfortunately is gonna be rather messy due to the various mobtypes involved. //This unfortunately is gonna be rather messy due to the various mobtypes involved.
/obj/item/weapon/spell/control/proc/select(var/mob/living/L) /obj/item/weapon/spell/control/proc/select(var/mob/living/L)
if(!(is_type_in_list(L, allowed_mobs))) if(!(L.mob_class & allowed_mob_classes))
return 0 return FALSE
if(istype(L, /mob/living/simple_animal)) if(!L.has_AI())
var/mob/living/simple_animal/SA = L return FALSE
SA.ai_inactive = 1
SA.friends |= src.owner
SA.stance = STANCE_IDLE
L.overlays |= control_overlay var/datum/ai_holder/AI = L.ai_holder
AI.hostile = FALSE // The Technomancer chooses the target, not the AI.
AI.retaliate = TRUE
AI.wander = FALSE
AI.forget_everything()
if(istype(L, /mob/living/simple_mob))
var/mob/living/simple_mob/SM = L
SM.friends |= src.owner
L.add_overlay(control_overlay, TRUE)
controlled_mobs |= L controlled_mobs |= L
/obj/item/weapon/spell/control/proc/deselect(var/mob/living/L) /obj/item/weapon/spell/control/proc/deselect(var/mob/living/L)
if(!(L in controlled_mobs)) if(!(L in controlled_mobs))
return 0 return FALSE
if(istype(L, /mob/living/simple_animal)) if(L.has_AI())
var/mob/living/simple_animal/SA = L var/datum/ai_holder/AI = L.ai_holder
SA.ai_inactive = 1 AI.hostile = initial(AI.hostile)
if(istype(SA, /mob/living/simple_animal/hostile)) AI.retaliate = initial(AI.retaliate)
var/mob/living/simple_animal/hostile/SAH = SA AI.wander = initial(AI.wander)
SAH.friends.Remove(owner) AI.forget_everything()
L.overlays.Remove(control_overlay) if(istype(L, /mob/living/simple_mob))
var/mob/living/simple_mob/SM = L
SM.friends -= owner
L.cut_overlay(control_overlay, TRUE)
controlled_mobs.Remove(L) controlled_mobs.Remove(L)
/obj/item/weapon/spell/control/proc/move_all(turf/T) /obj/item/weapon/spell/control/proc/move_all(turf/T)
for(var/mob/living/living in controlled_mobs) for(var/mob/living/L in controlled_mobs)
if(living.stat) if(!L.has_AI() || L.stat)
deselect(living) deselect(L)
continue continue
if(istype(living, /mob/living/simple_animal)) L.ai_holder.give_destination(T, 0, TRUE)
var/mob/living/simple_animal/SA = living
SA.target_mob = null
SA.stance = STANCE_IDLE
walk_towards(SA,T,SA.speed)
else
walk_towards(living,T,5)
/obj/item/weapon/spell/control/proc/attack_all(mob/target) /obj/item/weapon/spell/control/proc/attack_all(mob/target)
for(var/mob/living/L in controlled_mobs) for(var/mob/living/L in controlled_mobs)
if(L.stat) if(!L.has_AI() || L.stat)
deselect(L) deselect(L)
continue continue
if(istype(L, /mob/living/simple_animal/hostile)) L.ai_holder.give_target(target)
var/mob/living/simple_animal/hostile/SAH
SAH.target_mob = target
else if(istype(L, /mob/living/bot))
var/mob/living/bot/B = L
B.UnarmedAttack(L)
/obj/item/weapon/spell/control/New() /obj/item/weapon/spell/control/initialize()
control_overlay = image('icons/obj/spells.dmi',"controlled") control_overlay = image('icons/obj/spells.dmi',"controlled")
..() return ..()
/obj/item/weapon/spell/control/Destroy() /obj/item/weapon/spell/control/Destroy()
for(var/mob/living/simple_animal/hostile/SM in controlled_mobs) for(var/mob/living/L in controlled_mobs)
deselect(SM) deselect(L)
controlled_mobs = list() controlled_mobs = list()
return ..() return ..()
@@ -127,11 +104,14 @@
trying to use it on yourself, perhaps you're an exception? Regardless, nothing happens.</span>" trying to use it on yourself, perhaps you're an exception? Regardless, nothing happens.</span>"
return 0 return 0
if(is_type_in_list(L, allowed_mobs)) if(L.mob_class & allowed_mob_classes)
if(!(L in controlled_mobs)) //Selecting if(!(L in controlled_mobs)) //Selecting
if(L.client) if(L.client)
user << "<span class='danger'>\The [L] seems to resist you!</span>" user << "<span class='danger'>\The [L] seems to resist you!</span>"
return 0 return 0
if(!L.has_AI())
to_chat(user, span("warning", "\The [L] seems too dim for this to work on them."))
return FALSE
if(pay_energy(500)) if(pay_energy(500))
select(L) select(L)
user << "<span class='notice'>\The [L] is now under your (limited) control.</span>" user << "<span class='notice'>\The [L] is now under your (limited) control.</span>"

View File

@@ -75,9 +75,9 @@
for(var/mob/living/L in view(owner)) for(var/mob/living/L in view(owner))
// Spiders, carp... bears. // Spiders, carp... bears.
if(istype(L, /mob/living/simple_animal)) if(istype(L, /mob/living/simple_mob))
var/mob/living/simple_animal/SM = L var/mob/living/simple_mob/SM = L
if(!is_ally(SM) && SM.hostile) if(!is_ally(SM) && SM.has_AI() && SM.ai_holder.hostile)
hostile_mobs++ hostile_mobs++
if(SM.summoned || SM.supernatural) // Our creations might be trying to kill us. if(SM.summoned || SM.supernatural) // Our creations might be trying to kill us.
potential_spells |= /obj/item/weapon/spell/abjuration potential_spells |= /obj/item/weapon/spell/abjuration

View File

@@ -14,7 +14,7 @@
aspect = ASPECT_LIGHT aspect = ASPECT_LIGHT
cast_methods = CAST_RANGED | CAST_USE cast_methods = CAST_RANGED | CAST_USE
var/atom/movable/copied = null var/atom/movable/copied = null
var/mob/living/simple_animal/illusion/illusion = null var/mob/living/simple_mob/illusion/illusion = null
/obj/item/weapon/spell/illusion/on_ranged_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/illusion/on_ranged_cast(atom/hit_atom, mob/user)
if(istype(hit_atom, /atom/movable)) if(istype(hit_atom, /atom/movable))
@@ -33,17 +33,13 @@
if(pay_energy(500)) if(pay_energy(500))
illusion = new(T) illusion = new(T)
illusion.copy_appearance(copied) illusion.copy_appearance(copied)
if(ishuman(copied))
var/mob/living/carbon/human/H = copied
// This is to try to have the illusion move at the same rate the real mob world.
illusion.step_delay = max(H.movement_delay() + 4, 3)
user << "<span class='notice'>An illusion of \the [copied] is made on \the [T].</span>" user << "<span class='notice'>An illusion of \the [copied] is made on \the [T].</span>"
user << 'sound/effects/pop.ogg' user << 'sound/effects/pop.ogg'
return 1 return 1
else else
if(pay_energy(100)) if(pay_energy(100))
spawn(1) var/datum/ai_holder/AI = illusion.ai_holder
illusion.walk_loop(T) AI.give_destination(T)
/obj/item/weapon/spell/illusion/on_use_cast(mob/user) /obj/item/weapon/spell/illusion/on_use_cast(mob/user)
if(illusion) if(illusion)
@@ -76,116 +72,3 @@
temp_image.transform = M temp_image.transform = M
// temp_image.pixel_y = 8 // temp_image.pixel_y = 8
src.overlays.Add(temp_image) src.overlays.Add(temp_image)
/mob/living/simple_animal/illusion
name = "illusion" // gets overwritten
desc = "If you can read me, the game broke. Please report this to a coder."
resistance = 1000 // holograms are tough
wander = 0
response_help = "pushes a hand through"
response_disarm = "tried to disarm"
response_harm = "tried to punch"
var/atom/movable/copying = null
universal_speak = 1
var/realistic = 0
var/list/path = list() //Used for AStar pathfinding.
var/walking = 0
var/step_delay = 10
/mob/living/simple_animal/illusion/update_icon() // We don't want the appearance changing AT ALL unless by copy_appearance().
return
/mob/living/simple_animal/illusion/proc/copy_appearance(var/atom/movable/thing_to_copy)
if(!thing_to_copy)
return 0
name = thing_to_copy.name
desc = thing_to_copy.desc
gender = thing_to_copy.gender
appearance = thing_to_copy.appearance
copying = thing_to_copy
return 1
// We use special movement code for illusions, because BYOND's default pathfinding will use diagonal movement if it results
// in the shortest path. As players are incapable of moving in diagonals, we must do this or else illusions will not be convincing.
/mob/living/simple_animal/illusion/proc/calculate_path(var/turf/targeted_loc)
if(!path.len || !path)
spawn(0)
path = AStar(loc, targeted_loc, /turf/proc/CardinalTurfs, /turf/proc/Distance, 0, 10, id = null)
if(!path)
path = list()
return
/mob/living/simple_animal/illusion/proc/walk_path(var/turf/targeted_loc)
if(path && path.len)
step_to(src, path[1])
path -= path[1]
return
else
if(targeted_loc)
calculate_path(targeted_loc)
/mob/living/simple_animal/illusion/proc/walk_loop(var/turf/targeted_loc)
if(walking) //Already busy moving somewhere else.
return 0
walking = 1
calculate_path(targeted_loc)
if(!targeted_loc)
walking = 0
return 0
if(path.len == 0)
calculate_path(targeted_loc)
while(loc != targeted_loc)
walk_path(targeted_loc)
sleep(step_delay)
walking = 0
return 1
// Because we can't perfectly duplicate some examine() output, we directly examine the AM it is copying. It's messy but
// this is to prevent easy checks from the opposing force.
/mob/living/simple_animal/illusion/examine(mob/user)
if(copying)
copying.examine(user)
return
..()
/mob/living/simple_animal/illusion/bullet_act(var/obj/item/projectile/P)
if(!P)
return
if(realistic)
return ..()
return PROJECTILE_FORCE_MISS
/mob/living/simple_animal/illusion/attack_hand(mob/living/carbon/human/M)
if(!realistic)
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='warning'>[M]'s hand goes through \the [src]!</span>")
return
else
switch(M.a_intent)
if(I_HELP)
var/datum/gender/T = gender_datums[src.get_visible_gender()]
M.visible_message("<span class='notice'>[M] hugs [src] to make [T.him] feel better!</span>", \
"<span class='notice'>You hug [src] to make [T.him] feel better!</span>") // slightly redundant as at the moment most mobs still use the normal gender var, but it works and future-proofs it
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(I_DISARM)
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] attempted to disarm [src]!</span>")
M.do_attack_animation(src)
if(I_GRAB)
..()
if(I_HURT)
adjustBruteLoss(harm_intent_damage)
M.visible_message("<font color='red'>[M] [response_harm] \the [src]</font>")
M.do_attack_animation(src)
return
/mob/living/simple_animal/illusion/ex_act()
return

View File

@@ -15,11 +15,13 @@
/obj/item/weapon/spell/modifier/on_melee_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/modifier/on_melee_cast(atom/hit_atom, mob/user)
if(istype(hit_atom, /mob/living)) if(istype(hit_atom, /mob/living))
on_add_modifier(hit_atom) return on_add_modifier(hit_atom)
return FALSE
/obj/item/weapon/spell/modifier/on_ranged_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/modifier/on_ranged_cast(atom/hit_atom, mob/user)
if(istype(hit_atom, /mob/living)) if(istype(hit_atom, /mob/living))
on_add_modifier(hit_atom) return on_add_modifier(hit_atom)
return FALSE
/obj/item/weapon/spell/modifier/proc/on_add_modifier(var/mob/living/L) /obj/item/weapon/spell/modifier/proc/on_add_modifier(var/mob/living/L)
@@ -32,6 +34,7 @@
MT.spell_power = calculate_spell_power(1) MT.spell_power = calculate_spell_power(1)
log_and_message_admins("has casted [src] on [L].") log_and_message_admins("has casted [src] on [L].")
qdel(src) qdel(src)
return TRUE
// Technomancer specific subtype which keeps track of spell power and gets targeted specificially by Dispel. // Technomancer specific subtype which keeps track of spell power and gets targeted specificially by Dispel.
/datum/modifier/technomancer /datum/modifier/technomancer

View File

@@ -30,13 +30,13 @@
this point.</span>" this point.</span>"
return 0 return 0
user << "<span class='notice'>You stab \the [L] with a hidden integrated hypo, attempting to bring them back...</span>" user << "<span class='notice'>You stab \the [L] with a hidden integrated hypo, attempting to bring them back...</span>"
if(istype(L, /mob/living/simple_animal)) if(istype(L, /mob/living/simple_mob))
var/mob/living/simple_animal/SM = L var/mob/living/simple_mob/SM = L
SM.health = SM.getMaxHealth() / 3 SM.health = SM.getMaxHealth() / 3
SM.stat = CONSCIOUS SM.stat = CONSCIOUS
dead_mob_list -= SM dead_mob_list -= SM
living_mob_list += SM living_mob_list += SM
SM.icon_state = SM.icon_living SM.update_icon()
adjust_instability(15) adjust_instability(15)
else if(ishuman(L)) else if(ishuman(L))
var/mob/living/carbon/human/H = L var/mob/living/carbon/human/H = L

View File

@@ -11,7 +11,7 @@
icon_state = "radiance" icon_state = "radiance"
cast_methods = CAST_RANGED | CAST_THROW cast_methods = CAST_RANGED | CAST_THROW
aspect = ASPECT_EMP aspect = ASPECT_EMP
spawner_type = /obj/effect/temporary_effect/pulsar spawner_type = /obj/effect/temporary_effect/pulse/pulsar
/obj/item/weapon/spell/spawner/pulsar/New() /obj/item/weapon/spell/spawner/pulsar/New()
..() ..()
@@ -25,7 +25,29 @@
/obj/item/weapon/spell/spawner/pulsar/on_throw_cast(atom/hit_atom, mob/user) /obj/item/weapon/spell/spawner/pulsar/on_throw_cast(atom/hit_atom, mob/user)
empulse(hit_atom, 1, 1, 1, 1, log=1) empulse(hit_atom, 1, 1, 1, 1, log=1)
/obj/effect/temporary_effect/pulsar // Does something every so often. Deletes itself when pulses_remaining hits zero.
/obj/effect/temporary_effect/pulse
var/pulses_remaining = 3
var/pulse_delay = 2 SECONDS
/obj/effect/temporary_effect/pulse/initialize()
spawn(0)
pulse_loop()
return ..()
/obj/effect/temporary_effect/pulse/proc/pulse_loop()
while(pulses_remaining)
sleep(pulse_delay)
on_pulse()
pulses_remaining--
qdel(src)
// Override for specific effects.
/obj/effect/temporary_effect/pulse/proc/on_pulse()
/obj/effect/temporary_effect/pulse/pulsar
name = "pulsar" name = "pulsar"
desc = "Not a real pulsar, but still emits loads of EMP." desc = "Not a real pulsar, but still emits loads of EMP."
icon_state = "shield2" icon_state = "shield2"
@@ -33,17 +55,14 @@
light_range = 4 light_range = 4
light_power = 5 light_power = 5
light_color = "#2ECCFA" light_color = "#2ECCFA"
var/pulses_remaining = 3 pulses_remaining = 3
/obj/effect/temporary_effect/pulse/pulsar/on_pulse()
empulse(src, 1, 1, 2, 2, log = 1)
/obj/effect/temporary_effect/pulsar/New()
..()
spawn(0)
pulse_loop()
/obj/effect/temporary_effect/pulsar/proc/pulse_loop()
while(pulses_remaining)
sleep(2 SECONDS)
empulse(src, 1, 1, 2, 2, log = 1)
pulses_remaining--
qdel(src)

View File

@@ -16,34 +16,32 @@
desc = "Chitter chitter." desc = "Chitter chitter."
summoned_mob_type = null summoned_mob_type = null
summon_options = list( summon_options = list(
"Mouse" = /mob/living/simple_animal/mouse, "Mouse" = /mob/living/simple_mob/animal/passive/mouse,
"Lizard" = /mob/living/simple_animal/lizard, "Lizard" = /mob/living/simple_mob/animal/passive/lizard,
"Chicken" = /mob/living/simple_animal/chicken, "Chicken" = /mob/living/simple_mob/animal/passive/chicken,
"Chick" = /mob/living/simple_animal/chick, "Chick" = /mob/living/simple_mob/animal/passive/chick,
"Crab" = /mob/living/simple_animal/crab, "Crab" = /mob/living/simple_mob/animal/passive/crab,
"Parrot" = /mob/living/simple_animal/parrot, "Parrot" = /mob/living/simple_mob/animal/passive/bird/parrot,
"Goat" = /mob/living/simple_animal/retaliate/goat, "Goat" = /mob/living/simple_mob/animal/goat,
"Cat" = /mob/living/simple_animal/cat, "Cat" = /mob/living/simple_mob/animal/passive/cat,
"Kitten" = /mob/living/simple_animal/cat/kitten, "Kitten" = /mob/living/simple_mob/animal/passive/cat/kitten,
"Corgi" = /mob/living/simple_animal/corgi, "Corgi" = /mob/living/simple_mob/animal/passive/dog/corgi,
"Corgi Pup" = /mob/living/simple_animal/corgi/puppy, "Corgi Pup" = /mob/living/simple_mob/animal/passive/dog/corgi/puppy,
"BAT" = /mob/living/simple_animal/hostile/scarybat, "BAT" = /mob/living/simple_mob/animal/space/bats,
"SPIDER" = /mob/living/simple_animal/hostile/giant_spider, "SPIDER" = /mob/living/simple_mob/animal/giant_spider,
"SPIDER HUNTER" = /mob/living/simple_animal/hostile/giant_spider/hunter, "SPIDER HUNTER" = /mob/living/simple_mob/animal/giant_spider/hunter,
"SPIDER NURSE" = /mob/living/simple_animal/hostile/giant_spider/nurse, "SPIDER NURSE" = /mob/living/simple_mob/animal/giant_spider/nurse,
"CARP" = /mob/living/simple_animal/hostile/carp, "CARP" = /mob/living/simple_mob/animal/space/carp,
"BEAR" = /mob/living/simple_animal/hostile/bear "BEAR" = /mob/living/simple_mob/animal/space/bear
) // Vorestation edits to add vore versions. )
cooldown = 30 cooldown = 30
instability_cost = 10 instability_cost = 10
energy_cost = 1000 energy_cost = 1000
/obj/item/weapon/spell/summon/summon_creature/on_summon(var/mob/living/simple_animal/summoned) /obj/item/weapon/spell/summon/summon_creature/on_summon(var/mob/living/simple_mob/summoned)
if(check_for_scepter()) if(check_for_scepter())
// summoned.faction = "technomancer" // summoned.faction = "technomancer"
if(istype(summoned, /mob/living/simple_animal/hostile)) summoned.friends += owner
var/mob/living/simple_animal/SA = summoned
SA.friends.Add(owner)
// Makes their new pal big and strong, if they have spell power. // Makes their new pal big and strong, if they have spell power.
summoned.maxHealth = calculate_spell_power(summoned.maxHealth) summoned.maxHealth = calculate_spell_power(summoned.maxHealth)
@@ -51,15 +49,12 @@
summoned.melee_damage_lower = calculate_spell_power(summoned.melee_damage_lower) summoned.melee_damage_lower = calculate_spell_power(summoned.melee_damage_lower)
summoned.melee_damage_upper = calculate_spell_power(summoned.melee_damage_upper) summoned.melee_damage_upper = calculate_spell_power(summoned.melee_damage_upper)
// This makes the summon slower, so the crew has a chance to flee from massive monsters. // This makes the summon slower, so the crew has a chance to flee from massive monsters.
summoned.move_to_delay = calculate_spell_power(round(summoned.move_to_delay)) summoned.movement_cooldown = calculate_spell_power(round(summoned.movement_cooldown))
var/new_size = calculate_spell_power(1) var/new_size = calculate_spell_power(1)
if(new_size != 1) if(new_size != 1)
var/matrix/M = matrix() adjust_scale(new_size)
M.Scale(new_size)
M.Translate(0, 16*(new_size-1))
summoned.transform = M
// Now we hurt their new pal, because being forcefully abducted by teleportation can't be healthy. // Now we hurt their new pal, because being forcefully abducted by teleportation can't be healthy.
summoned.health = round(summoned.getMaxHealth() * 0.7) summoned.adjustBruteLoss(summoned.getMaxHealth() * 0.3) // Lose 30% of max health on arrival (but could be healed back up).

View File

@@ -1,9 +1,8 @@
/datum/technomancer/spell/summon_ward /datum/technomancer/spell/summon_ward
name = "Summon Ward" name = "Summon Monitor Ward"
desc = "Teleports a prefabricated 'ward' drone to the target location, which will alert you and your allies when it sees entities \ desc = "Teleports a prefabricated 'ward' drone to the target location, which will alert you when it sees entities \
moving around it, or when it is attacked. They can see for up to five meters." moving around it, or when it is attacked. They can see for up to five meters. It can also see invisible entities, and \
enhancement_desc = "Wards can detect invisibile entities, and are more specific in relaying information about what it sees. \ forcefully decloak them if close enough."
Invisible entities that are spotted by it will be decloaked."
cost = 25 cost = 25
obj_path = /obj/item/weapon/spell/summon/summon_ward obj_path = /obj/item/weapon/spell/summon/summon_ward
category = UTILITY_SPELLS category = UTILITY_SPELLS
@@ -12,116 +11,10 @@
name = "summon ward" name = "summon ward"
desc = "Finally, someone you can depend on to watch your back." desc = "Finally, someone you can depend on to watch your back."
cast_methods = CAST_RANGED cast_methods = CAST_RANGED
summoned_mob_type = /mob/living/simple_animal/ward summoned_mob_type = /mob/living/simple_mob/mechanical/ward/monitor
cooldown = 10 cooldown = 10
instability_cost = 5 instability_cost = 5
energy_cost = 500 energy_cost = 500
/obj/item/weapon/spell/summon/summon_ward/on_summon(var/mob/living/simple_animal/ward/ward) /obj/item/weapon/spell/summon/summon_ward/on_summon(var/mob/living/simple_mob/mechanical/ward/monitor/my_ward)
ward.creator = owner my_ward.owner = owner
if(check_for_scepter())
ward.true_sight = 1
ward.see_invisible = SEE_INVISIBLE_LEVEL_TWO
/mob/living/simple_animal/ward
name = "ward"
desc = "It's a little flying drone that seems to be watching you..."
icon = 'icons/mob/critter.dmi'
icon_state = "ward"
resistance = 5
wander = 0
response_help = "pets the"
response_disarm = "swats away"
response_harm = "punches"
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
minbodytemp = 0
maxbodytemp = 0
unsuitable_atoms_damage = 0
heat_damage_per_tick = 0
cold_damage_per_tick = 0
var/true_sight = 0 // If true, detects more than what the Technomancer normally can't.
var/mob/living/carbon/human/creator = null
var/list/seen_mobs = list()
/mob/living/simple_animal/ward/death()
if(creator)
creator << "<span class='danger'>Your ward inside [get_area(src)] was killed!</span>"
..()
qdel(src)
/mob/living/simple_animal/ward/proc/expire()
if(creator && src)
creator << "<span class='warning'>Your ward inside [get_area(src)] expired.</span>"
qdel(src)
/mob/living/simple_animal/ward/Life()
..()
detect_mobs()
update_icon()
/mob/living/simple_animal/ward/proc/detect_mobs()
var/list/things_in_sight = view(5,src)
var/list/newly_seen_mobs = list()
for(var/mob/living/L in things_in_sight)
if(L == creator) // I really wish is_ally() was usable here.
continue
if(istype(L, /mob/living/simple_animal/ward))
continue
if(istype(L, /mob/living/simple_animal))
var/mob/living/simple_animal/SA = L
if(creator in SA.friends)
continue
if(!true_sight)
var/turf/T = get_turf(L)
var/light_amount = T.get_lumcount()
if(light_amount <= 0.5)
continue // Too dark to see.
if(L.alpha <= 127)
continue // Too transparent, as a mercy to camo lings.
else
L.break_cloak()
// Warn the Technomancer when it sees a new mob.
if(!(L in seen_mobs))
seen_mobs.Add(L)
newly_seen_mobs.Add(L)
if(creator)
if(true_sight)
creator << "<span class='notice'>Your ward at [get_area(src)] detected [english_list(newly_seen_mobs)].</span>"
else
creator << "<span class='notice'>Your ward at [get_area(src)] detected something.</span>"
// Now get rid of old mobs that left vision.
for(var/mob/living/L in seen_mobs)
if(!(L in things_in_sight))
seen_mobs.Remove(L)
/mob/living/simple_animal/ward/update_icon()
if(seen_mobs.len)
icon_state = "ward_spotted"
set_light(3, 3, l_color = "FF0000")
else
icon_state = "ward"
set_light(3, 3, l_color = "00FF00")
if(true_sight)
overlays.Cut()
var/image/I = image('icons/mob/critter.dmi',"ward_truesight")
overlays.Add(I)
/mob/living/simple_animal/ward/invisible_detect
true_sight = 1
see_invisible = SEE_INVISIBLE_LEVEL_TWO

View File

@@ -49,10 +49,9 @@
if(occupant) if(occupant)
to_chat(user, "<span class='notice'>\The [src] is already occupied!</span>") to_chat(user, "<span class='notice'>\The [src] is already occupied!</span>")
return return
for(var/mob/living/simple_animal/slime/M in range(1, H.affecting)) if(H.affecting.has_buckled_mobs())
if(M.victim == H.affecting) to_chat(user, span("warning", "\The [H.affecting] has other entities attached to it. Remove them first."))
to_chat(user, "<span class='danger'>[H.affecting.name] has a slime attached to them, deal with that first.</span>") return
return
var/mob/M = H.affecting var/mob/M = H.affecting
if(M.abiotic()) if(M.abiotic())
to_chat(user, "<span class='notice'>Subject cannot have abiotic items on.</span>") to_chat(user, "<span class='notice'>Subject cannot have abiotic items on.</span>")
@@ -86,10 +85,9 @@
if(O.abiotic()) if(O.abiotic())
to_chat(user, "<span class='notice'>Subject cannot have abiotic items on.</span>") to_chat(user, "<span class='notice'>Subject cannot have abiotic items on.</span>")
return 0 return 0
for(var/mob/living/simple_animal/slime/M in range(1, O)) if(O.has_buckled_mobs())
if(M.victim == O) to_chat(user, span("warning", "\The [O] has other entities attached to it. Remove them first."))
to_chat(user, "<span class='danger'>[O] has a slime attached to them, deal with that first.</span>") return
return 0
if(O == user) if(O == user)
visible_message("[user] climbs into \the [src].") visible_message("[user] climbs into \the [src].")

View File

@@ -143,7 +143,7 @@
/obj/machinery/camera/attack_generic(mob/user as mob) /obj/machinery/camera/attack_generic(mob/user as mob)
if(isanimal(user)) if(isanimal(user))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = user
set_status(0) set_status(0)
S.do_attack_animation(src) S.do_attack_animation(src)
S.setClickCooldown(user.get_attack_speed()) S.setClickCooldown(user.get_attack_speed())

View File

@@ -201,7 +201,7 @@ var/prison_shuttle_timeleft = 0
for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area... for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area...
bug.gib() bug.gib()
for(var/mob/living/simple_animal/pest in end_location) // And for the other kind of bug... for(var/mob/living/simple_mob/pest in end_location) // And for the other kind of bug...
pest.gib() pest.gib()
start_location.move_contents_to(end_location) start_location.move_contents_to(end_location)

View File

@@ -81,7 +81,7 @@ var/specops_shuttle_timeleft = 0
for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area... for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area...
bug.gib() bug.gib()
for(var/mob/living/simple_animal/pest in end_location) // And for the other kind of bug... for(var/mob/living/simple_mob/pest in end_location) // And for the other kind of bug...
pest.gib() pest.gib()
start_location.move_contents_to(end_location) start_location.move_contents_to(end_location)

View File

@@ -166,7 +166,7 @@ var/syndicate_elite_shuttle_timeleft = 0
for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area... for(var/mob/living/carbon/bug in end_location) // If someone somehow is still in the shuttle's docking area...
bug.gib() bug.gib()
for(var/mob/living/simple_animal/pest in end_location) // And for the other kind of bug... for(var/mob/living/simple_mob/pest in end_location) // And for the other kind of bug...
pest.gib() pest.gib()
start_location.move_contents_to(end_location) start_location.move_contents_to(end_location)

View File

@@ -207,7 +207,7 @@
for(var/obj/effect/decal/cleanable/blood/B in linkedholodeck) for(var/obj/effect/decal/cleanable/blood/B in linkedholodeck)
qdel(B) qdel(B)
for(var/mob/living/simple_animal/hostile/carp/C in linkedholodeck) for(var/mob/living/simple_mob/animal/space/carp/C in linkedholodeck)
qdel(C) qdel(C)
holographic_items = A.copy_contents_to(linkedholodeck , 1) holographic_items = A.copy_contents_to(linkedholodeck , 1)
@@ -228,7 +228,7 @@
T.temperature = 5000 T.temperature = 5000
T.hotspot_expose(50000,50000,1) T.hotspot_expose(50000,50000,1)
if(L.name=="Holocarp Spawn") if(L.name=="Holocarp Spawn")
new /mob/living/simple_animal/hostile/carp(L.loc) new /mob/living/simple_mob/animal/space/carp(L.loc)
/datum/file/program/holodeck/proc/emergencyShutdown() /datum/file/program/holodeck/proc/emergencyShutdown()

View File

@@ -199,14 +199,13 @@
return return
if(occupant) if(occupant)
to_chat(user,"<span class='warning'>\The [src] is already occupied by [occupant].</span>") to_chat(user,"<span class='warning'>\The [src] is already occupied by [occupant].</span>")
for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting)) if(grab.affecting.has_buckled_mobs())
if(M.victim == grab.affecting) to_chat(user, span("warning", "\The [grab.affecting] has other entities attached to it. Remove them first."))
to_chat(usr, "[grab.affecting.name] will not fit into the cryo because they have a slime latched onto their head.") return
return
var/mob/M = grab.affecting var/mob/M = grab.affecting
qdel(grab) qdel(grab)
put_mob(M) put_mob(M)
return return
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(var/mob/target, var/mob/user) //Allows borgs to put people into cryo without external assistance /obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(var/mob/target, var/mob/user) //Allows borgs to put people into cryo without external assistance
@@ -349,14 +348,14 @@
set name = "Move Inside" set name = "Move Inside"
set category = "Object" set category = "Object"
set src in oview(1) set src in oview(1)
for(var/mob/living/simple_animal/slime/M in range(1,usr)) if(isliving(usr))
if(M.victim == usr) var/mob/living/L = usr
to_chat(usr, "You're too busy getting your life sucked out of you.") if(L.has_buckled_mobs())
to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
return return
if(usr.stat != 0) if(L.stat != CONSCIOUS)
return return
put_mob(usr) put_mob(L)
return
/atom/proc/return_air_for_internal_lifeform(var/mob/living/lifeform) /atom/proc/return_air_for_internal_lifeform(var/mob/living/lifeform)
return return_air() return return_air()

View File

@@ -574,9 +574,10 @@
to_chat(usr, "<span class='notice'><B>\The [src] is in use.</B></span>") to_chat(usr, "<span class='notice'><B>\The [src] is in use.</B></span>")
return return
for(var/mob/living/simple_animal/slime/M in range(1,usr)) if(isliving(usr))
if(M.victim == usr) var/mob/living/L = usr
to_chat(usr, "You're too busy getting your life sucked out of you.") if(L.has_buckled_mobs())
to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
return return
visible_message("[usr] [on_enter_visible_message] [src].", 3) visible_message("[usr] [on_enter_visible_message] [src].", 3)

View File

@@ -46,11 +46,12 @@
var/bolt_up_sound = 'sound/machines/boltsup.ogg' var/bolt_up_sound = 'sound/machines/boltsup.ogg'
var/bolt_down_sound = 'sound/machines/boltsdown.ogg' var/bolt_down_sound = 'sound/machines/boltsdown.ogg'
/obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage) /obj/machinery/door/airlock/attack_generic(var/mob/living/user, var/damage)
if(stat & (BROKEN|NOPOWER)) if(stat & (BROKEN|NOPOWER))
if(damage >= 10) if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
if(src.locked || src.welded) if(src.locked || src.welded)
visible_message("<span class='danger'>\The [user] begins breaking into \the [src] internals!</span>") visible_message("<span class='danger'>\The [user] begins breaking into \the [src] internals!</span>")
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
if(do_after(user,10 SECONDS,src)) if(do_after(user,10 SECONDS,src))
src.locked = 0 src.locked = 0
src.welded = 0 src.welded = 0
@@ -58,6 +59,7 @@
open(1) open(1)
if(prob(25)) if(prob(25))
src.shock(user, 100) src.shock(user, 100)
user.set_AI_busy(FALSE)
else if(src.density) else if(src.density)
visible_message("<span class='danger'>\The [user] forces \the [src] open!</span>") visible_message("<span class='danger'>\The [user] forces \the [src] open!</span>")
open(1) open(1)
@@ -508,9 +510,6 @@ About the new airlock wires panel:
return return
..(user) ..(user)
/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user as mob)
..(user)
/obj/machinery/door/airlock/proc/isElectrified() /obj/machinery/door/airlock/proc/isElectrified()
if(src.electrified_until != 0) if(src.electrified_until != 0)
return 1 return 1

View File

@@ -39,8 +39,8 @@
/obj/machinery/door/attack_generic(var/mob/user, var/damage) /obj/machinery/door/attack_generic(var/mob/user, var/damage)
if(isanimal(user)) if(isanimal(user))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = user
if(damage >= 10) if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
visible_message("<span class='danger'>\The [user] smashes into the [src]!</span>") visible_message("<span class='danger'>\The [user] smashes into the [src]!</span>")
playsound(src, S.attack_sound, 75, 1) playsound(src, S.attack_sound, 75, 1)
take_damage(damage) take_damage(damage)

View File

@@ -216,22 +216,26 @@
return return
..() ..()
/obj/machinery/door/firedoor/attack_generic(var/mob/user, var/damage) /obj/machinery/door/firedoor/attack_generic(var/mob/living/user, var/damage)
if(stat & (BROKEN|NOPOWER)) if(stat & (BROKEN|NOPOWER))
if(damage >= 10) if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
var/time_to_force = (2 + (2 * blocked)) * 5 var/time_to_force = (2 + (2 * blocked)) * 5
if(src.density) if(src.density)
visible_message("<span class='danger'>\The [user] starts forcing \the [src] open!</span>") visible_message("<span class='danger'>\The [user] starts forcing \the [src] open!</span>")
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
if(do_after(user, time_to_force, src)) if(do_after(user, time_to_force, src))
visible_message("<span class='danger'>\The [user] forces \the [src] open!</span>") visible_message("<span class='danger'>\The [user] forces \the [src] open!</span>")
src.blocked = 0 src.blocked = 0
open(1) open(1)
user.set_AI_busy(FALSE)
else else
time_to_force = (time_to_force / 2) time_to_force = (time_to_force / 2)
visible_message("<span class='danger'>\The [user] starts forcing \the [src] closed!</span>") visible_message("<span class='danger'>\The [user] starts forcing \the [src] closed!</span>")
user.set_AI_busy(TRUE) // If the mob doesn't have an AI attached, this won't do anything.
if(do_after(user, time_to_force, src)) if(do_after(user, time_to_force, src))
visible_message("<span class='danger'>\The [user] forces \the [src] closed!</span>") visible_message("<span class='danger'>\The [user] forces \the [src] closed!</span>")
close(1) close(1)
user.set_AI_busy(FALSE)
else else
visible_message("<span class='notice'>\The [user] strains fruitlessly to force \the [src] [density ? "open" : "closed"].</span>") visible_message("<span class='notice'>\The [user] strains fruitlessly to force \the [src] [density ? "open" : "closed"].</span>")
return return

View File

@@ -406,16 +406,16 @@ var/list/turret_icons
attacked = 0 attacked = 0
..() ..()
/obj/machinery/porta_turret/attack_generic(mob/user as mob, var/damage) /obj/machinery/porta_turret/attack_generic(mob/living/L, damage)
if(isanimal(user)) if(isanimal(L))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = L
if(damage >= 10) if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
var/incoming_damage = round(damage - (damage / 5)) //Turrets are slightly armored, assumedly. var/incoming_damage = round(damage - (damage / 5)) //Turrets are slightly armored, assumedly.
visible_message("<span class='danger'>\The [S] [pick(S.attacktext)] \the [src]!</span>") visible_message("<span class='danger'>\The [S] [pick(S.attacktext)] \the [src]!</span>")
take_damage(incoming_damage) take_damage(incoming_damage)
S.do_attack_animation(src) S.do_attack_animation(src)
return 1 return 1
visible_message("<span class='notice'>\The [user] bonks \the [src]'s casing!</span>") visible_message("<span class='notice'>\The [L] bonks \the [src]'s casing!</span>")
return ..() return ..()
/obj/machinery/porta_turret/emag_act(var/remaining_charges, var/mob/user) /obj/machinery/porta_turret/emag_act(var/remaining_charges, var/mob/user)

View File

@@ -69,7 +69,7 @@
for(var/obj/machinery/teleport/hub/H in range(1)) for(var/obj/machinery/teleport/hub/H in range(1))
var/amount = rand(2,5) var/amount = rand(2,5)
for(var/i=0;i<amount;i++) for(var/i=0;i<amount;i++)
new /mob/living/simple_animal/hostile/carp(get_turf(H)) new /mob/living/simple_mob/animal/space/carp(get_turf(H))
// //
else else
for(var/mob/O in hearers(src, null)) for(var/mob/O in hearers(src, null))

View File

@@ -40,10 +40,9 @@
if(occupant) if(occupant)
occupant_message("The sleeper is already occupied") occupant_message("The sleeper is already occupied")
return return
for(var/mob/living/simple_animal/slime/M in range(1,target)) if(target.has_buckled_mobs())
if(M.victim == target) occupant_message(span("warning", "\The [target] has other entities attached to it. Remove them first."))
occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.") return
return
occupant_message("You start putting [target] into [src].") occupant_message("You start putting [target] into [src].")
chassis.visible_message("[chassis] starts putting [target] into the [src].") chassis.visible_message("[chassis] starts putting [target] into the [src].")
var/C = chassis.loc var/C = chassis.loc

View File

@@ -1203,9 +1203,10 @@
usr << "<span class='danger'>Kinda hard to climb in while handcuffed don't you think?</span>" usr << "<span class='danger'>Kinda hard to climb in while handcuffed don't you think?</span>"
return return
for(var/mob/living/simple_animal/slime/M in range(1,usr)) if(isliving(usr))
if(M.victim == usr) var/mob/living/L = usr
usr << "<span class='danger'>You're too busy getting your life sucked out of you.</span>" if(L.has_buckled_mobs())
to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
return return
//search for a valid passenger compartment //search for a valid passenger compartment
@@ -1329,4 +1330,4 @@
/obj/item/mecha_parts/mecha_equipment/tool/jetpack/do_after_cooldown() /obj/item/mecha_parts/mecha_equipment/tool/jetpack/do_after_cooldown()
sleep(equip_cooldown) sleep(equip_cooldown)
wait = 0 wait = 0
return 1 return 1

View File

@@ -1154,10 +1154,12 @@
to_chat(usr,"<span class='warning'>Access denied</span>") to_chat(usr,"<span class='warning'>Access denied</span>")
src.log_append_to_last("Permission denied.") src.log_append_to_last("Permission denied.")
return return
for(var/mob/living/simple_animal/slime/M in range(1,usr)) if(isliving(usr))
if(M.victim == usr) var/mob/living/L = usr
to_chat(usr,"You're too busy getting your life sucked out of you.") if(L.has_buckled_mobs())
to_chat(L, span("warning", "You have other entities attached to yourself. Remove them first."))
return return
// usr << "You start climbing into [src.name]" // usr << "You start climbing into [src.name]"
visible_message("<span class='notice'>\The [usr] starts to climb into [src.name]</span>") visible_message("<span class='notice'>\The [usr] starts to climb into [src.name]</span>")

View File

@@ -99,6 +99,14 @@
name = "Dark Gygax wreckage" name = "Dark Gygax wreckage"
icon_state = "darkgygax-broken" icon_state = "darkgygax-broken"
/obj/effect/decal/mecha_wreckage/gygax/adv
name = "Advanced Dark Gygax wreckage"
icon_state = "darkgygax_adv-broken"
/obj/effect/decal/mecha_wreckage/gygax/medgax
name = "Medgax wreckage"
icon_state = "medgax-broken"
/obj/effect/decal/mecha_wreckage/marauder /obj/effect/decal/mecha_wreckage/marauder
name = "Marauder wreckage" name = "Marauder wreckage"
icon_state = "marauder-broken" icon_state = "marauder-broken"
@@ -198,6 +206,9 @@
parts -= part parts -= part
return return
/obj/effect/decal/mecha_wreckage/odysseus/murdysseus
icon_state = "murdysseus-broken"
/obj/effect/decal/mecha_wreckage/hoverpod /obj/effect/decal/mecha_wreckage/hoverpod
name = "Hover pod wreckage" name = "Hover pod wreckage"
icon_state = "engineering_pod-broken" icon_state = "engineering_pod-broken"

View File

@@ -109,7 +109,7 @@
else if(foundVirus) else if(foundVirus)
holder.icon_state = "hudill" holder.icon_state = "hudill"
else if(patient.has_brain_worms()) else if(patient.has_brain_worms())
var/mob/living/simple_animal/borer/B = patient.has_brain_worms() var/mob/living/simple_mob/animal/borer/B = patient.has_brain_worms()
if(B.controlling) if(B.controlling)
holder.icon_state = "hudbrainworm" holder.icon_state = "hudbrainworm"
else else

View File

@@ -250,4 +250,4 @@ var/global/list/image/splatter_cache=list()
/obj/effect/decal/cleanable/mucus/mapped/New() /obj/effect/decal/cleanable/mucus/mapped/New()
..() ..()
virus2 |= new /datum/disease2/disease virus2 |= new /datum/disease2/disease
virus2.makerandom() virus2[1].makerandom()

View File

@@ -99,3 +99,13 @@
mouse_opacity = FALSE mouse_opacity = FALSE
anchored = TRUE anchored = TRUE
plane = ABOVE_PLANE plane = ABOVE_PLANE
// Similar to the tesla ball but doesn't actually do anything and is purely visual.
/obj/effect/overlay/energy_ball
name = "energy ball"
desc = "An energy ball."
icon = 'icons/obj/tesla_engine/energy_ball.dmi'
icon_state = "energy_ball"
plane = PLANE_LIGHTING_ABOVE
pixel_x = -32
pixel_y = -32

View File

@@ -56,13 +56,15 @@
/obj/effect/spider/stickyweb /obj/effect/spider/stickyweb
icon_state = "stickyweb1" icon_state = "stickyweb1"
New()
if(prob(50)) /obj/effect/spider/stickyweb/initialize()
icon_state = "stickyweb2" if(prob(50))
icon_state = "stickyweb2"
return ..()
/obj/effect/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) /obj/effect/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(air_group || (height==0)) return 1 if(air_group || (height==0)) return 1
if(istype(mover, /mob/living/simple_animal/hostile/giant_spider)) if(istype(mover, /mob/living/simple_mob/animal/giant_spider))
return 1 return 1
else if(istype(mover, /mob/living)) else if(istype(mover, /mob/living))
if(prob(50)) if(prob(50))
@@ -80,10 +82,12 @@
var/spiders_min = 6 var/spiders_min = 6
var/spiders_max = 24 var/spiders_max = 24
var/spider_type = /obj/effect/spider/spiderling var/spider_type = /obj/effect/spider/spiderling
New()
pixel_x = rand(3,-3) /obj/effect/spider/eggcluster/initialize()
pixel_y = rand(3,-3) pixel_x = rand(3,-3)
processing_objects |= src pixel_y = rand(3,-3)
processing_objects |= src
return ..()
/obj/effect/spider/eggcluster/New(var/location, var/atom/parent) /obj/effect/spider/eggcluster/New(var/location, var/atom/parent)
get_light_and_color(parent) get_light_and_color(parent)
@@ -129,10 +133,10 @@
var/amount_grown = -1 var/amount_grown = -1
var/obj/machinery/atmospherics/unary/vent_pump/entry_vent var/obj/machinery/atmospherics/unary/vent_pump/entry_vent
var/travelling_in_vent = 0 var/travelling_in_vent = 0
var/list/grow_as = list(/mob/living/simple_animal/hostile/giant_spider, /mob/living/simple_animal/hostile/giant_spider/nurse, /mob/living/simple_animal/hostile/giant_spider/hunter) var/list/grow_as = list(/mob/living/simple_mob/animal/giant_spider, /mob/living/simple_mob/animal/giant_spider/nurse, /mob/living/simple_mob/animal/giant_spider/hunter)
/obj/effect/spider/spiderling/frost /obj/effect/spider/spiderling/frost
grow_as = list(/mob/living/simple_animal/hostile/giant_spider/frost) grow_as = list(/mob/living/simple_mob/animal/giant_spider/frost)
/obj/effect/spider/spiderling/New(var/location, var/atom/parent) /obj/effect/spider/spiderling/New(var/location, var/atom/parent)
pixel_x = rand(6,-6) pixel_x = rand(6,-6)

View File

@@ -107,7 +107,7 @@
return 0 return 0
if(!user.IsAdvancedToolUser() && isanimal(user)) if(!user.IsAdvancedToolUser() && isanimal(user))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = user
if(!S.IsHumanoidToolUser(src)) if(!S.IsHumanoidToolUser(src))
return 0 return 0

View File

@@ -166,7 +166,7 @@
outmsg = "<span class='info'>You missed the lens of [C] with [src].</span>" outmsg = "<span class='info'>You missed the lens of [C] with [src].</span>"
//cats! //cats!
for(var/mob/living/simple_animal/cat/C in viewers(1,targloc)) for(var/mob/living/simple_mob/animal/passive/cat/C in viewers(1,targloc))
if (!(C.stat || C.buckled)) if (!(C.stat || C.buckled))
if(prob(50) && !(C.client)) if(prob(50) && !(C.client))
C.visible_message("<span class='warning'>[C] pounces on the light!</span>", "<span class='warning'>You pounce on the light!</span>") C.visible_message("<span class='warning'>[C] pounces on the light!</span>", "<span class='warning'>You pounce on the light!</span>")

View File

@@ -451,15 +451,15 @@ HALOGEN COUNTER - Radcount on mobs
matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20)
/obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob)
if(!isslime(M)) if(!istype(M, /mob/living/simple_mob/slime/xenobio))
to_chat(user, "<B>This device can only scan slimes!</B>") to_chat(user, "<B>This device can only scan lab-grown slimes!</B>")
return return
var/mob/living/simple_animal/slime/S = M var/mob/living/simple_mob/slime/xenobio/S = M
user.show_message("Slime scan results:<br>[S.slime_color] [S.is_adult ? "adult" : "baby"] slime<br>Health: [S.health]<br>Mutation Probability: [S.mutation_chance]") user.show_message("Slime scan results:<br>[S.slime_color] [S.is_adult ? "adult" : "baby"] slime<br>Health: [S.health]<br>Mutation Probability: [S.mutation_chance]")
var/list/mutations = list() var/list/mutations = list()
for(var/potential_color in S.slime_mutation) for(var/potential_color in S.slime_mutation)
var/mob/living/simple_animal/slime/slime = potential_color var/mob/living/simple_mob/slime/xenobio/slime = potential_color
mutations.Add(initial(slime.slime_color)) mutations.Add(initial(slime.slime_color))
user.show_message("Potental to mutate into [english_list(mutations)] colors.<br>Extract potential: [S.cores]<br>Nutrition: [S.nutrition]/[S.get_max_nutrition()]") user.show_message("Potental to mutate into [english_list(mutations)] colors.<br>Extract potential: [S.cores]<br>Nutrition: [S.nutrition]/[S.get_max_nutrition()]")
@@ -469,12 +469,14 @@ HALOGEN COUNTER - Radcount on mobs
user.show_message("<span class='warning'>Warning: Subject is hungry.</span>") user.show_message("<span class='warning'>Warning: Subject is hungry.</span>")
user.show_message("Electric change strength: [S.power_charge]") user.show_message("Electric change strength: [S.power_charge]")
if(S.resentment) if(S.has_AI())
user.show_message("<span class='warning'>Warning: Subject is harboring resentment.</span>") var/datum/ai_holder/simple_mob/xenobio_slime/AI = S.ai_holder
if(S.docile) if(AI.resentment)
user.show_message("<span class='warning'>Warning: Subject is harboring resentment.</span>")
if(AI.rabid)
user.show_message("<span class='danger'>Subject is enraged and extremely dangerous!</span>")
if(S.harmless)
user.show_message("Subject has been pacified.") user.show_message("Subject has been pacified.")
if(S.rabid)
user.show_message("<span class='danger'>Subject is enraged and extremely dangerous!</span>")
if(S.unity) if(S.unity)
user.show_message("Subject is friendly to other slime colors.") user.show_message("Subject is friendly to other slime colors.")

View File

@@ -6,7 +6,7 @@
w_class = ITEMSIZE_SMALL w_class = ITEMSIZE_SMALL
matter = list("glass" = 200) matter = list("glass" = 200)
flags = NOBLUDGEON flags = NOBLUDGEON
var/list/accept_mobs = list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse) var/list/accept_mobs = list(/mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/mouse)
var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling
/obj/item/glass_jar/New() /obj/item/glass_jar/New()

View File

@@ -47,14 +47,3 @@
processing_objects -= src processing_objects -= src
return ..() return ..()
//Crashed Cargo Shuttle PoI
/obj/structure/largecrate/animal/crashedshuttle
name = "SCP"
/obj/structure/largecrate/animal/crashedshuttle/initialize()
starts_with = list(pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer)) // Starts_with has to be a list
name = pick("Spicy Crust Pizzeria", "Soap and Care Products", "Sally's Computer Parts", "Steve's Chocolate Pastries", "Smith & Christian's Plastics","Standard Containers & Packaging Co.", "Sanitary Chemical Purgation (LTD)")
name += " delivery crate"
return ..()

View File

@@ -275,13 +275,6 @@
add_flashes(W,user) add_flashes(W,user)
else else
add_flashes(W,user) add_flashes(W,user)
else if(istype(W, /obj/item/weapon/stock_parts/manipulator))
to_chat(user, "<span class='notice'>You install some manipulators and modify the head, creating a functional spider-bot!</span>")
new /mob/living/simple_animal/spiderbot(get_turf(loc))
user.drop_item()
qdel(W)
qdel(src)
return
return return
/obj/item/robot_parts/head/proc/add_flashes(obj/item/W as obj, mob/user as mob) //Made into a seperate proc to avoid copypasta /obj/item/robot_parts/head/proc/add_flashes(obj/item/W as obj, mob/user as mob) //Made into a seperate proc to avoid copypasta

2
code/game/objects/items/weapons/AI_modules.dm Executable file → Normal file
View File

@@ -23,7 +23,7 @@ AI MODULES
/obj/item/weapon/aiModule/proc/install(var/atom/movable/AM, var/mob/living/user) /obj/item/weapon/aiModule/proc/install(var/atom/movable/AM, var/mob/living/user)
if(!user.IsAdvancedToolUser() && isanimal(user)) if(!user.IsAdvancedToolUser() && isanimal(user))
var/mob/living/simple_animal/S = user var/mob/living/simple_mob/S = user
if(!S.IsHumanoidToolUser(src)) if(!S.IsHumanoidToolUser(src))
return 0 return 0

View File

@@ -31,19 +31,25 @@
/obj/item/weapon/grenade/spawnergrenade/manhacks /obj/item/weapon/grenade/spawnergrenade/manhacks
name = "manhack delivery grenade" name = "manhack delivery grenade"
spawner_type = /mob/living/simple_animal/hostile/viscerator spawner_type = /mob/living/simple_mob/mechanical/viscerator
deliveryamt = 5 deliveryamt = 5
origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4)
/obj/item/weapon/grenade/spawnergrenade/manhacks/mercenary
spawner_type = /mob/living/simple_mob/mechanical/viscerator/mercenary
/obj/item/weapon/grenade/spawnergrenade/manhacks/raider
spawner_type = /mob/living/simple_mob/mechanical/viscerator/raider
/obj/item/weapon/grenade/spawnergrenade/spesscarp /obj/item/weapon/grenade/spawnergrenade/spesscarp
name = "carp delivery grenade" name = "carp delivery grenade"
spawner_type = /mob/living/simple_animal/hostile/carp spawner_type = /mob/living/simple_mob/animal/space/carp
deliveryamt = 5 deliveryamt = 5
origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4)
/obj/item/weapon/grenade/spawnergrenade/spider /obj/item/weapon/grenade/spawnergrenade/spider
name = "spider delivery grenade" name = "spider delivery grenade"
spawner_type = /mob/living/simple_animal/hostile/giant_spider/hunter spawner_type = /mob/living/simple_mob/animal/giant_spider/hunter
deliveryamt = 3 deliveryamt = 3
origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4)

View File

@@ -336,4 +336,4 @@ var/last_chew = 0
target.m_intent = "walk" target.m_intent = "walk"
if(target.hud_used && user.hud_used.move_intent) if(target.hud_used && user.hud_used.move_intent)
target.hud_used.move_intent.icon_state = "walking" target.hud_used.move_intent.icon_state = "walking"
return 1 return 1

View File

@@ -79,10 +79,9 @@
var/obj/item/weapon/grab/grab = G var/obj/item/weapon/grab/grab = G
if(!ismob(grab.affecting)) if(!ismob(grab.affecting))
return return
for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting)) if(grab.affecting.has_buckled_mobs())
if(M.victim == grab.affecting) to_chat(user, span("warning", "\The [grab.affecting] has other entities attached to them. Remove them first."))
usr << "[grab.affecting.name] will not fit into the [src.name] because they have a slime latched onto their head." return
return
var/mob/M = grab.affecting var/mob/M = grab.affecting
if(put_mob(M)) if(put_mob(M))
qdel(G) qdel(G)

View File

@@ -233,11 +233,10 @@
playsound(get_turf(target), 'sound/weapons/blade1.ogg', 100, 1) playsound(get_turf(target), 'sound/weapons/blade1.ogg', 100, 1)
// Make lesser robots really mad at us. // Make lesser robots really mad at us.
if(istype(target, /mob/living/simple_animal)) if(target.mob_class & MOB_CLASS_SYNTHETIC)
var/mob/living/simple_animal/SA = target if(target.has_AI())
if(SA.intelligence_level == SA_ROBOTIC) target.taunt(user)
SA.taunt(user) target.adjustFireLoss(force * 6) // 30 Burn, for 50 total.
SA.adjustFireLoss(force * 6) // 30 Burn, for 50 total.
/* /*
*Energy Blade *Energy Blade

View File

@@ -292,7 +292,7 @@ var/list/tape_roll_applications = list()
add_fingerprint(M) add_fingerprint(M)
if (!allowed(M)) //only select few learn art of not crumpling the tape if (!allowed(M)) //only select few learn art of not crumpling the tape
M << "<span class='warning'>You are not supposed to go past [src]...</span>" M << "<span class='warning'>You are not supposed to go past [src]...</span>"
if(M.a_intent == I_HELP && !(istype(M, /mob/living/simple_animal))) if(M.a_intent == I_HELP && !(istype(M, /mob/living/simple_mob)))
return 0 return 0
crumple() crumple()
return ..(mover) return ..(mover)

View File

@@ -269,9 +269,8 @@
/obj/item/weapon/melee/baton/shocker/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) /obj/item/weapon/melee/baton/shocker/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
..(target, user, hit_zone) ..(target, user, hit_zone)
if(istype(target, /mob/living/simple_animal) && status) if(status && target.has_AI())
var/mob/living/simple_animal/SA = target target.taunt(user)
SA.taunt(user)
// Borg version, for the lost module. // Borg version, for the lost module.
/obj/item/weapon/melee/baton/shocker/robot /obj/item/weapon/melee/baton/shocker/robot

View File

@@ -122,4 +122,4 @@
counterpart.forceMove(get_turf(src)) counterpart.forceMove(get_turf(src))
src.forceMove(counterpart) src.forceMove(counterpart)
user.put_in_active_hand(counterpart) user.put_in_active_hand(counterpart)
to_chat(user, "<span class='notice'>You attach the bolt driver bit to [src].</span>") to_chat(user, "<span class='notice'>You attach the bolt driver bit to [src].</span>")

File diff suppressed because it is too large Load Diff

View File

@@ -68,4 +68,4 @@
counterpart.forceMove(get_turf(src)) counterpart.forceMove(get_turf(src))
src.forceMove(counterpart) src.forceMove(counterpart)
user.put_in_active_hand(counterpart) user.put_in_active_hand(counterpart)
to_chat(user, "<span class='notice'>You attach the screw driver bit to [src].</span>") to_chat(user, "<span class='notice'>You attach the screw driver bit to [src].</span>")

View File

@@ -9,8 +9,8 @@
var/spawn_delay = 10 MINUTES var/spawn_delay = 10 MINUTES
var/list/spawn_types = list( var/list/spawn_types = list(
/mob/living/simple_animal/corgi = 100, /mob/living/simple_mob/animal/passive/dog/corgi = 100,
/mob/living/simple_animal/cat = 25 /mob/living/simple_mob/animal/passive/cat = 25
) )
var/total_spawns = -1 //Total mob spawns, over all time, -1 for no limit var/total_spawns = -1 //Total mob spawns, over all time, -1 for no limit
@@ -129,15 +129,14 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
////////////// //////////////
// Spawners // // Spawners //
///////////// /////////////
/obj/structure/mob_spawner/scanner/corgi /obj/structure/mob_spawner/scanner/corgi
name = "Corgi Lazy Spawner" name = "Corgi Lazy Spawner"
desc = "This is a proof of concept, not sure why you would use this one" desc = "This is a proof of concept, not sure why you would use this one"
spawn_delay = 3 MINUTES spawn_delay = 3 MINUTES
mob_faction = "Corgi" mob_faction = "Corgi"
spawn_types = list( spawn_types = list(
/mob/living/simple_animal/corgi = 75, /mob/living/simple_mob/animal/passive/dog/corgi = 75,
/mob/living/simple_animal/corgi/puppy = 50 /mob/living/simple_mob/animal/passive/dog/corgi/puppy = 50
) )
simultaneous_spawns = 5 simultaneous_spawns = 5
@@ -157,10 +156,10 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
anchored = 1 anchored = 1
invisibility = 101 invisibility = 101
spawn_types = list( spawn_types = list(
/mob/living/simple_animal/retaliate/gaslamp = 20, /mob/living/simple_mob/animal/space/gaslamp = 20,
/mob/living/simple_animal/otie/feral = 10, // /mob/living/simple_mob/otie/feral = 10,
/mob/living/simple_animal/hostile/dino/virgo3b = 5, /mob/living/simple_mob/vore/dino/virgo3b = 5,
/mob/living/simple_animal/hostile/dragon/virgo3b = 1 /mob/living/simple_mob/vore/dragon/virgo3b = 1
) )
/obj/structure/mob_spawner/scanner/xenos /obj/structure/mob_spawner/scanner/xenos
@@ -176,10 +175,10 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
icon = 'icons/mob/actions.dmi' icon = 'icons/mob/actions.dmi'
icon_state = "alien_egg" icon_state = "alien_egg"
spawn_types = list( spawn_types = list(
/mob/living/simple_animal/hostile/alien/drone = 20, /mob/living/simple_mob/animal/space/alien/drone = 20,
/mob/living/simple_animal/hostile/alien = 10, /mob/living/simple_mob/animal/space/alien = 10,
/mob/living/simple_animal/hostile/alien/sentinel = 5, /mob/living/simple_mob/animal/space/alien/sentinel = 5,
/mob/living/simple_animal/hostile/alien/queen = 1 /mob/living/simple_mob/animal/space/alien/queen = 1
) )
/obj/structure/mob_spawner/scanner/xenos/royal /obj/structure/mob_spawner/scanner/xenos/royal
@@ -195,5 +194,5 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
icon = 'icons/mob/actions.dmi' icon = 'icons/mob/actions.dmi'
icon_state = "alien_egg" icon_state = "alien_egg"
spawn_types = list( spawn_types = list(
/mob/living/simple_animal/hostile/alien/queen = 5, /mob/living/simple_mob/animal/space/alien/queen = 5,
) )

View File

@@ -18,44 +18,47 @@
var/mob_retaliate = 0 var/mob_retaliate = 0
/obj/random/mob/item_to_spawn() /obj/random/mob/item_to_spawn()
return pick(prob(10);/mob/living/simple_animal/lizard, return pick(prob(10);/mob/living/simple_mob/animal/passive/lizard,
prob(6);/mob/living/simple_animal/retaliate/diyaab, prob(6);/mob/living/simple_mob/animal/sif/diyaab,
prob(10);/mob/living/simple_animal/cat/fluff, prob(10);/mob/living/simple_mob/animal/passive/cat,
prob(6);/mob/living/simple_animal/cat/kitten, prob(6);/mob/living/simple_mob/animal/passive/cat,
prob(10);/mob/living/simple_animal/corgi, prob(10);/mob/living/simple_mob/animal/passive/dog/corgi,
prob(6);/mob/living/simple_animal/corgi/puppy, prob(6);/mob/living/simple_mob/animal/passive/dog/corgi/puppy,
prob(10);/mob/living/simple_animal/crab, prob(10);/mob/living/simple_mob/animal/passive/crab,
prob(10);/mob/living/simple_animal/chicken, prob(10);/mob/living/simple_mob/animal/passive/chicken,
prob(6);/mob/living/simple_animal/chick, prob(6);/mob/living/simple_mob/animal/passive/chick,
prob(10);/mob/living/simple_animal/cow, prob(10);/mob/living/simple_mob/animal/passive/cow,
prob(6);/mob/living/simple_animal/retaliate/goat, prob(6);/mob/living/simple_mob/animal/goat,
prob(10);/mob/living/simple_animal/penguin, prob(10);/mob/living/simple_mob/animal/passive/penguin,
prob(10);/mob/living/simple_animal/mouse, prob(10);/mob/living/simple_mob/animal/passive/mouse,
prob(10);/mob/living/simple_animal/yithian, prob(10);/mob/living/simple_mob/animal/passive/yithian,
prob(10);/mob/living/simple_animal/tindalos, prob(10);/mob/living/simple_mob/animal/passive/tindalos,
prob(10);/mob/living/simple_animal/corgi/tamaskan, prob(10);/mob/living/simple_mob/animal/passive/dog/tamaskan,
prob(3);/mob/living/simple_animal/parrot, prob(3);/mob/living/simple_mob/animal/passive/bird/parrot,
prob(1);/mob/living/simple_animal/giant_crab) prob(1);/mob/living/simple_mob/animal/passive/crab)
/obj/random/mob/spawn_item() //These should only ever have simple mobs. /obj/random/mob/spawn_item() //These should only ever have simple mobs.
var/build_path = item_to_spawn() var/build_path = item_to_spawn()
var/mob/living/simple_animal/M = new build_path(src.loc) var/mob/living/simple_mob/M = new build_path(src.loc)
M.ai_inactive = 1 //Don't fight eachother while we're still setting up! if(!istype(M))
if(mob_faction) return
M.faction = mob_faction if(M.has_AI())
M.returns_home = mob_returns_home var/datum/ai_holder/AI = M.ai_holder
M.wander = mob_wander AI.go_sleep() //Don't fight eachother while we're still setting up!
M.wander_distance = mob_wander_distance AI.returns_home = mob_returns_home
if(overwrite_hostility) AI.wander = mob_wander
M.hostile = mob_hostile AI.max_home_distance = mob_wander_distance
M.retaliate = mob_retaliate if(overwrite_hostility)
M.ai_inactive = 0 //Now you can kill eachother if your faction didn't override. AI.hostile = mob_hostile
AI.retaliate = mob_retaliate
AI.go_wake() //Now you can kill eachother if your faction didn't override.
if(pixel_x || pixel_y) if(pixel_x || pixel_y)
M.pixel_x = pixel_x M.pixel_x = pixel_x
M.pixel_y = pixel_y M.pixel_y = pixel_y
/obj/random/mob/sif /obj/random/mob/sif
name = "Random Sif Animal" name = "Random Sif Animal"
desc = "This is a random cold weather animal." desc = "This is a random cold weather animal."
@@ -65,14 +68,14 @@
mob_wander_distance = 10 mob_wander_distance = 10
/obj/random/mob/sif/item_to_spawn() /obj/random/mob/sif/item_to_spawn()
return pick(prob(30);/mob/living/simple_animal/retaliate/diyaab, return pick(prob(30);/mob/living/simple_mob/animal/sif/diyaab,
prob(15);/mob/living/simple_animal/crab, prob(15);/mob/living/simple_mob/animal/passive/crab,
prob(15);/mob/living/simple_animal/penguin, prob(15);/mob/living/simple_mob/animal/passive/penguin,
prob(15);/mob/living/simple_animal/mouse, prob(15);/mob/living/simple_mob/animal/passive/mouse,
prob(15);/mob/living/simple_animal/corgi/tamaskan, prob(15);/mob/living/simple_mob/animal/passive/dog/tamaskan,
prob(2);/mob/living/simple_animal/hostile/giant_spider/frost, prob(2);/mob/living/simple_mob/animal/giant_spider/frost,
prob(1);/mob/living/simple_animal/hostile/goose, prob(1);/mob/living/simple_mob/animal/space/goose,
prob(20);/mob/living/simple_animal/giant_crab) prob(20);/mob/living/simple_mob/animal/passive/crab)
/obj/random/mob/sif/peaceful /obj/random/mob/sif/peaceful
@@ -84,12 +87,12 @@
mob_wander_distance = 12 mob_wander_distance = 12
/obj/random/mob/sif/peaceful/item_to_spawn() /obj/random/mob/sif/peaceful/item_to_spawn()
return pick(prob(30);/mob/living/simple_animal/retaliate/diyaab, return pick(prob(30);/mob/living/simple_mob/animal/sif/diyaab,
prob(15);/mob/living/simple_animal/crab, prob(15);/mob/living/simple_mob/animal/passive/crab,
prob(15);/mob/living/simple_animal/penguin, prob(15);/mob/living/simple_mob/animal/passive/penguin,
prob(15);/mob/living/simple_animal/mouse, prob(15);/mob/living/simple_mob/animal/passive/mouse,
prob(15);/mob/living/simple_animal/corgi/tamaskan, prob(15);/mob/living/simple_mob/animal/passive/dog/tamaskan,
prob(20);/mob/living/simple_animal/giant_crab) prob(20);/mob/living/simple_mob/animal/sif/hooligan_crab)
/obj/random/mob/sif/hostile /obj/random/mob/sif/hostile
name = "Random Hostile Sif Animal" name = "Random Hostile Sif Animal"
@@ -97,9 +100,9 @@
icon_state = "frost" icon_state = "frost"
/obj/random/mob/sif/hostile/item_to_spawn() /obj/random/mob/sif/hostile/item_to_spawn()
return pick(prob(22);/mob/living/simple_animal/hostile/savik, return pick(prob(22);/mob/living/simple_mob/animal/sif/savik,
prob(33);/mob/living/simple_animal/hostile/giant_spider/frost, prob(33);/mob/living/simple_mob/animal/giant_spider/frost,
prob(45);/mob/living/simple_animal/hostile/shantak) prob(45);/mob/living/simple_mob/animal/sif/shantak)
/obj/random/mob/spider /obj/random/mob/spider
name = "Random Spider" //Spiders should patrol where they spawn. name = "Random Spider" //Spiders should patrol where they spawn.
@@ -110,9 +113,9 @@
mob_wander_distance = 4 mob_wander_distance = 4
/obj/random/mob/spider/item_to_spawn() /obj/random/mob/spider/item_to_spawn()
return pick(prob(22);/mob/living/simple_animal/hostile/giant_spider/nurse, return pick(prob(22);/mob/living/simple_mob/animal/giant_spider/nurse,
prob(33);/mob/living/simple_animal/hostile/giant_spider/hunter, prob(33);/mob/living/simple_mob/animal/giant_spider/hunter,
prob(45);/mob/living/simple_animal/hostile/giant_spider) prob(45);/mob/living/simple_mob/animal/giant_spider)
/obj/random/mob/spider/nurse /obj/random/mob/spider/nurse
name = "Random Nurse Spider" name = "Random Nurse Spider"
@@ -123,8 +126,8 @@
mob_wander_distance = 4 mob_wander_distance = 4
/obj/random/mob/spider/nurse/item_to_spawn() /obj/random/mob/spider/nurse/item_to_spawn()
return pick(prob(22);/mob/living/simple_animal/hostile/giant_spider/nurse/hat, return pick(prob(22);/mob/living/simple_mob/animal/giant_spider/nurse/hat,
prob(45);/mob/living/simple_animal/hostile/giant_spider/nurse) prob(45);/mob/living/simple_mob/animal/giant_spider/nurse)
/obj/random/mob/spider/mutant /obj/random/mob/spider/mutant
name = "Random Mutant Spider" name = "Random Mutant Spider"
@@ -133,15 +136,15 @@
/obj/random/mob/spider/mutant/item_to_spawn() /obj/random/mob/spider/mutant/item_to_spawn()
return pick(prob(5);/obj/random/mob/spider, return pick(prob(5);/obj/random/mob/spider,
prob(10);/mob/living/simple_animal/hostile/giant_spider/webslinger, prob(10);/mob/living/simple_mob/animal/giant_spider/webslinger,
prob(10);/mob/living/simple_animal/hostile/giant_spider/carrier, prob(10);/mob/living/simple_mob/animal/giant_spider/carrier,
prob(33);/mob/living/simple_animal/hostile/giant_spider/lurker, prob(33);/mob/living/simple_mob/animal/giant_spider/lurker,
prob(33);/mob/living/simple_animal/hostile/giant_spider/tunneler, prob(33);/mob/living/simple_mob/animal/giant_spider/tunneler,
prob(40);/mob/living/simple_animal/hostile/giant_spider/pepper, prob(40);/mob/living/simple_mob/animal/giant_spider/pepper,
prob(20);/mob/living/simple_animal/hostile/giant_spider/thermic, prob(20);/mob/living/simple_mob/animal/giant_spider/thermic,
prob(40);/mob/living/simple_animal/hostile/giant_spider/electric, prob(40);/mob/living/simple_mob/animal/giant_spider/electric,
prob(1);/mob/living/simple_animal/hostile/giant_spider/phorogenic, prob(1);/mob/living/simple_mob/animal/giant_spider/phorogenic,
prob(40);/mob/living/simple_animal/hostile/giant_spider/frost) prob(40);/mob/living/simple_mob/animal/giant_spider/frost)
/obj/random/mob/robotic /obj/random/mob/robotic
name = "Random Robot Mob" name = "Random Robot Mob"
@@ -158,17 +161,18 @@
mob_retaliate = 1 mob_retaliate = 1
/obj/random/mob/robotic/item_to_spawn() //Hivebots have a total number of 'lots' equal to the lesser drone, at 60. /obj/random/mob/robotic/item_to_spawn() //Hivebots have a total number of 'lots' equal to the lesser drone, at 60.
return pick(prob(60);/mob/living/simple_animal/hostile/malf_drone/lesser, return pick(prob(60);/mob/living/simple_mob/mechanical/combat_drone/lesser,
prob(50);/mob/living/simple_animal/hostile/malf_drone, prob(50);/mob/living/simple_mob/mechanical/combat_drone,
prob(15);/mob/living/simple_animal/hostile/mecha/malf_drone, prob(15);/mob/living/simple_mob/mechanical/mecha/ripley,
prob(10);/mob/living/simple_animal/hostile/hivebot, prob(15);/mob/living/simple_mob/mechanical/mecha/odysseus,
prob(15);/mob/living/simple_animal/hostile/hivebot/swarm, prob(10);/mob/living/simple_mob/mechanical/hivebot,
prob(10);/mob/living/simple_animal/hostile/hivebot/range, prob(15);/mob/living/simple_mob/mechanical/hivebot/swarm,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/rapid, prob(10);/mob/living/simple_mob/mechanical/hivebot/ranged_damage,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/ion, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/rapid,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/laser, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/ion,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/strong, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/guard) prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong,
prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong/guard)
/obj/random/mob/robotic/hivebot /obj/random/mob/robotic/hivebot
name = "Random Hivebot" name = "Random Hivebot"
@@ -178,14 +182,14 @@
mob_faction = "hivebot" mob_faction = "hivebot"
/obj/random/mob/robotic/hivebot/item_to_spawn() /obj/random/mob/robotic/hivebot/item_to_spawn()
return pick(prob(10);/mob/living/simple_animal/hostile/hivebot, return pick(prob(10);/mob/living/simple_mob/mechanical/hivebot,
prob(15);/mob/living/simple_animal/hostile/hivebot/swarm, prob(15);/mob/living/simple_mob/mechanical/hivebot/swarm,
prob(10);/mob/living/simple_animal/hostile/hivebot/range, prob(10);/mob/living/simple_mob/mechanical/hivebot/ranged_damage,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/rapid, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/rapid,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/ion, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/ion,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/laser, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/strong, prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/guard) prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong/guard)
//Mice //Mice
@@ -195,7 +199,7 @@
icon_state = "mouse_gray" icon_state = "mouse_gray"
/obj/random/mob/mouse/item_to_spawn() /obj/random/mob/mouse/item_to_spawn()
return pick(prob(15);/mob/living/simple_animal/mouse/white, return pick(prob(15);/mob/living/simple_mob/animal/passive/mouse/white,
prob(30);/mob/living/simple_animal/mouse/brown, prob(30);/mob/living/simple_mob/animal/passive/mouse/brown,
prob(30);/mob/living/simple_animal/mouse/gray, prob(30);/mob/living/simple_mob/animal/passive/mouse/gray,
prob(25);/obj/random/mouseremains) //because figuring out how to come up with it picking nothing is beyond my coding ability. prob(25);/obj/random/mouseremains) //because figuring out how to come up with it picking nothing is beyond my coding ability.

View File

@@ -1531,24 +1531,24 @@ var/list/multi_point_spawns
icon_state = "chicken_white" icon_state = "chicken_white"
/obj/random/mob/item_to_spawn() /obj/random/mob/item_to_spawn()
return pick(prob(10);/mob/living/simple_animal/lizard, return pick(prob(10);/mob/living/simple_mob/lizard,
prob(6);/mob/living/simple_animal/retaliate/diyaab, prob(6);/mob/living/simple_mob/retaliate/diyaab,
prob(10);/mob/living/simple_animal/cat/fluff, prob(10);/mob/living/simple_mob/cat/fluff,
prob(6);/mob/living/simple_animal/cat/kitten, prob(6);/mob/living/simple_mob/cat/kitten,
prob(10);/mob/living/simple_animal/corgi, prob(10);/mob/living/simple_mob/corgi,
prob(6);/mob/living/simple_animal/corgi/puppy, prob(6);/mob/living/simple_mob/corgi/puppy,
prob(10);/mob/living/simple_animal/crab, prob(10);/mob/living/simple_mob/crab,
prob(10);/mob/living/simple_animal/chicken, prob(10);/mob/living/simple_mob/chicken,
prob(6);/mob/living/simple_animal/chick, prob(6);/mob/living/simple_mob/chick,
prob(10);/mob/living/simple_animal/cow, prob(10);/mob/living/simple_mob/cow,
prob(6);/mob/living/simple_animal/retaliate/goat, prob(6);/mob/living/simple_mob/retaliate/goat,
prob(10);/mob/living/simple_animal/penguin, prob(10);/mob/living/simple_mob/penguin,
prob(10);/mob/living/simple_animal/mouse, prob(10);/mob/living/simple_mob/mouse,
prob(10);/mob/living/simple_animal/yithian, prob(10);/mob/living/simple_mob/yithian,
prob(10);/mob/living/simple_animal/tindalos, prob(10);/mob/living/simple_mob/tindalos,
prob(10);/mob/living/simple_animal/corgi/tamaskan, prob(10);/mob/living/simple_mob/corgi/tamaskan,
prob(3);/mob/living/simple_animal/parrot, prob(3);/mob/living/simple_mob/parrot,
prob(1);/mob/living/simple_animal/giant_crab) prob(1);/mob/living/simple_mob/giant_crab)
/obj/random/mob/sif /obj/random/mob/sif
name = "Random Sif Animal" name = "Random Sif Animal"
@@ -1556,14 +1556,14 @@ var/list/multi_point_spawns
icon_state = "penguin" icon_state = "penguin"
/obj/random/mob/sif/item_to_spawn() /obj/random/mob/sif/item_to_spawn()
return pick(prob(30);/mob/living/simple_animal/retaliate/diyaab, return pick(prob(30);/mob/living/simple_mob/retaliate/diyaab,
prob(15);/mob/living/simple_animal/crab, prob(15);/mob/living/simple_mob/crab,
prob(15);/mob/living/simple_animal/penguin, prob(15);/mob/living/simple_mob/penguin,
prob(15);/mob/living/simple_animal/mouse, prob(15);/mob/living/simple_mob/mouse,
prob(15);/mob/living/simple_animal/corgi/tamaskan, prob(15);/mob/living/simple_mob/corgi/tamaskan,
prob(2);/mob/living/simple_animal/hostile/giant_spider/frost, prob(2);/mob/living/simple_mob/hostile/giant_spider/frost,
prob(1);/mob/living/simple_animal/hostile/goose, prob(1);/mob/living/simple_mob/hostile/goose,
prob(20);/mob/living/simple_animal/giant_crab) prob(20);/mob/living/simple_mob/giant_crab)
/obj/random/mob/sif/hostile /obj/random/mob/sif/hostile
name = "Random Hostile Sif Animal" name = "Random Hostile Sif Animal"
@@ -1571,9 +1571,9 @@ var/list/multi_point_spawns
icon_state = "frost" icon_state = "frost"
/obj/random/mob/sif/hostile/item_to_spawn() /obj/random/mob/sif/hostile/item_to_spawn()
return pick(prob(22);/mob/living/simple_animal/hostile/savik, return pick(prob(22);/mob/living/simple_mob/hostile/savik,
prob(33);/mob/living/simple_animal/hostile/giant_spider/frost, prob(33);/mob/living/simple_mob/hostile/giant_spider/frost,
prob(45);/mob/living/simple_animal/hostile/shantak) prob(45);/mob/living/simple_mob/hostile/shantak)
/obj/random/mob/spider /obj/random/mob/spider
name = "Random Spider" name = "Random Spider"
@@ -1581,9 +1581,9 @@ var/list/multi_point_spawns
icon_state = "guard" icon_state = "guard"
/obj/random/mob/spider/item_to_spawn() /obj/random/mob/spider/item_to_spawn()
return pick(prob(22);/mob/living/simple_animal/hostile/giant_spider/nurse, return pick(prob(22);/mob/living/simple_mob/hostile/giant_spider/nurse,
prob(33);/mob/living/simple_animal/hostile/giant_spider/hunter, prob(33);/mob/living/simple_mob/hostile/giant_spider/hunter,
prob(45);/mob/living/simple_animal/hostile/giant_spider) prob(45);/mob/living/simple_mob/hostile/giant_spider)
/obj/random/mob/spider/mutant /obj/random/mob/spider/mutant
name = "Random Mutant Spider" name = "Random Mutant Spider"
@@ -1592,15 +1592,15 @@ var/list/multi_point_spawns
/obj/random/mob/spider/mutant/item_to_spawn() /obj/random/mob/spider/mutant/item_to_spawn()
return pick(prob(5);/obj/random/mob/spider, return pick(prob(5);/obj/random/mob/spider,
prob(10);/mob/living/simple_animal/hostile/giant_spider/webslinger, prob(10);/mob/living/simple_mob/hostile/giant_spider/webslinger,
prob(10);/mob/living/simple_animal/hostile/giant_spider/carrier, prob(10);/mob/living/simple_mob/hostile/giant_spider/carrier,
prob(33);/mob/living/simple_animal/hostile/giant_spider/lurker, prob(33);/mob/living/simple_mob/hostile/giant_spider/lurker,
prob(33);/mob/living/simple_animal/hostile/giant_spider/tunneler, prob(33);/mob/living/simple_mob/hostile/giant_spider/tunneler,
prob(40);/mob/living/simple_animal/hostile/giant_spider/pepper, prob(40);/mob/living/simple_mob/hostile/giant_spider/pepper,
prob(20);/mob/living/simple_animal/hostile/giant_spider/thermic, prob(20);/mob/living/simple_mob/hostile/giant_spider/thermic,
prob(40);/mob/living/simple_animal/hostile/giant_spider/electric, prob(40);/mob/living/simple_mob/hostile/giant_spider/electric,
prob(1);/mob/living/simple_animal/hostile/giant_spider/phorogenic, prob(1);/mob/living/simple_mob/hostile/giant_spider/phorogenic,
prob(40);/mob/living/simple_animal/hostile/giant_spider/frost) prob(40);/mob/living/simple_mob/hostile/giant_spider/frost)
/obj/random/mob/robotic /obj/random/mob/robotic
name = "Random Robot Mob" name = "Random Robot Mob"
@@ -1608,17 +1608,17 @@ var/list/multi_point_spawns
icon_state = "drone_dead" icon_state = "drone_dead"
/obj/random/mob/robotic/item_to_spawn() //Hivebots have a total number of 'lots' equal to the lesser drone, at 60. /obj/random/mob/robotic/item_to_spawn() //Hivebots have a total number of 'lots' equal to the lesser drone, at 60.
return pick(prob(60);/mob/living/simple_animal/hostile/malf_drone/lesser, return pick(prob(60);/mob/living/simple_mob/hostile/malf_drone/lesser,
prob(50);/mob/living/simple_animal/hostile/malf_drone, prob(50);/mob/living/simple_mob/hostile/malf_drone,
prob(15);/mob/living/simple_animal/hostile/mecha/malf_drone, prob(15);/mob/living/simple_mob/hostile/mecha/malf_drone,
prob(10);/mob/living/simple_animal/hostile/hivebot, prob(10);/mob/living/simple_mob/hostile/hivebot,
prob(15);/mob/living/simple_animal/hostile/hivebot/swarm, prob(15);/mob/living/simple_mob/hostile/hivebot/swarm,
prob(10);/mob/living/simple_animal/hostile/hivebot/range, prob(10);/mob/living/simple_mob/hostile/hivebot/range,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/rapid, prob(5);/mob/living/simple_mob/hostile/hivebot/range/rapid,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/ion, prob(5);/mob/living/simple_mob/hostile/hivebot/range/ion,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/laser, prob(5);/mob/living/simple_mob/hostile/hivebot/range/laser,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/strong, prob(5);/mob/living/simple_mob/hostile/hivebot/range/strong,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/guard) prob(5);/mob/living/simple_mob/hostile/hivebot/range/guard)
/obj/random/mob/robotic/hivebot /obj/random/mob/robotic/hivebot
name = "Random Hivebot" name = "Random Hivebot"
@@ -1626,11 +1626,11 @@ var/list/multi_point_spawns
icon_state = "drone3" icon_state = "drone3"
/obj/random/mob/robotic/hivebot/item_to_spawn() /obj/random/mob/robotic/hivebot/item_to_spawn()
return pick(prob(10);/mob/living/simple_animal/hostile/hivebot, return pick(prob(10);/mob/living/simple_mob/hostile/hivebot,
prob(15);/mob/living/simple_animal/hostile/hivebot/swarm, prob(15);/mob/living/simple_mob/hostile/hivebot/swarm,
prob(10);/mob/living/simple_animal/hostile/hivebot/range, prob(10);/mob/living/simple_mob/hostile/hivebot/range,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/rapid, prob(5);/mob/living/simple_mob/hostile/hivebot/range/rapid,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/ion, prob(5);/mob/living/simple_mob/hostile/hivebot/range/ion,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/laser, prob(5);/mob/living/simple_mob/hostile/hivebot/range/laser,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/strong, prob(5);/mob/living/simple_mob/hostile/hivebot/range/strong,
prob(5);/mob/living/simple_animal/hostile/hivebot/range/guard) prob(5);/mob/living/simple_mob/hostile/hivebot/range/guard)

View File

@@ -181,15 +181,15 @@
/obj/random/outside_mob/item_to_spawn() // Special version for mobs to have the same faction. /obj/random/outside_mob/item_to_spawn() // Special version for mobs to have the same faction.
return pick( return pick(
prob(50);/mob/living/simple_animal/retaliate/gaslamp, prob(50);/mob/living/simple_mob/animal/space/gaslamp,
// prob(50);/mob/living/simple_animal/otie/feral, // Removed until Otie code is unfucked. // prob(50);/mob/living/simple_mob/otie/feral, // Removed until Otie code is unfucked.
prob(20);/mob/living/simple_animal/hostile/dino/virgo3b, prob(20);/mob/living/simple_mob/vore/dino/virgo3b,
prob(1);/mob/living/simple_animal/hostile/dragon/virgo3b) prob(1);/mob/living/simple_mob/vore/dragon/virgo3b)
/obj/random/outside_mob/spawn_item() /obj/random/outside_mob/spawn_item()
. = ..() . = ..()
if(istype(., /mob/living/simple_animal)) if(istype(., /mob/living/simple_mob))
var/mob/living/simple_animal/this_mob = . var/mob/living/simple_mob/this_mob = .
this_mob.faction = src.faction this_mob.faction = src.faction
if (this_mob.minbodytemp > 200) // Temporary hotfix. Eventually I'll add code to change all mob vars to fit the environment they are spawned in. if (this_mob.minbodytemp > 200) // Temporary hotfix. Eventually I'll add code to change all mob vars to fit the environment they are spawned in.
this_mob.minbodytemp = 200 this_mob.minbodytemp = 200

View File

@@ -176,8 +176,8 @@
return 0 return 0
return 1 return 1
/obj/structure/attack_generic(var/mob/user, var/damage, var/attack_verb, var/wallbreaker) /obj/structure/attack_generic(var/mob/user, var/damage, var/attack_verb)
if(!breakable || damage < 10 || !wallbreaker) if(!breakable || damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
return 0 return 0
visible_message("<span class='danger'>[user] [attack_verb] the [src] apart!</span>") visible_message("<span class='danger'>[user] [attack_verb] the [src] apart!</span>")
user.do_attack_animation(src) user.do_attack_animation(src)

View File

@@ -381,8 +381,8 @@
else else
icon_state = icon_opened icon_state = icon_opened
/obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys", var/wallbreaker) /obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys")
if(damage < 10 || !wallbreaker) if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
return return
user.do_attack_animation(src) user.do_attack_animation(src)
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>") visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")
@@ -459,4 +459,4 @@
if(src.loc) if(src.loc)
if(istype(src.loc, /obj/structure/closet)) if(istype(src.loc, /obj/structure/closet))
return (loc.return_air_for_internal_lifeform(L)) return (loc.return_air_for_internal_lifeform(L))
return return_air() return return_air()

View File

@@ -90,23 +90,23 @@
/obj/structure/largecrate/animal/corgi /obj/structure/largecrate/animal/corgi
name = "corgi carrier" name = "corgi carrier"
starts_with = list(/mob/living/simple_animal/corgi) starts_with = list(/mob/living/simple_mob/animal/passive/dog/corgi)
/obj/structure/largecrate/animal/cow /obj/structure/largecrate/animal/cow
name = "cow crate" name = "cow crate"
starts_with = list(/mob/living/simple_animal/cow) starts_with = list(/mob/living/simple_mob/animal/passive/cow)
/obj/structure/largecrate/animal/goat /obj/structure/largecrate/animal/goat
name = "goat crate" name = "goat crate"
starts_with = list(/mob/living/simple_animal/retaliate/goat) starts_with = list(/mob/living/simple_mob/animal/goat)
/obj/structure/largecrate/animal/cat /obj/structure/largecrate/animal/cat
name = "cat carrier" name = "cat carrier"
starts_with = list(/mob/living/simple_animal/cat) starts_with = list(/mob/living/simple_mob/animal/passive/cat)
/obj/structure/largecrate/animal/cat/bones /obj/structure/largecrate/animal/cat/bones
starts_with = list(/mob/living/simple_animal/cat/fluff/bones) starts_with = list(/mob/living/simple_mob/animal/passive/cat/bones)
/obj/structure/largecrate/animal/chick /obj/structure/largecrate/animal/chick
name = "chicken crate" name = "chicken crate"
starts_with = list(/mob/living/simple_animal/chick = 5) starts_with = list(/mob/living/simple_mob/animal/passive/chick = 5)

View File

@@ -5,28 +5,27 @@
/obj/structure/largecrate/birds/attackby(obj/item/weapon/W as obj, mob/user as mob) /obj/structure/largecrate/birds/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_crowbar()) if(W.is_crowbar())
new /obj/item/stack/material/wood(src) new /obj/item/stack/material/wood(src)
new /mob/living/simple_animal/bird(src) new /mob/living/simple_mob/animal/passive/bird(src)
new /mob/living/simple_animal/bird/kea(src) new /mob/living/simple_mob/animal/passive/bird/parrot/kea(src)
new /mob/living/simple_animal/bird/eclectus(src) new /mob/living/simple_mob/animal/passive/bird/parrot/eclectus(src)
new /mob/living/simple_animal/bird/greybird(src) new /mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot(src)
new /mob/living/simple_animal/bird/eclectusf(src) new /mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique(src)
new /mob/living/simple_animal/bird/blue_caique(src) new /mob/living/simple_mob/animal/passive/bird/parrot/white_caique(src)
new /mob/living/simple_animal/bird/white_caique(src) new /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar(src)
new /mob/living/simple_animal/bird/green_budgerigar(src) new /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue(src)
new /mob/living/simple_animal/bird/blue_Budgerigar(src) new /mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen(src)
new /mob/living/simple_animal/bird/bluegreen_Budgerigar(src) new /mob/living/simple_mob/animal/passive/bird/black_bird(src)
new /mob/living/simple_animal/bird/commonblackbird(src) new /mob/living/simple_mob/animal/passive/bird/azure_tit(src)
new /mob/living/simple_animal/bird/azuretit(src) new /mob/living/simple_mob/animal/passive/bird/european_robin(src)
new /mob/living/simple_animal/bird/europeanrobin(src) new /mob/living/simple_mob/animal/passive/bird/goldcrest(src)
new /mob/living/simple_animal/bird/goldcrest(src) new /mob/living/simple_mob/animal/passive/bird/ringneck_dove(src)
new /mob/living/simple_animal/bird/ringneckdove(src) new /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel(src)
new /mob/living/simple_animal/bird/cockatiel(src) new /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white(src)
new /mob/living/simple_animal/bird/white_cockatiel(src) new /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish(src)
new /mob/living/simple_animal/bird/yellowish_cockatiel(src) new /mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey(src)
new /mob/living/simple_animal/bird/grey_cockatiel(src) new /mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo(src)
new /mob/living/simple_animal/bird/too(src) new /mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo(src)
new /mob/living/simple_animal/bird/hooded_too(src) new /mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo(src)
new /mob/living/simple_animal/bird/pink_too(src)
var/turf/T = get_turf(src) var/turf/T = get_turf(src)
for(var/atom/movable/AM in contents) for(var/atom/movable/AM in contents)
if(AM.simulated) AM.forceMove(T) if(AM.simulated) AM.forceMove(T)
@@ -39,72 +38,72 @@
/obj/structure/largecrate/animal/pred /obj/structure/largecrate/animal/pred
name = "Predator carrier" name = "Predator carrier"
starts_with = list(/mob/living/simple_animal/catgirl) starts_with = list(/mob/living/simple_mob/vore/catgirl)
/obj/structure/largecrate/animal/pred/initialize() //This is nessesary to get a random one each time. /obj/structure/largecrate/animal/pred/initialize() //This is nessesary to get a random one each time.
starts_with = list(pick(/mob/living/simple_animal/retaliate/bee, starts_with = list(pick(/mob/living/simple_mob/vore/bee,
/mob/living/simple_animal/catgirl;3, /mob/living/simple_mob/vore/catgirl;3,
/mob/living/simple_animal/hostile/frog, /mob/living/simple_mob/vore/frog,
/mob/living/simple_animal/horse, /mob/living/simple_mob/horse,
/mob/living/simple_animal/hostile/panther, /mob/living/simple_mob/vore/panther,
/mob/living/simple_animal/hostile/giant_snake, /mob/living/simple_mob/vore/giant_snake,
/mob/living/simple_animal/hostile/wolf, /mob/living/simple_mob/vore/wolf,
/mob/living/simple_animal/hostile/bear;0.5, /mob/living/simple_mob/animal/space/bear;0.5,
/mob/living/simple_animal/hostile/bear/brown;0.5, /mob/living/simple_mob/animal/space/carp,
/mob/living/simple_animal/hostile/carp, /mob/living/simple_mob/animal/space/mimic,
/mob/living/simple_animal/hostile/mimic, /mob/living/simple_mob/vore/rat,
/mob/living/simple_animal/hostile/rat, /mob/living/simple_mob/vore/rat/passive,
/mob/living/simple_animal/hostile/rat/passive, // /mob/living/simple_mob/otie;0.5
/mob/living/simple_animal/otie;0.5)) ))
return ..() return ..()
/obj/structure/largecrate/animal/dangerous /obj/structure/largecrate/animal/dangerous
name = "Dangerous Predator carrier" name = "Dangerous Predator carrier"
starts_with = list(/mob/living/simple_animal/hostile/alien) starts_with = list(/mob/living/simple_mob/animal/space/alien)
/obj/structure/largecrate/animal/dangerous/initialize() /obj/structure/largecrate/animal/dangerous/initialize()
starts_with = list(pick(/mob/living/simple_animal/hostile/carp/pike, starts_with = list(pick(/mob/living/simple_mob/animal/space/carp/large,
/mob/living/simple_animal/hostile/deathclaw, /mob/living/simple_mob/hostile/deathclaw,
/mob/living/simple_animal/hostile/dino, /mob/living/simple_mob/vore/dino,
/mob/living/simple_animal/hostile/alien, /mob/living/simple_mob/animal/space/alien,
/mob/living/simple_animal/hostile/alien/drone, /mob/living/simple_mob/animal/space/alien/drone,
/mob/living/simple_animal/hostile/alien/sentinel, /mob/living/simple_mob/animal/space/alien/sentinel,
/mob/living/simple_animal/hostile/alien/queen, /mob/living/simple_mob/animal/space/alien/queen,
/mob/living/simple_animal/otie/feral, // /mob/living/simple_mob/otie/feral,
/mob/living/simple_animal/otie/red, // /mob/living/simple_mob/otie/red,
/mob/living/simple_animal/hostile/corrupthound)) /mob/living/simple_mob/vore/corrupthound))
return ..() return ..()
/*
/obj/structure/largecrate/animal/guardbeast /obj/structure/largecrate/animal/guardbeast
name = "VARMAcorp autoNOMous security solution" name = "VARMAcorp autoNOMous security solution"
desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs." desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs."
icon = 'icons/obj/storage_vr.dmi' icon = 'icons/obj/storage_vr.dmi'
icon_state = "sotiecrate" icon_state = "sotiecrate"
starts_with = list(/mob/living/simple_animal/otie/security) starts_with = list(/mob/living/simple_mob/otie/security)
/obj/structure/largecrate/animal/guardmutant /obj/structure/largecrate/animal/guardmutant
name = "VARMAcorp autoNOMous security solution for hostile environments." name = "VARMAcorp autoNOMous security solution for hostile environments."
desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs. This one can survive hostile atmosphere." desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs. This one can survive hostile atmosphere."
icon = 'icons/obj/storage_vr.dmi' icon = 'icons/obj/storage_vr.dmi'
icon_state = "sotiecrate" icon_state = "sotiecrate"
starts_with = list(/mob/living/simple_animal/otie/security/phoron) starts_with = list(/mob/living/simple_mob/otie/security/phoron)
/obj/structure/largecrate/animal/otie /obj/structure/largecrate/animal/otie
name = "VARMAcorp adoptable reject (Dangerous!)" name = "VARMAcorp adoptable reject (Dangerous!)"
desc = "A warning on the side says the creature inside was returned to the supplier after injuring or devouring several unlucky members of the previous adoption family. It was given a second chance with the next customer. Godspeed and good luck with your new pet!" desc = "A warning on the side says the creature inside was returned to the supplier after injuring or devouring several unlucky members of the previous adoption family. It was given a second chance with the next customer. Godspeed and good luck with your new pet!"
icon = 'icons/obj/storage_vr.dmi' icon = 'icons/obj/storage_vr.dmi'
icon_state = "otiecrate2" icon_state = "otiecrate2"
starts_with = list(/mob/living/simple_animal/otie/cotie) starts_with = list(/mob/living/simple_mob/otie/cotie)
var/taped = 1 var/taped = 1
/obj/structure/largecrate/animal/otie/phoron /obj/structure/largecrate/animal/otie/phoron
name = "VARMAcorp adaptive beta subject (Experimental)" name = "VARMAcorp adaptive beta subject (Experimental)"
desc = "VARMAcorp experimental hostile environment adaptive breeding development kit. WARNING, DO NOT RELEASE IN WILD!" desc = "VARMAcorp experimental hostile environment adaptive breeding development kit. WARNING, DO NOT RELEASE IN WILD!"
starts_with = list(/mob/living/simple_animal/otie/cotie/phoron) starts_with = list(/mob/living/simple_mob/otie/cotie/phoron)
/obj/structure/largecrate/animal/otie/phoron/initialize() /obj/structure/largecrate/animal/otie/phoron/initialize()
starts_with = list(pick(/mob/living/simple_animal/otie/cotie/phoron;2, starts_with = list(pick(/mob/living/simple_mob/otie/cotie/phoron;2,
/mob/living/simple_animal/otie/red/friendly;0.5)) /mob/living/simple_mob/otie/red/friendly;0.5))
return ..() return ..()
/obj/structure/largecrate/animal/otie/attack_hand(mob/living/carbon/human/M as mob)//I just couldn't decide between the icons lmao /obj/structure/largecrate/animal/otie/attack_hand(mob/living/carbon/human/M as mob)//I just couldn't decide between the icons lmao
@@ -113,23 +112,24 @@
icon_state = "otiecrate" icon_state = "otiecrate"
taped = 0 taped = 0
..() ..()
*/ //VORESTATION AI REMOVAL, Oties are still fucking broken.
/obj/structure/largecrate/animal/catgirl /obj/structure/largecrate/animal/catgirl
name = "Catgirl Crate" name = "Catgirl Crate"
desc = "A sketchy looking crate with airholes that seems to have had most marks and stickers removed. You can almost make out 'genetically-engineered subject' written on it." desc = "A sketchy looking crate with airholes that seems to have had most marks and stickers removed. You can almost make out 'genetically-engineered subject' written on it."
starts_with = list(/mob/living/simple_animal/catgirl) starts_with = list(/mob/living/simple_mob/vore/catgirl)
/obj/structure/largecrate/animal/wolfgirl /obj/structure/largecrate/animal/wolfgirl
name = "Wolfgirl Crate" name = "Wolfgirl Crate"
desc = "A sketchy looking crate with airholes that shakes and thuds every now and then. Someone seems to be demanding they be let out." desc = "A sketchy looking crate with airholes that shakes and thuds every now and then. Someone seems to be demanding they be let out."
starts_with = list(/mob/living/simple_animal/retaliate/wolfgirl) starts_with = list(/mob/living/simple_mob/vore/wolfgirl)
/obj/structure/largecrate/animal/fennec /obj/structure/largecrate/animal/fennec
name = "Fennec Crate" name = "Fennec Crate"
desc = "Bounces around a lot. Looks messily packaged, were they in a hurry?" desc = "Bounces around a lot. Looks messily packaged, were they in a hurry?"
starts_with = list(/mob/living/simple_animal/fennec) starts_with = list(/mob/living/simple_mob/fennec)
/obj/structure/largecrate/animal/fennec/initialize() /obj/structure/largecrate/animal/fennec/initialize()
starts_with = list(pick(/mob/living/simple_animal/fennec, starts_with = list(pick(/mob/living/simple_mob/fennec,
/mob/living/simple_animal/retaliate/fennix;0.5)) /mob/living/simple_mob/vore/fennix;0.5))
return ..() return ..()

View File

@@ -15,7 +15,7 @@
/obj/structure/ghost_pod/manual/corgi/create_occupant(var/mob/M) /obj/structure/ghost_pod/manual/corgi/create_occupant(var/mob/M)
lightning_strike(get_turf(src), cosmetic = TRUE) lightning_strike(get_turf(src), cosmetic = TRUE)
density = FALSE density = FALSE
var/mob/living/simple_animal/corgi/R = new(get_turf(src)) var/mob/living/simple_mob/animal/passive/dog/corgi/R = new(get_turf(src))
if(M.mind) if(M.mind)
M.mind.transfer_to(R) M.mind.transfer_to(R)
to_chat(M, "<span class='notice'>You are a <b>Corgi</b>! Woof!</span>") to_chat(M, "<span class='notice'>You are a <b>Corgi</b>! Woof!</span>")
@@ -47,4 +47,4 @@
R.ghost_inhabit(M) R.ghost_inhabit(M)
visible_message("<span class='warning'>The blade shines brightly for a brief moment as [usr] pulls it out of the stone!</span>") visible_message("<span class='warning'>The blade shines brightly for a brief moment as [usr] pulls it out of the stone!</span>")
log_and_message_admins("successfully acquired a cursed sword.") log_and_message_admins("successfully acquired a cursed sword.")
..() ..()

View File

@@ -83,8 +83,8 @@
health = (displaced_health - round(current_damage / 4)) health = (displaced_health - round(current_damage / 4))
cover = 25 cover = 25
/obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart", var/wallbreaker) /obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart")
if(!damage || !wallbreaker) if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
return 0 return 0
user.do_attack_animation(src) user.do_attack_animation(src)
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>") visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")

View File

@@ -126,7 +126,7 @@
src.set_dir(turn(src.dir, 90)) src.set_dir(turn(src.dir, 90))
return return
else else
if(istype(usr,/mob/living/simple_animal/mouse)) if(ismouse(usr))
return return
if(!usr || !isturf(usr.loc)) if(!usr || !isturf(usr.loc))
return return

View File

@@ -574,6 +574,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
icon = 'icons/mecha/mecha.dmi' icon = 'icons/mecha/mecha.dmi'
icon_state = "engineering_pod-broken" icon_state = "engineering_pod-broken"
density = TRUE density = TRUE
anchored = FALSE // In case a dead mecha-mob dies in a bad spot.
chance_uncommon = 20 chance_uncommon = 20
chance_rare = 10 chance_rare = 10
@@ -615,7 +616,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/structure/loot_pile/mecha/ripley /obj/structure/loot_pile/mecha/ripley
name = "ripley wreckage" name = "ripley wreckage"
desc = "The ruins of some unfortunate ripley. Perhaps something is salvageable." desc = "The ruins of some unfortunate ripley. Perhaps something is salvageable."
icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old") icon_state = "ripley-broken"
common_loot = list( common_loot = list(
/obj/random/tool, /obj/random/tool,
@@ -649,6 +650,12 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged /obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged
) )
/obj/structure/loot_pile/mecha/ripley/firefighter
icon_state = "firefighter-broken"
/obj/structure/loot_pile/mecha/ripley/random_sprite
icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old")
//Death-Ripley, same common, but more combat-exosuit-based //Death-Ripley, same common, but more combat-exosuit-based
/obj/structure/loot_pile/mecha/deathripley /obj/structure/loot_pile/mecha/deathripley
name = "strange ripley wreckage" name = "strange ripley wreckage"
@@ -719,6 +726,14 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/shocker /obj/item/mecha_parts/mecha_equipment/shocker
) )
/obj/structure/loot_pile/mecha/odysseus/murdysseus
icon_state = "murdysseus-broken"
/obj/structure/loot_pile/mecha/hoverpod
name = "hoverpod wreckage"
desc = "The ruins of some unfortunate hoverpod. Perhaps something is salvageable."
icon_state = "engineering_pod"
/obj/structure/loot_pile/mecha/gygax /obj/structure/loot_pile/mecha/gygax
name = "gygax wreckage" name = "gygax wreckage"
desc = "The ruins of some unfortunate gygax. Perhaps something is salvageable." desc = "The ruins of some unfortunate gygax. Perhaps something is salvageable."
@@ -759,6 +774,18 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
) )
/obj/structure/loot_pile/mecha/gygax/dark
icon_state = "darkgygax-broken"
// Todo: Better loot.
/obj/structure/loot_pile/mecha/gygax/dark/adv
icon_state = "darkgygax_adv-broken"
icon_scale = 1.5
pixel_y = 8
/obj/structure/loot_pile/mecha/gygax/medgax
icon_state = "medgax-broken"
/obj/structure/loot_pile/mecha/durand /obj/structure/loot_pile/mecha/durand
name = "durand wreckage" name = "durand wreckage"
desc = "The ruins of some unfortunate durand. Perhaps something is salvageable." desc = "The ruins of some unfortunate durand. Perhaps something is salvageable."
@@ -799,6 +826,22 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
) )
/obj/structure/loot_pile/mecha/marauder
name = "marauder wreckage"
desc = "The ruins of some unfortunate marauder. Perhaps something is salvagable."
icon_state = "marauder-broken"
// Todo: Better loot.
/obj/structure/loot_pile/mecha/marauder/seraph
name = "seraph wreckage"
desc = "The ruins of some unfortunate seraph. Perhaps something is salvagable."
icon_state = "seraph-broken"
/obj/structure/loot_pile/mecha/marauder/mauler
name = "mauler wreckage"
desc = "The ruins of some unfortunate mauler. Perhaps something is salvagable."
icon_state = "mauler-broken"
/obj/structure/loot_pile/mecha/phazon /obj/structure/loot_pile/mecha/phazon
name = "phazon wreckage" name = "phazon wreckage"
desc = "The ruins of some unfortunate phazon. Perhaps something is salvageable." desc = "The ruins of some unfortunate phazon. Perhaps something is salvageable."

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