diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 9f6451adf93..5f5f5bf347a 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -241,7 +241,7 @@ mob/living/carbon/human/airflow_hit(atom/A) zone/proc/movables() . = list() for(var/turf/T in contents) - for(var/atom/A in T) - if(istype(A, /obj/effect) || istype(A, /mob/aiEye)) + for(var/atom/movable/A in T) + if(!A.simulated || A.anchored || istype(A, /obj/effect) || istype(A, /mob/aiEye)) continue . += A diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm index 048cd644d5e..56c95535fec 100644 --- a/code/__defines/lighting.dm +++ b/code/__defines/lighting.dm @@ -2,3 +2,5 @@ dview_mob.loc = center; \ dview_mob.see_invisible = invis_flags; \ for(type in view(range, dview_mob)) + +#define END_FOR_DVIEW dview_mob.loc = null diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index ecca29bfd19..9fb8f2c33a3 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -12,7 +12,7 @@ #define INVISIBILITY_EYE 61 #define SEE_INVISIBLE_LIVING 25 -#define SEE_INVISIBLE_OBSERVER_NOLIGHTING 15 +#define SEE_INVISIBLE_NOLIGHTING 15 #define SEE_INVISIBLE_LEVEL_ONE 35 #define SEE_INVISIBLE_LEVEL_TWO 45 #define SEE_INVISIBLE_CULT 60 @@ -117,8 +117,8 @@ #define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 #define DOOR_CLOSED_LAYER 3.1 //Above most items if closed #define LIGHTING_LAYER 11 -#define OBFUSCATION_LAYER 14 //Where images covering the view for eyes are put -#define SCREEN_LAYER 17 //Mob HUD/effects layer +#define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put +#define SCREEN_LAYER 22 //Mob HUD/effects layer // Convoluted setup so defines can be supplied by Bay12 main server compile script. // Should still work fine for people jamming the icons into their repo. @@ -154,3 +154,7 @@ #define BOMBCAP_HEAVY_RADIUS (max_explosion_range/2) #define BOMBCAP_LIGHT_RADIUS max_explosion_range #define BOMBCAP_FLASH_RADIUS (max_explosion_range*1.5) + +// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile. +#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act() +#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs. diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index 3f351989bdc..fbea0437875 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -44,4 +44,5 @@ #define NONGLOBAL 32 // Do not add to general languages list. #define INNATE 64 // All mobs can be assumed to speak and understand this language. (audible emotes) #define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message -#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems \ No newline at end of file +#define NO_STUTTER 256 // No stuttering, slurring, or other speech problems +#define COMMON_VERBS 512 // Robots will apply regular verbs to this diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index dd4039bbe86..589103d4b03 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -871,6 +871,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) // Movement based on lower left corner. Tiles that do not fit // into the new area will not be moved. + // Does *not* affect gases etc; copied turfs will be changed via ChangeTurf, and the dir, icon, and icon_state copied. All other vars will remain default. + if(!A || !src) return 0 var/list/turfs_src = get_area_turfs(src.type) @@ -924,7 +926,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) if(istype(B, get_base_turf(B.z))) continue moving - var/turf/X = new T.type(B) + var/turf/X = B + X.ChangeTurf(T.type) X.set_dir(old_dir1) X.icon_state = old_icon_state1 X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi @@ -964,12 +967,6 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) copiedobjs += newobjs copiedobjs += newmobs - - - for(var/V in T.vars) - if(!(V in list("type","loc","locs","vars", "parent", "parent_type","verbs","ckey","key","x","y","z","contents", "luminosity"))) - X.vars[V] = T.vars[V] - // var/area/AR = X.loc // if(AR.lighting_use_dynamic) @@ -985,22 +982,9 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) - var/list/doors = new/list() - if(toupdate.len) for(var/turf/simulated/T1 in toupdate) - for(var/obj/machinery/door/D2 in T1) - doors += D2 - /*if(T1.parent) - air_master.groups_to_rebuild += T1.parent - else - air_master.tiles_to_update += T1*/ - - for(var/obj/O in doors) - O:update_nearby_tiles(1) - - - + air_master.mark_for_update(T1) return copiedobjs @@ -1317,3 +1301,11 @@ var/mob/dview/dview_mob = new color = origin.color set_light(origin.light_range, origin.light_power, origin.light_color) +/mob/dview/New() + ..() + // We don't want to be in any mob lists; we're a dummy not a mob. + mob_list -= src + if(stat == DEAD) + dead_mob_list -= src + else + living_mob_list -= src diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 4859ce2239f..84a64d8ade4 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -138,9 +138,160 @@ proc/get_id_photo(var/mob/living/carbon/human/H) - H.regenerate_icons() - var/icon/preview_icon = icon(H.icon) - for(var/image/I in H.overlays_standing) - if(I && I.icon) - preview_icon.Blend(icon(I.icon, I.icon_state), ICON_OVERLAY) + var/icon/preview_icon = null + + var/g = "m" + if (H.gender == FEMALE) + g = "f" + + var/icon/icobase = H.species.icobase + + preview_icon = new /icon(icobase, "torso_[g]") + var/icon/temp + temp = new /icon(icobase, "groin_[g]") + preview_icon.Blend(temp, ICON_OVERLAY) + temp = new /icon(icobase, "head_[g]") + preview_icon.Blend(temp, ICON_OVERLAY) + + for(var/obj/item/organ/external/E in H.organs) + preview_icon.Blend(E.get_icon(), ICON_OVERLAY) + + //Tail + if(H.species.tail) + temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.species.tail]_s") + preview_icon.Blend(temp, ICON_OVERLAY) + + // Skin tone + if(H.species.flags & HAS_SKIN_TONE) + if (H.s_tone >= 0) + preview_icon.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD) + else + preview_icon.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT) + + // Skin color + if(H.species.flags & HAS_SKIN_TONE) + if(!H.species || H.species.flags & HAS_SKIN_COLOR) + preview_icon.Blend(rgb(H.r_skin, H.g_skin, H.b_skin), ICON_ADD) + + var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = H.species ? H.species.eyes : "eyes_s") + + if (H.species.flags & HAS_EYE_COLOR) + eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD) + + var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] + if(hair_style) + var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) + eyes_s.Blend(hair_s, ICON_OVERLAY) + + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] + if(facial_hair_style) + var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") + facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) + eyes_s.Blend(facial_s, ICON_OVERLAY) + + var/icon/clothes_s = null + switch(H.mind.assigned_role) + if("Head of Personnel") + clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if("Bartender") + clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Gardener") + clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Chef") + clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Janitor") + clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Librarian") + clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Quartermaster") + clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if("Cargo Technician") + clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Shaft Miner") + clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Lawyer") + clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if("Chaplain") + clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if("Research Director") + clothes_s = new /icon('icons/mob/uniform.dmi', "director_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + if("Scientist") + clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) + if("Chemist") + clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY) + if("Chief Medical Officer") + clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY) + if("Medical Doctor") + clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + if("Geneticist") + clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY) + if("Virologist") + clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY) + if("Captain") + clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if("Head of Security") + clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + if("Warden") + clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + if("Detective") + clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY) + if("Security Officer") + clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + if("Chief Engineer") + clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + if("Station Engineer") + clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + if("Atmospheric Technician") + clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + if("Roboticist") + clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + else + clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + preview_icon.Blend(eyes_s, ICON_OVERLAY) + if(clothes_s) + preview_icon.Blend(clothes_s, ICON_OVERLAY) + qdel(eyes_s) + qdel(clothes_s) + return preview_icon diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index efe744174bf..8916316f9a3 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -60,7 +60,8 @@ /datum/antagonist/proc/get_candidates(var/ghosts_only) candidates = list() // Clear. candidates = ticker.mode.get_players_for_role(role_type, id) - // Prune restricted jobs and status. Broke it up for readability. + // Prune restricted status. Broke it up for readability. + // Note that this is done before jobs are handed out. for(var/datum/mind/player in candidates) if(ghosts_only && !istype(player.current, /mob/dead)) candidates -= player @@ -98,17 +99,29 @@ if(!candidates.len) return 0 + // Not sure if this is necessary, just in case. + pending_antagonists = candidates + candidates = list() + //Grab candidates randomly until we have enough. - while(candidates.len) + while(candidates.len && pending_antagonists.len < cur_max) var/datum/mind/player = pick(candidates) pending_antagonists |= player candidates -= player return 1 +//Drafting players into the antagonist role must be done when antagonists are finalized. +//This ensures that if a player is a candidate for multiple antag roles, they do not prevent other +//players from being selected for all of the other antag roles that the player was not selected for. /datum/antagonist/proc/finalize_spawn() - if(!pending_antagonists || !pending_antagonists.len) + if(!pending_antagonists) return - for(var/datum/mind/player in pending_antagonists) + + while(pending_antagonists.len && current_antagonists.len < cur_max) + var/datum/mind/player = pick(pending_antagonists) + pending_antagonists -= player + + //Check for restricted job status since players will have been assigned jobs by this point. + //Or if the player has already been given an antag role. if(can_become_antag(player) && !player.special_role) add_antagonist(player,0,0,1) - pending_antagonists.Cut() \ No newline at end of file diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 461cdc92113..e80389021c8 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -42,7 +42,13 @@ return W /datum/antagonist/proc/create_radio(var/freq, var/mob/living/carbon/human/player) - var/obj/item/device/radio/R = new /obj/item/device/radio/headset(player) + var/obj/item/device/radio/R + + if(freq == SYND_FREQ) + R = new/obj/item/device/radio/headset/syndicate(player) + else + R = new/obj/item/device/radio/headset(player) + R.set_frequency(freq) player.equip_to_slot_or_del(R, slot_l_ear) return R diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index ff5b7ff8806..5060b964ca9 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -592,6 +592,7 @@ var/list/sacrificed = list() usr.whisper("[input]") input = sanitize(input) + log_and_message_admins("used a communicate rune to say '[input]'") for(var/datum/mind/H in cult.current_antagonists) if (H.current) H.current << "[input]" diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 9ae0320b679..5047562e902 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -170,8 +170,6 @@ var/global/list/additional_antag_types = list() var/datum/antagonist/main_antags = antag_templates[1] var/list/candidates = main_antags.get_candidates() if(candidates.len >= required_enemies) - for(var/datum/antagonist/antag in antag_templates) - antag.attempt_spawn() return 1 return 0 @@ -185,6 +183,17 @@ var/global/list/additional_antag_types = list() var/datum/event_container/EMajor = event_manager.event_containers[EVENT_LEVEL_MAJOR] EMajor.delay_modifier = event_delay_mod_major +/datum/game_mode/proc/pre_setup() + //antag roles that replace jobs need to be assigned before the job controller hands out jobs. + if(antag_templates) + for(var/datum/antagonist/antag in antag_templates) + antag.attempt_spawn() //selects antag role candidates + + if(antag.flags & ANTAG_OVERRIDE_JOB) + antag.finalize_spawn() + if(antag.is_latejoin_template()) + latejoin_templates |= antag + ///post_setup() /datum/game_mode/proc/post_setup() @@ -198,6 +207,7 @@ var/global/list/additional_antag_types = list() spawn(rand(100,150)) announce_ert_disabled() + //Assign all antag types for this game mode. Any players spawned as antags earlier should have been removed from the pending list, so no need to worry about those. if(antag_templates && antag_templates.len) for(var/datum/antagonist/antag in antag_templates) antag.finalize_spawn() diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index c0f8d57f08b..70fd6eb1992 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -91,6 +91,8 @@ var/global/datum/controller/gameticker/ticker else src.mode = config.pick_mode(master_mode) + src.mode.pre_setup() + job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. if(!mode_started && !src.mode.can_start()) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 7e1ba6d3684..03680c8ff34 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -20,12 +20,3 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' if (skipjack && skipjack.returned_home) return 1 return 0 - -/datum/game_mode/heist/cleanup() - //the skipjack and everything in it have left and aren't coming back, so get rid of them. - var/area/skipjack = locate(/area/shuttle/skipjack/station) - for (var/mob/living/M in skipjack.contents) - //maybe send the player a message that they've gone home/been kidnapped? Someone responsible for vox lore should write that. - qdel(M) - for (var/obj/O in skipjack.contents) - qdel(O) //no hiding in lockers or anything \ No newline at end of file diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 95e043db28b..834f3f37499 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -919,7 +919,7 @@ FIRE ALARM /obj/machinery/firealarm/attack_ai(mob/user as mob) return src.attack_hand(user) -/obj/machinery/firealarm/bullet_act(BLAH) +/obj/machinery/firealarm/bullet_act() return src.alarm() /obj/machinery/firealarm/emp_act(severity) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 407b007c240..7ebdeef8cd6 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -201,6 +201,7 @@ transfer.control_disabled = 0 transfer.aiRadio.disabledAi = 0 transfer.loc = get_turf(src) + transfer.create_eyeobj() transfer.cancel_camera() user << "Transfer successful: [transfer.name] ([rand(1000,9999)].exe) downloaded to host terminal. Local copy wiped." transfer << "You have been uploaded to a stationary terminal. Remote device connection restored." diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 0e26be38a85..d6a09e3b93f 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -624,6 +624,14 @@ var/list/turret_icons // Emagged turrets again use twice as much power due to higher firing rates use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged)) + //Turrets aim for the center of mass by default. + //If the target is grabbing someone then the turret smartly aims for extremities + var/obj/item/weapon/grab/G = locate() in target + if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people. + A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg") + else + A.def_zone = pick("chest", "groin") + //Shooting Code: A.current = T A.starting = T diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index 35c2ecdc1f5..f91fd2d40c5 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -40,8 +40,8 @@ id = "Hub" network = "tcommsat" autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "science", "medical", - "supply", "service", "common", "command", "engineering", "security", - "receiverA", "receiverB", "broadcasterA", "broadcasterB") + "supply", "service", "common", "command", "engineering", "security", "unused", + "receiverA", "broadcasterA") /obj/machinery/telecomms/hub/preset_cent id = "CentComm Hub" @@ -52,22 +52,11 @@ //Receivers -//--PRESET LEFT--// - -/obj/machinery/telecomms/receiver/preset_left +/obj/machinery/telecomms/receiver/preset_right id = "Receiver A" network = "tcommsat" autolinkers = list("receiverA") // link to relay - freq_listening = list(SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ) // science, medical, supply, service - - -//--PRESET RIGHT--// - -/obj/machinery/telecomms/receiver/preset_right - id = "Receiver B" - network = "tcommsat" - autolinkers = list("receiverB") // link to relay - freq_listening = list(COMM_FREQ, ENG_FREQ, SEC_FREQ) //command, engineering, security + freq_listening = list(SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ) //Common and other radio frequencies for people to freely use New() @@ -95,7 +84,14 @@ id = "Bus 2" network = "tcommsat" freq_listening = list(SUP_FREQ, SRV_FREQ) - autolinkers = list("processor2", "supply", "service") + autolinkers = list("processor2", "supply", "service", "unused") + +/obj/machinery/telecomms/bus/preset_two/New() + for(var/i = 1441, i < 1489, i += 2) + if(i == AI_FREQ || i == PUB_FREQ) + continue + freq_listening |= i + ..() /obj/machinery/telecomms/bus/preset_three id = "Bus 3" @@ -106,14 +102,9 @@ /obj/machinery/telecomms/bus/preset_four id = "Bus 4" network = "tcommsat" - freq_listening = list(ENG_FREQ) + freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ) autolinkers = list("processor4", "engineering", "common") -/obj/machinery/telecomms/bus/preset_four/New() - for(var/i = 1441, i < 1489, i += 2) - freq_listening |= i - ..() - /obj/machinery/telecomms/bus/preset_cent id = "CentComm Bus" network = "tcommsat" @@ -169,7 +160,7 @@ id = "Supply Server" freq_listening = list(SUP_FREQ) autolinkers = list("supply") - + /obj/machinery/telecomms/server/presets/service id = "Service Server" freq_listening = list(SRV_FREQ) @@ -177,13 +168,19 @@ /obj/machinery/telecomms/server/presets/common id = "Common Server" - freq_listening = list() + freq_listening = list(PUB_FREQ, AI_FREQ) // AI Private and Common autolinkers = list("common") - //Common and other radio frequencies for people to freely use - // 1441 to 1489 -/obj/machinery/telecomms/server/presets/common/New() +// "Unused" channels, AKA all others. +/obj/machinery/telecomms/server/presets/unused + id = "Unused Server" + freq_listening = list() + autolinkers = list("unused") + +/obj/machinery/telecomms/server/presets/unused/New() for(var/i = 1441, i < 1489, i += 2) + if(i == AI_FREQ || i == PUB_FREQ) + continue freq_listening |= i ..() @@ -213,18 +210,11 @@ //--PRESET LEFT--// -/obj/machinery/telecomms/broadcaster/preset_left +/obj/machinery/telecomms/broadcaster/preset_right id = "Broadcaster A" network = "tcommsat" autolinkers = list("broadcasterA") -//--PRESET RIGHT--// - -/obj/machinery/telecomms/broadcaster/preset_right - id = "Broadcaster B" - network = "tcommsat" - autolinkers = list("broadcasterB") - /obj/machinery/telecomms/broadcaster/preset_cent id = "CentComm Broadcaster" network = "tcommsat" diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index a3ac073a90b..db548443cab 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -266,6 +266,15 @@ else A = new /obj/item/projectile/energy/electrode( loc ) use_power(200) + + //Turrets aim for the center of mass by default. + //If the target is grabbing someone then the turret smartly aims for extremities + var/obj/item/weapon/grab/G = locate() in target + if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people. + A.def_zone = pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg") + else + A.def_zone = pick("chest", "groin") + A.current = T A.starting = T A.yo = U.y - T.y diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index e4d1c57a0d0..6b239c6b072 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -110,6 +110,7 @@ ai.loc = src ai.cancel_camera() + ai.destroy_eyeobj(src) ai.control_disabled = 1 ai.aiRestorePowerRoutine = 0 carded_ai = ai diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm index 5f14980373b..f1c9aa2d145 100644 --- a/code/game/objects/items/shooting_range.dm +++ b/code/game/objects/items/shooting_range.dm @@ -146,7 +146,7 @@ return - return -1 // the bullet/projectile goes through the target! Ie, you missed + return PROJECTILE_CONTINUE // the bullet/projectile goes through the target! // Small memory holder entity for transparent bullet holes diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 7bd266f2410..ccb61a5abf9 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -212,8 +212,12 @@ /obj/item/weapon/weldingtool/process() - if(welding && prob(5) && !remove_fuel(1)) - setWelding(0) + if(welding) + if(prob(5)) + remove_fuel(1) + + if(get_fuel() == 0) + setWelding(0) //I'm not sure what this does. I assume it has to do with starting fires... //...but it doesnt check to see if the welder is on or not. diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index d217b101970..0b634b192e9 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -25,7 +25,7 @@ /obj/structure/girder/bullet_act(var/obj/item/projectile/Proj) //Girders only provide partial cover. There's a chance that the projectiles will just pass through. (unless you are trying to shoot the girder) if(Proj.original != src && !prob(cover)) - return -1 //pass through + return PROJECTILE_CONTINUE //pass through //Tasers and the like should not damage girders. if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 331529b87d8..149d6bf3941 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -91,7 +91,7 @@ passthrough = 1 if(passthrough) - . = -1 + . = PROJECTILE_CONTINUE damage = between(0, (damage - Proj.damage)*(Proj.damage_type == BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage src.health -= damage*0.2 diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm index fa6ee92855e..364f58c29e9 100644 --- a/code/game/turfs/simulated/wall_icon.dm +++ b/code/game/turfs/simulated/wall_icon.dm @@ -44,6 +44,7 @@ return overlays.Cut() + damage_overlay = 0 if(!wall_cache["[new_state]-[material.icon_colour]"]) var/image/I = image(icon='icons/turf/wall_masks.dmi',icon_state="[new_state]") @@ -74,7 +75,6 @@ check_relatives(1) /turf/simulated/wall/proc/update_icon() - if(!material) return @@ -86,15 +86,23 @@ else set_wall_state("[material.icon_base]fwall_open") - var/dmg_amt = material.integrity - if(reinf_material) - dmg_amt += reinf_material.integrity - var/overlay = round(damage / dmg_amt * damage_overlays.len) + 1 - if(overlay > damage_overlays.len) - overlay = damage_overlays.len - if(density) + if(damage == 0) + if(damage_overlay != 0) + overlays -= damage_overlays[damage_overlay] + damage_overlay = 0 + else if(density) + var/integrity = material.integrity + if(reinf_material) + integrity += reinf_material.integrity + + var/overlay = round(damage / integrity * damage_overlays.len) + 1 + if(overlay > damage_overlays.len) + overlay = damage_overlays.len + if(damage_overlay && overlay == damage_overlay) //No need to update. return + + if(damage_overlay) overlays -= damage_overlays[damage_overlay] overlays += damage_overlays[overlay] damage_overlay = overlay return @@ -131,4 +139,4 @@ /turf/simulated/wall/proc/can_join_with(var/turf/simulated/wall/W) if(material && W.material && material.icon_base == W.material.icon_base) return 1 - return 0 \ No newline at end of file + return 0 diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index af371f7a48f..0ba950dfd06 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -12,8 +12,8 @@ var/list/global/wall_cache = list() heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall var/damage = 0 - var/damage_overlay - var/global/damage_overlays[8] + var/damage_overlay = 0 + var/global/damage_overlays[16] var/active var/can_open = 0 var/material/material diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index b415a317fc2..c3b3fb54eec 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -83,10 +83,12 @@ var/list/admin_verbs_admin = list( /client/proc/allow_character_respawn, /* Allows a ghost to respawn */ /client/proc/event_manager_panel, /client/proc/empty_ai_core_toggle_latejoin, + /client/proc/empty_ai_core_toggle_latejoin, /client/proc/aooc, /client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */ /client/proc/change_human_appearance_self, /* Allows the human-based mob itself change its basic appearance */ - /client/proc/change_security_level + /client/proc/change_security_level, + /client/proc/view_chemical_reaction_logs ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm index c5a54694c81..4a28ece9151 100644 --- a/code/modules/admin/player_notes.dm +++ b/code/modules/admin/player_notes.dm @@ -1,147 +1,147 @@ -//This stuff was originally intended to be integrated into the ban-system I was working on -//but it's safe to say that'll never be finished. So I've merged it into the current player panel. -//enjoy ~Carn -/* -#define NOTESFILE "data/player_notes.sav" //where the player notes are saved - -datum/admins/proc/notes_show(var/ckey) - usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400") - - -datum/admins/proc/notes_gethtml(var/ckey) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return "Error: Cannot access [NOTESFILE]" - if(ckey) - . = "Notes for [ckey]: \[+\] \[-\]
" - notesfile.cd = "/[ckey]" - var/index = 1 - while( !notesfile.eof ) - var/note - notesfile >> note - . += "[note] \[-\]
" - index++ - else - . = "All Notes: \[+\] \[-\]
" - notesfile.cd = "/" - for(var/dir in notesfile.dir) - . += "[dir]
" - return - -//handles removing entries from the buffer, or removing the entire directory if no start_index is given -/proc/notes_remove(var/ckey, var/start_index, var/end_index) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return - - if(!ckey) - notesfile.cd = "/" - ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir) - if(!ckey) return - - if(start_index) - notesfile.cd = "/[ckey]" - var/list/noteslist = list() - if(!end_index) end_index = start_index - var/index = 0 - while( !notesfile.eof ) - index++ - var/temp - notesfile >> temp - if( (start_index <= index) && (index <= end_index) ) - continue - noteslist += temp - - notesfile.eof = -2 //Move to the start of the buffer and then erase. - - for( var/note in noteslist ) - notesfile << note - else - notesfile.cd = "/" - if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes") - notesfile.dir.Remove(ckey) - return - -#undef NOTESFILE -*/ - -//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky. - +//This stuff was originally intended to be integrated into the ban-system I was working on +//but it's safe to say that'll never be finished. So I've merged it into the current player panel. +//enjoy ~Carn +/* +#define NOTESFILE "data/player_notes.sav" //where the player notes are saved + +datum/admins/proc/notes_show(var/ckey) + usr << browse("Player Notes[notes_gethtml(ckey)]","window=player_notes;size=700x400") + + +datum/admins/proc/notes_gethtml(var/ckey) + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) return "Error: Cannot access [NOTESFILE]" + if(ckey) + . = "Notes for [ckey]: \[+\] \[-\]
" + notesfile.cd = "/[ckey]" + var/index = 1 + while( !notesfile.eof ) + var/note + notesfile >> note + . += "[note] \[-\]
" + index++ + else + . = "All Notes: \[+\] \[-\]
" + notesfile.cd = "/" + for(var/dir in notesfile.dir) + . += "[dir]
" + return + +//handles removing entries from the buffer, or removing the entire directory if no start_index is given +/proc/notes_remove(var/ckey, var/start_index, var/end_index) + var/savefile/notesfile = new(NOTESFILE) + if(!notesfile) return + + if(!ckey) + notesfile.cd = "/" + ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir) + if(!ckey) return + + if(start_index) + notesfile.cd = "/[ckey]" + var/list/noteslist = list() + if(!end_index) end_index = start_index + var/index = 0 + while( !notesfile.eof ) + index++ + var/temp + notesfile >> temp + if( (start_index <= index) && (index <= end_index) ) + continue + noteslist += temp + + notesfile.eof = -2 //Move to the start of the buffer and then erase. + + for( var/note in noteslist ) + notesfile << note + else + notesfile.cd = "/" + if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes") + notesfile.dir.Remove(ckey) + return + +#undef NOTESFILE +*/ + +//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky. + /proc/notes_add(var/key, var/note, var/mob/user) - if (!key || !note) - return - - //Loading list of notes for this key - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) infos = list() - - //Overly complex timestamp creation - var/modifyer = "th" - switch(time2text(world.timeofday, "DD")) - if("01","21","31") - modifyer = "st" - if("02","22",) - modifyer = "nd" - if("03","23") - modifyer = "rd" - var/day_string = "[time2text(world.timeofday, "DD")][modifyer]" - if(copytext(day_string,1,2) == "0") - day_string = copytext(day_string,2) - var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY") - var/day_loc = findtext(full_date, time2text(world.timeofday, "DD")) - - var/datum/player_info/P = new + if (!key || !note) + return + + //Loading list of notes for this key + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) infos = list() + + //Overly complex timestamp creation + var/modifyer = "th" + switch(time2text(world.timeofday, "DD")) + if("01","21","31") + modifyer = "st" + if("02","22",) + modifyer = "nd" + if("03","23") + modifyer = "rd" + var/day_string = "[time2text(world.timeofday, "DD")][modifyer]" + if(copytext(day_string,1,2) == "0") + day_string = copytext(day_string,2) + var/full_date = time2text(world.timeofday, "DDD, Month DD of YYYY") + var/day_loc = findtext(full_date, time2text(world.timeofday, "DD")) + + var/datum/player_info/P = new if (user) P.author = user.key P.rank = user.client.holder.rank - else - P.author = "Adminbot" - P.rank = "Friendly Robot" - P.content = note - P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]" - - infos += P - info << infos - + else + P.author = "Adminbot" + P.rank = "Friendly Robot" + P.content = note + P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]" + + infos += P + info << infos + message_admins("\blue [key_name_admin(user)] has edited [key]'s notes.") log_admin("[key_name(user)] has edited [key]'s notes.") - - qdel(info) - - //Updating list of keys with notes on them - var/savefile/note_list = new("data/player_notes.sav") - var/list/note_keys - note_list >> note_keys - if(!note_keys) note_keys = list() - if(!note_keys.Find(key)) note_keys += key - note_list << note_keys - qdel(note_list) - - -/proc/notes_del(var/key, var/index) - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos || infos.len < index) return - - var/datum/player_info/item = infos[index] - infos.Remove(item) - info << infos - - message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.") - log_admin("[key_name(usr)] deleted one of [key]'s notes.") - - qdel(info) - -/proc/show_player_info_irc(var/key as text) - var/dat = " Info on [key]%0D%0A" - var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") - var/list/infos - info >> infos - if(!infos) - dat = "No information found on the given key." - else - for(var/datum/player_info/I in infos) - dat += "[I.content]%0D%0Aby [I.author] ([I.rank]) on [I.timestamp]%0D%0A%0D%0A" - - return dat + + qdel(info) + + //Updating list of keys with notes on them + var/savefile/note_list = new("data/player_notes.sav") + var/list/note_keys + note_list >> note_keys + if(!note_keys) note_keys = list() + if(!note_keys.Find(key)) note_keys += key + note_list << note_keys + qdel(note_list) + + +/proc/notes_del(var/key, var/index) + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos || infos.len < index) return + + var/datum/player_info/item = infos[index] + infos.Remove(item) + info << infos + + message_admins("\blue [key_name_admin(usr)] deleted one of [key]'s notes.") + log_admin("[key_name(usr)] deleted one of [key]'s notes.") + + qdel(info) + +/proc/show_player_info_irc(var/key as text) + var/dat = " Info on [key]\n" + var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") + var/list/infos + info >> infos + if(!infos) + dat = "No information found on the given key." + else + for(var/datum/player_info/I in infos) + dat += "[I.content]\nby [I.author] ([I.rank]) on [I.timestamp]\n\n" + + return list2params(list(dat)) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 0d8a754ce0d..198244a4a1b 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -64,6 +64,28 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null if(!procname) return + + if(targetselected) + if(!target) + usr << "Your target no longer exists." + return + if(!hascall(target,procname)) + usr << "Error: callproc(): target has no such call [procname]." + return + else + if(copytext(procname, 1, 7) == "/proc/") + // nothing + else if(copytext(procname, 1, 6) == "proc/") + procname = "/[procname]" + else if(copytext(procname, 1, 2) == "/") + procname = "/proc[procname]" + else + procname = "/proc/[procname]" + // Procs have the strange property that text2path will return non-null, but ispath() will return false. + var/path = text2path(procname) + if(!path || ispath(path)) + usr << "Invalid proc [procname]" + return var/argnum = input("Number of arguments","Number:",0) as num|null if(!argnum && (argnum!=0)) return @@ -117,13 +139,9 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that if(!target) usr << "Error: callproc(): owner of proc no longer exists." return - if(!hascall(target,procname)) - usr << "Error: callproc(): target has no such call [procname]." - return log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc else - //this currently has no hascall protection. wasn't able to get it working. log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 0cafdb182ee..e96afb3a56a 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -85,7 +85,6 @@ datum/preferences var/religion = "None" //Religious association. //Mob preview - var/mob/living/carbon/human/dummy //the mannequin var/icon/preview_icon = null var/icon/preview_icon_front = null var/icon/preview_icon_side = null @@ -1641,18 +1640,30 @@ datum/preferences character.gen_record = gen_record character.exploit_record = exploit_record - character.change_gender(gender) + character.gender = gender character.age = age character.b_type = b_type - character.change_eye_color(r_eyes,g_eyes,b_eyes) - character.change_hair_color(r_hair,g_hair,b_hair) - character.change_facial_hair_color(r_facial,g_facial,b_facial) - character.change_skin_color(r_skin,g_skin,b_skin) - character.change_skin_tone(s_tone) + character.r_eyes = r_eyes + character.g_eyes = g_eyes + character.b_eyes = b_eyes - character.change_hair(h_style) - character.change_facial_hair(f_style) + character.r_hair = r_hair + character.g_hair = g_hair + character.b_hair = b_hair + + character.r_facial = r_facial + character.g_facial = g_facial + character.b_facial = b_facial + + character.r_skin = r_skin + character.g_skin = g_skin + character.b_skin = b_skin + + character.s_tone = s_tone + + character.h_style = h_style + character.f_style = f_style character.home_system = home_system character.citizenship = citizenship diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 8ec49ecd5f1..0cf15d0d0d1 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -176,7 +176,7 @@ BLIND // can't see anything slot_flags = SLOT_EYES var/vision_flags = 0 var/darkness_view = 0//Base human is 2 - var/invisa_view = 0 + var/see_invisible = -1 sprite_sheets = list("Vox" = 'icons/mob/species/vox/eyes.dmi') /obj/item/clothing/glasses/update_clothing_icon() diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 9d3d0333596..68640cfcce3 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -7,7 +7,6 @@ //slot_flags = SLOT_EYES //var/vision_flags = 0 //var/darkness_view = 0//Base human is 2 - //var/invisa_view = 0 var/prescription = 0 var/toggleable = 0 var/off_state = "degoggles" @@ -75,6 +74,7 @@ origin_tech = list(TECH_MAGNET = 2) darkness_view = 7 toggleable = 1 + see_invisible = SEE_INVISIBLE_NOLIGHTING off_state = "denight" /obj/item/clothing/glasses/night/New() @@ -220,7 +220,6 @@ origin_tech = list(TECH_MAGNET = 3) toggleable = 1 vision_flags = SEE_MOBS - invisa_view = 2 emp_act(severity) if(istype(src.loc, /mob/living/carbon/human)) diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index fa273534e6b..2938ef4688a 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -33,7 +33,7 @@ icon_state = "jensenshades" item_state = "jensenshades" vision_flags = SEE_MOBS - invisa_view = 2 + see_invisible = SEE_INVISIBLE_NOLIGHTING /obj/item/clothing/glasses/hud/security/process_hud(var/mob/M) process_sec_hud(M, 1) diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index 9552a0f17d5..f3eb8a81831 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -46,6 +46,8 @@ /obj/item/clothing/mask/gas/swat/vox name = "\improper alien mask" desc = "Clearly not designed for a human face." + body_parts_covered = 0 //Hack to allow vox to eat while wearing this mask. + species_restricted = list("Vox") /obj/item/clothing/mask/gas/syndicate name = "tactical mask" diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 83b2be54138..60197daef79 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -71,6 +71,7 @@ var/offline_slowdown = 3 // If the suit is deployed and unpowered, it sets slowdown to this. var/vision_restriction var/offline_vision_restriction = 1 // 0 - none, 1 - welder vision, 2 - blind. Maybe move this to helmets. + var/airtight = 1 //If set, will adjust AIRTIGHT and STOPPRESSUREDAMAGE flags on components. Otherwise it should leave them untouched. var/emp_protection = 0 @@ -178,8 +179,9 @@ for(var/obj/item/piece in list(helmet,boots,gloves,chest)) if(!piece) continue piece.icon_state = "[initial(icon_state)]" - piece.flags &= ~STOPPRESSUREDAMAGE - piece.flags &= ~AIRTIGHT + if(airtight) + piece.flags &= ~STOPPRESSUREDAMAGE + piece.flags &= ~AIRTIGHT update_icon(1) /obj/item/weapon/rig/proc/toggle_seals(var/mob/living/carbon/human/M,var/instant) @@ -247,11 +249,6 @@ M << "\The [piece] hisses [!seal_target ? "closed" : "open"]." M.update_inv_head() if(helmet) - if(!seal_target) - if(flags & AIRTIGHT) - helmet.flags |= AIRTIGHT - else - helmet.flags &= ~AIRTIGHT helmet.update_light(wearer) //sealed pieces become airtight, protecting against diseases @@ -273,13 +270,8 @@ if(!piece) continue piece.icon_state = "[initial(icon_state)][!seal_target ? "" : "_sealed"]" canremove = !seal_target - if(helmet) - if(canremove) - if(flags & AIRTIGHT) - helmet.flags |= AIRTIGHT - else - if(flags & AIRTIGHT) - helmet.flags &= ~AIRTIGHT + if(airtight) + update_component_sealed() update_icon(1) return 0 @@ -290,15 +282,18 @@ if(canremove) for(var/obj/item/rig_module/module in installed_modules) module.deactivate() + if(airtight) + update_component_sealed() + update_icon(1) + +/obj/item/weapon/rig/proc/update_component_sealed() for(var/obj/item/piece in list(helmet,boots,gloves,chest)) - if(!piece) continue if(canremove) piece.flags &= ~STOPPRESSUREDAMAGE piece.flags &= ~AIRTIGHT else piece.flags |= STOPPRESSUREDAMAGE piece.flags |= AIRTIGHT - update_icon(1) /obj/item/weapon/rig/process() diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces.dm b/code/modules/clothing/spacesuits/rig/rig_pieces.dm index 294644f3cba..e38fa950ff2 100644 --- a/code/modules/clothing/spacesuits/rig/rig_pieces.dm +++ b/code/modules/clothing/spacesuits/rig/rig_pieces.dm @@ -24,6 +24,7 @@ /obj/item/clothing/shoes/magboots/rig name = "boots" + body_parts_covered = FEET cold_protection = FEET heat_protection = FEET species_restricted = null @@ -69,3 +70,38 @@ return 1 return 0 + +//Rig pieces for non-spacesuit based rigs + +/obj/item/clothing/head/lightrig + name = "mask" + body_parts_covered = HEAD|FACE|EYES + heat_protection = HEAD|FACE|EYES + cold_protection = HEAD|FACE|EYES + flags = THICKMATERIAL|AIRTIGHT + +/obj/item/clothing/suit/lightrig + name = "suit" + allowed = list(/obj/item/device/flashlight) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + flags_inv = HIDEJUMPSUIT + flags = THICKMATERIAL + +/obj/item/clothing/shoes/lightrig + name = "boots" + body_parts_covered = FEET + cold_protection = FEET + heat_protection = FEET + species_restricted = null + gender = PLURAL + +/obj/item/clothing/gloves/lightrig + name = "gloves" + flags = THICKMATERIAL + body_parts_covered = HANDS + heat_protection = HANDS + cold_protection = HANDS + species_restricted = null + gender = PLURAL diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm index 8aa50f4ab9a..270e7a37613 100644 --- a/code/modules/clothing/spacesuits/rig/suits/light.dm +++ b/code/modules/clothing/spacesuits/rig/suits/light.dm @@ -33,22 +33,43 @@ /obj/item/weapon/rig/light/hacker name = "cybersuit control module" suit_type = "cyber" - desc = "An advanced powered armour suit with many cyberwarfare enhancements." + desc = "An advanced powered armour suit with many cyberwarfare enhancements. Comes with built-in insulated gloves for safely tampering with electronics." icon_state = "hacker_rig" req_access = list(access_syndicate) - helm_type = /obj/item/clothing/head/helmet/space/rig/mask + airtight = 0 + seal_delay = 5 //not being vaccum-proof has an upside I guess + + helm_type = /obj/item/clothing/head/lightrig/hacker + chest_type = /obj/item/clothing/suit/lightrig/hacker + glove_type = /obj/item/clothing/gloves/lightrig/hacker + boot_type = /obj/item/clothing/shoes/lightrig/hacker initial_modules = list( /obj/item/rig_module/ai_container, /obj/item/rig_module/power_sink, - /obj/item/rig_module/datajack + /obj/item/rig_module/datajack, + /obj/item/rig_module/electrowarfare_suite, + /obj/item/rig_module/voice, + /obj/item/rig_module/vision, ) -/obj/item/clothing/head/helmet/space/rig/mask - name = "mask" - flags = THICKMATERIAL +//The cybersuit is not space-proof. It does however, have good siemens_coefficient values +/obj/item/clothing/head/lightrig/hacker + name = "HUD" + siemens_coefficient = 0.4 + flags = 0 + +/obj/item/clothing/suit/lightrig/hacker + siemens_coefficient = 0.4 + +/obj/item/clothing/shoes/lightrig/hacker + siemens_coefficient = 0.4 + flags = NOSLIP //All the other rigs have magboots anyways, hopefully gives the hacker suit something more going for it. + +/obj/item/clothing/gloves/lightrig/hacker + siemens_coefficient = 0 /obj/item/weapon/rig/light/ninja name = "ominous suit control module" @@ -92,7 +113,7 @@ name = "stealth suit control module" suit_type = "stealth" desc = "A highly advanced and expensive suit designed for covert operations." - icon_state = "ninja_rig" + icon_state = "stealth_rig" req_access = list(access_syndicate) diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm index 1ee235fa6f6..ce2ee837a62 100644 --- a/code/modules/lighting/light_source.dm +++ b/code/modules/lighting/light_source.dm @@ -177,6 +177,7 @@ T.affecting_lights += src effect_turf += T + END_FOR_DVIEW /datum/light_source/proc/remove_lum() applied = 0 @@ -201,11 +202,11 @@ var/list/view[0] FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) view += T //Filter out turfs. + END_FOR_DVIEW //This is the part where we calculate new turfs (if any) var/list/new_turfs = view - effect_turf //This will result with all the tiles that are added. for(var/turf/T in new_turfs) - //Big huge copy paste from apply_lum() incoming because screw unreadable defines and screw proc call overhead. if(T.lighting_overlay) LUM_FALLOFF(., T, source_turf) . *= light_power diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 92500ecc1d9..6968a4ed63f 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -46,21 +46,13 @@ T.reconsider_lights() return ..() -/atom/movable/Move() - var/turf/old_loc = loc +/atom/Entered(atom/movable/obj, atom/prev_loc) . = ..() - if(loc != old_loc) - for(var/datum/light_source/L in light_sources) + if(obj && prev_loc != src) + for(var/datum/light_source/L in obj.light_sources) L.source_atom.update_light() - var/turf/new_loc = loc - if(istype(old_loc) && opacity) - old_loc.reconsider_lights() - - if(istype(new_loc) && opacity) - new_loc.reconsider_lights() - /atom/proc/set_opacity(new_opacity) var/old_opacity = opacity opacity = new_opacity diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index ca9d9b391f5..2dd3889e4e9 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -98,3 +98,5 @@ var/turf/T = loc if(istype(T)) T.lighting_overlay = null + + ..() diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index a7a59907097..e261931c41c 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -16,3 +16,13 @@ if(A.lighting_use_dynamic) var/atom/movable/lighting_overlay/O = PoolOrNew(/atom/movable/lighting_overlay, src) lighting_overlay = O + +/turf/Entered(atom/movable/obj) + . = ..() + if(obj && obj.opacity) + reconsider_lights() + +/turf/Exited(atom/movable/obj) + . = ..() + if(obj && obj.opacity) + reconsider_lights() diff --git a/code/modules/mining/alloys.dm b/code/modules/mining/alloys.dm index 9461c1e6b92..dac05badd02 100644 --- a/code/modules/mining/alloys.dm +++ b/code/modules/mining/alloys.dm @@ -12,7 +12,7 @@ metaltag = "plasteel" requires = list( "platinum" = 1, - "coal" = 2, + "carbon" = 2, "hematite" = 2 ) product_mod = 0.3 @@ -21,7 +21,7 @@ /datum/alloy/steel metaltag = DEFAULT_WALL_MATERIAL requires = list( - "coal" = 1, + "carbon" = 1, "hematite" = 1 ) product = /obj/item/stack/material/steel \ No newline at end of file diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 052c47987ae..af4ebfdaf70 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -114,16 +114,17 @@ var/sheets_per_tick = 10 var/list/ores_processing[0] var/list/ores_stored[0] - var/list/alloy_data[0] + var/static/list/alloy_data var/active = 0 /obj/machinery/mineral/processing_unit/New() - ..() - //TODO: Ore and alloy global storage datum. - for(var/alloytype in typesof(/datum/alloy)-/datum/alloy) - alloy_data += new alloytype() + // initialize static alloy_data list + if(!alloy_data) + alloy_data = list() + for(var/alloytype in typesof(/datum/alloy)-/datum/alloy) + alloy_data += new alloytype() if(!ore_data || !ore_data.len) for(var/oretype in typesof(/ore)-/ore) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index ed71989e500..892558d293c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -566,7 +566,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp toggle_visibility(1) else user.visible_message ( \ - "[user] just tried to smash his book into that ghost! It's not very effective.", \ + "[user] just tried to smash \his book into that ghost! It's not very effective.", \ "You get the feeling that the ghost can't become any more visible." \ ) @@ -634,7 +634,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/proc/updateghostsight() if (!seedarkness) - see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING + see_invisible = SEE_INVISIBLE_NOLIGHTING else see_invisible = SEE_INVISIBLE_OBSERVER if (!ghostvision) diff --git a/code/modules/mob/freelook/ai/eye.dm b/code/modules/mob/freelook/ai/eye.dm index e554d579ee4..dce53bb3ca4 100644 --- a/code/modules/mob/freelook/ai/eye.dm +++ b/code/modules/mob/freelook/ai/eye.dm @@ -28,23 +28,37 @@ // The AI's "eye". Described on the top of the page. /mob/living/silicon/ai - eyeobj = new /mob/eye/aiEye() var/obj/machinery/hologram/holopad/holo = null +/mob/living/silicon/ai/proc/destroy_eyeobj(var/atom/new_eye) + if(!eyeobj) return + if(!new_eye) + new_eye = src + eyeobj.owner = null + qdel(eyeobj) // No AI, no Eye + eyeobj = null + if(client) + client.eye = new_eye + +/mob/living/silicon/ai/proc/create_eyeobj(var/newloc) + if(eyeobj) destroy_eyeobj() + if(!newloc) newloc = src.loc + eyeobj = PoolOrNew(/mob/eye/aiEye, newloc) + eyeobj.owner = src + eyeobj.name = "[src.name] (AI Eye)" // Give it a name + if(client) client.eye = eyeobj + SetName(src.name) + // Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us. /mob/living/silicon/ai/New() ..() - eyeobj.owner = src - eyeobj.name = "[src.name] (AI Eye)" // Give it a name + create_eyeobj() spawn(5) if(eyeobj) eyeobj.loc = src.loc /mob/living/silicon/ai/Destroy() - if(eyeobj) - eyeobj.owner = null - qdel(eyeobj) // No AI, no Eye - eyeobj = null + destroy_eyeobj() ..() /atom/proc/move_camera_by_click() @@ -54,23 +68,18 @@ AI.eyeobj.setLoc(src) // Return to the Core. - /mob/living/silicon/ai/proc/core() set category = "AI Commands" set name = "AI Core" view_core() - /mob/living/silicon/ai/proc/view_core() camera = null unset_machine() if(!src.eyeobj) - src << "ERROR: Eyeobj not found. Creating new eye..." - src.eyeobj = new(src.loc) - src.eyeobj.owner = src - src.SetName(src.name) + return if(client && client.eye) client.eye = src diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm index d93edf3ac2d..17a145ae021 100644 --- a/code/modules/mob/language/generic.dm +++ b/code/modules/mob/language/generic.dm @@ -25,7 +25,7 @@ speech_verb = "says" whisper_verb = "whispers" key = "0" - flags = RESTRICTED + flags = RESTRICTED | COMMON_VERBS syllables = list("blah","blah","blah","bleh","meh","neh","nah","wah") //TODO flag certain languages to use the mob-type specific say_quote and then get rid of these. diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index af603fcb9bd..8f825046097 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -32,7 +32,7 @@ var/obj/item/organ/brain/sponge = internal_organs_by_name["brain"] if(sponge) sponge.take_damage(amount) - sponge.damage = min(max(brainloss, 0),(maxHealth*2)) + sponge.damage = min(max(sponge.damage, 0),(maxHealth*2)) brainloss = sponge.damage else brainloss = 200 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 1faf2f7e7ab..cdaad1c42f9 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -10,9 +10,11 @@ emp_act /mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) - var/obj/item/organ/external/organ = get_organ(check_zone(def_zone)) - if(!organ) - return + def_zone = check_zone(def_zone) + if(!has_organ(def_zone)) + return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by. + + var/obj/item/organ/external/organ = get_organ() //Shields if(check_shields(P.damage, "the [P.name]")) @@ -37,7 +39,7 @@ emp_act // redirect the projectile P.redirect(new_x, new_y, curloc, src) - return -1 // complete projectile permutation + return PROJECTILE_CONTINUE // complete projectile permutation //Shrapnel if(P.can_embed()) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 34668d0b66e..cdd556034d4 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1397,6 +1397,8 @@ sight |= G.vision_flags if(!druggy && !seer) see_invisible = SEE_INVISIBLE_MINIMUM + if(G.see_invisible >= 0) + see_invisible = G.see_invisible if(istype(G,/obj/item/clothing/glasses/night) && !seer) see_invisible = SEE_INVISIBLE_MINIMUM /* HUD shit goes here, as long as it doesn't modify sight flags */ diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index a126bccc876..90f82d9304e 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -128,6 +128,7 @@ proc/get_radio_key_from_channel(var/channel) return verb /mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="") + if(client) if(client.prefs.muted & MUTE_IC) src << "\red You cannot speak in IC (Muted)." @@ -165,7 +166,6 @@ proc/get_radio_key_from_channel(var/channel) else speaking = get_default_language() - var/ending = copytext(message, length(message)) if (speaking) // This is broadcast to all mobs with the language, // irrespective of distance or anything else. @@ -173,9 +173,12 @@ proc/get_radio_key_from_channel(var/channel) speaking.broadcast(src,trim(message)) return //If we've gotten this far, keep going! - verb = speaking.get_spoken_verb(ending) + if(speaking.flags & COMMON_VERBS) + verb = say_quote(message) + else + verb = speaking.get_spoken_verb(copytext(message, length(message))) else - verb = get_speech_ending(verb, ending) + verb = say_quote(message) message = trim_left(message) diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index 69d957fbaf9..c4a4d634488 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -39,20 +39,23 @@ laws.delete_law(law) log_and_message_admins("has deleted a law belonging to [src]: [law.law]") -/mob/living/silicon/proc/clear_inherent_laws() +/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0) laws_sanity_check() laws.clear_inherent_laws() - log_and_message_admins("cleared the inherent laws of [src]") + if(!silent) + log_and_message_admins("cleared the inherent laws of [src]") -/mob/living/silicon/proc/clear_ion_laws() +/mob/living/silicon/proc/clear_ion_laws(var/silent = 0) laws_sanity_check() laws.clear_ion_laws() - log_and_message_admins("cleared the ion laws of [src]") + if(!silent) + log_and_message_admins("cleared the ion laws of [src]") -/mob/living/silicon/proc/clear_supplied_laws() +/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0) laws_sanity_check() laws.clear_supplied_laws() - log_and_message_admins("cleared the supplied laws of [src]") + if(!silent) + log_and_message_admins("cleared the supplied laws of [src]") /mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) var/prefix = "" diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 3662ef72475..89df6fad397 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -213,9 +213,9 @@ death() /mob/living/silicon/robot/drone/proc/full_law_reset() - clear_supplied_laws() - clear_inherent_laws() - clear_ion_laws() + clear_supplied_laws(1) + clear_inherent_laws(1) + clear_ion_laws(1) laws = new law_type //Reboot procs. @@ -257,7 +257,7 @@ src << "You are a maintenance drone, a tiny-brained robotic repair machine." src << "You have no individual will, no personality, and no drives or urges other than your laws." src << "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI." - src << "Use :d to talk to other drones and say to speak silently to your nearby fellows." + src << "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows." /mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm new file mode 100644 index 00000000000..71ca1c6918c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm @@ -0,0 +1,40 @@ +/mob/living/silicon/robot/drone/say(var/message) + if(local_transmit) + if (src.client) + if(client.prefs.muted & MUTE_IC) + src << "You cannot send IC messages (muted)." + return 0 + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return 0 + + message = sanitize(message) + + if (stat == 2) + return say_dead(message) + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + if(copytext(message,1,2) == ";") + var/datum/language/L = all_languages["Drone Talk"] + if(istype(L)) + return L.broadcast(src,trim(copytext(message,2))) + + //Must be concious to speak + if (stat) + return 0 + + var/list/listeners = hearers(5,src) + listeners |= src + + for(var/mob/living/silicon/D in listeners) + if(D.client && D.local_transmit) + D << "[src] transmits, \"[message]\"" + + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + if(M.client) M << "[src] transmits, \"[message]\"" + return 1 + ..(message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 1fefa272e56..25052354ed8 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -1,3 +1,35 @@ +/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + log_say("[key_name(src)] : [message]") + +/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode) + if(!is_component_functioning("radio")) + src << "Your radio isn't functional at this time." + return 0 + if(message_mode == "general") + message_mode = null + return radio.talk_into(src,message,message_mode,verb,speaking) + +/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode == "department") + return holopad_talk(message, verb, speaking) + else if(message_mode) + if (aiRadio.disabledAi || aiRestorePowerRoutine || stat) + src << "System Error - Transceiver Disabled." + return 0 + if(message_mode == "general") + message_mode = null + return aiRadio.talk_into(src,message,message_mode,verb,speaking) + +/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode) + if(message_mode == "general") + message_mode = null + return radio.talk_into(src,message,message_mode,verb,speaking) + /mob/living/silicon/say_quote(var/text) var/ending = copytext(text, length(text)) @@ -23,131 +55,6 @@ return 1 return ..() -/mob/living/silicon/say(var/message) - if (!message) - return 0 - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "You cannot send IC messages (muted)." - return 0 - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return 0 - - message = sanitize(message) - - if (stat == 2) - return say_dead(message) - - if(copytext(message,1,2) == "*") - return emote(copytext(message,2)) - - var/bot_type = 0 //Let's not do a fuck ton of type checks, thanks. - if(istype(src, /mob/living/silicon/ai)) - bot_type = IS_AI - else if(istype(src, /mob/living/silicon/robot)) - bot_type = IS_ROBOT - else if(istype(src, /mob/living/silicon/pai)) - bot_type = IS_PAI - - var/mob/living/silicon/ai/AI = src //and let's not declare vars over and over and over for these guys. - var/mob/living/silicon/robot/R = src - var/mob/living/silicon/pai/P = src - - //Must be concious to speak - if (stat) - return 0 - - var/verb = say_quote(message) - - //parse radio key and consume it - var/message_mode = parse_message_mode(message, "general") - if (message_mode) - if (message_mode == "general") - message = trim(copytext(message,2)) - else - message = trim(copytext(message,3)) - - //parse language key and consume it - var/datum/language/speaking = parse_language(message) - if (speaking) - verb = speaking.speech_verb - message = trim(copytext(message,2+length(speaking.key))) - - if(speaking.flags & HIVEMIND) - speaking.broadcast(src,trim(message)) - return 1 - - // Currently used by drones. - if(local_transmit) - var/list/listeners = hearers(5,src) - listeners |= src - - for(var/mob/living/silicon/D in listeners) - if(D.client && istype(D,src.type)) - D << "[src] transmits, \"[message]\"" - - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) - if(M.client) M << "[src] transmits, \"[message]\"" - return 1 - - if(message_mode && bot_type == IS_ROBOT && !R.is_component_functioning("radio")) - src << "\red Your radio isn't functional at this time." - return 0 - - switch(message_mode) - if("department") - switch(bot_type) - if(IS_AI) - return AI.holopad_talk(message, verb, speaking) - if(IS_ROBOT) - log_say("[key_name(src)] : [message]") - return R.radio.talk_into(src,message,message_mode,verb,speaking) - if(IS_PAI) - log_say("[key_name(src)] : [message]") - return P.radio.talk_into(src,message,message_mode,verb,speaking) - return 0 - - if("general") - switch(bot_type) - if(IS_AI) - if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat) - src << "\red System Error - Transceiver Disabled" - return 0 - else - log_say("[key_name(src)] : [message]") - return AI.aiRadio.talk_into(src,message,null,verb,speaking) - if(IS_ROBOT) - log_say("[key_name(src)] : [message]") - return R.radio.talk_into(src,message,null,verb,speaking) - if(IS_PAI) - log_say("[key_name(src)] : [message]") - return P.radio.talk_into(src,message,null,verb,speaking) - return 0 - - else - if(message_mode) - switch(bot_type) - if(IS_AI) - if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat) - src << "\red System Error - Transceiver Disabled" - return 0 - else - log_say("[key_name(src)] : [message]") - return AI.aiRadio.talk_into(src,message,message_mode,verb,speaking) - if(IS_ROBOT) - log_say("[key_name(src)] : [message]") - return R.radio.talk_into(src,message,message_mode,verb,speaking) - if(IS_PAI) - log_say("[key_name(src)] : [message]") - return P.radio.talk_into(src,message,message_mode,verb,speaking) - return 0 - - return ..(message,speaking,verb) - //For holopads only. Usable by AI. /mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index b496a554b4d..c9998888f57 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -268,11 +268,11 @@ var/list/global/organ_rel_size = list( /proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0) zone = check_zone(zone) - // you cannot miss if your target is prone or restrained - if(target.buckled || target.lying) - return zone - // if your target is being grabbed aggressively by someone you cannot miss either if(!ranged_attack) + // you cannot miss if your target is prone or restrained + if(target.buckled || target.lying) + return zone + // if your target is being grabbed aggressively by someone you cannot miss either for(var/obj/item/weapon/grab/G in target.grabbed_by) if(G.state >= GRAB_AGGRESSIVE) return zone diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 4d3f68ceec3..f29330f5bd4 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -5,7 +5,6 @@ var/spawning = 0//Referenced when you want to delete the new_player later on in the code. var/totalPlayers = 0 //Player counts for the Lobby tab var/totalPlayersReady = 0 - universal_speak = 1 invisibility = 101 @@ -134,8 +133,6 @@ if(client.prefs.be_random_name) client.prefs.real_name = random_name(client.prefs.gender) - if(client.prefs.dummy) - qdel(client.prefs.dummy) observer.real_name = client.prefs.real_name observer.name = observer.real_name if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. @@ -455,8 +452,7 @@ client.prefs.randomize_appearance_for(new_character) else client.prefs.copy_to(new_character) - if(client.prefs.dummy) - qdel(client.prefs.dummy) + src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo if(mind) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index d3800f5b024..00b6a3b8e4a 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -178,46 +178,519 @@ datum/preferences b_skin = blue - proc/update_preview_icon() //seriously. This is horrendous. //less so now - if(!dummy) - dummy = new(null, species) - dummy.set_species(species) - dummy.flags |= GODMODE - copy_to(dummy) - for (var/obj/item/I in dummy) - dummy.drop_from_inventory(I) - if(I.loc != dummy) - qdel(I) - var/jobflag - var/dept - if (job_civilian_low & ASSISTANT) - jobflag = job_civilian_low - dept = CIVILIAN - else if(job_civilian_high) - jobflag = job_civilian_high - dept = CIVILIAN - else if (job_medsci_high) - jobflag = job_medsci_high - dept = MEDSCI - else if (job_engsec_high) - jobflag = job_engsec_high - dept = ENGSEC - if(jobflag && dept && job_master) - for (var/datum/job/J in job_master.occupations) - if((J.department_flag & dept) && (J.flag & jobflag)) - var/alt = GetPlayerAltTitle(J) - if(alt) //more hacks - if(!dummy.mind) - dummy.mind = new - dummy.mind.role_alt_title = alt - J.equip_preview(dummy) - break - dummy.update_eyes() - dummy.force_update_limbs() - dummy.regenerate_icons() - preview_icon = icon(dummy.icon) - for(var/image/I in dummy.overlays_standing) - if(I && I.icon) - preview_icon.Blend(icon(I.icon, I.icon_state), ICON_OVERLAY) + proc/update_preview_icon() //seriously. This is horrendous. + qdel(preview_icon_front) + qdel(preview_icon_side) + qdel(preview_icon) + + var/g = "m" + if(gender == FEMALE) g = "f" + + var/icon/icobase + var/datum/species/current_species = all_species[species] + + if(current_species) + icobase = current_species.icobase + else + icobase = 'icons/mob/human_races/r_human.dmi' + + preview_icon = new /icon(icobase, "torso_[g]") + preview_icon.Blend(new /icon(icobase, "groin_[g]"), ICON_OVERLAY) + preview_icon.Blend(new /icon(icobase, "head_[g]"), ICON_OVERLAY) + + for(var/name in list("r_arm","r_hand","r_leg","r_foot","l_leg","l_foot","l_arm","l_hand")) + if(organ_data[name] == "amputated") continue + if(organ_data[name] == "cyborg") + var/datum/robolimb/R + if(rlimb_data[name]) R = all_robolimbs[rlimb_data[name]] + if(!R) R = basic_robolimb + preview_icon.Blend(icon(R.icon, "[name]"), ICON_OVERLAY) // This doesn't check gendered_icon. Not an issue while only limbs can be robotic. + continue + preview_icon.Blend(new /icon(icobase, "[name]"), ICON_OVERLAY) + + //Tail + if(current_species && (current_species.tail)) + var/icon/temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[current_species.tail]_s") + preview_icon.Blend(temp, ICON_OVERLAY) + + // Skin color + if(current_species && (current_species.flags & HAS_SKIN_COLOR)) + preview_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) + + // Skin tone + if(current_species && (current_species.flags & HAS_SKIN_TONE)) + if (s_tone >= 0) + preview_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) + else + preview_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) + + var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = current_species ? current_species.eyes : "eyes_s") + if ((current_species && (current_species.flags & HAS_EYE_COLOR))) + eyes_s.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) + + var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + if(hair_style) + var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + eyes_s.Blend(hair_s, ICON_OVERLAY) + + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] + if(facial_hair_style) + var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") + facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) + eyes_s.Blend(facial_s, ICON_OVERLAY) + + var/icon/underwear_s = null + if(underwear && current_species.flags & HAS_UNDERWEAR) + underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear) + + var/icon/undershirt_s = null + if(undershirt && current_species.flags & HAS_UNDERWEAR) + undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = undershirt) + + var/icon/clothes_s = null + if(job_civilian_low & ASSISTANT)//This gives the preview icon clothes depending on which job(if any) is set to 'high' + clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if(backbag == 2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + else if(backbag == 3 || backbag == 4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + + else if(job_civilian_high)//I hate how this looks, but there's no reason to go through this switch if it's empty + switch(job_civilian_high) + if(HOP) + clothes_s = new /icon('icons/mob/uniform.dmi', "hop_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "ianshirt"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(BARTENDER) + clothes_s = new /icon('icons/mob/uniform.dmi', "ba_suit_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "tophat"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(BOTANIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "hydroponics_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "ggloves"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apron"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "nymph"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-hyd"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CHEF) + clothes_s = new /icon('icons/mob/uniform.dmi', "chef_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "chefhat"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "apronchef"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(JANITOR) + clothes_s = new /icon('icons/mob/uniform.dmi', "janitor_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_janitor"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(LIBRARIAN) + clothes_s = new /icon('icons/mob/uniform.dmi', "red_suit_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "hairflower"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(QUARTERMASTER) + clothes_s = new /icon('icons/mob/uniform.dmi', "qm_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "poncho"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CARGOTECH) + clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "flat_cap"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(MINER) + clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "bearpelt"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(LAWYER) + clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "briefcase"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suitjacket_blue"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CHAPLAIN) + clothes_s = new /icon('icons/mob/uniform.dmi', "chapblack_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "imperium_monk"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CLOWN) + clothes_s = new /icon('icons/mob/uniform.dmi', "clown_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "clown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/mask.dmi', "clown"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "clownpack"), ICON_OVERLAY) + if(MIME) + clothes_s = new /icon('icons/mob/uniform.dmi', "mime_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "lgloves"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/mask.dmi', "mime"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "beret"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "suspenders"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + + else if(job_medsci_high) + switch(job_medsci_high) + if(RD) + clothes_s = new /icon('icons/mob/uniform.dmi', "director_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "petehat"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(SCIENTIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(XENOBIOLOGIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "sciencewhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "metroid"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-tox"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CHEMIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "chemistrywhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labgreen"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_chem_open"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-chem"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CMO) + clothes_s = new /icon('icons/mob/uniform.dmi', "cmo_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "bio_cmo"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_cmo_open"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(DOCTOR) + clothes_s = new /icon('icons/mob/uniform.dmi', "medical_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "surgeon"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-med"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(GENETICIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "geneticswhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "monkeysuit"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_gen_open"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-gen"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(VIROLOGIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "virologywhite_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/mask.dmi', "sterile"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_vir_open"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "plaguedoctor"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "medicalpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-vir"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(ROBOTICIST) + clothes_s = new /icon('icons/mob/uniform.dmi', "robotics_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "toolbox_blue"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + + else if(job_engsec_high) + switch(job_engsec_high) + if(CAPTAIN) + clothes_s = new /icon('icons/mob/uniform.dmi', "captain_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "centcomcaptain"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/head.dmi', "captain"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-cap"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(HOS) + clothes_s = new /icon('icons/mob/uniform.dmi', "hosred_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "hosberet"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(WARDEN) + clothes_s = new /icon('icons/mob/uniform.dmi', "warden_s") + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "slippers_worn"), ICON_OVERLAY) + else + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(DETECTIVE) + clothes_s = new /icon('icons/mob/uniform.dmi', "detective_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/mask.dmi', "cigaron"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "detective"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "detective"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(OFFICER) + clothes_s = new /icon('icons/mob/uniform.dmi', "secred_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "jackboots"), ICON_UNDERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "officerberet"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "securitypack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-sec"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CHIEF) + clothes_s = new /icon('icons/mob/uniform.dmi', "chief_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_white"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon(INV_R_HAND_DEF_ICON, "blueprints"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(ENGINEER) + clothes_s = new /icon('icons/mob/uniform.dmi', "engine_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "orange"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "hardhat0_yellow"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "hazard"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "engiepack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(ATMOSTECH) + clothes_s = new /icon('icons/mob/uniform.dmi', "atmos_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/belt.dmi', "utility"), ICON_OVERLAY) + if(prob(1)) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "firesuit"), ICON_OVERLAY) + switch(backbag) + if(2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + if(3) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-norm"), ICON_OVERLAY) + if(4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + + if(AI)//Gives AI and borgs assistant-wear, so they can still customize their character + clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "straight_jacket"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY) + if(backbag == 2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + else if(backbag == 3 || backbag == 4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + if(CYBORG) + clothes_s = new /icon('icons/mob/uniform.dmi', "grey_s") + clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY) + clothes_s.Blend(new /icon('icons/mob/suit.dmi', "cardborg"), ICON_OVERLAY) + clothes_s.Blend(new /icon('icons/mob/head.dmi', "cardborg_h"), ICON_OVERLAY) + if(backbag == 2) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY) + else if(backbag == 3 || backbag == 4) + clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY) + + if(disabilities & NEARSIGHTED) + preview_icon.Blend(new /icon('icons/mob/eyes.dmi', "glasses"), ICON_OVERLAY) + + preview_icon.Blend(eyes_s, ICON_OVERLAY) + if(underwear_s) + preview_icon.Blend(underwear_s, ICON_OVERLAY) + if(undershirt_s) + preview_icon.Blend(undershirt_s, ICON_OVERLAY) + if(clothes_s) + preview_icon.Blend(clothes_s, ICON_OVERLAY) preview_icon_front = new(preview_icon, dir = SOUTH) - preview_icon_side = new(preview_icon, dir = WEST) \ No newline at end of file + preview_icon_side = new(preview_icon, dir = WEST) + + qdel(eyes_s) + qdel(underwear_s) + qdel(undershirt_s) + qdel(clothes_s) diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm index 340e0497632..a0a9280653e 100644 --- a/code/modules/nano/modules/crew_monitor.dm +++ b/code/modules/nano/modules/crew_monitor.dm @@ -3,17 +3,11 @@ var/list/tracked = new /datum/nano_module/crew_monitor/Topic(href, href_list) - if(..()) return - var/turf/T = get_turf(src) + if(..()) return 1 + var/turf/T = get_turf(nano_host()) // TODO: Allow setting any config.contact_levels from the interface. if (!T || !(T.z in config.player_levels)) usr << "Unable to establish a connection: You're too far away from the station!" return 0 - if(href_list["close"] ) - var/mob/user = usr - var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") - usr.unset_machine() - ui.close() - return 0 if(href_list["track"]) if(usr.isMobAI()) var/mob/living/silicon/ai/AI = usr @@ -23,11 +17,11 @@ return 1 /datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - user.set_machine(src) + // TODO: Move this to a singleton instance that does the scan every X seconds (if the info is being requested), to offer some antag balance and to reduce load in the case of multiple viewers. src.scan() var/data[0] - var/turf/T = get_turf(src) + var/turf/T = get_turf(nano_host()) var/list/crewmembers = list() for(var/obj/item/clothing/under/C in src.tracked) diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm index 8f39b91555a..850f5114c03 100644 --- a/code/modules/organs/wound.dm +++ b/code/modules/organs/wound.dm @@ -36,9 +36,8 @@ var/list/stages // internal wounds can only be fixed through surgery var/internal = 0 - // maximum stage at which bleeding should still happen, counted from the right rather than the left of the list - // 1 means all stages except the last should bleed - var/max_bleeding_stage = 1 + // maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented. + var/max_bleeding_stage = 0 // one of CUT, BRUISE, BURN var/damage_type = CUT // whether this wound needs a bandage/salve to heal at all @@ -64,8 +63,6 @@ src.damage = damage - max_bleeding_stage = src.desc_list.len - max_bleeding_stage - // initialize with the appropriate stage src.init_stage(damage) @@ -248,7 +245,9 @@ /** CUTS **/ /datum/wound/cut/small // link wound descriptions to amounts of damage - max_bleeding_stage = 2 + // Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name. + // The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor). + max_bleeding_stage = 3 stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0) damage_type = CUT @@ -263,25 +262,25 @@ damage_type = CUT /datum/wound/cut/gaping - max_bleeding_stage = 2 - stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "large clot" = 15, "small angry scar" = 5, "small straight scar" = 0) + max_bleeding_stage = 3 + stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0) damage_type = CUT /datum/wound/cut/gaping_big - max_bleeding_stage = 2 - stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large angry scar" = 10, "large straight scar" = 0) + max_bleeding_stage = 3 + stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0) damage_type = CUT datum/wound/cut/massive - max_bleeding_stage = 2 - stages = list("massive wound" = 70, "massive healing wound" = 50, "massive angry scar" = 10, "massive jagged scar" = 0) + max_bleeding_stage = 3 + stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0) damage_type = CUT /** BRUISES **/ /datum/wound/bruise - stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,\ + stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30, "moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5) - max_bleeding_stage = 3 + max_bleeding_stage = 3 //only large bruise and above can bleed. autoheal_cutoff = 30 damage_type = BRUISE @@ -311,7 +310,7 @@ datum/wound/cut/massive internal = 1 stages = list("severed artery" = 30, "cut artery" = 20, "damaged artery" = 10, "bruised artery" = 5) autoheal_cutoff = 5 - max_bleeding_stage = 0 //all stages bleed. It's called internal bleeding after all. + max_bleeding_stage = 4 //all stages bleed. It's called internal bleeding after all. /** EXTERNAL ORGAN LOSS **/ /datum/wound/lost_limb @@ -323,7 +322,7 @@ datum/wound/cut/massive switch(losstype) if(DROPLIMB_EDGE, DROPLIMB_BLUNT) damage_type = CUT - max_bleeding_stage = 3 + max_bleeding_stage = 3 //clotted stump and above can bleed. stages = list( "ripped stump" = damage_amt*1.3, "bloody stump" = damage_amt, @@ -332,7 +331,6 @@ datum/wound/cut/massive ) if(DROPLIMB_BURN) damage_type = BURN - max_bleeding_stage = 1 stages = list( "ripped charred stump" = damage_amt*1.3, "charred stump" = damage_amt, diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index f13ad242873..6d8c40c16c2 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -165,14 +165,17 @@ //roll to-hit miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0) - var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1)) - if(!hit_zone) + var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss + + var/result = PROJECTILE_FORCE_MISS + if(hit_zone) + def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part + result = target_mob.bullet_act(src, def_zone) + + if(result == PROJECTILE_FORCE_MISS) visible_message("\The [src] misses [target_mob] narrowly!") return 0 - //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part - def_zone = hit_zone - //hit messages if(silenced) target_mob << "You've been hit in the [parse_zone(def_zone)] by \the [src]!" @@ -193,7 +196,7 @@ msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with \a [src] (JMP)") //sometimes bullet_act() will want the projectile to continue flying - if (target_mob.bullet_act(src, def_zone) == -1) + if (result == PROJECTILE_CONTINUE) return 0 return 1 @@ -227,7 +230,7 @@ else passthrough = 1 //so ghosts don't stop bullets else - passthrough = (A.bullet_act(src, def_zone) == -1) //backwards compatibility + passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility if(isturf(A)) for(var/obj/O in A) O.bullet_act(src) diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm new file mode 100644 index 00000000000..1432b18a2e8 --- /dev/null +++ b/code/modules/reagents/Chemistry-Logging.dm @@ -0,0 +1,28 @@ + +/var/list/chemical_reaction_logs = list() + +/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier) + if(!A || !R) + return + + var/turf/T = get_turf(A) + var/logstr = "[usr ? key_name(usr) : "EVENT"] mixed [R.name] ([R.result]) (x[multiplier]) in \the [A] at [T ? "[T.x],[T.y],[T.z]" : "*null*"]" + + chemical_reaction_logs += "\[[time_stamp()]\] [logstr]" + + if(R.log_is_important) + message_admins(logstr) + log_admin(logstr) + +/client/proc/view_chemical_reaction_logs() + set name = "Show Chemical Reactions" + set category = "Admin" + + if(!check_rights(R_ADMIN)) + return + + var/html = "" + for(var/entry in chemical_reaction_logs) + html += "[entry]
" + + usr << browse(html, "window=chemlogs") diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 251c7d8a62b..b907215061e 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -52,6 +52,7 @@ var/mix_message = "The solution begins to bubble." var/reaction_sound = 'sound/effects/bubbles.ogg' + var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file. /datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder) //check that all the required reagents are present if(!holder.has_all_reagents(required_reagents)) @@ -271,6 +272,7 @@ result = "kelotane" required_reagents = list("silicon" = 1, "carbon" = 1) result_amount = 2 + log_is_important = 1 /datum/chemical_reaction/peridaxon name = "Peridaxon" @@ -517,6 +519,7 @@ result = "coolant" required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1) result_amount = 3 + log_is_important = 1 /datum/chemical_reaction/rezadone name = "Rezadone" @@ -652,6 +655,7 @@ result = "nitroglycerin" required_reagents = list("glycerol" = 1, "pacid" = 1, "sacid" = 1) result_amount = 2 + log_is_important = 1 /datum/chemical_reaction/nitroglycerin/on_reaction(var/datum/reagents/holder, var/created_volume) var/datum/effect/effect/system/reagents_explosion/e = new() diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm index d88d5cb5947..3ee774e0123 100644 --- a/code/modules/recycling/disposal-construction.dm +++ b/code/modules/recycling/disposal-construction.dm @@ -83,7 +83,7 @@ ///// Z-Level stuff - if(ptype<6 || ptype>8 && !(ptype==11 || ptype==12)) + if(!(ptype in list(6, 7, 8, 11, 12, 13, 14))) ///// Z-Level stuff icon_state = "con[base_state]" else diff --git a/code/world.dm b/code/world.dm index 79b6c059c8d..9a5508ffe91 100644 --- a/code/world.dm +++ b/code/world.dm @@ -127,7 +127,8 @@ var/world_topic_spam_protect_time = world.timeofday n++ return n - else if (T == "status") + else if (copytext(T,1,7) == "status") + var/input[] = params2list(T) var/list/s = list() s["version"] = game_version s["mode"] = master_mode @@ -136,21 +137,37 @@ var/world_topic_spam_protect_time = world.timeofday s["vote"] = config.allow_vote_mode s["ai"] = config.allow_ai s["host"] = host ? host : null - s["players"] = list() s["stationtime"] = worldtime2text() - var/n = 0 - var/admins = 0 - for(var/client/C in clients) - if(C.holder) - if(C.holder.fakekey) - continue //so stealthmins aren't revealed by the hub - admins++ - s["player[n]"] = C.key - n++ - s["players"] = n + if(input["status"] == "2") + var/list/players = list() + var/list/admins = list() - s["admins"] = admins + for(var/client/C in clients) + if(C.holder) + if(C.holder.fakekey) + continue + admins[C.key] = C.holder.rank + players += C.key + + s["players"] = players.len + s["playerlist"] = list2params(players) + s["admins"] = admins.len + s["adminlist"] = list2params(admins) + else + var/n = 0 + var/admins = 0 + + for(var/client/C in clients) + if(C.holder) + if(C.holder.fakekey) + continue //so stealthmins aren't revealed by the hub + admins++ + s["player[n]"] = C.key + n++ + + s["players"] = n + s["admins"] = admins return list2params(s) diff --git a/html/changelog.html b/html/changelog.html index d2bc033a607..7e11154c81e 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,19 @@ -->
+

31 July 2015

+

HarpyEagle updated:

+ + +

29 July 2015

+

Karolis2011 updated:

+ +

27 July 2015

Kelenius updated: