diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index c6a78c418e6..b6fcfc104c8 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -188,3 +188,36 @@ // teehee no one will find these here #define MFOAM_ALUMINUM 1 #define MFOAM_IRON 2 + +//Human Overlays Indexes///////// +#define MUTANTRACE_LAYER 1 +#define TAIL_UNDERLIMBS_LAYER 2 +#define LIMBS_LAYER 3 +#define MARKINGS_LAYER 4 +#define UNDERWEAR_LAYER 5 +#define MUTATIONS_LAYER 6 +#define DAMAGE_LAYER 7 +#define UNIFORM_LAYER 8 +#define ID_LAYER 9 +#define SHOES_LAYER 10 +#define GLOVES_LAYER 11 +#define EARS_LAYER 12 +#define SUIT_LAYER 13 +#define GLASSES_LAYER 14 +#define BELT_LAYER 15 //Possible make this an overlay of somethign required to wear a belt? +#define SUIT_STORE_LAYER 16 +#define BACK_LAYER 17 +#define TAIL_LAYER 18 //bs12 specific. this hack is probably gonna come back to haunt me +#define HAIR_LAYER 19 //TODO: make part of head layer? +#define HEAD_ACCESSORY_LAYER 20 +#define FHAIR_LAYER 21 +#define FACEMASK_LAYER 22 +#define HEAD_LAYER 23 +#define COLLAR_LAYER 24 +#define HANDCUFF_LAYER 25 +#define LEGCUFF_LAYER 26 +#define L_HAND_LAYER 27 +#define R_HAND_LAYER 28 +#define TARGETED_LAYER 29 //BS12: Layer for the target overlay from weapon targeting system +#define FIRE_LAYER 30 //If you're on fire +#define TOTAL_LAYERS 30 \ No newline at end of file diff --git a/code/datums/helper_datums/icon_snapshot.dm b/code/datums/helper_datums/icon_snapshot.dm new file mode 100644 index 00000000000..22b402be446 --- /dev/null +++ b/code/datums/helper_datums/icon_snapshot.dm @@ -0,0 +1,15 @@ +/datum/icon_snapshot + var/name + var/icon + var/icon_state + var/list/overlays + +/datum/icon_snapshot/proc/makeImg() + if(!icon || !icon_state) + return + var/obj/temp = new + temp.icon = icon + temp.icon_state = icon_state + temp.overlays = overlays.Copy() + var/icon/tempicon = getFlatIcon(temp) // TODO Actually write something less heavy-handed for this + return tempicon diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm new file mode 100644 index 00000000000..6345fb4e830 --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/abduction.dm @@ -0,0 +1,459 @@ +/datum/game_mode + var/abductor_teams = 0 + var/list/datum/mind/abductors = list() + var/list/datum/mind/abductees = list() + +/datum/game_mode/abduction + name = "abduction" + config_tag = "abduction" + recommended_enemies = 2 + required_players = 15 + required_players_secret = 15 + var/max_teams = 4 + abductor_teams = 1 + var/list/datum/mind/scientists = list() + var/list/datum/mind/agents = list() + var/list/datum/objective/team_objectives = list() + var/list/team_names = list() + var/finished = 0 + var/list/datum/mind/possible_abductors = list() + +/datum/game_mode/abduction/announce() + to_chat(world, "The current game mode is - Abduction!") + to_chat(world, "There are alien abductors sent to [world.name] to perform nefarious experiments!") + to_chat(world, "Abductors - kidnap the crew and replace their organs with experimental ones.") + to_chat(world, "Crew - don't get abducted and stop the abductors.") + +/datum/game_mode/abduction/pre_setup() + possible_abductors = get_players_for_role(ROLE_ABDUCTOR) + + if(!possible_abductors.len) + return 0 + + abductor_teams = max(1, min(max_teams,round(num_players()/15))) + var/possible_teams = max(1,round(possible_abductors.len / 2)) + abductor_teams = min(abductor_teams,possible_teams) + + abductors.len = 2*abductor_teams + scientists.len = abductor_teams + agents.len = abductor_teams + team_objectives.len = abductor_teams + team_names.len = abductor_teams + + for(var/i=1,i<=abductor_teams,i++) + if(!make_abductor_team(i)) + return 0 + + return 1 + +/datum/game_mode/abduction/proc/make_abductor_team(team_number,preset_agent=null,preset_scientist=null) + //Team Name + team_names[team_number] = "Mothership [pick(possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names + //Team Objective + var/datum/objective/experiment/team_objective = new + team_objective.team = team_number + team_objectives[team_number] = team_objective + //Team Members + + if(!preset_agent || !preset_scientist) + if(possible_abductors.len <=2) + return 0 + + var/datum/mind/scientist + var/datum/mind/agent + + if(!preset_scientist) + scientist = pick(possible_abductors) + possible_abductors -= scientist + else + scientist = preset_scientist + + if(!preset_agent) + agent = pick(possible_abductors) + possible_abductors -= agent + else + agent = preset_agent + + + scientist.assigned_role = "abductor scientist" + scientist.special_role = "abductor scientist" + log_game("[scientist.key] (ckey) has been selected as an abductor team [team_number] scientist.") + + agent.assigned_role = "abductor agent" + agent.special_role = "abductor agent" + log_game("[agent.key] (ckey) has been selected as an abductor team [team_number] agent.") + + abductors |= agent + abductors |= scientist + scientists[team_number] = scientist + agents[team_number] = agent + return 1 + +/datum/game_mode/abduction/post_setup() + //Spawn Team + var/list/obj/effect/landmark/abductor/agent_landmarks = new + var/list/obj/effect/landmark/abductor/scientist_landmarks = new + agent_landmarks.len = max_teams + scientist_landmarks.len = max_teams + for(var/obj/effect/landmark/abductor/A in landmarks_list) + if(istype(A,/obj/effect/landmark/abductor/agent)) + agent_landmarks[text2num(A.team)] = A + else if(istype(A,/obj/effect/landmark/abductor/scientist)) + scientist_landmarks[text2num(A.team)] = A + + var/datum/mind/agent + var/obj/effect/landmark/L + var/datum/mind/scientist + var/team_name + var/mob/living/carbon/human/H + var/datum/species/abductor/S + for(var/team_number=1,team_number<=abductor_teams,team_number++) + team_name = team_names[team_number] + agent = agents[team_number] + H = agent.current + L = agent_landmarks[team_number] + H.loc = L.loc + H.set_species("Abductor") + S = H.dna.species + S.agent = 1 + S.team = team_number + H.real_name = team_name + " Agent" + equip_common(H,team_number) + equip_agent(H,team_number) + greet_agent(agent,team_number) + + scientist = scientists[team_number] + H = scientist.current + L = scientist_landmarks[team_number] + H.loc = L.loc + H.set_species("Abductor") + S = H.dna.species + S.scientist = 1 + S.team = team_number + H.real_name = team_name + " Scientist" + equip_common(H,team_number) + equip_scientist(H,team_number) + greet_scientist(scientist,team_number) + return ..() + +//Used for create antag buttons +/datum/game_mode/abduction/proc/post_setup_team(team_number) + var/list/obj/effect/landmark/abductor/agent_landmarks = new + var/list/obj/effect/landmark/abductor/scientist_landmarks = new + agent_landmarks.len = max_teams + scientist_landmarks.len = max_teams + for(var/obj/effect/landmark/abductor/A in landmarks_list) + if(istype(A,/obj/effect/landmark/abductor/agent)) + agent_landmarks[text2num(A.team)] = A + else if(istype(A,/obj/effect/landmark/abductor/scientist)) + scientist_landmarks[text2num(A.team)] = A + + var/datum/mind/agent + var/obj/effect/landmark/L + var/datum/mind/scientist + var/team_name + var/mob/living/carbon/human/H + var/datum/species/abductor/S + + team_name = team_names[team_number] + agent = agents[team_number] + H = agent.current + L = agent_landmarks[team_number] + H.loc = L.loc + H.set_species("Abductor") + S = H.dna.species + S.agent = 1 + S.team = team_number + H.real_name = team_name + " Agent" + equip_common(H,team_number) + equip_agent(H,team_number) + greet_agent(agent,team_number) + + + scientist = scientists[team_number] + H = scientist.current + L = scientist_landmarks[team_number] + H.loc = L.loc + H.set_species("Abductor") + S = H.dna.species + S.scientist = 1 + S.team = team_number + H.real_name = team_name + " Scientist" + equip_common(H,team_number) + equip_scientist(H,team_number) + greet_scientist(scientist,team_number) + + + +/datum/game_mode/abduction/proc/greet_agent(datum/mind/abductor,team_number) + abductor.objectives += team_objectives[team_number] + var/team_name = team_names[team_number] + + to_chat(abductor.current, "You are an agent of [team_name]!") + to_chat(abductor.current, "With the help of your teammate, kidnap and experiment on station crew members!") + to_chat(abductor.current, "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve.") + + var/obj_count = 1 + for(var/datum/objective/objective in abductor.objectives) + to_chat(abductor.current, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + return + +/datum/game_mode/abduction/proc/greet_scientist(datum/mind/abductor,team_number) + abductor.objectives += team_objectives[team_number] + var/team_name = team_names[team_number] + + to_chat(abductor.current, "You are a scientist of [team_name]!") + to_chat(abductor.current, "With the help of your teammate, kidnap and experiment on station crew members!") + to_chat(abductor.current, "Use your tool and ship consoles to support the agent and retrieve human specimens.") + + var/obj_count = 1 + for(var/datum/objective/objective in abductor.objectives) + to_chat(abductor.current, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + return + +/datum/game_mode/abduction/proc/equip_common(mob/living/carbon/human/agent,team_number) + var/radio_freq = SYND_FREQ + + var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate/alt(agent) + R.set_frequency(radio_freq) + agent.equip_to_slot_or_del(R, slot_l_ear) + agent.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(agent), slot_shoes) + agent.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(agent), slot_w_uniform) //they're greys gettit + agent.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(agent), slot_back) + +/datum/game_mode/abduction/proc/get_team_console(team) + var/obj/machinery/abductor/console/console + for(var/obj/machinery/abductor/console/c in machines) + if(c.team == team) + console = c + break + return console + +/datum/game_mode/abduction/proc/equip_agent(mob/living/carbon/human/agent,team_number) + if(!team_number) + var/datum/species/abductor/S = agent.dna.species + team_number = S.team + + var/obj/machinery/abductor/console/console = get_team_console(team_number) + var/obj/item/clothing/suit/armor/abductor/vest/V = new /obj/item/clothing/suit/armor/abductor/vest(agent) + if(console!=null) + console.vest = V + V.flags |= NODROP + agent.equip_to_slot_or_del(V, slot_wear_suit) + agent.equip_to_slot_or_del(new /obj/item/weapon/abductor_baton(agent), slot_in_backpack) + agent.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/decloner/alien(agent), slot_belt) + agent.equip_to_slot_or_del(new /obj/item/device/abductor/silencer(agent), slot_in_backpack) + agent.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/abductor(agent), slot_head) + + +/datum/game_mode/abduction/proc/equip_scientist(var/mob/living/carbon/human/scientist,var/team_number) + if(!team_number) + var/datum/species/abductor/S = scientist.dna.species + team_number = S.team + + var/obj/machinery/abductor/console/console = get_team_console(team_number) + var/obj/item/device/abductor/gizmo/G = new /obj/item/device/abductor/gizmo(scientist) + if(console!=null) + console.gizmo = G + G.console = console + scientist.equip_to_slot_or_del(G, slot_in_backpack) + + var/obj/item/weapon/implant/abductor/beamplant = new /obj/item/weapon/implant/abductor(scientist) + beamplant.implant(scientist) + + +/datum/game_mode/abduction/check_finished() + if(!finished) + for(var/team_number=1,team_number<=abductor_teams,team_number++) + var/obj/machinery/abductor/console/con = get_team_console(team_number) + var/datum/objective/objective = team_objectives[team_number] + if (con.experiment.points >= objective.target_amount) + shuttle_master.emergency.request(null, 0.5) + finished = 1 + return ..() + return ..() + +/datum/game_mode/abduction/declare_completion() + for(var/team_number=1,team_number<=abductor_teams,team_number++) + var/obj/machinery/abductor/console/console = get_team_console(team_number) + var/datum/objective/objective = team_objectives[team_number] + var/team_name = team_names[team_number] + if(console.experiment.points >= objective.target_amount) + to_chat(world, "[team_name] team fullfilled its mission!") + else + to_chat(world, "[team_name] team failed its mission.") + ..() + return 1 + +/datum/game_mode/proc/auto_declare_completion_abduction() + if(abductors.len) + to_chat(world, "Abductors:") + for(var/datum/mind/M in abductors) + to_chat(world, "Abductor [M.current ? M.current.name : "Abductor"]([M.key])") + return + +//Landmarks +// TODO: Split into seperate landmarks for prettier ships +/obj/effect/landmark/abductor + var/team = 1 + +/obj/effect/landmark/abductor/console/New() + var/obj/machinery/abductor/console/c = new /obj/machinery/abductor/console(src.loc) + c.team = team + + spawn(5) // I'd do this properly when i got some time, temporary hack for mappers + c.Initialize() + qdel(src) + + +/obj/effect/landmark/abductor/agent +/obj/effect/landmark/abductor/scientist + + +// OBJECTIVES +/datum/objective/experiment + target_amount = 6 + var/team + +/datum/objective/experiment/New() + explanation_text = "Experiment on [target_amount] humans." + +/datum/objective/experiment/check_completion() + var/ab_team = team + if(owner) + if(!owner.current || !ishuman(owner.current)) + return 0 + var/mob/living/carbon/human/H = owner.current + if(H.get_species() != "Abductor") + return 0 + var/datum/species/abductor/S = H.dna.species + ab_team = S.team + for(var/obj/machinery/abductor/experiment/E in machines) + if(E.team == ab_team) + if(E.points >= target_amount) + return 1 + else + return 0 + return 0 + +/datum/game_mode/proc/update_abductor_icons_added(datum/mind/alien_mind) + var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_ABDUCTOR] + hud.join_hud(alien_mind.current) + set_antag_hud(alien_mind.current, ((alien_mind in abductors) ? "abductor" : "abductee")) + +/datum/game_mode/proc/update_abductor_icons_removed(datum/mind/alien_mind) + var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_ABDUCTOR] + hud.leave_hud(alien_mind.current) + set_antag_hud(alien_mind.current, null) + +/datum/objective/abductee + completed = 1 + +/datum/objective/abductee/steal + explanation_text = "Steal all" + +/datum/objective/abductee/steal/New() + var/target = pick(list("pets","lights","monkeys","fruits","shoes","bars of soap")) + explanation_text+=" [target]." + +/datum/objective/abductee/capture + explanation_text = "Capture" + +/datum/objective/abductee/capture/New() + var/list/jobs = job_master.occupations.Copy() + for(var/datum/job/J in jobs) + if(J.current_positions < 1) + jobs -= J + if(jobs.len > 0) + var/datum/job/target = pick(jobs) + explanation_text += " a [target.title]." + else + explanation_text += " someone." + +/datum/objective/abductee/shuttle + explanation_text = "You must escape the station! Get the shuttle called!" + +/datum/objective/abductee/noclone + explanation_text = "Don't allow anyone to be cloned." + +/datum/objective/abductee/oxygen + explanation_text = "The oxygen is killing them all and they don't even know it. Make sure no oxygen is on the station." + +/datum/objective/abductee/blazeit + explanation_text = "Your body must be improved. Ingest as many drugs as you can." + +/datum/objective/abductee/yumyum + explanation_text = "You are hungry. Eat as much food as you can find." + +/datum/objective/abductee/insane + explanation_text = "You see you see what they cannot you see the open door you seeE you SEeEe you SEe yOU seEee SHOW THEM ALL" + +/datum/objective/abductee/cannotmove + explanation_text = "Convince the crew that you are a paraplegic." + +/datum/objective/abductee/deadbodies + explanation_text = "Start a collection of corpses. Don't kill people to get these corpses." + +/datum/objective/abductee/floors + explanation_text = "Replace all the floor tiles with carpeting, wooden boards, or grass." + +/datum/objective/abductee/POWERUNLIMITED + explanation_text = "Flood the station's powernet with as much electricity as you can." + +/datum/objective/abductee/pristine + explanation_text = "Ensure the station is in absolutely pristine condition." + +/datum/objective/abductee/window + explanation_text = "Replace all normal windows with reinforced windows." + +/datum/objective/abductee/nations + explanation_text = "Ensure your department prospers over all else." + +/datum/objective/abductee/abductception + explanation_text = "You have been changed forever. Find the ones that did this to you and give them a taste of their own medicine." + +/datum/objective/abductee/ghosts + explanation_text = "Conduct a seance with the spirits of the afterlife." + +/datum/objective/abductee/summon + explanation_text = "Conduct a ritual to summon an elder god." + +/datum/objective/abductee/machine + explanation_text = "You are secretly an android. Interface with as many machines as you can to boost your own power." + +/datum/objective/abductee/prevent + explanation_text = "You have been enlightened. This knowledge must not escape. Ensure nobody else can become enlightened." + +/datum/objective/abductee/calling + explanation_text = "Call forth a spirit from the other side." + +/datum/objective/abductee/calling/New() + var/mob/dead/D = pick(dead_mob_list) + if(D) + explanation_text = "You know that [D] has perished. Call them from the spirit realm." + +/datum/objective/abductee/social_experiment + explanation_text = "This is a secret social experiment conducted by Nanotrasen. Convince the crew that this is the truth." + +/datum/objective/abductee/vr + explanation_text = "It's all an entirely virtual simulation within an underground vault. Convince the crew to escape the shackles of VR." + +/datum/objective/abductee/pets + explanation_text = "Nanotrasen is abusing the animals! Save as many as you can!" + +/datum/objective/abductee/defect + explanation_text = "Defect from your employer." + +/datum/objective/abductee/promote + explanation_text = "Climb the corporate ladder all the way to the top!" + +/datum/objective/abductee/science + explanation_text = "So much lies undiscovered. Look deeper into the machinations of the universe." + +/datum/objective/abductee/build + explanation_text = "Expand the station." + +/datum/objective/abductee/pragnant + explanation_text = "You are pregnant and soon due. Find a safe place to deliver your baby." diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm new file mode 100644 index 00000000000..689398af78d --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -0,0 +1,644 @@ +#define VEST_STEALTH 1 +#define VEST_COMBAT 2 +#define GIZMO_SCAN 1 +#define GIZMO_MARK 2 + +//AGENT VEST +/obj/item/clothing/suit/armor/abductor/vest + name = "agent vest" + desc = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth." + icon = 'icons/obj/abductor.dmi' + icon_state = "vest_stealth" + item_state = "armor" + blood_overlay_type = "armor" + origin_tech = "materials=5;biotech=4;powerstorage=5;abductor=3" + armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15) + action_button_is_hands_free = 1 + var/mode = VEST_STEALTH + var/stealth_active = 0 + var/combat_cooldown = 10 + var/datum/icon_snapshot/disguise + var/stealth_armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15) + var/combat_armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 50, bio = 50, rad = 50) + +/obj/item/clothing/suit/armor/abductor/vest/proc/flip_mode() + switch(mode) + if(VEST_STEALTH) + mode = VEST_COMBAT + DeactivateStealth() + armor = combat_armor + icon_state = "vest_combat" + if(istype(loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = loc + H.update_inv_wear_suit() + return + if(VEST_COMBAT)// TO STEALTH + mode = VEST_STEALTH + armor = stealth_armor + icon_state = "vest_stealth" + if(istype(loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = loc + H.update_inv_wear_suit() + return + +/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(datum/icon_snapshot/entry) + disguise = entry + +/obj/item/clothing/suit/armor/abductor/vest/proc/ActivateStealth() + if(disguise == null) + return + stealth_active = 1 + if(istype(src.loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = src.loc + spawn(0) + anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir) + + M.name_override = disguise.name + M.icon = disguise.icon + M.icon_state = disguise.icon_state + M.overlays = disguise.overlays + M.update_inv_r_hand() + M.update_inv_l_hand() + return + +/obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth() + if(!stealth_active) + return + stealth_active = 0 + if(istype(src.loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = src.loc + spawn(0) + anim(M.loc,M,'icons/mob/mob.dmi',,"uncloak",,M.dir) + M.name_override = null + M.overlays.Cut() + M.regenerate_icons() + return + +/obj/item/clothing/suit/armor/abductor/vest/IsShield() + DeactivateStealth() + return 0 + +/obj/item/clothing/suit/armor/abductor/vest/IsReflect() + DeactivateStealth() + return 0 + +/obj/item/clothing/suit/armor/abductor/vest/ui_action_click() + switch(mode) + if(VEST_COMBAT) + Adrenaline() + if(VEST_STEALTH) + if(stealth_active) + DeactivateStealth() + else + ActivateStealth() + +/obj/item/clothing/suit/armor/abductor/vest/proc/Adrenaline() + if(istype(src.loc, /mob/living/carbon/human)) + if(combat_cooldown != initial(combat_cooldown)) + to_chat(src.loc, "Combat injection is still recharging.") + var/mob/living/carbon/human/M = src.loc + M.adjustStaminaLoss(-75) + M.SetParalysis(0) + M.SetStunned(0) + M.SetWeakened(0) + combat_cooldown = 0 + processing_objects.Add(src) + +/obj/item/clothing/suit/armor/abductor/vest/process() + combat_cooldown++ + if(combat_cooldown==initial(combat_cooldown)) + processing_objects.Remove(src) + +/obj/item/device/abductor/proc/IsAbductor(user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.get_species() != "Abductor") + return 0 + return 1 + return 0 + +/obj/item/device/abductor/proc/AbductorCheck(user) + if(IsAbductor(user)) + return 1 + to_chat(user, "You can't figure how this works!") + return 0 + +/obj/item/device/abductor/proc/ScientistCheck(user) + var/mob/living/carbon/human/H = user + var/datum/species/abductor/S = H.dna.species + return S.scientist + +/obj/item/device/abductor/gizmo + name = "science tool" + desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras." + icon = 'icons/obj/abductor.dmi' + icon_state = "gizmo_scan" + item_state = "silencer" + origin_tech = "materials=5;magnets=5;bluespace=6;abductor=4" + var/mode = GIZMO_SCAN + var/mob/living/marked = null + var/obj/machinery/abductor/console/console + +/obj/item/device/abductor/gizmo/attack_self(mob/user) + if(!AbductorCheck(user)) + return + if(!ScientistCheck(user)) + to_chat(user, "You're not trained to use this!") + return + if(mode == GIZMO_SCAN) + mode = GIZMO_MARK + icon_state = "gizmo_mark" + else + mode = GIZMO_SCAN + icon_state = "gizmo_scan" + to_chat(user, "You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE") + +/obj/item/device/abductor/gizmo/attack(mob/living/M, mob/user) + if(!AbductorCheck(user)) + return + if(!ScientistCheck(user)) + to_chat(user, "You're not trained to use this") + return + switch(mode) + if(GIZMO_SCAN) + scan(M, user) + if(GIZMO_MARK) + mark(M, user) + + +/obj/item/device/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params) + if(flag) + return + if(!AbductorCheck(user)) + return + if(!ScientistCheck(user)) + to_chat(user, "You're not trained to use this") + return + switch(mode) + if(GIZMO_SCAN) + scan(target, user) + if(GIZMO_MARK) + mark(target, user) + +/obj/item/device/abductor/gizmo/proc/scan(atom/target, mob/living/user) + if(istype(target,/mob/living/carbon/human)) + if(console!=null) + console.AddSnapshot(target) + to_chat(user, "You scan [target] and add them to the database.") + +/obj/item/device/abductor/gizmo/proc/mark(atom/target, mob/living/user) + if(marked == target) + to_chat(user, "This specimen is already marked!") + return + if(istype(target,/mob/living/carbon/human)) + if(IsAbductor(target)) + marked = target + to_chat(user, "You mark [target] for future retrieval.") + else + prepare(target,user) + else + prepare(target,user) + +/obj/item/device/abductor/gizmo/proc/prepare(atom/target, mob/living/user) + if(get_dist(target,user)>1) + to_chat(user, "You need to be next to the specimen to prepare it for transport!") + return + to_chat(user, "You begin preparing [target] for transport...") + if(do_after(user, 100, target = target)) + marked = target + to_chat(user, "You finish preparing [target] for transport.") + + +/obj/item/device/abductor/silencer + name = "abductor silencer" + desc = "A compact device used to shut down communications equipment." + icon = 'icons/obj/abductor.dmi' + icon_state = "silencer" + item_state = "gizmo" + origin_tech = "materials=5;magnets=5;abductor=3" + +/obj/item/device/abductor/silencer/attack(mob/living/M, mob/user) + if(!AbductorCheck(user)) + return + radio_off(M, user) + +/obj/item/device/abductor/silencer/afterattack(atom/target, mob/living/user, flag, params) + if(flag) + return + if(!AbductorCheck(user)) + return + radio_off(target, user) + +/obj/item/device/abductor/silencer/proc/radio_off(atom/target, mob/living/user) + if( !(user in (viewers(7,target))) ) + return + + var/turf/targloc = get_turf(target) + + var/mob/living/carbon/human/M + for(M in view(2,targloc)) + if(M == user) + continue + to_chat(user, "You silence [M]'s radio devices.") + radio_off_mob(M) + +/obj/item/device/abductor/silencer/proc/radio_off_mob(mob/living/carbon/human/M) + var/list/all_items = M.GetAllContents() + + for(var/obj/I in all_items) + if(istype(I,/obj/item/device/radio/)) + var/obj/item/device/radio/r = I + r.listening = 0 + if(!istype(I,/obj/item/device/radio/headset)) + r.broadcasting = 0 //goddamned headset hacks + + +/obj/item/weapon/implant/abductor + name = "recall implant" + desc = "Returns you to the mothership." + icon = 'icons/obj/abductor.dmi' + icon_state = "implant" + activated = 1 + origin_tech = "materials=2;biotech=3;magnets=4;bluespace=5;abductor=5" + var/obj/machinery/abductor/pad/home + var/cooldown = 30 + +/obj/item/weapon/implant/abductor/activate() + if(cooldown == initial(cooldown)) + home.Retrieve(imp_in,1) + cooldown = 0 + processing_objects.Add(src) + else + to_chat(imp_in, "You must wait [30 - cooldown] seconds to use [src] again!") + return + +/obj/item/weapon/implant/abductor/process() + if(cooldown < initial(cooldown)) + cooldown++ + if(cooldown == initial(cooldown)) + processing_objects.Remove(src) + +/obj/item/weapon/implant/abductor/implant(var/mob/source, var/mob/user) + if(..()) + var/obj/machinery/abductor/console/console + if(ishuman(source)) + var/mob/living/carbon/human/H = source + if(H.get_species() == "Abductor") + var/datum/species/abductor/S = H.dna.species + console = get_team_console(S.team) + home = console.pad + + if(!home) + console = get_team_console(pick(1, 2, 3, 4)) + home = console.pad + return 1 + +/obj/item/weapon/implant/abductor/proc/get_team_console(var/team) + var/obj/machinery/abductor/console/console + for(var/obj/machinery/abductor/console/c in machines) + if(c.team == team) + console = c + break + return console + +/obj/item/weapon/gun/energy/decloner/alien + name = "alien pistol" + desc = "A complicated gun that fires bursts of high-intensity radiation." + icon_state = "alienpistol" + item_state = "alienpistol" + origin_tech = "combat=5;materials=4;powerstorage=3;abductor=3" + +/obj/item/weapon/paper/abductor + name = "Dissection Guide" + icon_state = "alienpaper_words" + info = {"Dissection for Dummies
+ +
+ 1.Acquire fresh specimen.
+ 2.Put the specimen on operating table
+ 3.Apply surgical drapes preparing for dissection
+ 4.Apply scalpel to specimen torso
+ 5.Retract skin from specimen's torso
+ 6.Apply scalpel to specimen's torso
+ 7.Search through the specimen's torso with your hands to remove any organs
+ 8.Insert replacement gland (Retrieve one from gland storage)
+ 9.Consider dressing the specimen back to not disturb the habitat
+ 10.Put the specimen in the experiment machinery
+ 11.Choose one of the machine options and follow displayed instructions
+
+Congratulations! You are now trained for xenobiology research!"} + +/obj/item/weapon/paper/abductor/update_icon() + return + +#define BATON_STUN 0 +#define BATON_SLEEP 1 +#define BATON_CUFF 2 +#define BATON_PROBE 3 +#define BATON_MODES 4 + +/obj/item/weapon/abductor_baton + name = "advanced baton" + desc = "A quad-mode baton used for incapacitation and restraining of specimens." + var/mode = BATON_STUN + icon = 'icons/obj/abductor.dmi' + icon_state = "wonderprodStun" + item_state = "wonderprod" + slot_flags = SLOT_BELT + origin_tech = "materials=6;combat=5;biotech=7;abductor=4" + force = 7 + w_class = 3 + action_button_name = "Toggle Mode" + +/obj/item/weapon/abductor_baton/proc/toggle(mob/living/user=usr) + mode = (mode+1)%BATON_MODES + var/txt + switch(mode) + if(BATON_STUN) + txt = "stunning" + if(BATON_SLEEP) + txt = "sleep inducement" + if(BATON_CUFF) + txt = "restraining" + if(BATON_PROBE) + txt = "probing" + + to_chat(usr, "You switch the baton to [txt] mode.") + update_icon() + +/obj/item/weapon/abductor_baton/update_icon() + switch(mode) + if(BATON_STUN) + icon_state = "wonderprodStun" + item_state = "wonderprodStun" + if(BATON_SLEEP) + icon_state = "wonderprodSleep" + item_state = "wonderprodSleep" + if(BATON_CUFF) + icon_state = "wonderprodCuff" + item_state = "wonderprodCuff" + if(BATON_PROBE) + icon_state = "wonderprodProbe" + item_state = "wonderprodProbe" + +/obj/item/weapon/abductor_baton/proc/IsAbductor(mob/living/user) + if(!ishuman(user)) + return 0 + var/mob/living/carbon/human/H = user + if(H.get_species() != "Abductor") + return 0 + return 1 + +/obj/item/weapon/abductor_baton/attack(mob/target, mob/living/user) + if(!IsAbductor(user)) + return + + if(isrobot(target)) + ..() + return + + if(!isliving(target)) + return + + var/mob/living/L = target + + user.do_attack_animation(L) + + switch (mode) + if(BATON_STUN) + StunAttack(L,user) + if(BATON_SLEEP) + SleepAttack(L,user) + if(BATON_CUFF) + CuffAttack(L,user) + if(BATON_PROBE) + ProbeAttack(L,user) + +/obj/item/weapon/abductor_baton/attack_self(mob/living/user) + toggle(user) + +/obj/item/weapon/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user) + user.lastattacked = L + L.lastattacker = user + + L.Stun(7) + L.Weaken(7) + L.apply_effect(STUTTER, 7) + + L.visible_message("[user] has stunned [L] with [src]!", \ + "[user] has stunned you with [src]!") + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.forcesay(hit_appends) + + add_logs(user, L, "stunned") + return + +/obj/item/weapon/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user) + if(L.stunned) + L.visible_message("[user] has induced sleep in [L] with [src]!", \ + "You suddenly feel very drowsy!") + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + L.Sleeping(60) + add_logs(user, L, "put to sleep") + else + L.drowsyness += 1 + to_chat(user, "Sleep inducement works fully only on stunned specimens! ") + L.visible_message("[user] tried to induce sleep in [L] with [src]!", \ + "You suddenly feel drowsy!") + return + +/obj/item/weapon/abductor_baton/proc/CuffAttack(mob/living/L,mob/living/user) + if(!iscarbon(L)) + return + var/mob/living/carbon/C = L + if(!C.handcuffed) + playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) + C.visible_message("[user] begins restraining [C] with [src]!", \ + "[user] begins shaping an energy field around your hands!") + if(do_mob(user, C, 30)) + if(!C.handcuffed) + C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/used(C) + C.update_inv_handcuffed(0) + to_chat(user, "You handcuff [C].") + add_logs(user, C, "handcuffed") + else + to_chat(user, "You fail to handcuff [C].") + return + +/obj/item/weapon/abductor_baton/proc/ProbeAttack(mob/living/L,mob/living/user) + L.visible_message("[user] probes [L] with [src]!", \ + "[user] probes you!") + + var/species = "Unknown species" + var/helptext = "Species unsuitable for experiments." + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + species = "[H.species.name]" + if(L.mind && L.mind.changeling) + species = "Changeling lifeform" + var/obj/item/organ/internal/gland/temp = locate() in H.internal_organs + if(temp) + helptext = "Experimental gland detected!" + else + helptext = "Subject suitable for experiments." + + to_chat(user,"Probing result:[species]") + to_chat(user, "[helptext]") + +/obj/item/weapon/restraints/handcuffs/energy + name = "hard-light energy field" + desc = "A hard-light field restraining the hands." + icon_state = "cuff_white" // Needs sprite + breakouttime = 450 + trashtype = /obj/item/weapon/restraints/handcuffs/energy/used + origin_tech = "materials=2;magnets=5;abductor=2" + +/obj/item/weapon/restraints/handcuffs/energy/used + desc = "energy discharge" + +/obj/item/weapon/restraints/handcuffs/energy/used/dropped(mob/user) + user.visible_message("[user]'s [src] break in a discharge of energy!", \ + "[user]'s [src] break in a discharge of energy!") + var/datum/effect/system/spark_spread/S = new + S.set_up(4,0,user.loc) + S.start() + qdel(src) + +/obj/item/weapon/abductor_baton/examine(mob/user) + ..() + switch(mode) + if(BATON_STUN) + to_chat(user, "The baton is in stun mode.") + if(BATON_SLEEP) + to_chat(user, "The baton is in sleep inducement mode.") + if(BATON_CUFF) + to_chat(user, "The baton is in restraining mode.") + if(BATON_PROBE) + to_chat(user, "The baton is in probing mode.") + + +/obj/item/weapon/scalpel/alien + name = "alien scalpel" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/weapon/hemostat/alien + name = "alien hemostat" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/weapon/retractor/alien + name = "alien retractor" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/weapon/circular_saw/alien + name = "alien saw" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/weapon/surgicaldrill/alien + name = "alien drill" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/weapon/cautery/alien + name = "alien cautery" + icon = 'icons/obj/abductor.dmi' + origin_tech = "materials=2;biotech=2;abductor=2" + +/obj/item/clothing/head/helmet/abductor + name = "agent headgear" + desc = "Abduct with style - spiky style. Prevents digital tracking." + icon_state = "alienhelmet" + item_state = "alienhelmet" + blockTracking = 1 + origin_tech = "materials=6;magnets=5;abductor=3" + flags = BLOCKHAIR + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE + +// Operating Table / Beds / Lockers + +/obj/machinery/optable/abductor + icon = 'icons/obj/abductor.dmi' + icon_state = "bed" + +/obj/structure/stool/bed/abductor + name = "resting contraption" + desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?" + icon = 'icons/obj/abductor.dmi' + icon_state = "bed" + +/obj/structure/abductor_tableframe + name = "alien table frame" + desc = "A sturdy table frame made from alien alloy." + icon_state = "alien_frame" + density = 1 + +/obj/structure/abductor_tableframe/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/wrench)) + to_chat(user, "You start disassembling [src]...") + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 30, target = src)) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + new /obj/item/stack/sheet/mineral/abductor(get_turf(src)) + qdel(src) + return + if(istype(I, /obj/item/stack/sheet/mineral/abductor)) + var/obj/item/stack/sheet/P = I + if(P.get_amount() < 1) + to_chat(user, "You need one alien alloy sheet to do this!") + return + to_chat(user, "You start adding [P] to [src]...") + if(do_after(user, 50, target = src)) + P.use(1) + new /obj/structure/table/abductor(src.loc) + qdel(src) + return + +/obj/structure/table/abductor + name = "alien table" + desc = "Advanced flat surface technology at work!" + icon = 'icons/obj/smooth_structures/alien_table.dmi' + icon_state = "alien_table" + canSmoothWith = null + parts = /obj/item/stack/sheet/mineral/abductor + +/obj/structure/closet/abductor + name = "alien locker" + desc = "Contains secrets of the universe." + icon_state = "abductor" + material_drop = /obj/item/stack/sheet/mineral/abductor + +/obj/structure/door_assembly/door_assembly_abductor + name = "alien airlock assembly" + icon = 'icons/obj/doors/abductor/abductor_airlock.dmi' + base_name = "abductor" + base_icon_state = "abductor" + airlock_type = "/abductor" + anchored = 1 + state = 1 + +/obj/structure/door_assembly/door_assembly_abductor/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/weapon/weldingtool) && !anchored ) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(0,user)) + user.visible_message("[user] disassembles the airlock assembly.", \ + "You start to disassemble the airlock assembly...") + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + if(do_after(user, 40, target = src)) + if( !WT.isOn() ) + return + to_chat(user, "You disassemble the airlock assembly.") + new /obj/item/stack/sheet/mineral/abductor(get_turf(src), 4) + qdel(src) + else + return + else if(istype(W, /obj/item/stack/sheet)) + return // no material modding + else + ..() \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm new file mode 100644 index 00000000000..a9df076eea3 --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm @@ -0,0 +1,56 @@ +/datum/surgery/organ_extraction + name = "experimental dissection" + steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/open_encased/saw, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/internal/extract_organ, /datum/surgery_step/internal/gland_insert) + possible_locs = list("chest") + +/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target) + if(!ishuman(user)) + return 0 + var/mob/living/carbon/human/H = user + if(H.get_species() == "Abductor") + return 1 + if((locate(/obj/item/weapon/implant/abductor) in H)) + return 1 + return 0 + + +/datum/surgery_step/internal/extract_organ + name = "remove heart" + accept_hand = 1 + time = 32 + var/obj/item/organ/internal/IC = null + var/list/organ_types = list(/obj/item/organ/internal/heart) + +/datum/surgery_step/internal/extract_organ/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + for(var/obj/item/I in target.internal_organs) + if(I.type in organ_types) + IC = I + break + user.visible_message("[user] starts to remove [target]'s organs.", "You start to remove [target]'s organs...") + ..() + +/datum/surgery_step/internal/extract_organ/end_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(IC) + user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].") + user.put_in_hands(IC) + IC.remove(target, special = 1) + return 1 + else + to_chat(user, "You don't find anything in [target]'s [target_zone]!") + return 0 + +/datum/surgery_step/internal/gland_insert + name = "insert gland" + allowed_tools = list(/obj/item/organ/internal/gland = 100) + time = 32 + +/datum/surgery_step/internal/gland_insert/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] starts to insert [tool] into [target].", "You start to insert [tool] into [target]...") + ..() + +/datum/surgery_step/internal/gland_insert/end_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] inserts [tool] into [target].", "You insert [tool] into [target].") + user.drop_item() + var/obj/item/organ/internal/gland/gland = tool + gland.insert(target, 2) + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm new file mode 100644 index 00000000000..51396f1d7ce --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -0,0 +1,281 @@ +/obj/item/organ/internal/gland + name = "fleshy mass" + desc = "A nausea-inducing hunk of twisting flesh and metal." + icon = 'icons/obj/abductor.dmi' + parent_organ = "chest" + slot = "gland" + icon_state = "gland" + status = ORGAN_ROBOT + origin_tech = "materials=4;biotech=5;abductor=3" + var/cooldown_low = 300 + var/cooldown_high = 300 + var/next_activation = 0 + var/uses // -1 For inifinite + var/human_only = 0 + var/active = 0 + tough = 1 //not easily broken by combat damage + sterile = 1 //not very germy + +/obj/item/organ/internal/gland/proc/ownerCheck() + if(ishuman(owner)) + return 1 + if(!human_only && iscarbon(owner)) + return 1 + return 0 + +/obj/item/organ/internal/gland/proc/Start() + active = 1 + next_activation = world.time + rand(cooldown_low,cooldown_high) + + +/obj/item/organ/internal/gland/remove(var/mob/living/carbon/M, special = 0) + active = 0 + if(initial(uses) == 1) + uses = initial(uses) + ..() + +/obj/item/organ/internal/gland/insert(var/mob/living/carbon/M, special = 0) + ..() + if(special != 2 && uses) // Special 2 means abductor surgery + Start() + +/obj/item/organ/internal/gland/on_life() + if(!active) + return + if(!ownerCheck()) + active = 0 + return + if(next_activation <= world.time) + activate() + uses-- + next_activation = world.time + rand(cooldown_low,cooldown_high) + if(!uses) + active = 0 + +/obj/item/organ/internal/gland/proc/activate() + return + +/obj/item/organ/internal/gland/heals + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 200 + cooldown_high = 400 + uses = -1 + icon_state = "health" + +/obj/item/organ/internal/gland/heals/activate() + to_chat(owner, "You feel curiously revitalized.") + owner.adjustBruteLoss(-20) + owner.adjustOxyLoss(-20) + owner.adjustFireLoss(-20) + +/obj/item/organ/internal/gland/slime + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 600 + cooldown_high = 1200 + uses = -1 + icon_state = "slime" + +/obj/item/organ/internal/gland/slime/activate() + to_chat(owner, "You feel nauseous!") + owner.vomit(20) + + var/mob/living/carbon/slime/Slime = new/mob/living/carbon/slime(get_turf(owner)) + Slime.Friends = list(owner) + Slime.Leader = owner + +/obj/item/organ/internal/gland/mindshock + origin_tech = "materials=4;biotech=5;magnets=3;abductor=3" + cooldown_low = 300 + cooldown_high = 300 + uses = -1 + icon_state = "mindshock" + +/obj/item/organ/internal/gland/mindshock/activate() + to_chat(owner, "You get a headache.") + + var/turf/T = get_turf(owner) + for(var/mob/living/carbon/H in orange(4,T)) + if(H == owner) + continue + to_chat(H, "You hear a buzz in your head.") + H.confused += 20 + +/obj/item/organ/internal/gland/pop + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 900 + cooldown_high = 1800 + uses = 6 + human_only = 1 + icon_state = "species" + +/obj/item/organ/internal/gland/pop/activate() + to_chat(owner, "You feel unlike yourself.") + var/species = pick("Unathi","Skrell","Diona","Tajaran","Vulpkanin","Kidan","Grey","Diona") + owner.set_species(species) + +/obj/item/organ/internal/gland/ventcrawling + origin_tech = "materials=4;biotech=5;bluespace=3;abductor=3" + cooldown_low = 1800 + cooldown_high = 2400 + uses = 1 + icon_state = "vent" + +/obj/item/organ/internal/gland/ventcrawling/activate() + to_chat(owner, "You feel very stretchy.") + owner.ventcrawler = 2 + return + + +/obj/item/organ/internal/gland/viral + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 1800 + cooldown_high = 2400 + uses = 1 + icon_state = "viral" + +/obj/item/organ/internal/gland/viral/activate() + to_chat(owner, "You feel sick.") + var/virus_type = pick(/datum/disease/beesease, /datum/disease/brainrot, /datum/disease/magnitis) + var/datum/disease/D = new virus_type() + D.carrier = 1 + owner.viruses += D + D.affected_mob = owner + D.holder = owner + owner.med_hud_set_status() + + +/obj/item/organ/internal/gland/emp //TODO : Replace with something more interesting + origin_tech = "materials=4;biotech=5;magnets=3;abductor=3" + cooldown_low = 900 + cooldown_high = 1600 + uses = 10 + icon_state = "emp" + +/obj/item/organ/internal/gland/emp/activate() + to_chat(owner, "You feel a spike of pain in your head.") + empulse(get_turf(owner), 2, 5, 1) + +/obj/item/organ/internal/gland/spiderman + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 450 + cooldown_high = 900 + uses = 10 + icon_state = "spider" + +/obj/item/organ/internal/gland/spiderman/activate() + to_chat(owner, "You feel something crawling in your skin.") + owner.faction |= "spiders" + new /obj/effect/spider/spiderling(owner.loc) + +/obj/item/organ/internal/gland/egg + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 300 + cooldown_high = 400 + uses = -1 + icon_state = "egg" + +/obj/item/organ/internal/gland/egg/activate() + to_chat(owner, "You lay an egg!") + var/obj/item/weapon/reagent_containers/food/snacks/egg/egg = new(owner.loc) + egg.reagents.add_reagent("sacid",20) + egg.desc += " It smells bad." + +/obj/item/organ/internal/gland/bloody + origin_tech = "materials=4;biotech=6;abductor=3" + cooldown_low = 200 + cooldown_high = 400 + uses = -1 + +/obj/item/organ/internal/gland/bloody/activate() + owner.adjustBruteLoss(15) + + owner.visible_message("[owner]'s skin erupts with blood!",\ + "Blood pours from your skin!") + + for(var/turf/T in oview(3,owner)) //Make this respect walls and such + T.add_blood_floor(owner) + for(var/mob/living/carbon/human/H in oview(3,owner)) //Blood decals for simple animals would be neat. aka Carp with blood on it. + if(H.wear_suit) + H.wear_suit.add_blood(owner) + H.update_inv_wear_suit(0) + else if(H.w_uniform) + H.w_uniform.add_blood(owner) + H.update_inv_w_uniform(0) + +/obj/item/organ/internal/gland/bodysnatch + origin_tech = "materials=4;biotech=7;abductor=3" + cooldown_low = 600 + cooldown_high = 600 + human_only = 1 + uses = 1 + +/obj/item/organ/internal/gland/bodysnatch/activate() + to_chat(owner, "You feel something moving around inside you...") + //spawn cocoon with clone greytide snpc inside + if(ishuman(owner)) + var/obj/effect/cocoon/abductor/C = new (get_turf(owner)) + C.Copy(owner) + C.Start() + owner.gib() + return + +/obj/effect/cocoon/abductor + name = "slimy cocoon" + desc = "Something is moving inside." + icon = 'icons/effects/effects.dmi' + icon_state = "cocoon_large3" + color = rgb(10,120,10) + density = 1 + var/hatch_time = 0 + +/obj/effect/cocoon/abductor/proc/Copy(mob/living/carbon/human/H) + var/mob/living/carbon/human/interactive/greytide/clone = new(src) + var/datum/dna/owner_dna = H.dna + clone.real_name = owner_dna.real_name + clone.set_species(H.species.name) + clone.body_accessory = H.body_accessory + clone.dna = owner_dna.Clone() + clone.UpdateAppearance() + domutcheck(clone) + + //There's no define for this / get all items ? + var/list/slots = list(slot_back,slot_w_uniform,slot_wear_suit,\ + slot_wear_mask,slot_head,slot_shoes,slot_gloves,slot_l_ear,slot_r_ear,\ + slot_glasses,slot_belt,slot_s_store,slot_l_store,slot_r_store,slot_wear_id,slot_wear_pda) + + for(var/slot in slots) + var/obj/item/I = H.get_item_by_slot(slot) + if(I) + clone.equip_to_slot_if_possible(I,slot) + +/obj/effect/cocoon/abductor/proc/Start() + hatch_time = world.time + 600 + processing_objects.Add(src) + +/obj/effect/cocoon/abductor/process() + if(world.time > hatch_time) + processing_objects.Remove(src) + for(var/mob/M in contents) + src.visible_message("[src] hatches!") + M.loc = src.loc + qdel(src) + +/obj/item/organ/internal/gland/plasma + cooldown_low = 2400 + cooldown_high = 3000 + origin_tech = "materials=4;biotech=5;plasmatech=3;abductor=3" + uses = 1 + +/obj/item/organ/internal/gland/plasma/activate() + to_chat(owner, "You feel bloated.") + sleep(150) + if(!owner) return + to_chat(owner, "A massive stomachache overcomes you.") + sleep(50) + if(!owner) return + owner.visible_message("[owner] explodes in a cloud of plasma!") + var/turf/simulated/T = get_turf(owner) + if(istype(T)) + T.atmos_spawn_air(SPAWN_TOXINS|SPAWN_20C,300) + owner.gib() + return \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/machinery/camera.dm b/code/game/gamemodes/miniantags/abduction/machinery/camera.dm new file mode 100644 index 00000000000..8368b8c06e4 --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/machinery/camera.dm @@ -0,0 +1,165 @@ +/obj/machinery/computer/camera_advanced/abductor + name = "Human Observation Console" + var/team = 0 + networks = list("SS13","Abductor") + off_action = new/datum/action/camera_off/abductor //specific datum + var/datum/action/teleport_in/tele_in_action = new + var/datum/action/teleport_out/tele_out_action = new + var/datum/action/teleport_self/tele_self_action = new + var/datum/action/vest_mode_swap/vest_mode_action = new + var/datum/action/vest_disguise_swap/vest_disguise_action = new + var/datum/action/set_droppoint/set_droppoint_action = new + var/obj/machinery/abductor/console/console + + icon = 'icons/obj/abductor.dmi' + icon_state = "camera" + +/obj/machinery/computer/camera_advanced/abductor/CreateEye() + ..() + eyeobj.visible_icon = 1 + eyeobj.icon = 'icons/obj/abductor.dmi' + eyeobj.icon_state = "camera_target" + +/obj/machinery/computer/camera_advanced/abductor/GrantActions(mob/living/carbon/user) + off_action.target = user + off_action.Grant(user) + + jump_action.target = user + jump_action.Grant(user) + //TODO : add null checks + tele_in_action.target = console.pad + tele_in_action.Grant(user) + + tele_out_action.target = console + tele_out_action.Grant(user) + + tele_self_action.target = console.pad + tele_self_action.Grant(user) + + vest_mode_action.target = console + vest_mode_action.Grant(user) + + vest_disguise_action.target = console + vest_disguise_action.Grant(user) + + set_droppoint_action.target = console + set_droppoint_action.Grant(user) + +/obj/machinery/computer/camera_advanced/abductor/proc/IsAbductor(mob/living/carbon/human/H) + return H.get_species() == "Abductor" + +/obj/machinery/computer/camera_advanced/abductor/proc/IsScientist(mob/living/carbon/human/H) + var/datum/species/abductor/S = H.dna.species + return S.scientist + +/obj/machinery/computer/camera_advanced/abductor/attack_hand(mob/user) + if(!iscarbon(user) || !IsAbductor(user)) + return + return ..() + +/datum/action/camera_off/abductor/Activate() + if(!target || !iscarbon(target)) + return + var/mob/living/carbon/C = target + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/computer/camera_advanced/abductor/origin = remote_eye.origin + C.remote_view = 0 + origin.current_user = null + origin.jump_action.Remove(C) + origin.tele_in_action.Remove(C) + origin.tele_out_action.Remove(C) + origin.tele_self_action.Remove(C) + origin.vest_mode_action.Remove(C) + origin.vest_disguise_action.Remove(C) + origin.set_droppoint_action.Remove(C) + remote_eye.user = null + if(C.client) + C.client.perspective = MOB_PERSPECTIVE + C.client.eye = src + C.client.images -= remote_eye.user_image + for(var/datum/camerachunk/chunk in remote_eye.visibleCameraChunks) + C.client.images -= chunk.obscured + C.remote_control = null + C.unset_machine() + src.Remove(C) + + +/datum/action/teleport_in + name = "Send To" + button_icon_state = "beam_down" + action_type = AB_INNATE + +/datum/action/teleport_in/Activate() + if(!target || !iscarbon(owner)) + return + var/mob/living/carbon/human/C = owner + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/abductor/pad/P = target + + if(cameranet.checkTurfVis(remote_eye.loc)) + P.PadToLoc(remote_eye.loc) + +/datum/action/teleport_out + name = "Retrieve" + button_icon_state = "beam_up" + action_type = AB_INNATE + +/datum/action/teleport_out/Activate() + if(!target || !iscarbon(owner)) + return + var/obj/machinery/abductor/console/console = target + + console.TeleporterRetrieve() + +/datum/action/teleport_self + name = "Send Self" + button_icon_state = "beam_down" + action_type = AB_INNATE + +/datum/action/teleport_self/Activate() + if(!target || !iscarbon(owner)) + return + var/mob/living/carbon/human/C = owner + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/abductor/pad/P = target + + if(cameranet.checkTurfVis(remote_eye.loc)) + P.MobToLoc(remote_eye.loc,C) + +/datum/action/vest_mode_swap + name = "Switch Vest Mode" + button_icon_state = "vest_mode" + action_type = AB_INNATE + +/datum/action/vest_mode_swap/Activate() + if(!target || !iscarbon(owner)) + return + var/obj/machinery/abductor/console/console = target + console.FlipVest() + + +/datum/action/vest_disguise_swap + name = "Switch Vest Disguise" + button_icon_state = "vest_disguise" + action_type = AB_INNATE + +/datum/action/vest_disguise_swap/Activate() + if(!target || !iscarbon(owner)) + return + var/obj/machinery/abductor/console/console = target + console.SelectDisguise(remote=1) + +/datum/action/set_droppoint + name = "Set Experiment Release Point" + button_icon_state = "set_drop" + action_type = AB_INNATE + +/datum/action/set_droppoint/Activate() + if(!target || !iscarbon(owner)) + return + + var/mob/living/carbon/human/C = owner + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + + var/obj/machinery/abductor/console/console = target + console.SetDroppoint(remote_eye.loc,owner) \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm new file mode 100644 index 00000000000..b9f6a983b9c --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm @@ -0,0 +1,211 @@ +//Common + +/obj/machinery/abductor + var/team = 0 + +/obj/machinery/abductor/proc/IsAbductor(mob/living/carbon/human/H) + return H.get_species() == "Abductor" + +/obj/machinery/abductor/proc/IsAgent(mob/living/carbon/human/H) + if(H.get_species() == "Abductor") + var/datum/species/abductor/S = H.dna.species + return S.agent + return 0 + +/obj/machinery/abductor/proc/IsScientist(mob/living/carbon/human/H) + if(H.get_species() == "Abductor") + var/datum/species/abductor/S = H.dna.species + return S.scientist + return 0 + +//Console + +/obj/machinery/abductor/console + name = "Abductor console" + desc = "Ship command center." + icon = 'icons/obj/abductor.dmi' + icon_state = "console" + density = 1 + anchored = 1 + var/obj/item/device/abductor/gizmo/gizmo + var/obj/item/clothing/suit/armor/abductor/vest/vest + var/obj/machinery/abductor/experiment/experiment + var/obj/machinery/abductor/pad/pad + var/obj/machinery/computer/camera_advanced/abductor/camera + var/list/datum/icon_snapshot/disguises = list() + +/obj/machinery/abductor/console/attack_hand(mob/user) + if(..()) + return + if(!IsAbductor(user)) + to_chat(user, "You start mashing alien buttons at random!") + if(do_after(user,100, target = src)) + TeleporterSend() + return + user.set_machine(src) + var/dat = "" + dat += "

