Space Meth. A tutorial of how to add new drugs to A9

Started by ItchyFlea, February 03, 2015, 02:38:34 AM

Previous topic - Next topic

ItchyFlea

This is a tutorial on what I learned when adding the dangerous drug space meth to the game. I want to give a special thanks to Tynan for giving me the original code used for Hediff_Alcohol, as well as some other useful feedback about how to do specific things.

If you don't want the new drug to have after-effects, like how too much alcohol gives a colonist a hangover, you don't need any code and this can be done purely with .xml.
If you do want it to do something, you'll need code.

You'll want to be messing with 3 files for drugs. (Of course, you can use your own names for those files)
1) /Defs/ThingDefs/Items_Drugs.xml
2) /Defs/HediffDefs/Hediffs_Drugs.xml
3) /Defs/ThoughtDefs/Thoughts_Drugs.xml

1) The ThingDef for the drug itself. See the Core thingdef with the same name to see how alcohol is added.
2) This is what health effects your colonist will suffer/benefit from when using your drug. This file works similar to diseases.
3) This is what they think about during the different stages of drug use.

I've written some comments into the .xml files I've used in the Space Meth mod. I'll write better comments and expand this article more later on when I've got some free time, as I've run out of it tonight.

The mod: Space Meth
This was made and tested in version 0.9.706

[attachment deleted due to age]
All my mods are licensed under a Attribution-NonCommercial-ShareAlike 4.0 International
Ask for permission before using in ModPacks

Click here for a list of the mods I've created

Tynan

Tynan Sylvester - @TynanSylvester - Tynan's Blog

skullywag

Space Meth lol awesome. Looking forward to another load of code to learn.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Ramsis

Dear Flea,

Please go ahead and make a random batch of drugs in a mod for us to play with while testing/non-testing. Some that are bad, other's that have good benefits (like Minami's old drug batch before he exploded) like anti-sleepers, fast movers, and everyone's favorite "how the hell are you not hungry from shooting up" drug.

Sincerely,
That guy Ramsi <3
Ugh... I have SO MANY MESSES TO CLEAN UP. Oh also I slap people around who work on mods <3

"Back off man, I'm a scientist."
- Egon Stetmann


Awoo~

JuliaEllie

Itchy. We have to cook!!

Pretty cool. In terms of complexity it seems to be similar to implants. I was looking into the drugs to create some more booze because only beer is a bit boring and I stumbled across quite a few changes in the Defs and corresponding tags. I guess its going to be a pain in the ass to update.. again :D

ItchyFlea

All my mods are licensed under a Attribution-NonCommercial-ShareAlike 4.0 International
Ask for permission before using in ModPacks

Click here for a list of the mods I've created

Ramsis

Ugh... I have SO MANY MESSES TO CLEAN UP. Oh also I slap people around who work on mods <3

"Back off man, I'm a scientist."
- Egon Stetmann


Awoo~

ItchyFlea

I've added 3 more drugs to the mod and have attached it below.

We've now get Space Speed, Space Cannabis and Space Anti Sleep.
The speed just makes pawns a whole lot faster.
The cannabis doesn't really do what I'd intended, which was to make them hungrier quicker. Perhaps someone with better programming knowledge (looks at JuliaEllie) could do that.
The anti-sleep does as it's name says. It immediately sets the colonists rest level to 100% and keeps it there because I couldn't find an easy way of switching off the effect once the level was at 100%.

I've included the updated source code in the mod, and added a couple of comments to the space meth source code.

And now to mention some things I've noticed about the code.
For the ThingDef of the drug in question, under <ingestible> you've got <hediffGivers> which is a list. In here you define what effects, or combination thereof, the drug gives to the colonist. It's a chance based system as well, so you can add some really nasty low-chance side effects to your drugs if you want.

For the HediffDef of the drugs effects, you've got <stagedProps>, which is where the fun begins.

First off there's <initialSeverity>.
This is where you can choose what effect your colonist has from taking 1 of your drug. Beer demonstrates how to make consuming the drug multiple times can make the effects of the drug worse and worse.
Then there's <treatable>, which is a true or false thing. Either your colonists can treat the poor sod or not. Space Meth uses this.
There's <severityPerDay> which can either make the effects of the drug go up or down over time. If treatable is set to false, you'd want this tag to go down, unless you want the effects of the drug to progressively get worse for the colonist with no hope of them ever going down again.
If you've got treatable to true, you'll want to also have <severityPerDayTreatedOffset> set in there. I'm not entirely sure how this tag works.

Then we get into the real fun, <severityStages>.
This is a list tag where we can set what effects the drug does, and how that effects the colonist.
First off we've got <fromSeverity>, which lets you define at what severity level this effect hits your colonist.
<label> is what this effect gets labelled as in the colonist Health tab.
There's also <vomitFrequency>. I think that speaks for itself as to what it does.
And there's <tale>, but I haven't touched that, so I don't know what it does.

<modifiers> is where the fun is. In here we've got the list tag <actMods>.
If it's listed in \Core\Defs\PawnActivityDefs\PawnActivities.xml then you can affect it here, with either positive or negative effects.
There's <activity>, which is the defName of the PawnActivityDef.
Then you can modify that activity with either <offset> which increases or decreases the pawns current activity by a specific amount, or <setMax>, which sets the activity to what you specify. This can be used to kill or incapacitate colonists.

Finally there are the thoughts your colonist has.
They are also a list like the severityStages, and each list item corresponds to the list item in there. If you've got 5 stages to a drug, and only want the colonist to have a thought when they reach the 5th stage, use this list item 4 times and then have your thought as the 5th one:
  <li>
        <label>hidden</label>
        <description>Should not appear.</description>
        <baseMoodEffect>0</baseMoodEffect>
        <visible>false</visible>
      </li>

