Modding:Mutations: Difference between revisions

Jump to navigation Jump to search
2,576 bytes removed ,  23:49, 16 April 2021
Rm refs to IPart.Name and IPart.DisplayName
imported>Teamtotobot
m (Teamtotobot moved page Modding: Creating New Mutations to Modding/Creating New Mutations: Bot: Moved page)
(Rm refs to IPart.Name and IPart.DisplayName)
 
(9 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Modding]]{{Modding Info}}
[[Category:Script Modding]]{{Modding Info}}{{Modding Topic Prerequisites|Modding:C Sharp Scripting}}
== Tutorial ==
== Tutorial ==
First, include a mutations.xml in your mod that defines a new mutation.
First, include a mutations.xml in your mod that defines a new mutation.
Line 22: Line 22:
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using System.Text;
 
using XRL.Rules;
using XRL.Rules;
using XRL.Messages;
using XRL.Messages;
using ConsoleLib.Console;
using ConsoleLib.Console;
 
namespace XRL.World.Parts.Mutation
namespace XRL.World.Parts.Mutation
{
{
Line 32: Line 32:
     class FreeholdTutorial_Udder : BaseMutation
     class FreeholdTutorial_Udder : BaseMutation
     {
     {
        public FreeholdTutorial_Udder()
        {
            Name = "FreeholdTutorial_Udder";
            DisplayName = "Udder";
        }
         public override void Register(GameObject Object)
         public override void Register(GameObject Object)
         {
         {
         }
         }
       
 
         public override string GetDescription()
         public override string GetDescription()
         {
         {
             return "";
             return "";
         }
         }
 
         public override string GetLevelText(int Level)
         public override string GetLevelText(int Level)
         {
         {
Line 52: Line 46:
             return Ret;
             return Ret;
         }
         }
 
         public override bool BeforeRender(Event E)
         public override bool WantEvent(int ID, int cascade)
        {
            return base.WantEvent(ID, cascade) || ID == BeforeRenderEvent.ID;
        }
 
        public override bool HandleEvent(BeforeRenderEvent e)
         {
         {
             if (ParentObject.IsPlayer())
             if (ParentObject.IsPlayer())
Line 64: Line 63:
             return true;
             return true;
         }
         }
 
         public override bool FireEvent(Event E)
         public override bool FireEvent(Event E)
         {
         {
             return base.FireEvent(E);
             return base.FireEvent(E);
         }
         }
 
         public override bool ChangeLevel(int NewLevel)
         public override bool ChangeLevel(int NewLevel)
         {
         {
             return true;
             return true;
         }
         }
 
         public override bool Mutate(GameObject GO, int Level)
         public override bool Mutate(GameObject GO, int Level)
         {
         {
             return true;
             return true;
         }
         }
 
         public override bool Unmutate(GameObject GO)
         public override bool Unmutate(GameObject GO)
         {
         {
Line 89: Line 88:
   
   


Here's a full example of the Flaming Hands mutation from the game's source code.
Here's a full decompiled example of the [[Flaming Hands]] mutation from the game's source code. (Note that, because it's decompiled, some of the variables have very generic names, like <code>gameObject</code> instead of something more descriptive, like <code>target</code>)
Flaming Hands - Full Example .cs
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading;
using ConsoleLib.Console;
using XRL.Core;
using XRL.Rules;
using XRL.UI;
using XRL.UI;
using ConsoleLib.Console;
 
namespace XRL.World.Parts.Mutation
namespace XRL.World.Parts.Mutation
{
{
    [Serializable]
[Serializable]
    class FlamingHands : BaseMutation
public class FlamingHands : BaseMutation
    {
{
        public FlamingHands()
public override bool GeneratesEquipment()
        {
{
            Name = "FlamingHands";
return true;
            DisplayName = "Flaming Hands";
}
        }
 
public override void Register(GameObject Object)
        public Guid FlamingHandsActivatedAbilityID = Guid.Empty;
{
        public ActivatedAbilityEntry FlamingHandsActivatedAbility = null;
Object.RegisterPartEvent(this, "CommandFlamingHands");
Object.RegisterPartEvent(this, "AIGetOffensiveMutationList");
        public override void Register(GameObject Object)
base.Register(Object);
        {
}
            Object.RegisterPartEvent(this, "BeginEquip");
 
            Object.RegisterPartEvent(this, "CommandFlamingHands");
public override string GetDescription()
            Object.RegisterPartEvent(this, "AIGetOffensiveMutationList");
{
        }
return "You emit jets of flame from your hands.";
}
        public override string GetDescription()
 
        {
public override string GetLevelText(int Level)
            return "You emit jets of flame from your hands.";
{
        }
return "Emits a 9-square ray of flame in the direction of your choice\n" + "Cooldown: 10 rounds\n" + "Damage: " + this.ComputeDamage(Level) + "\n" + "Cannot wear gloves";
}
        public override string GetLevelText(int Level)
 
        {
public string ComputeDamage(int UseLevel)
            string Ret = "Emits a 9-square ray of flame in the direction of your choice\n";
{
            Ret += "Cooldown: 10 rounds\n";
string text = UseLevel + "d4";
            Ret += "Damage: " + Level + "d6\n";
if (this.ParentObject != null)
            Ret += "Cannot wear gloves";
{
            return Ret;
int partCount = this.ParentObject.GetPart<Body>().GetPartCount(this.BodyPartType);
        }
if (partCount > 0)
{
        public void Flame(Cell C, ScreenBuffer Buffer)
text = text + "+" + partCount;
        {
}
            string Damage = Level + "d6";
}
else
            Body pBody = ParentObject.GetPart("Body") as Body;
{
            int nHandCount = pBody.GetPart("Hands").Count-1;
text += "+1";
            if (nHandCount > 0) Damage += "+" + nHandCount.ToString();
}
return text;
            if (C != null)
}
            {
 
                List<GameObject> Objects = C.GetObjectsInCell();
public string ComputeDamage()
{
                foreach (GameObject GO in Objects)
return this.ComputeDamage(base.Level);
                {
}
                    if( GO.PhasedMatches( ParentObject ) )
 
                    {
public void Flame(Cell C, ScreenBuffer Buffer, bool doEffect = true)
                        GO.FireEvent(Event.New("TemperatureChange", "Amount", 310 + (30 * Level), "Owner", ParentObject));
{
                        for (int x = 0; x < 5; x++) GO.ParticleText("&r" + (char)(219 + Rules.Stat.Random(0, 4)), 2.9f, 1);
string dice = this.ComputeDamage();
                        for (int x = 0; x < 5; x++) GO.ParticleText("&R" + (char)(219 + Rules.Stat.Random(0, 4)), 2.9f, 1);
if (C != null)
                        for (int x = 0; x < 5; x++) GO.ParticleText("&W" + (char)(219 + Rules.Stat.Random(0, 4)), 2.9f, 1);
{
                    }
foreach (GameObject gameObject in C.GetObjectsInCell())
                }
{
if (gameObject.PhaseMatches(this.ParentObject))
                foreach (GameObject GO in C.GetObjectsWithPart("Combat"))
{
                {
gameObject.TemperatureChange(310 + 25 * base.Level, this.ParentObject, false, false, false, 0, null, null);
                    if( GO.PhasedMatches( ParentObject ) )
if (doEffect)
                    {
{
                        Damage Dmg = new Damage(Rules.Stat.Roll(Damage));
for (int i = 0; i < 5; i++)
                        Dmg.AddAttribute("Fire");
{
                        Dmg.AddAttribute("Heat");
gameObject.ParticleText("&r" + ((char)(219 + Stat.Random(0, 4))).ToString(), 2.9f, 1);
}
                        Event eTakeDamage = Event.New("TakeDamage");
for (int j = 0; j < 5; j++)
                        eTakeDamage.AddParameter("Damage", Dmg);
{
                        eTakeDamage.AddParameter("Owner", ParentObject);
gameObject.ParticleText("&R" + ((char)(219 + Stat.Random(0, 4))).ToString(), 2.9f, 1);
                        eTakeDamage.AddParameter("Attacker", ParentObject);
}
                        eTakeDamage.AddParameter("Message", "from %o flames!");
for (int k = 0; k < 5; k++)
{
                        GO.FireEvent(eTakeDamage);
gameObject.ParticleText("&W" + ((char)(219 + Stat.Random(0, 4))).ToString(), 2.9f, 1);
                    }
}
                }
}
            }
}
}
            Buffer.Goto(C.X, C.Y);
DieRoll cachedDieRoll = dice.GetCachedDieRoll();
            string sColor = "&C";
foreach (GameObject gameObject2 in C.GetObjectsWithPartReadonly("Combat"))
            int r = Rules.Stat.Random(1, 3);
{
            if (r == 1) sColor = "&R";
if (gameObject2.PhaseMatches(this.ParentObject))
            if (r == 2) sColor = "&r";
{
            if (r == 3) sColor = "&W";
Damage damage = new Damage(cachedDieRoll.Resolve());
damage.AddAttribute("Fire");
            r = Rules.Stat.Random(1, 3);
damage.AddAttribute("Heat");
            if (r == 1) sColor += "^R";
Event @event = Event.New("TakeDamage", 0, 0, 0);
            if (r == 2) sColor += "^r";
@event.SetParameter("Damage", damage);
            if (r == 3) sColor += "^W";
@event.SetParameter("Owner", this.ParentObject);
@event.SetParameter("Attacker", this.ParentObject);
            if( C.ParentZone == XRL.Core.XRLCore.Core.Game.ZoneManager.ActiveZone )
@event.SetParameter("Message", "from %o flames!");
            {
gameObject2.FireEvent(@event);
                r = Rules.Stat.Random(1, 3);
}
                Buffer.Write(sColor + (char)(219 + Rules.Stat.Random(0, 4)));
}
                Popup._TextConsole.DrawBuffer(Buffer);
}
                System.Threading.Thread.Sleep(10);
if (doEffect)
            }
{
        }
Buffer.Goto(C.X, C.Y);
string str = "&C";
        public override bool FireEvent(Event E)
int num = Stat.Random(1, 3);
        {
if (num == 1)
            if (E.ID == "AIGetOffensiveMutationList")
{
            {
str = "&R";
                int Distance = (int)E.GetParameter("Distance");
}
                GameObject Target = E.GetParameter("Target") as GameObject;
if (num == 2)
                List<XRL.World.AI.GoalHandlers.AICommandList> CommandList = (List<XRL.World.AI.GoalHandlers.AICommandList>)E.GetParameter("List");
{
str = "&r";
                if (FlamingHandsActivatedAbility != null && FlamingHandsActivatedAbility.Cooldown <= 0 && Distance <= 9 && ParentObject.HasLOSTo(Target) ) CommandList.Add(new XRL.World.AI.GoalHandlers.AICommandList("CommandFlamingHands", 1));
}
                return true;
if (num == 3)
            }
{
str = "&W";
            if (E.ID == "CommandFlamingHands")
}
            {
int num2 = Stat.Random(1, 3);
                ScreenBuffer Buffer = new ScreenBuffer(80, 25);
if (num2 == 1)
                Core.XRLCore.Core.RenderMapToBuffer(Buffer);
{
str += "^R";
                List<Cell> TargetCell = PickLine(9, AllowVis.Any);
}
                if (TargetCell == null) return true;
if (num2 == 2)
                if (TargetCell.Count <= 0) return true;
{
str += "^r";
                if (TargetCell != null)
}
                {
if (num2 == 3)
                    if (TargetCell.Count == 1)
{
                    {
str += "^W";
                        if (ParentObject.IsPlayer())
}
                            if (UI.Popup.ShowYesNoCancel("Are you sure you want to target yourself?") != DialogResult.Yes)
if (C.ParentZone == XRLCore.Core.Game.ZoneManager.ActiveZone)
                            {
{
                                return true;
Stat.Random(1, 3);
                            }
Buffer.Write(str + ((char)(219 + Stat.Random(0, 4))).ToString(), true);
                    }
Popup._TextConsole.DrawBuffer(Buffer, null, false);
Thread.Sleep(10);
                    if( FlamingHandsActivatedAbility != null ) FlamingHandsActivatedAbility.Cooldown = 110;
}
                    ParentObject.FireEvent(Event.New("UseEnergy", "Amount", 1000, "Type", "Physical Mutation"));
}
                   
}
                    for (int x = 0; x < 9 && x < TargetCell.Count; x++)
 
                    {
public static bool Cast(FlamingHands mutation = null, string level = "5-6")
                        if (TargetCell.Count == 1 || TargetCell[x] != ParentObject.pPhysics.CurrentCell)
{
                        Flame(TargetCell[x],Buffer);
if (mutation == null)
{
                        foreach( GameObject GO in TargetCell[x].GetObjectsWithPart("Physics") )
mutation = new FlamingHands();
                        {
mutation.Level = Stat.Roll(level, null);
                            if (GO.pPhysics.Solid)
mutation.ParentObject = XRLCore.Core.Game.Player.Body;
                            {
}
                                x = 999;
ScreenBuffer scrapBuffer = ScreenBuffer.GetScrapBuffer1(true);
                                break;
XRLCore.Core.RenderMapToBuffer(scrapBuffer);
                            }
List<Cell> list = mutation.PickLine(9, AllowVis.Any, null, false, null);
                        }
if (list == null)
                    }
{
                }
return true;
            }
}
if (list.Count <= 0)
            if (E.ID == "BeginEquip")
{
            {
return true;
                GameObject Equipment = E.GetParameter("Object") as GameObject;
}
                string BodyPartName = E.GetParameter("BodyPartName") as string;
if (list != null)
{
                if (BodyPartName == "Hands")
if (list.Count == 1 && mutation.ParentObject.IsPlayer() && Popup.ShowYesNoCancel("Are you sure you want to target yourself?") != DialogResult.Yes)
                {
{
                    if (IsPlayer())
return true;
                    {
}
                        UI.Popup.Show("Your flaming hands prevents you from equipping " + Equipment.DisplayName + "!");
mutation.CooldownMyActivatedAbility(mutation.FlamingHandsActivatedAbilityID, 10, null);
                    }
mutation.UseEnergy(1000);
mutation.PlayWorldSound(mutation.Sound, 0.5f, 0f, true, null);
                    E.bCancelled = true;
int num = 0;
                    return false;
while (num < 9 && num < list.Count)
                }
{
            }
if (list.Count == 1 || list[num] != mutation.ParentObject.pPhysics.CurrentCell)
{
            return true;
mutation.Flame(list[num], scrapBuffer, true);
        }
}
foreach (GameObject gameObject in list[num].LoopObjectsWithPart("Physics"))
{
        int OldFlame = -1;
if (gameObject.pPhysics.Solid && gameObject.GetIntProperty("AllowMissiles", 0) == 0)
        int OldVapor = -1;
{
Forcefield part = gameObject.GetPart<Forcefield>();
        public override bool ChangeLevel(int NewLevel)
if (part == null || !part.CanMissilePassFrom(mutation.ParentObject, null))
        {
{
            Physics pPhysics = ParentObject.GetPart("Physics") as Physics;
num = 999;
break;
            TemperatureOnHit pTemp = FlamesObject.GetPart("TemperatureOnHit") as TemperatureOnHit;
}
            pTemp.Amount = (Level*2) + "d8";
}
}
            return base.ChangeLevel(NewLevel);
num++;
        }
}
}
        public override bool Mutate(GameObject GO, int Level)
return true;
        {
}
            Unmutate(GO);
 
public override bool FireEvent(Event E)
            ActivatedAbilities pAA = GO.GetPart("ActivatedAbilities") as ActivatedAbilities;
{
            Physics pPhysics = GO.GetPart("Physics") as Physics;
if (E.ID == "AIGetOffensiveMutationList")
{
            if (pPhysics != null)
if (E.GetIntParameter("Distance", 0) <= 9 && base.IsMyActivatedAbilityAIUsable(this.FlamingHandsActivatedAbilityID, null) && this.ParentObject.HasLOSTo(E.GetGameObjectParameter("Target"), true, true, null))
            {
{
                OldFlame = pPhysics.FlameTemperature;
E.AddAICommand("CommandFlamingHands", 1, null, false);
                OldVapor = pPhysics.VaporTemperature;
}
            }
}
           
else if (E.ID == "CommandFlamingHands")
            Body pBody = GO.GetPart("Body") as Body;
{
            if (pBody != null)
return FlamingHands.Cast(this, "5-6");
            {
}
                GO.FireEvent(Event.New("CommandForceUnequipObject", "BodyPartName", "Hands"));
return true;
                FlamesObject = GameObjectFactory.Factory.CreateObject("Ghostly Flames");
}
                Event eCommandEquipObject = Event.New("CommandEquipObject");
 
                eCommandEquipObject.AddParameter("Object", FlamesObject);
public override bool ChangeLevel(int NewLevel)
                eCommandEquipObject.AddParameter("BodyPartName", "Hands");
{
                GO.FireEvent(eCommandEquipObject);
if (GameObject.validate(ref this.FlamesObject))
            }
{
this.FlamesObject.GetPart<TemperatureOnHit>().Amount = base.Level * 2 + "d8";
            FlamingHandsActivatedAbilityID = pAA.AddAbility("Flaming Hands", "CommandFlamingHands", "Physical Mutation");
}
            FlamingHandsActivatedAbility = pAA.AbilityByGuid[FlamingHandsActivatedAbilityID];
return base.ChangeLevel(NewLevel);
            return true;
}
        }
 
private void AddAbility()
        public GameObject FlamesObject = null;
{
this.FlamingHandsActivatedAbilityID = base.AddMyActivatedAbility("Flaming Hands", "CommandFlamingHands", "Physical Mutation", -1, null, "\a", false, false, false, false, false, false, null);
        public override bool Unmutate(GameObject GO)
}
        {
 
            Physics pPhysics = GO.GetPart("Physics") as Physics;
public override bool Mutate(GameObject GO, int Level)
{
            if (pPhysics != null)
this.Unmutate(GO);
            {
if (this.CreateObject)
                if (OldFlame != -1) pPhysics.FlameTemperature = OldFlame;
{
                if (OldVapor != -1) pPhysics.BrittleTemperature = OldVapor;
Body part = GO.GetPart<Body>();
                OldFlame = -1;
if (part != null)
                OldVapor = -1;
{
BodyPart firstPart = part.GetFirstPart(this.BodyPartType);
                pPhysics.Temperature = 25;
if (firstPart != null)
            }
{
           
GO.FireEvent(Event.New("CommandForceUnequipObject", "BodyPart", firstPart));
            Body pBody = GO.GetPart("Body") as Body;
this.FlamesObject = GameObject.create("Ghostly Flames");
            if (pBody != null)
this.FlamesObject.GetPart<Armor>().WornOn = firstPart.Type;
            {
Event @event = Event.New("CommandForceEquipObject", 0, 0, 0);
                BodyPart pMainBody = pBody.GetPartByName("Hands");
@event.SetParameter("Object", this.FlamesObject);
                if( pMainBody != null )
@event.SetParameter("BodyPart", firstPart);
                if (pMainBody.Equipped != null)
@event.SetSilent(true);
                {
GO.FireEvent(@event);
                    if (pMainBody.Equipped.Blueprint == "Ghostly Flames")
this.AddAbility();
                    {
}
                        pMainBody.Equipped.FireEvent(Event.New("Unequipped", "UnequippingObject", ParentObject, "BodyPart", pMainBody));
}
                        pMainBody.Unequip();
}
                    }
else
                }
{
            }
this.AddAbility();
}
            if (FlamingHandsActivatedAbilityID != Guid.Empty)
this.ChangeLevel(Level);
            {
return base.Mutate(GO, Level);
                ActivatedAbilities pAA = GO.GetPart("ActivatedAbilities") as ActivatedAbilities;
}
                pAA.RemoveAbility(FlamingHandsActivatedAbilityID);
 
                FlamingHandsActivatedAbilityID = Guid.Empty;
public override bool Unmutate(GameObject GO)
            }
{
base.CleanUpMutationEquipment(GO, ref this.FlamesObject);
            return true;
base.RemoveMyActivatedAbility(ref this.FlamingHandsActivatedAbilityID, null);
        }
return base.Unmutate(GO);
    }
}
 
public string BodyPartType = "Hands";
 
public bool CreateObject = true;
 
public string Sound = "burn_crackling";
 
public GameObject FlamesObject;
 
public Guid FlamingHandsActivatedAbilityID = Guid.Empty;
}
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 360: Line 371:
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading;
using ConsoleLib.Console;
using XRL.Core;
using XRL.Rules;
using XRL.UI;
using XRL.UI;
using ConsoleLib.Console;
 
namespace XRL.World.Parts.Mutation
namespace XRL.World.Parts.Mutation
{
{
    [Serializable]
[Serializable]
    class FlamingHands : BaseMutation
public class FlamingHands : BaseMutation
    {
{
</syntaxhighlight>
</syntaxhighlight>


Line 373: Line 387:
GetDescription and GetLevelText are called to generate the descriptive for a given level of the mutation.
GetDescription and GetLevelText are called to generate the descriptive for a given level of the mutation.
<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
        public override string GetDescription()
public override string GetDescription()
        {
{
            return "You emit jets of flame from your hands.";
return "You emit jets of flame from your hands.";
        }
}
 
 
        public override string GetLevelText(int Level)
public override string GetLevelText(int Level)
        {
{
            string Ret = "Emits a 9-square ray of flame in the direction of your choice\n";
return "Emits a 9-square ray of flame in the direction of your choice\n" + "Cooldown: 10 rounds\n" + "Damage: " + this.ComputeDamage(Level) + "\n" + "Cannot wear gloves";
            Ret += "Cooldown: 10 rounds\n";
}
            Ret += "Damage: " + Level + "d6\n";
            Ret += "Cannot wear gloves";
            return Ret;
        }
</syntaxhighlight>
</syntaxhighlight>
   
   
Line 393: Line 403:
public override bool ChangeLevel(int NewLevel)
public override bool ChangeLevel(int NewLevel)
{
{
    Physics pPhysics = ParentObject.GetPart("Physics") as Physics;
if (GameObject.validate(ref this.FlamesObject))
{
    TemperatureOnHit pTemp = FlamesObject.GetPart("TemperatureOnHit") as TemperatureOnHit;
this.FlamesObject.GetPart<TemperatureOnHit>().Amount = base.Level * 2 + "d8";
    pTemp.Amount = (Level*2) + "d8";
}
return base.ChangeLevel(NewLevel);
    return base.ChangeLevel(NewLevel);
}
}
</syntaxhighlight>
</syntaxhighlight>

Navigation menu