Abductsoft 3000

" + + if(experiment != null) + var/points = experiment.points + dat += "Collected Samples : [points]
" + dat += "Transfer data in exchange for supplies:
" + dat += "Advanced Baton
" + dat += "Agent Helmet
" + dat += "Radio Silencer
" + dat += "Science Tool
" + else + dat += "NO EXPERIMENT MACHINE DETECTED
" + + if(pad!=null) + dat += "Emergency Teleporter System." + dat += "Consider using primary observation console first." + dat += "Activate Teleporter
" + if(gizmo!=null && gizmo.marked!=null) + dat += "Retrieve Mark
" + else + dat += "Retrieve Mark
" + else + dat += "NO TELEPAD DETECTED
" + + if(vest!=null) + dat += "

Agent Vest Mode


" + var/mode = vest.mode + if(mode == VEST_STEALTH) + dat += "Combat" + dat += "Stealth" + else + dat += "Combat" + dat += "Stealth" + + dat+="
" + dat += "Select Agent Vest Disguise
" + else + dat += "NO AGENT VEST DETECTED" + var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + return + +/obj/machinery/abductor/console/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + if(href_list["teleporter_send"]) + TeleporterSend() + else if(href_list["teleporter_retrieve"]) + TeleporterRetrieve() + else if(href_list["flip_vest"]) + FlipVest() + else if(href_list["select_disguise"]) + SelectDisguise() + else if(href_list["dispense"]) + switch(href_list["dispense"]) + if("baton") + Dispense(/obj/item/weapon/abductor_baton,cost=2) + if("helmet") + Dispense(/obj/item/clothing/head/helmet/abductor) + if("silencer") + Dispense(/obj/item/device/abductor/silencer) + if("tool") + Dispense(/obj/item/device/abductor/gizmo) + src.updateUsrDialog() + + +/obj/machinery/abductor/console/proc/TeleporterRetrieve() + if(gizmo!=null && pad!=null && gizmo.marked) + pad.Retrieve(gizmo.marked) + return + +/obj/machinery/abductor/console/proc/TeleporterSend() + if(pad!=null) + pad.Send() + return + +/obj/machinery/abductor/console/proc/FlipVest() + if(vest!=null) + vest.flip_mode() + return + +/obj/machinery/abductor/console/proc/SelectDisguise(remote=0) + var/list/entries = list() + var/tempname + var/datum/icon_snapshot/temp + for(var/i = 1; i <= disguises.len; i++) + temp = disguises[i] + tempname = temp.name + entries["[tempname]"] = disguises[i] + var/entry_name = input( "Choose Disguise", "Disguise") in entries + var/datum/icon_snapshot/chosen = entries[entry_name] + if(chosen && (remote || in_range(usr,src))) + vest.SetDisguise(chosen) + return + +/obj/machinery/abductor/console/proc/SetDroppoint(turf/location,user) + if(!istype(location)) + to_chat(user, "That place is not safe for the specimen.") + return + + if(pad) + pad.teleport_target = location + to_chat(user, "Location marked as test subject release point.") + + +/obj/machinery/abductor/console/proc/Initialize() + + for(var/obj/machinery/abductor/pad/p in machines) + if(p.team == team) + pad = p + break + + for(var/obj/machinery/abductor/experiment/e in machines) + if(e.team == team) + experiment = e + e.console = src + + for(var/obj/machinery/computer/camera_advanced/abductor/c in machines) + if(c.team == team) + camera = c + c.console = src + +/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target) + var/datum/icon_snapshot/entry = new + entry.name = target.name + entry.icon = target.icon + entry.icon_state = target.icon_state + entry.overlays = target.get_overlays_copy(list(L_HAND_LAYER,R_HAND_LAYER)) + for(var/i=1,i<=disguises.len,i++) + var/datum/icon_snapshot/temp = disguises[i] + if(temp.name == entry.name) + disguises[i] = entry + return + disguises.Add(entry) + return + +/obj/machinery/abductor/console/attackby(obj/O, mob/user, params) + if(istype(O, /obj/item/device/abductor/gizmo)) + var/obj/item/device/abductor/gizmo/G = O + to_chat(user, "You link the tool to the console.") + gizmo = G + G.console = src + else if(istype(O, /obj/item/clothing/suit/armor/abductor/vest)) + var/obj/item/clothing/suit/armor/abductor/vest/V = O + to_chat(user, "You link the vest to the console.") + vest = V + else + ..() + +/obj/machinery/abductor/console/proc/Dispense(item,cost=1) + if(experiment && experiment.points >= cost) + experiment.points-=cost + atom_say("Incoming supply!") + if(pad) + flick("alien-pad", pad) + new item(pad.loc) + else + new item(src.loc) + else + atom_say("Insufficent data!") + return \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/machinery/dispenser.dm b/code/game/gamemodes/miniantags/abduction/machinery/dispenser.dm new file mode 100644 index 00000000000..aacf75770e9 --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/machinery/dispenser.dm @@ -0,0 +1,83 @@ +/obj/machinery/abductor/gland_dispenser + name = "Replacement Organ Storage" + desc = "A tank filled with replacement organs" + icon = 'icons/obj/abductor.dmi' + icon_state = "dispenser" + density = 1 + anchored = 1 + var/list/gland_types + var/list/gland_colors + var/list/amounts + +/obj/machinery/abductor/gland_dispenser/proc/random_color() + //TODO : replace with presets or spectrum + return rgb(rand(0,255),rand(0,255),rand(0,255)) + +/obj/machinery/abductor/gland_dispenser/New() + gland_types = subtypesof(/obj/item/organ/internal/gland) + gland_types = shuffle(gland_types) + gland_colors = new/list(gland_types.len) + amounts = new/list(gland_types.len) + for(var/i=1,i<=gland_types.len,i++) + gland_colors[i] = random_color() + amounts[i] = rand(1,5) + +/obj/machinery/abductor/gland_dispenser/attack_hand(mob/user) + if(..()) + return + if(!IsAbductor(user)) + return + user.set_machine(src) + var/box_css = {" + "} + var/dat = "" + var/item_count = 0 + for(var/i=1,i<=gland_colors.len,i++) + item_count++ + var/g_color = gland_colors[i] + var/amount = amounts[i] + dat += "[amount]" + if(item_count == 3) // Three boxes per line + dat +="