<visible>false</visible> means the player won't see this thought. If you want the player to see the thought, don't use this line at all.

[attachment deleted due to age]
All my mods are licensed under a Attribution-NonCommercial-ShareAlike 4.0 International
Ask for permission before using in ModPacks

Click here for a list of the mods I've created

ItchyFlea

I've attached to this post a version that works with the current Alpha 9. The versions I've posted in this thread don't work correctly/at all since they were made against the tester version of the game.

The 3 drugs added are not balanced and I don't intend to balance them at this time. This is more of a demo of how the drug system works in Alpha 9. At least, how I believe it works.

[attachment deleted due to age]
All my mods are licensed under a Attribution-NonCommercial-ShareAlike 4.0 International
Ask for permission before using in ModPacks

Click here for a list of the mods I've created

DeaconBlues

Very cool, this could serve as a good example for my mod -- assuming I can figure out the whole assembly thing  :).  I'm curious though, does anyone know what causes colonists to automatically consume beer?  I thought it was maybe related to <isPleasureDrug> but this doesn't seem to be the case.

Wendigo

Yes, how exactly do we cause colonists to consume drugs automatically?  Any info would be appreciated.

DeaconBlues

Alright, so I managed to track down the code that tells the colonists to consume beer and I've attempted to adapt it to look for a random def that has <isPleasureDrug>.  Unfortunately it doesn't seem to be working and I'm not quite sure why -- I have no experience in C# so it could be a number of things.  I did try to point to one of my defs explicitly in case it was the random portion that wasn't working, but still no go.  I'm thinking (Predicate<Thing>)null is likely the issue, but I have no idea how to fix it.  Any help would be much appreciated.

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using Verse.AI;
using RimWorld;

namespace FinerThings
{

  public class JobGiver_SeekOtherDrugs : ThinkNode_JobGiver
  {
    public static ThingDef RandomDrug()
    {
        return GenCollection.RandomElement<ThingDef>(Enumerable.Where<ThingDef>(DefDatabase<ThingDef>.AllDefs, (Func<ThingDef, bool>)(def =>
        {
            if (def.category == EntityCategory.Item)
            {
                return def.ingestible.isPleasureDrug;
            }
            else
            {
                return false;
            }
        })));
    }

    public static class DrugThingDefOf
    {
        public static ThingDef Coffee;
        public static ThingDef Espresso;
        public static ThingDef Cigar;
        public static ThingDef Cigarillos;
    }

    private static readonly SimpleCurve DrugUseIntervalFactorCurve_Mood = new SimpleCurve()
    {
      new CurvePoint(20f, 0.4f),
      new CurvePoint(60f, 1f)
    };
    private static readonly SimpleCurve DrugUseIntervalFactorCurve_Drunkness = new SimpleCurve()
    {
      new CurvePoint(0.0f, 1f),
      new CurvePoint(1f, 4f)
    };
    private const int BaseDrugUseInterval = 60000;
    private const int DrugUseIntervalBinging = 600;

    protected override Job TryGiveTerminalJob(Pawn pawn)
    {
      int num1 = pawn.story.traits.DegreeOfTrait(TraitDefOf.DrugDesire);
      if (num1 < 0)
      {
          return (Job)null;
      }
      int num2;
      if (pawn.mindState.broken.CurStateDef != null && pawn.mindState.broken.CurStateDef == BrokenStateDefOf.BingingAlcohol)
      {
        return (Job) null;
      }
      else
      {
          num2 = (int)(60000.0 * (double)JobGiver_SeekOtherDrugs.DrugUseIntervalFactorCurve_Mood.Evaluate(pawn.needs.mood.CurLevel));
        if (num1 == 1)
          num2 = (int) ((double) num2 * 0.5);
        else if (num1 > 1)
          num2 = (int) ((double) num2 * 0.280000001192093);
      }

      if (Find.TickManager.TicksGame - pawn.mindState.lastPleasureDrugUseTick > num2)
      {
          Job job = JobGiver_SeekOtherDrugs.ConsumeDrug(pawn);
          if (job != null)
          {
              return job;
          }
      }
      return (Job) null;
    }

    private static Job ConsumeDrug(Pawn pawn)
    {
      Thing thing = GenClosest.ClosestThingReachable(pawn.Position, ThingRequest.ForDef(RandomDrug()), PathMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, true), 9999f, (Predicate<Thing>)null, (IEnumerable<Thing>)null, -1);
      if (thing == null)
          return (Job)null;
      return new Job(JobDefOf.Ingest, (TargetInfo) thing)
      {
        maxNumToCarry = Mathf.Min(thing.stackCount, thing.def.ingestible.maxNumToIngestAtOnce),
      };
    }
  }
}

Ykara

I've tried it with the space meth code, but my pawns get a hangover everytime they have consumed the drug. Even if they just take one they're immediately hungover. Is there a way to fix this?

ItchyFlea

Quote from: Ykara on March 30, 2015, 06:24:54 AM
I've tried it with the space meth code, but my pawns get a hangover everytime they have consumed the drug. Even if they just take one they're immediately hungover. Is there a way to fix this?
I included Tynan's original Alcohol code in the file attached to this post: https://ludeon.com/forums/index.php?topic=9895.msg104057#msg104057
His code is what will sometimes apply the hangover effect. The space meth code always applies it's effect.
All my mods are licensed under a Attribution-NonCommercial-ShareAlike 4.0 International
Ask for permission before using in ModPacks

Click here for a list of the mods I've created

RickyMartini

Has anyone understood what vomitMtbDays influences exactly? Like what does the value 1 mean? 1 vomit per 24 hours? 1 vomit per hour? 1 vomit per stage?