tgstation-maintainers
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- tags: Appended, Science title: "Experi-Sci (Bobbah, Floyd, and Arcane)" --- :::warning **Coders, wait a second!** Considering designing your own experiments or handlers? Make sure to check out our [Ethical and Moral Considerations to Avoid Angering Players](#Ethical-and-Moral-Considerations-to-Avoid-Angering-Players) section! ::: # Experi-Sci Hello and welcome to an exciting new DLC for techwebs, the Experi-Sci™ system. ## What is it In short, the Experi-Sci system is an addition to our existing techwebs. It aims to add experiments that the crew may perform, and these experiments are used as a discount or requirement for certain techweb nodes. The experiments are designed to be elements to encourage players to interact with all facets of the station and game, which we hope will help to reduce burnout and increase cooperation within the crew. In a technical description, this system implements a framework of components and base classes (the experiments) that are the foundation of the Experi-Sci system. Techweb nodes may now have experiments, ``/datum/experiment``, added as a requirement for their research or a discount towards the points required for it. Once an experiment is marked as complete by the research subsystem, the node can then be researched (if required), or the point cost will be discounted. These experiments are handled using components, ``/datum/component/experiment_handler``, which provides both the functionality of performing experiments as well as a generic UI which greatly simplifies their implementation on objects. That's right, to add experiment-handling devices and brand new experiment types, you likely won't need to make a UI! ## What it is not Do not add experiments that give you a reward of points, or random items, they exist soley to interact with the techwebs framework, changing this point will require extensive discussion ## The Framework As noted above, the core of the Experi-Sci system is a framework. This framework is described below in a brief technical manner, though I would recommend consulting the extensive documentation on the Experi-Sci module for up-to-date information. ### Experiment Datums Location: ``code\modules\experisci\experiment\types\experiment.dm`` The base experiment datum is akin to an interface, in that it is designed to have several methods that must be overridden to produce a functional experiment. These methods are intended to be very abstract concepts in order to allow for a great deal of creativity in performing them. They must implement the following... #### ``is_complete()`` A boolean method which describes if the experiment is complete or not. #### ``check_progress()`` A method which returns a collection of experiment stages, the stages are simple lists of a stage type (boolean, integer, float), a description, and value(s) which are used to display the experiment's progress on UI elements. These are produced using the experiment progress macros (see ``code\_DEFINES\experisci.dm``). #### ``actionable(...)`` A boolean method which returns true or false depending on if the experiment can be actioned (performed) with the provided arguments. This is intended to be used to ensure an experiment can be performed prior to initiating the task. #### ``perform_experiment_actions(datum/component/experiment_handler/experiment_handler, ...)`` A boolean method which attempts to perform the experiment with the provided arguments, and returns true or false based on if the experiment was performed successfully. ### Experiment Handlers Location: ``code\modules\experisci\experiment\handlers\experiment_handler.dm`` Experiment handlers are the component which interacts with the techweb, and handles the UI for the Experi-Sci system. This generic component can be attached to any object, and allows for a rapid addition of experiment-performing capabilities to virtually any object. Note that these handlers use signals to communicate and perform their functions. There are a few important things to note about experiment handlers, namely the constructor for the class. The arguments for this constructor are explained below: - ``allowed_experiments``: a list of /datum/experiment types which can be performed by this handler. - ``blacklisted_experiments``: A list of /datum/experiment types that cannot be performed by this handler. This blacklisting system allows for disallowing certain subtypes of experiments (like destructive scanning experiments) that otherwise would fall under the set of allowed experiments. - ``config_mode``: A defined constant, used for determining the behaviour of how the UI is opened. - ``config_flags``: Flags that control the operation behaviour of the experiment handler, see experisci defines. - ``start_experiment_callback``: When provided adds a UI button to use this callback to start the experiment. As well as this, it is also important to note that the constructor of this component is where the signals for how experiments are performed are registered. ## Example Implementations To help exemplify the simplicity of this system, I would like to show two different implementations below. ### The Experi-Scanner The hand-held experiment scanner is a great example of how simple an experiment handler can be to implement. Say that we want a hand-held tool that upon attacking an object performs our experiment, and this experiment is scanning. Not only this, but we don't want this hand-held scanner to be capable of performing destructive experiments, as it's too simple of an item to do such! To accomplish this, the code is very simple as we are essentially creating an object to attach our experiment handler component to. ```dm /obj/item/experi_scanner name = "Experi-Scanner" desc = "A handheld scanner used for completing the many experiments of modern science." w_class = WEIGHT_CLASS_SMALL icon = 'icons/obj/device.dmi' icon_state = "experiscanner" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' /obj/item/experi_scanner/Initialize() ..() return INITIALIZE_HINT_LATELOAD // Late initialize to allow for the rnd servers to initialize first /obj/item/experi_scanner/LateInitialize() . = ..() AddComponent(/datum/component/experiment_handler, \ allowed_experiments = list(/datum/experiment/scanning, /datum/experiment/physical),\ disallowed_traits = EXPERIMENT_TRAIT_DESTRUCTIVE) ``` As well as this, we must add some code in ``/datum/component/experiment_handler`` to specify how to handle hand-held scanning experiments, so we add the following into the constructor (``Initialize(...)``) ```dm if(isitem(parent)) RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, .proc/try_run_handheld_experiment) RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/ignored_handheld_experiment_attempt) ``` and later on, defining our two procs to handle these experiments within the same file, ``try_run_handheld_experiment`` and ``ignored_handheld_experiment_attempt`` ```dm /** * Hooks on attack to try and run an experiment (When using a handheld handler) */ /datum/component/experiment_handler/proc/try_run_handheld_experiment(datum/source, atom/target, mob/user, params) SIGNAL_HANDLER if (!should_run_handheld_experiment(source, target, user, params)) return INVOKE_ASYNC(src, .proc/try_run_handheld_experiment_async, source, target, user, params) return COMPONENT_CANCEL_ATTACK_CHAIN /** * Provides feedback when an item isn't related to an experiment, and has fully passed the attack chain */ /datum/component/experiment_handler/proc/ignored_handheld_experiment_attempt(datum/source, atom/target, mob/user, proximity_flag, params) SIGNAL_HANDLER if (!proximity_flag || (selected_experiment == null && !(config_flags & EXPERIMENT_CONFIG_ALWAYS_ACTIVE))) return playsound(user, 'sound/machines/buzz-sigh.ogg', 25) to_chat(user, "<span class='notice'>[target] is not related to your currently selected experiment.</span>") ``` That's it, we now have a working hand-held scanner! ### Vat-Growing Scanning Experiments Let's say we want to sub-class our scanning experiment type to add new experiments for vat-growing. This requires slight modification to the scanning experiment's ``get_contributing_index(atom/target)`` proc as we need to ensure that all of our scanned targets have the ``TRAIT_VATGROWN`` trait. This is necessary because vat-grown creatures are often regular mobs, but we don't want players to merely be able to scan the regular mobs. They MUST be vat-grown! To do this is a simple modification... ```dm /datum/experiment/scanning/random/cytology name = "Cytology Scanning Experiment" description = "Base experiment for scanning atoms that were vatgrown" exp_tag = "Cytology Scan" total_requirement = 1 possible_types = list(/mob/living/simple_animal/hostile/cockroach) traits = EXPERIMENT_TRAIT_DESTRUCTIVE /datum/experiment/scanning/random/cytology/final_contributing_index_checks(atom/target, typepath) return ..() && HAS_TRAIT(target, TRAIT_VATGROWN) // note that we have to overload the serialize_progress_stage proc, as the progress differs depending on if an experiment // is destructive or not. /datum/experiment/scanning/random/cytology/serialize_progress_stage(atom/target, list/seen_instances) return EXPERIMENT_PROG_INT("Scan samples of \a vat-grown [initial(target.name)]", \ traits & EXPERIMENT_TRAIT_DESTRUCTIVE ? scanned[target] : seen_instances.len, required_atoms[target]) ``` Now we have a working sub-type of scanning experiments which allows us to only scan vat-grown creatures. Perfect! ### Explosive Experiments A slightly more complex example is that of explosive experiments. Say that we want to add a type of experiment for recording explosions of certain sizes, and we want to add the ability to perform these experiments to the doppler scanner in the toxins testing lab. It may sound daunting, but complex ideas like these are very easy to implement with a few small code changes which are mostly just implementing the experiment datum "interface". First, the experiment itself... ```dm /datum/experiment/explosion name = "Explosive Experiment" description = "An experiment requiring an explosion to progress" exp_tag = "Explosion" performance_hint = "Perform explosive experiments using the research doppler array in the toxins lab." /// The required devastation range to complete the experiment var/required_devastation = 0 /// The required heavy impact range to complete the experiment var/required_heavy = 0 /// The required light impact range to complete the experiment var/required_light = 0 /// The last measured devastation range var/last_devastation /// The last measured heavy range var/last_heavy /// The last measured light range var/last_light /datum/experiment/explosion/is_complete() return required_devastation <= last_devastation \ && required_heavy <= last_heavy \ && required_light <= last_light /datum/experiment/explosion/check_progress() var/status_message = "You must record an explosion with ranges of at least \ [required_devastation] devastation, [required_heavy] heavy, and [required_light] light." if (last_devastation || last_heavy || last_light) status_message += " The last attempt had ranges of [last_devastation]D/[last_heavy]H/[last_light]L." . += EXPERIMENT_PROG_BOOL(status_message, is_complete()) /datum/experiment/explosion/perform_experiment_actions(datum/component/experiment_handler/experiment_handler, devastation, heavy, light) last_devastation = devastation last_heavy = heavy last_light = light return is_complete() ``` There is nothing terribly interesting to note here, it's rather simple! Following this, we have to implement a slight change to the handler component. This will allow us to register to recieve the signal for performing our experiment on the doppler array. As well as this, we need to define a new signal for the handler component to recieve when an explosion is detected on the doppler array, as there is not yet one. We merely define a new signal in ``_DEFINES/dcs/signals.dm``, insert two new lines into the constructor of the handler component, and quickly define what performing a doppler array experiment looks like. ```dm /* Inserted into the signals file to define our new signal */ ///from /obj/machinery/doppler_array/proc/sense_explosion(...): Runs when an explosion is succesfully detected by a doppler array(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) #define COMSIG_DOPPLER_ARRAY_EXPLOSION_DETECTED "atom_dopplerarray_explosion_detected" /* Inserted into Initialize for the experiment handler datum */ if(istype(parent, /obj/machinery/doppler_array)) RegisterSignal(parent, COMSIG_DOPPLER_ARRAY_EXPLOSION_DETECTED, .proc/try_run_doppler_experiment) /* Inserted into the experiment handler datum */ /** * Hooks on successful explosions on the doppler array this is attached to */ /datum/component/experiment_handler/proc/try_run_doppler_experiment(datum/source, turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range ) SIGNAL_HANDLER var/atom/movable/our_array = parent if(action_experiment(source, devastation_range, heavy_impact_range, light_impact_range)) playsound(src, 'sound/machines/ping.ogg', 25) else playsound(src, 'sound/machines/buzz-sigh.ogg', 25) our_array.say("Insufficient explosion to contribute to current experiment.") ``` Finally the last thing we have to do is implement the registration of the component on the doppler array, and implement the new signal we had to add so that the handler can know when an experiment is performed. ```dm /* Added to the existing proc, sense_explosion(), on the doppler array */ SEND_SIGNAL(src, COMSIG_DOPPLER_ARRAY_EXPLOSION_DETECTED, epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) /* Added to the research variant of the doppler array */ /obj/machinery/doppler_array/research/Initialize() ..() linked_techweb = SSresearch.science_tech return INITIALIZE_HINT_LATELOAD // Late initialize to allow the server machinery to initialize first /obj/machinery/doppler_array/research/LateInitialize() . = ..() AddComponent(/datum/component/experiment_handler, \ allowed_experiments = list(/datum/experiment/explosion), \ config_mode = EXPERIMENT_CONFIG_UI, \ config_flags = EXPERIMENT_CONFIG_ALWAYS_ACTIVE) ``` That's it. We now have a machine with a working UI for performing experiments, and the experiments for that machine as well. I've included a couple of examples of an implemented explosion experiment below, to give you an idea of what those may look like. ```dm /datum/experiment/explosion/calibration name = "Is This Thing On?" description = "The engineers from last shift left a notice for us that the doppler array seemed to be malfunctioning. \ Could you check that it is still working? Any explosion will do!" required_light = 1 /datum/experiment/explosion/maxcap name = "Mother of God" description = "A recent outbreak of a blood-cult in a nearby sector necessitates the development of a large explosive. \ Create a large enough explosion to prove your bomb, we'll be watching." /datum/experiment/explosion/maxcap/New() required_devastation = GLOB.MAX_EX_DEVESTATION_RANGE required_heavy = GLOB.MAX_EX_HEAVY_RANGE required_light = GLOB.MAX_EX_LIGHT_RANGE ``` ## Ethical and Moral Considerations to Avoid Angering Players During the time which Experi-Sci was being developed and tested alongside our playerbase at /tg/ several important guidelines became evident to ensure that the experiments and other features you produce in this system coincide well with gameplay. We have tried to summarize these below, though note that this list is not final, and you should always use caution with the player mob; they can be very angry fellows! Additionally, if you have any further suggestions from your own experience, please feel free to suggest them, or contact me on Discord: ``bobbahbrown#0001`` ### 1. Why Experiments Exist First and foremost, I feel it is very important to re-state why experiments exist. We want to create a **fun** and **engaging** system that hopefully forces some more player interaction with content they otherwise may not have seen, as well as encouraging co-operation between crewmen. To this extent, experiments should **never** be created for tedium; they should always aim to express some content or job feature. For example, experiments that have players scan slime cores aim to encourage peforming xenobiology. As well as this, experiments that have players create bombs hope to bring more creative minds to toxins, and provide more legitimacy to this often-disregarded division. Perhaps then, for inspiration, you can leverage experiments to bring back your favourite dead departments, or encourage new (_fun_) gameplay styles! ### 2. We Won't Always Have High-Pop So, you might be thinking at this point, "*let's start time-gating all the fun content with required experiments to really force our players to work together!*" Well, hold your horses fine coder, because we won't always have a bazillion crewmen ready to readily perform all of our busywork. What happens when the late-night deadpop skeleton crew is running the entire station? Is science abandoned? Is all hope lost? It is for this reason that we must **embrace the discount experiments more than the required experiments**. Discount experiments seek to encourage performing the related experiments, whilst allowing a low-pop or otherwise unproductive science division to still have some degree of progress within the techweb. Leverage this tool which is available to you, and you will see far less resistance to your changes! ### 3. We Shouldn't Complete Everything To help produce a system which provides a *depth* of content for players to engage and explore, **we shouldn't design for every single technology to be researched inside a given (*average*) round**. Base technologies which are critical to jobs on-board should always be accessible, but we should not reward a crew who does not perform their duties, or provide those same benefits of a high-pop crew to those at low-pop. To this extent, consider 'balancing' the placement of your experiments and point costs to allow the techweb to require multiple rounds for any given player to experience all technologies. This helps to ensure that high-level technologies can actually feel like a reward rather than just another small step in a never-changing game loop. *This note on design falls more into the overall design focus for science within /tg/, but we feel it is important to consider in all codebases. This is a way you can encourage players to engage with more content in a meaningful manner.* ### 4. We Can't Require Everything Very closely related to the point above, what happens when key technologies like mining tech or industrial engineering find themselves locked behind some (hopefully minor) tedium? Riots, that's what! **Always be careful when making an experiment required instead of discounted**, and ask yourself if the node it is blocking could cause major gameplay disruptions. Required experiments can be the achilles heel to an otherwise fun mechanic, or even cripple a crew outright if placed poorly. Discounts are generally the way to go, dear coder. ### 5. ...But Some Things Are OK To Require As the title implies, you should not disregard required experiments altogether. It would be wise to use these as a tool to prevent the crew from progressing too fast over a 'section' of content which the experiment (or a group of experiments) targets. If used sparingly, we feel that required experiments can help to represent content which must always be performed, helping to effect player mentality around an area of content, or even tasks which can be seen as achievements for the crew. ### 6. Don't make fetch quest experiments If your experiment amounts to travelling to some department and doing something with a single item, but doesn't promote actually engaging with other sytems like botany or toxins, then please, please do not make an experiment

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully