diff --git a/code/__DEFINES/devices.dm b/code/__DEFINES/devices.dm index 412e5d416d7..d28e16ff433 100644 --- a/code/__DEFINES/devices.dm +++ b/code/__DEFINES/devices.dm @@ -18,3 +18,16 @@ // Used by PDA and cartridge code to reduce repetitiveness of spritesheets #define PDAIMG(what) {""} + +//N-spect scanner defines +#define INSPECTOR_PRINT_SOUND_MODE_NORMAL 1 +#define INSPECTOR_PRINT_SOUND_MODE_CLASSIC 2 +#define INSPECTOR_PRINT_SOUND_MODE_HONK 3 +#define INSPECTOR_PRINT_SOUND_MODE_FAFAFOGGY 4 +#define BANANIUM_CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST 4 +#define CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST 4 +#define INSPECTOR_POWER_USAGE_HONK 15 +#define INSPECTOR_POWER_USAGE_NORMAL 5 +#define INSPECTOR_TIME_MODE_SLOW 1 +#define INSPECTOR_TIME_MODE_FAST 2 +#define INSPECTOR_TIME_MODE_HONK 3 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 7bf6ef94192..6f2a79583c6 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -430,6 +430,7 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE))) #define BONE_SCAR_FILE "wounds/bone_scar_desc.json" #define SCAR_LOC_FILE "wounds/scar_loc.json" #define EXODRONE_FILE "exodrone.json" +#define CLOWN_NONSENSE_FILE "clown_nonsense.json" //Fullscreen overlay resolution in tiles. #define FULLSCREEN_OVERLAY_RESOLUTION_X 15 diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 16391ced4dd..2f96cdd9a73 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -1288,6 +1288,17 @@ /datum/reagent/consumable/ice = 10 ) category = CAT_CHEMISTRY + +/** + * Recipe used for upgrading fake N-spect scanners to bananium HONK-spect scanners + */ +/datum/crafting_recipe/clown_scanner_upgrade + name = "Bananium HONK-spect scanner" + result = /obj/item/inspector/clown/bananium + reqs = list(/obj/item/inspector/clown = 1, /obj/item/stack/sticky_tape = 3, /obj/item/stack/sheet/mineral/bananium = 5) //the chainsaw of prank tools + tool_paths = list(/obj/item/bikehorn) + time = 40 SECONDS + category = CAT_MISC #undef CRAFTING_MACHINERY_CONSUME #undef CRAFTING_MACHINERY_USE diff --git a/code/game/objects/items/documents.dm b/code/game/objects/items/documents.dm index 54367e75bd1..deff2b6e50b 100644 --- a/code/game/objects/items/documents.dm +++ b/code/game/objects/items/documents.dm @@ -57,6 +57,11 @@ to_chat(user, "You forge the official seal with a [C.crayon_color] crayon. No one will notice... right?") update_appearance() +/** + * # N-spect scanner + * + * Creates reports for area inspection bounties. + */ /obj/item/inspector name = "\improper N-spect scanner" desc = "Central Command-issued inspection device. Performs inspections according to Nanotrasen protocols when activated, then \ @@ -69,18 +74,124 @@ w_class = WEIGHT_CLASS_TINY throw_range = 1 throw_speed = 1 + ///How long it takes to print on time each mode, ordered NORMAL, FAST, HONK + var/list/time_list = list(5 SECONDS, 1 SECONDS, 0.1 SECONDS) + ///Which print time mode we're on. + var/time_mode = INSPECTOR_TIME_MODE_SLOW + ///determines the sound that plays when printing a report + var/print_sound_mode = INSPECTOR_PRINT_SOUND_MODE_NORMAL + ///Power cell used to power the scanner. Paths g + var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/crap + ///Cell cover status + var/cell_cover_open = FALSE + ///Power used per print in cell units + var/power_per_print = INSPECTOR_POWER_USAGE_NORMAL + ///Power used to say an error message + var/power_to_speak = 1 + +/obj/item/inspector/Initialize() + . = ..() + if(ispath(cell)) + cell = new cell(src) + +// Clean up the cell on destroy +/obj/item/clothing/suit/space/Destroy() + if(cell) + QDEL_NULL(cell) + return ..() + +// Clean up the cell on destroy +/obj/item/inspector/handle_atom_del(atom/A) + if(A == cell) + cell = null + return ..() + +// support for items that interact with the cell +/obj/item/inspector/get_cell() + return cell /obj/item/inspector/attack_self(mob/user) . = ..() - if(do_after(user, 5 SECONDS, target = user, progress=TRUE)) - print_report() + if(do_after(user, time_list[time_mode], target = user, progress=TRUE)) + print_report(user) -///Prints out a report for bounty purposes, and plays a short audio blip. -/obj/item/inspector/proc/print_report() - // Create our report +/obj/item/inspector/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + if(user.combat_mode) + return + cell_cover_open = !cell_cover_open + balloon_alert(user, "You [cell_cover_open ? "open" : "close"] the cell cover on \the [src].") + return TRUE + + +/obj/item/inspector/attackby(obj/item/I, mob/user, params) + if(cell_cover_open && istype(I, /obj/item/stock_parts/cell)) + if(cell) + to_chat(user, "[src] already has a cell installed.") + return + if(user.transferItemToLoc(I, src)) + cell = I + to_chat(user, "You successfully install \the [cell] into [src].") + return + return ..() + +/obj/item/inspector/CtrlClick(mob/living/user) + if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE, !iscyborg(user)) || !cell_cover_open || !cell) + return ..() + user.visible_message("[user] removes \the [cell] from [src]!", \ + "You remove [cell].") + cell.add_fingerprint(user) + user.put_in_hands(cell) + cell = null + + +/obj/item/inspector/examine(mob/user) + . = ..() + if(!cell_cover_open) + . += "Its cell cover is closed. It looks like it could be pried out, but doing so would require an appropriate tool." + return + . += "It's cell cover is open, exposing the cell slot. It looks like it could be pried in, but doing so would require an appropriate tool." + if(!cell) + . += "The slot for a cell is empty." + else + . += "\The [cell] is firmly in place. Ctrl-click with an empty hand to remove it." + +/** + * Create our report + * + * Arguments: + */ +/obj/item/inspector/proc/create_slip() var/obj/item/paper/report/slip = new(get_turf(src)) slip.generate_report(get_area(src)) - playsound(src, 'sound/machines/high_tech_confirm.ogg', 50, FALSE) + +/** + * Prints out a report for bounty purposes, and plays a short audio blip. + * + * Arguments: +*/ +/obj/item/inspector/proc/print_report(mob/user) + if(!cell) + to_chat(user, "\The [src] doesn't seem to be on... It feels quite light. Perhaps it lacks a power cell?") + return + if(cell.charge == 0) + to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") + return + if(!cell.use(power_per_print)) + if(cell.use(power_to_speak)) + say("ERROR! POWER CELL CHARGE LEVEL TOO LOW TO PRINT REPORT!") + return + + create_slip() + switch(print_sound_mode) + if(INSPECTOR_PRINT_SOUND_MODE_NORMAL) + playsound(src, 'sound/machines/high_tech_confirm.ogg', 50, FALSE) + if(INSPECTOR_PRINT_SOUND_MODE_CLASSIC) + playsound(src, 'sound/items/biddledeep.ogg', 50, FALSE) + if(INSPECTOR_PRINT_SOUND_MODE_HONK) + playsound(src, 'sound/items/bikehorn.ogg', 50, FALSE) + if(INSPECTOR_PRINT_SOUND_MODE_FAFAFOGGY) + playsound(src, pick(list('sound/items/robofafafoggy.ogg', 'sound/items/robofafafoggy2.ogg')), 50, FALSE) /obj/item/paper/report name = "encrypted station inspection" @@ -115,3 +226,223 @@ . += "Wait a minute, this isn't an encrypted inspection report! You should throw it away." else . += "Wait a minute, this thing's blank! You should throw it away." + +/** + * # Fake N-spect scanner + * + * A clown variant of the N-spect scanner + * + * This prints fake reports with garbage in them, + * can be set to print them instantly with a screwdriver. + * By default it plays the old "woody" scanning sound, scanning sounds can be cycled by clicking with a multitool. + * Can be crafted into a bananium HONK-spect scanner + */ +/obj/item/inspector/clown + ///will only cycle through modes with numbers lower than this + var/max_mode = CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST + ///names of modes, ordered first to last + var/list/mode_names = list("normal", "classic", "honk", "fafafoggy") + +/obj/item/inspector/clown/attack(mob/living/M, mob/living/user) + . = ..() + print_report(user) + +/obj/item/inspector/clown/screwdriver_act(mob/living/user, obj/item/tool) + if(!cell_cover_open) + return ..() + cycle_print_time(user) + return TRUE + +/obj/item/inspector/clown/attackby(obj/item/I, mob/user, params) + if(cell_cover_open && istype(I, /obj/item/kitchen/fork)) + cycle_sound(user) + return + return ..() + +/obj/item/inspector/clown/examine(mob/user) + . = ..() + if(cell_cover_open) + . += "Two weird settings dials are visible within the battery compartment." + +/obj/item/inspector/clown/examine_more(mob/user) + if(!cell_cover_open) + return ..() + . = list("Both setting dials are flush with the surface of the battery compartment, and seem to be impossible to move with bare hands.") + . += "\tThe first dial is labeled \"SPEED\" and looks a bit like a screw head." + . += "\tThe second dial is labeled \"SOUND\". It has four small holes in it. Perhaps it can be turned with a fork?" + . += "\tA small bananium part labeled \"ADVANCED WATER CHIP 23000000\" is visible within the battery compartment. It looks completely unlike normal modern electronics, disturbing it would be rather unwise." + + +/obj/item/inspector/clown/proc/cycle_print_time(mob/user) + var/message + if(time_mode == INSPECTOR_TIME_MODE_FAST) + time_mode = INSPECTOR_TIME_MODE_SLOW + message = "SLOW." + else + time_mode = INSPECTOR_TIME_MODE_FAST + message = "LIGHTNING FAST." + + balloon_alert(user, "You turn the screw-like dial, setting the device's scanning speed to [message]") + +/obj/item/inspector/clown/proc/cycle_sound(mob/user) + print_sound_mode++ + if(print_sound_mode > max_mode) + print_sound_mode = INSPECTOR_PRINT_SOUND_MODE_NORMAL + balloon_alert(user, "You turn the dial with holes in it, setting the device's bleep setting to [mode_names[print_sound_mode]] mode.") + +/obj/item/inspector/clown/create_slip() + var/obj/item/paper/fake_report/slip = new(get_turf(src)) + slip.generate_report(get_area(src)) + +/** + * # Bananium HONK-spect scanner + * + * An upgraded version of the fake N-spect scanner + * + * Can print things way faster, at full power the reports printed by this will destroy + * themselves and leave water behind when folding is attempted by someone who isn't an + * origami master. Printing at full power costs INSPECTOR_POWER_USAGE_HONK cell units + * instead of INSPECTOR_POWER_USAGE_NORMAL cell units. + */ +/obj/item/inspector/clown/bananium + name = "\improper Bananium HONK-spect scanner" + desc = "Honkmother-blessed inspection device. Performs inspections according to Clown protocols when activated, then \ + prints a clowncrypted report regarding the maintenance of the station. Hard to replace." + icon = 'icons/obj/tools.dmi' + icon_state = "bananium_inspector" + w_class = WEIGHT_CLASS_SMALL + max_mode = BANANIUM_CLOWN_INSPECTOR_PRINT_SOUND_MODE_LAST + ///How many more times can we print? + var/paper_charges = 32 + ///Max value of paper_charges + var/max_paper_charges = 32 + ///How much charges are restored per paper consumed + var/charges_per_paper = 1 + +/obj/item/inspector/clown/bananium/proc/check_settings_legality() + if(print_sound_mode == INSPECTOR_PRINT_SOUND_MODE_NORMAL && time_mode == INSPECTOR_TIME_MODE_HONK) + if(cell.use(power_to_speak)) + say("Setting combination forbidden by Geneva convention revision CCXXIII selected, reverting to defaults") + time_mode = INSPECTOR_TIME_MODE_SLOW + print_sound_mode = INSPECTOR_PRINT_SOUND_MODE_NORMAL + power_per_print = INSPECTOR_POWER_USAGE_NORMAL + +/obj/item/inspector/clown/bananium/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + check_settings_legality() + return TRUE + +/obj/item/inspector/clown/bananium/attackby(obj/item/I, mob/user, params) + . = ..() + if(cell_cover_open) + check_settings_legality() + if(istype(I, /obj/item/paper/fake_report) || paper_charges >= max_paper_charges) + to_chat(user, "\The [src] refuses to consume \the [I]!") + return + if(istype(I, /obj/item/paper)) + to_chat(user, "\The [src] consumes \the [I]!") + paper_charges = min(paper_charges + charges_per_paper, max_paper_charges) + qdel(I) + +/obj/item/inspector/clown/bananium/Initialize() + . = ..() + playsound(src, 'sound/effects/angryboat.ogg', 150, FALSE) + +/obj/item/inspector/clown/bananium/create_slip() + if(time_mode == INSPECTOR_TIME_MODE_HONK) + var/obj/item/paper/fake_report/water/slip = new(get_turf(src)) + slip.generate_report(get_area(src)) + return + return ..() + +/obj/item/inspector/clown/bananium/print_report(mob/user) + if(time_mode != INSPECTOR_TIME_MODE_HONK) + return ..() + if(paper_charges == 0) + if(cell.use(power_to_speak)) + say("ERROR! OUT OF PAPER! MAXIMUM PRINTING SPEED UNAVAIBLE! SWITCH TO A SLOWER SPEED TO OR PROVIDE PAPER!") + else + to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") + return + paper_charges-- + return ..() + +/obj/item/inspector/clown/bananium/cycle_print_time(mob/user) + var/message + switch(time_mode) + if(INSPECTOR_TIME_MODE_HONK) + power_per_print = INSPECTOR_POWER_USAGE_NORMAL + time_mode = INSPECTOR_TIME_MODE_SLOW + message = "SLOW." + if(INSPECTOR_TIME_MODE_SLOW) + time_mode = INSPECTOR_TIME_MODE_FAST + message = "LIGHTNING FAST." + else + time_mode = INSPECTOR_TIME_MODE_HONK + power_per_print = INSPECTOR_POWER_USAGE_HONK + message = "HONK!" + balloon_alert(user, "You turn the screw-like dial, setting the device's scanning speed to [message]") + +/** + * Reports printed by fake N-spect scanner + * + * Not valid for the bounty. + */ +/obj/item/paper/fake_report + name = "encrypted station inspection" + desc = "Contains no information about the station's current status." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "slip" + show_written_words = FALSE + ///What area the inspector scanned when the report was made. Used to generate the examine text of the report + var/area/scanned_area + +/obj/item/paper/fake_report/proc/generate_report(area/scan_area) + scanned_area = scan_area + icon_state = "slipfull" + + var/list/new_info = list() + for(var/i in 1 to rand(23, 123)) + var/roll = rand(0, 1000) + switch(roll) + if(0 to 900) + new_info += pick_list_replacements(CLOWN_NONSENSE_FILE, "honk") + if(901 to 999) + new_info += pick_list_replacements(CLOWN_NONSENSE_FILE, "non-honk-clown-words") + if(1000) + new_info += pick_list_replacements(CLOWN_NONSENSE_FILE, "rare") + info += new_info.Join() + +/obj/item/paper/fake_report/examine(mob/user) + . = ..() + if(scanned_area?.name) + . += "\The [src] contains no data on [scanned_area.name]." + else if(scanned_area) + . += "\The [src] contains no data on a vague area on station, you should throw it away." + else if(info) + . += "Wait a minute, this isn't an encrypted inspection report! You should throw it away." + else + . += "Wait a minute, this thing's blank! You should throw it away." + +/** + * # Fake report made of water + * + * Fake report but it turns into water under certain circumstances. + * + * If someone who isn't an origami master tries to fold it into a paper plane, it will make the floor it's on wet and disappear. + * If it is ground, it will turn into 5u water. + */ +/obj/item/paper/fake_report/water + grind_results = list(/datum/reagent/water = 5) + +/obj/item/paper/fake_report/water/AltClick(mob/living/user, obj/item/I) + if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE, TRUE)) + return + var/datum/action/innate/origami/origami_action = locate() in user.actions + if(origami_action?.active) //Origami masters can fold water + make_plane(user, I, /obj/item/paperplane/syndicate) + else if(do_after(user, 1 SECONDS, target = src, progress=TRUE)) + var/turf/open/target = get_turf(src) + target.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) + to_chat(user, "As you try to fold [src] into the shape of a plane, it disintegrates into water!") + qdel(src) diff --git a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm index 0b2cb16aa82..65543d1fd0b 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm @@ -80,3 +80,19 @@ price_max = 200 stock_max = 3 availability_prob = 50 + +/** + * # Fake N-spect scanner black market entry + */ +/datum/blackmarket_item/tool/fake_scanner + name = "Clowny N-spect scanner" + desc = "This UPGRADED N-spect scanner can play FIVE HIGH-QUALITY SOUNDS (fork required for sound adjustment not included) and print reports \ + LIGHTNING FAST (screwdriver necessary to activate maximum speed not included). We make no claims as to the usefulness of the reports printed by this. \ + Any and all implied warranties are void if the device is touched, moved, kicked, thrown or modified with bananium sheets. Batteries included. \ + Crowbar necessary to change batteries and adjust settings not included." + item = /obj/item/inspector/clown + + price_min = 230 + price_max = 323 + stock_max = 2 + availability_prob = 50 diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index 01140868b01..42ee665ab6e 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -123,14 +123,24 @@ if(!Carbon.iscopy && !Carbon.copied) to_chat(user, "Take off the carbon copy first.") return - to_chat(user, "You fold [src] into the shape of a plane!") - user.temporarilyRemoveItemFromInventory(src) - var/obj/item/paperplane/plane_type = /obj/item/paperplane //Origami Master var/datum/action/innate/origami/origami_action = locate() in user.actions if(origami_action?.active) - plane_type = /obj/item/paperplane/syndicate + make_plane(user, I, /obj/item/paperplane/syndicate) + else + make_plane(user, I, /obj/item/paperplane) +/** + * Paper plane folding + * + * Arguments: + * * mob/living/user - who's folding + * * obj/item/I - what's being folded + * * obj/item/paperplane/plane_type - what it will be folded into (path) + */ +/obj/item/paper/proc/make_plane(mob/living/user, obj/item/I, obj/item/paperplane/plane_type = /obj/item/paperplane) + to_chat(user, "You fold [src] into the shape of a plane!") + user.temporarilyRemoveItemFromInventory(src) I = new plane_type(loc, src) if(user.Adjacent(I)) user.put_in_hands(I) diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi index 63b4603fd0f..5cc32e7af07 100644 Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ diff --git a/sound/effects/angryboat.ogg b/sound/effects/angryboat.ogg new file mode 100644 index 00000000000..0cf6d1723fc Binary files /dev/null and b/sound/effects/angryboat.ogg differ diff --git a/sound/items/robofafafoggy.ogg b/sound/items/robofafafoggy.ogg new file mode 100644 index 00000000000..16d8af77fc5 Binary files /dev/null and b/sound/items/robofafafoggy.ogg differ diff --git a/sound/items/robofafafoggy2.ogg b/sound/items/robofafafoggy2.ogg new file mode 100644 index 00000000000..11bea909b6d Binary files /dev/null and b/sound/items/robofafafoggy2.ogg differ diff --git a/strings/clown_nonsense.json b/strings/clown_nonsense.json new file mode 100644 index 00000000000..bb565efc24d --- /dev/null +++ b/strings/clown_nonsense.json @@ -0,0 +1,38 @@ +{ + "honk": [ + "honk", + "HONK", + "HONK!", + "HONK!!!", + "HENK", + "HOOOOOOONK" + ], + + "rare": [ + "HOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", + "damn", + ":))))))))))))))))))))))))", + " :) ", + "Hink", + "HAHAHAA HEEHEEHEE", + " Laugh sound. ", + "Extreme Ruckus at the Party" + ], + + "non-honk-clown-words": [ + "bananas", + "chapiteau", + "entrée", + "pranking", + "peel", + "banana peel", + "party", + "juggling", + "... ", + "cat", + "balagan", + "pie", + "slip" + ] + +}