" + item_count = 0 + var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200) + popup.add_head_content(box_css) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + return + +/obj/machinery/abductor/gland_dispenser/attackby(obj/item/weapon/W, mob/user, params) + if(istype(W, /obj/item/organ/internal/gland)) + if(!user.drop_item()) + return + W.loc = src + for(var/i=1,i<=gland_colors.len,i++) + if(gland_types[i] == W.type) + amounts[i]++ + +/obj/machinery/abductor/gland_dispenser/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + + if(href_list["dispense"]) + Dispense(text2num(href_list["dispense"])) + src.updateUsrDialog() + +/obj/machinery/abductor/gland_dispenser/proc/Dispense(count) + if(amounts[count]>0) + amounts[count]-- + var/T = gland_types[count] + new T(get_turf(src)) \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm new file mode 100644 index 00000000000..37814139778 --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm @@ -0,0 +1,194 @@ +/obj/machinery/abductor/experiment + name = "experimentation machine" + desc = "A large man-sized tube sporting a complex array of surgical apparatus." + icon = 'icons/obj/abductor.dmi' + icon_state = "experiment-open" + anchored = 1 + var/points = 0 + var/list/history = list() + var/list/abductee_minds = list() + var/flash = " - || - " + var/obj/machinery/abductor/console/console + var/mob/living/carbon/human/occupant + +/obj/machinery/abductor/experiment/Destroy() + eject_abductee() + return ..() + +/obj/machinery/abductor/experiment/MouseDrop_T(mob/living/carbon/human/target, mob/user) + if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target)) + return + if(IsAbductor(target)) + return + if(occupant) + to_chat(user, "\The [src] is already occupied.") + return //occupied + if(target.buckled) + return + for(var/mob/living/carbon/slime/M in range(1, target)) + if(M.Victim == target) + to_chat(user, "[target] has a slime attached to them, deal with that first.") + return + visible_message("[user] puts [target] into the [src].") + + target.forceMove(src) + occupant = target + icon_state = "experiment" + add_fingerprint(user) + +/obj/machinery/abductor/experiment/attack_hand(mob/user) + if(..()) + return + + experimentUI(user) + +/obj/machinery/abductor/experiment/proc/experimentUI(mob/user) + var/dat + dat += "

Experiment

" + if(occupant) + dat += "
" + dat += "" + dat += "Probe
" + dat += "Dissect
" + dat += "Analyze
" + dat += "
" + else + dat += "Experiment " + + if(!occupant) + dat += "

Machine Unoccupied

" + else + dat += "

Subject Status :

" + dat += "[occupant.name] => " + switch(occupant.stat) + if(0) + dat += "Conscious" + if(1) + dat += "Unconscious" + else + dat += "Deceased" + dat += "
" + dat += "[flash]" + dat += "
" + dat += "Scan" + dat += "Occupied" : "eject=1'>Eject"]" + var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) + popup.set_content(dat) + popup.open() + +/obj/machinery/abductor/experiment/Topic(href, href_list) + if(..() || usr == occupant) + return + usr.set_machine(src) + if(href_list["refresh"]) + updateUsrDialog() + return + if(href_list["eject"]) + eject_abductee() + return + if(occupant && occupant.stat != DEAD) + if(href_list["experiment"]) + flash = Experiment(occupant,href_list["experiment"]) + updateUsrDialog() + add_fingerprint(usr) + +/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type) + var/mob/living/carbon/human/H = occupant + var/point_reward = 0 + if(H in history) + return "Specimen already in database." + if(H.stat == DEAD) + atom_say("Specimen deceased - please provide fresh sample.") + return "Specimen deceased." + var/obj/item/organ/internal/gland/GlandTest = locate() in H.internal_organs + if(!GlandTest) + atom_say("Experimental dissection not detected!") + return "No glands detected!" + if(H.mind != null && H.ckey != null) + history += H + abductee_minds += H.mind + atom_say("Processing specimen...") + sleep(5) + switch(text2num(type)) + if(1) + to_chat(H, "You feel violated.") + if(2) + to_chat(H, "You feel yourself being sliced apart and put back together.") + if(3) + to_chat(H, "You feel intensely watched.") + sleep(5) + to_chat(H, "Your mind snaps!") + var/objtype = pick(subtypesof(/datum/objective/abductee/)) + var/datum/objective/abductee/O = new objtype() + ticker.mode.abductees += H.mind + H.mind.objectives += O + var/obj_count = 1 + to_chat(H, "Your current objectives:") + for(var/datum/objective/objective in H.mind.objectives) + to_chat(H, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + ticker.mode.update_abductor_icons_added(H.mind) + + for(var/obj/item/organ/internal/gland/G in H.internal_organs) + G.Start() + point_reward++ + if(point_reward > 0) + eject_abductee() + SendBack(H) + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + points += point_reward + return "Experiment successful! [point_reward] new data-points collected." + else + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) + return "Experiment failed! No replacement organ detected." + else + atom_say("Brain activity nonexistant - disposing sample...") + eject_abductee() + SendBack(H) + return "Specimen braindead - disposed." + return "ERROR" + + +/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H) + H.Sleeping(8) + if(console && console.pad && console.pad.teleport_target) + H.forceMove(console.pad.teleport_target) + H.uncuff() + return + //Area not chosen / It's not safe area - teleport to arrivals + H.forceMove(pick(latejoin)) + H.uncuff() + return + +/obj/machinery/abductor/experiment/attackby(obj/item/weapon/G, mob/user) + if(istype(G, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/grabbed = G + if(!ishuman(grabbed.affecting)) + return + if(IsAbductor(grabbed.affecting)) + return + if(occupant) + to_chat(user, "The [src] is already occupied!") + return + for(var/mob/living/carbon/slime/S in range(1, grabbed.affecting)) + if(S.Victim == grabbed.affecting) + to_chat(user, "[grabbed.affecting] has a slime attached to them, deal with that first.") + return + visible_message("[user] puts [grabbed.affecting] into the [src].") + var/mob/living/carbon/human/H = grabbed.affecting + H.forceMove(src) + occupant = H + icon_state = "experiment" + add_fingerprint(user) + qdel(G) + +/obj/machinery/abductor/experiment/proc/eject_abductee() + if(!occupant) + return + if(occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.forceMove(get_turf(src)) + occupant = null + icon_state = "experiment-open" \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/abduction/machinery/pad.dm b/code/game/gamemodes/miniantags/abduction/machinery/pad.dm new file mode 100644 index 00000000000..285b097d06a --- /dev/null +++ b/code/game/gamemodes/miniantags/abduction/machinery/pad.dm @@ -0,0 +1,54 @@ +/obj/machinery/abductor/pad + name = "Alien Telepad" + desc = "Use this to transport to and from human habitat" + icon = 'icons/obj/abductor.dmi' + icon_state = "alien-pad-idle" + anchored = 1 + var/turf/teleport_target + +/obj/machinery/abductor/pad/proc/Warp(mob/living/target) + target.Move(src.loc) + +/obj/machinery/abductor/pad/proc/Send() + if(teleport_target == null) + teleport_target = teleportlocs[pick(teleportlocs)] + flick("alien-pad", src) + for(var/mob/living/target in loc) + target.forceMove(teleport_target) + spawn(0) + anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir) + +/obj/machinery/abductor/pad/proc/Retrieve(mob/living/target) + flick("alien-pad", src) + spawn(0) + anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir) + Warp(target) + +/obj/machinery/abductor/pad/proc/MobToLoc(place,mob/living/target) + new/obj/effect/overlay/temp/teleport_abductor(place) + sleep(80) + flick("alien-pad", src) + target.forceMove(place) + anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir) + +/obj/machinery/abductor/pad/proc/PadToLoc(place) + new/obj/effect/overlay/temp/teleport_abductor(place) + sleep(80) + flick("alien-pad", src) + for(var/mob/living/target in src.loc) + target.forceMove(place) + spawn(0) + anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir) + + +/obj/effect/overlay/temp/teleport_abductor + name = "Huh" + icon = 'icons/obj/abductor.dmi' + icon_state = "teleport" + duration = 80 + +/obj/effect/overlay/temp/teleport_abductor/New() + var/datum/effect/system/spark_spread/S = new + S.set_up(10,0,loc) + S.start() + ..() \ No newline at end of file diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 26d159e959a..8d31f9e8a2b 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -299,6 +299,16 @@ icon = 'icons/obj/doors/doorshuttle.dmi' assembly_type = /obj/structure/door_assembly/door_assembly_shuttle +/obj/machinery/door/airlock/abductor + name = "alien airlock" + desc = "With humanity's current technological level, it could take years to hack this advanced airlock... or maybe we should give a screwdriver a try?" + icon = 'icons/obj/doors/abductor/abductor_airlock.dmi' + assembly_type = /obj/structure/door_assembly/door_assembly_abductor + opacity = 1 + explosion_block = 3 + hackProof = 1 + aiControlDisabled = 1 + /obj/machinery/door/airlock/alien name = "Alien Airlock" desc = "A mysterious alien airlock with a complicated opening mechanism." diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 03890ce4372..6c7e32f8f94 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -193,3 +193,32 @@ var/global/list/datum/stack_recipe/mime_recipes = list ( \ icon_state = "sheet-enruranium" origin_tech = "materials=6" materials = list(MAT_URANIUM=3000) + +/* + * Alien Alloy + */ +/obj/item/stack/sheet/mineral/abductor + name = "alien alloy" + icon = 'icons/obj/abductor.dmi' + icon_state = "sheet-abductor" + singular_name = "alien alloy sheet" + force = 5 + throwforce = 5 + w_class = 3 + throw_speed = 1 + throw_range = 3 + origin_tech = "materials=6;abductor=1" + sheettype = "abductor" + +var/global/list/datum/stack_recipe/abductor_recipes = list ( \ + new/datum/stack_recipe("alien bed", /obj/structure/stool/bed/abductor, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 1, time = 15, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("alien table frame", /obj/structure/abductor_tableframe, 1, time = 15, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 20, one_per_turf = 1, on_floor = 1), \ + null, \ + new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20), \ + ) + +/obj/item/stack/sheet/mineral/abductor/New(var/loc, var/amount=null) + recipes = abductor_recipes + ..() \ No newline at end of file diff --git a/code/game/objects/items/stacks/tiles/tile_mineral.dm b/code/game/objects/items/stacks/tiles/tile_mineral.dm new file mode 100644 index 00000000000..7e6d5459dbf --- /dev/null +++ b/code/game/objects/items/stacks/tiles/tile_mineral.dm @@ -0,0 +1,9 @@ +/obj/item/stack/tile/mineral/abductor + name = "alien floor tile" + singular_name = "alien floor tile" + desc = "A tile made out of alien alloy." + icon = 'icons/obj/abductor.dmi' + icon_state = "tile_abductor" + origin_tech = "materials=6;abductor=1" + turf_type = /turf/simulated/floor/mineral/abductor + mineralType = "abductor" \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 5d52fa223ec..a6b19ebbea5 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -11,9 +11,11 @@ var/wall_mounted = 0 //never solid (You can always pass over it) var/health = 100 var/lastbang + var/cutting_tool = /obj/item/weapon/weldingtool var/sound = 'sound/machines/click.ogg' - var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate - //then open it in a populated area to crash clients. + var/cutting_sound = 'sound/items/Welder.ogg' + var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients. + var/material_drop = /obj/item/stack/sheet/metal /obj/structure/closet/New() ..() @@ -257,16 +259,24 @@ src.MouseDrop_T(W:affecting, user) //act like they were dragged onto the closet if(istype(W,/obj/item/tk_grab)) return 0 - if(istype(W, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - if(!WT.remove_fuel(0,user)) - to_chat(user, "You need more welding fuel to complete this task.") - return - new /obj/item/stack/sheet/metal(src.loc) - for(var/mob/M in viewers(src)) - M.show_message("\The [src] has been cut apart by [user] with \the [WT].", 3, "You hear welding.", 2) - qdel(src) - return + if(istype(W, cutting_tool)) + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if(!WT.remove_fuel(0, user)) + return + to_chat(user, "You begin cutting \the [src] apart...") + playsound(loc, cutting_sound, 40, 1) + if(do_after(user, 40, 1, target = src)) + if(!opened || !WT.isOn()) + return + playsound(loc, cutting_sound, 50, 1) + visible_message("[user] slices apart \the [src].", + "You cut \the [src] apart with \the [WT].", + "You hear welding.") + var/turf/T = get_turf(src) + new material_drop(T) + qdel(src) + return if(isrobot(user)) return if(!usr.drop_item()) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index 824cff35ece..dad7aecb190 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -6,6 +6,8 @@ icon_closed = "cardboard" health = 10 sound = 'sound/effects/rustle2.ogg' + material_drop = /obj/item/stack/sheet/cardboard + cutting_sound = 'sound/items/poster_ripped.ogg' var/move_delay = 0 var/egged = 0 diff --git a/code/game/objects/structures/crates_lockers/closets/crittercrate.dm b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm index d3ab79e7688..6a295ca4307 100644 --- a/code/game/objects/structures/crates_lockers/closets/crittercrate.dm +++ b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm @@ -3,4 +3,5 @@ desc = "A crate which can sustain life for a while." icon_state = "critter" icon_opened = "critteropen" - icon_closed = "critter" \ No newline at end of file + icon_closed = "critter" + material_drop = /obj/item/stack/sheet/wood \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/mineral.dm b/code/game/turfs/simulated/floor/mineral.dm new file mode 100644 index 00000000000..9ef70522ec4 --- /dev/null +++ b/code/game/turfs/simulated/floor/mineral.dm @@ -0,0 +1,48 @@ +/turf/simulated/floor/mineral + name = "mineral floor" + icon_state = "" + var/list/icons = list() + + + +/turf/simulated/floor/mineral/New() + ..() + broken_states = list("[initial(icon_state)]_dam") + +/turf/simulated/floor/mineral/update_icon() + if(!..()) + return 0 + if(!broken && !burnt) + if( !(icon_state in icons) ) + icon_state = initial(icon_state) + +// ALIEN ALLOY +/turf/simulated/floor/mineral/abductor + name = "alien floor" + icon_state = "alienpod1" + floor_tile = /obj/item/stack/tile/mineral/abductor + icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9") + +/turf/simulated/floor/mineral/New() + ..() + icon_state = "alienpod[rand(1,9)]" + +/turf/simulated/floor/mineral/break_tile() + return //unbreakable + +/turf/simulated/floor/mineral/abductor/burn_tile() + return //unburnable + +/turf/simulated/floor/mineral/abductor/make_plating() + return ChangeTurf(/turf/simulated/floor/plating/abductor2) + + +/turf/simulated/floor/plating/abductor2 + name = "alien plating" + icon_state = "alienplating" + +/turf/simulated/floor/plating/abductor2/break_tile() + return //unbreakable + +/turf/simulated/floor/plating/abductor2/burn_tile() + return //unburnable \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 2a239ea04ee..764ca6055d4 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -292,4 +292,12 @@ /turf/simulated/floor/plasteel/airless/New() ..() - name = "floor" \ No newline at end of file + name = "floor" + +/turf/simulated/floor/plating/abductor + name = "alien floor" + icon_state = "alienpod1" + +/turf/simulated/floor/plating/abductor/New() + ..() + icon_state = "alienpod[rand(1,9)]" diff --git a/code/game/turfs/unsimulated/walls.dm b/code/game/turfs/unsimulated/walls.dm index 7926a864c49..571983f0966 100644 --- a/code/game/turfs/unsimulated/walls.dm +++ b/code/game/turfs/unsimulated/walls.dm @@ -23,4 +23,8 @@ turf/unsimulated/wall/splashscreen layer = FLY_LAYER /turf/unsimulated/wall/other - icon_state = "r_wall" \ No newline at end of file + icon_state = "r_wall" + +/turf/unsimulated/wall/abductor + icon_state = "alien1" + explosion_block = 50 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 5d27605b13c..4d3b571091c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -694,6 +694,8 @@ return get_id_name("Unknown") //Likewise for hats var/face_name = get_face_name() var/id_name = get_id_name("") + if(name_override) + return name_override if(id_name && (id_name != face_name)) return "[face_name] (as [id_name])" return face_name diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index afbe24be5ac..96104fb6862 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -80,6 +80,8 @@ var/hand_blood_color + var/name_override //For temporary visible name changes + var/xylophone = 0 //For the spoooooooky xylophone cooldown var/mob/remoteview_target = null diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 73bbd5a4281..5af2622162b 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -104,41 +104,6 @@ If you have any questions/constructive-comments/bugs-to-report/or have a massivl Please contact me on #coderbus IRC. ~Carn x */ -//Human Overlays Indexes///////// -#define MUTANTRACE_LAYER 1 -#define TAIL_UNDERLIMBS_LAYER 2 -#define LIMBS_LAYER 3 -#define MARKINGS_LAYER 4 -#define UNDERWEAR_LAYER 5 -#define MUTATIONS_LAYER 6 -#define DAMAGE_LAYER 7 -#define UNIFORM_LAYER 8 -#define ID_LAYER 9 -#define SHOES_LAYER 10 -#define GLOVES_LAYER 11 -#define EARS_LAYER 12 -#define SUIT_LAYER 13 -#define GLASSES_LAYER 14 -#define BELT_LAYER 15 //Possible make this an overlay of somethign required to wear a belt? -#define SUIT_STORE_LAYER 16 -#define BACK_LAYER 17 -#define TAIL_LAYER 18 //bs12 specific. this hack is probably gonna come back to haunt me -#define HAIR_LAYER 19 //TODO: make part of head layer? -#define HEAD_ACCESSORY_LAYER 20 -#define FHAIR_LAYER 21 -#define FACEMASK_LAYER 22 -#define HEAD_LAYER 23 -#define COLLAR_LAYER 24 -#define HANDCUFF_LAYER 25 -#define LEGCUFF_LAYER 26 -#define L_HAND_LAYER 27 -#define R_HAND_LAYER 28 -#define TARGETED_LAYER 29 //BS12: Layer for the target overlay from weapon targeting system -#define FIRE_LAYER 30 //If you're on fire -#define TOTAL_LAYERS 30 - - - /mob/living/carbon/human var/list/overlays_standing[TOTAL_LAYERS] var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed @@ -1237,34 +1202,11 @@ var/global/list/damage_icon_parts = list() O.sync_colour_to_human(src) update_body(0) -//Human Overlays Indexes///////// -#undef MUTANTRACE_LAYER -#undef TAIL_UNDERLIMBS_LAYER -#undef LIMBS_LAYER -#undef MARKINGS_LAYER -#undef MUTATIONS_LAYER -#undef DAMAGE_LAYER -#undef UNIFORM_LAYER -#undef ID_LAYER -#undef SHOES_LAYER -#undef GLOVES_LAYER -#undef EARS_LAYER -#undef SUIT_LAYER -#undef GLASSES_LAYER -#undef FACEMASK_LAYER -#undef BELT_LAYER -#undef SUIT_STORE_LAYER -#undef BACK_LAYER -#undef TAIL_LAYER -#undef HAIR_LAYER -#undef HEAD_LAYER -#undef HEAD_ACCESSORY_LAYER -#undef FHAIR_LAYER -#undef COLLAR_LAYER -#undef HANDCUFF_LAYER -#undef LEGCUFF_LAYER -#undef L_HAND_LAYER -#undef R_HAND_LAYER -#undef TARGETED_LAYER -#undef FIRE_LAYER -#undef TOTAL_LAYERS +/mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers) + var/list/out = new + for(var/i=1;i<=TOTAL_LAYERS;i++) + if(overlays_standing[i]) + if(i in unwantedLayers) + continue + out += overlays_standing[i] + return out diff --git a/icons/obj/doors/abductor/abductor_airlock.dmi b/icons/obj/doors/abductor/abductor_airlock.dmi new file mode 100644 index 00000000000..d0ef3d2462d Binary files /dev/null and b/icons/obj/doors/abductor/abductor_airlock.dmi differ diff --git a/icons/obj/doors/abductor/overlays.dmi b/icons/obj/doors/abductor/overlays.dmi new file mode 100644 index 00000000000..6efad60d9c4 Binary files /dev/null and b/icons/obj/doors/abductor/overlays.dmi differ diff --git a/paradise.dme b/paradise.dme index 5493536e2b0..628458d4b7d 100644 --- a/paradise.dme +++ b/paradise.dme @@ -257,6 +257,7 @@ #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\global_iterator.dm" +#include "code\datums\helper_datums\icon_snapshot.dm" #include "code\datums\helper_datums\map_template.dm" #include "code\datums\helper_datums\teleport.dm" #include "code\datums\helper_datums\topic_input.dm" @@ -397,6 +398,15 @@ #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" +#include "code\game\gamemodes\miniantags\abduction\abduction.dm" +#include "code\game\gamemodes\miniantags\abduction\abduction_gear.dm" +#include "code\game\gamemodes\miniantags\abduction\abduction_surgery.dm" +#include "code\game\gamemodes\miniantags\abduction\gland.dm" +#include "code\game\gamemodes\miniantags\abduction\machinery\camera.dm" +#include "code\game\gamemodes\miniantags\abduction\machinery\console.dm" +#include "code\game\gamemodes\miniantags\abduction\machinery\dispenser.dm" +#include "code\game\gamemodes\miniantags\abduction\machinery\experiment.dm" +#include "code\game\gamemodes\miniantags\abduction\machinery\pad.dm" #include "code\game\gamemodes\miniantags\borer\borer.dm" #include "code\game\gamemodes\miniantags\borer\borer_event.dm" #include "code\game\gamemodes\miniantags\bot_swarm\swarmer.dm" @@ -752,6 +762,7 @@ #include "code\game\objects\items\stacks\sheets\mineral.dm" #include "code\game\objects\items\stacks\sheets\sheet_types.dm" #include "code\game\objects\items\stacks\sheets\sheets.dm" +#include "code\game\objects\items\stacks\tiles\tile_mineral.dm" #include "code\game\objects\items\stacks\tiles\tile_types.dm" #include "code\game\objects\items\weapons\AI_modules.dm" #include "code\game\objects\items\weapons\alien_specific.dm" @@ -947,6 +958,7 @@ #include "code\game\turfs\simulated\walls_reinforced.dm" #include "code\game\turfs\simulated\floor\fancy_floor.dm" #include "code\game\turfs\simulated\floor\light_floor.dm" +#include "code\game\turfs\simulated\floor\mineral.dm" #include "code\game\turfs\simulated\floor\misc_floor.dm" #include "code\game\turfs\simulated\floor\plasteel_floor.dm" #include "code\game\turfs\simulated\floor\plating.dm"