Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
First, include a mutations.xml in your mod that defines a new mutation.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<?xml version="1.0" encoding="utf-8" ?> <mutations> <category Name="Physical"> <mutation Name="Udder" Cost="1" MaxSelected="1" Class="FreeholdTutorial_Udder" Exclusions="" Code="ea"></mutation> </category> </mutations> |
Then add a new .cs file in your mod that implements the class. Here's a skeletal implementation of the entry above. It must be in the XRL.World.Parts.Mutation namespace and must ultimately descend from BaseMutation. (Though not necessarily directly, if you have a very complex mod)
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using System; using System.Collections.Generic; using System.Text; using XRL.Rules; using XRL.Messages; using ConsoleLib.Console; namespace XRL.World.Parts.Mutation { [Serializable] class FreeholdTutorial_Udder : BaseMutation { public FreeholdTutorial_Udder() { Name = "FreeholdTutorial_Udder"; DisplayName = "Udder"; } public override void Register(GameObject Object) { } public override string GetDescription() { return ""; } public override string GetLevelText(int Level) { string Ret = "You have udders.\n"; return Ret; } public override bool BeforeRender(Event E) { if (ParentObject.IsPlayer()) { if (ParentObject.pPhysics != null && ParentObject.pPhysics.CurrentCell != null) { ParentObject.pPhysics.CurrentCell.ParentZone.AddLight(ParentObject.pPhysics.CurrentCell.X, ParentObject.pPhysics.CurrentCell.Y, Level, LightLevel.Darkvision); } } return true; } public override bool FireEvent(Event E) { return base.FireEvent(E); } public override bool ChangeLevel(int NewLevel) { return true; } public override bool Mutate(GameObject GO, int Level) { return true; } public override bool Unmutate(GameObject GO) { return true; } } } |
Here's a full example of the Flaming Hands mutation from the game's source code.
Code Block | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
using System; using System.Collections.Generic; using XRL.UI; using ConsoleLib.Console; namespace XRL.World.Parts.Mutation { [Serializable] class FlamingHands : BaseMutation { public FlamingHands() { Name = "FlamingHands"; DisplayName = "Flaming Hands"; } public Guid FlamingHandsActivatedAbilityID = Guid.Empty; public ActivatedAbilityEntry FlamingHandsActivatedAbility = null; public override void Register(GameObject Object) { Object.RegisterPartEvent(this, "BeginEquip"); Object.RegisterPartEvent(this, "CommandFlamingHands"); Object.RegisterPartEvent(this, "AIGetOffensiveMutationList"); } public override string GetDescription() { return "You emit jets of flame from your hands."; } public override string GetLevelText(int Level) { string Ret = "Emits a 9-square ray of flame in the direction of your choice\n"; Ret += "Cooldown: 10 rounds\n"; Ret += "Damage: " + Level + "d6\n"; Ret += "Cannot wear gloves"; return Ret; } public void Flame(Cell C, ScreenBuffer Buffer) { string Damage = Level + "d6"; Body pBody = ParentObject.GetPart("Body") as Body; int nHandCount = pBody.GetPart("Hands").Count-1; if (nHandCount > 0) Damage += "+" + nHandCount.ToString(); if (C != null) { List<GameObject> Objects = C.GetObjectsInCell(); foreach (GameObject GO in Objects) { if( GO.PhasedMatches( ParentObject ) ) { 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); for (int x = 0; x < 5; x++) GO.ParticleText("&R" + (char)(219 + Rules.Stat.Random(0, 4)), 2.9f, 1); for (int x = 0; x < 5; x++) GO.ParticleText("&W" + (char)(219 + Rules.Stat.Random(0, 4)), 2.9f, 1); } } foreach (GameObject GO in C.GetObjectsWithPart("Combat")) { if( GO.PhasedMatches( ParentObject ) ) { Damage Dmg = new Damage(Rules.Stat.Roll(Damage)); Dmg.AddAttribute("Fire"); Dmg.AddAttribute("Heat"); Event eTakeDamage = Event.New("TakeDamage"); eTakeDamage.AddParameter("Damage", Dmg); eTakeDamage.AddParameter("Owner", ParentObject); eTakeDamage.AddParameter("Attacker", ParentObject); eTakeDamage.AddParameter("Message", "from %o flames!"); GO.FireEvent(eTakeDamage); } } } Buffer.Goto(C.X, C.Y); string sColor = "&C"; int r = Rules.Stat.Random(1, 3); if (r == 1) sColor = "&R"; if (r == 2) sColor = "&r"; if (r == 3) sColor = "&W"; r = Rules.Stat.Random(1, 3); if (r == 1) sColor += "^R"; if (r == 2) sColor += "^r"; if (r == 3) sColor += "^W"; if( C.ParentZone == XRL.Core.XRLCore.Core.Game.ZoneManager.ActiveZone ) { 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); } } public override bool FireEvent(Event E) { if (E.ID == "AIGetOffensiveMutationList") { int Distance = (int)E.GetParameter("Distance"); GameObject Target = E.GetParameter("Target") as GameObject; List<XRL.World.AI.GoalHandlers.AICommandList> CommandList = (List<XRL.World.AI.GoalHandlers.AICommandList>)E.GetParameter("List"); if (FlamingHandsActivatedAbility != null && FlamingHandsActivatedAbility.Cooldown <= 0 && Distance <= 9 && ParentObject.HasLOSTo(Target) ) CommandList.Add(new XRL.World.AI.GoalHandlers.AICommandList("CommandFlamingHands", 1)); return true; } if (E.ID == "CommandFlamingHands") { ScreenBuffer Buffer = new ScreenBuffer(80, 25); Core.XRLCore.Core.RenderMapToBuffer(Buffer); List<Cell> TargetCell = PickLine(9, AllowVis.Any); if (TargetCell == null) return true; if (TargetCell.Count <= 0) return true; if (TargetCell != null) { if (TargetCell.Count == 1) { if (ParentObject.IsPlayer()) if (UI.Popup.ShowYesNoCancel("Are you sure you want to target yourself?") != DialogResult.Yes) { return true; } } 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++) { if (TargetCell.Count == 1 || TargetCell[x] != ParentObject.pPhysics.CurrentCell) Flame(TargetCell[x],Buffer); foreach( GameObject GO in TargetCell[x].GetObjectsWithPart("Physics") ) { if (GO.pPhysics.Solid) { x = 999; break; } } } } } if (E.ID == "BeginEquip") { GameObject Equipment = E.GetParameter("Object") as GameObject; string BodyPartName = E.GetParameter("BodyPartName") as string; if (BodyPartName == "Hands") { if (IsPlayer()) { UI.Popup.Show("Your flaming hands prevents you from equipping " + Equipment.DisplayName + "!"); } E.bCancelled = true; return false; } } return true; } int OldFlame = -1; int OldVapor = -1; public override bool ChangeLevel(int NewLevel) { Physics pPhysics = ParentObject.GetPart("Physics") as Physics; TemperatureOnHit pTemp = FlamesObject.GetPart("TemperatureOnHit") as TemperatureOnHit; pTemp.Amount = (Level*2) + "d8"; return base.ChangeLevel(NewLevel); } public override bool Mutate(GameObject GO, int Level) { Unmutate(GO); ActivatedAbilities pAA = GO.GetPart("ActivatedAbilities") as ActivatedAbilities; Physics pPhysics = GO.GetPart("Physics") as Physics; if (pPhysics != null) { OldFlame = pPhysics.FlameTemperature; OldVapor = pPhysics.VaporTemperature; } Body pBody = GO.GetPart("Body") as Body; if (pBody != null) { GO.FireEvent(Event.New("CommandForceUnequipObject", "BodyPartName", "Hands")); FlamesObject = GameObjectFactory.Factory.CreateObject("Ghostly Flames"); Event eCommandEquipObject = Event.New("CommandEquipObject"); eCommandEquipObject.AddParameter("Object", FlamesObject); eCommandEquipObject.AddParameter("BodyPartName", "Hands"); GO.FireEvent(eCommandEquipObject); } FlamingHandsActivatedAbilityID = pAA.AddAbility("Flaming Hands", "CommandFlamingHands", "Physical Mutation"); FlamingHandsActivatedAbility = pAA.AbilityByGuid[FlamingHandsActivatedAbilityID]; return true; } public GameObject FlamesObject = null; public override bool Unmutate(GameObject GO) { Physics pPhysics = GO.GetPart("Physics") as Physics; if (pPhysics != null) { if (OldFlame != -1) pPhysics.FlameTemperature = OldFlame; if (OldVapor != -1) pPhysics.BrittleTemperature = OldVapor; OldFlame = -1; OldVapor = -1; pPhysics.Temperature = 25; } Body pBody = GO.GetPart("Body") as Body; if (pBody != null) { BodyPart pMainBody = pBody.GetPartByName("Hands"); if( pMainBody != null ) if (pMainBody.Equipped != null) { if (pMainBody.Equipped.Blueprint == "Ghostly Flames") { pMainBody.Equipped.FireEvent(Event.New("Unequipped", "UnequippingObject", ParentObject, "BodyPart", pMainBody)); pMainBody.Unequip(); } } } if (FlamingHandsActivatedAbilityID != Guid.Empty) { ActivatedAbilities pAA = GO.GetPart("ActivatedAbilities") as ActivatedAbilities; pAA.RemoveAbility(FlamingHandsActivatedAbilityID); FlamingHandsActivatedAbilityID = Guid.Empty; } return true; } } } |
Your namespace should be XRL.World.Parts.Mutations, the class should be marked serializeable and derived from BaseMutation.
Code Block |
---|
using System; using System.Collections.Generic; using XRL.UI; using ConsoleLib.Console; namespace XRL.World.Parts.Mutation { [Serializable] class FlamingHands : BaseMutation { |
GetDescription and GetLevelText are called to generate the descriptive for a given level of the mutation.
Code Block |
---|
public override string GetDescription() { return "You emit jets of flame from your hands."; } public override string GetLevelText(int Level) { string Ret = "Emits a 9-square ray of flame in the direction of your choice\n"; Ret += "Cooldown: 10 rounds\n"; Ret += "Damage: " + Level + "d6\n"; Ret += "Cannot wear gloves"; return Ret; } |
Change level is called any time the mutation changes level.
Code Block |
---|
public override bool ChangeLevel(int NewLevel) { Physics pPhysics = ParentObject.GetPart("Physics") as Physics; TemperatureOnHit pTemp = FlamesObject.GetPart("TemperatureOnHit") as TemperatureOnHit; pTemp.Amount = (Level*2) + "d8"; return base.ChangeLevel(NewLevel); } |
Mutate and Unmutate are called on an object when it gains or loses the mutation.
Code Block |
---|
public override bool Mutate(GameObject GO, int Level) public override bool Unmutate(GameObject GO) |
BaseMutation derives from Part, so the typical event registration and handling functions are available
Code Block |
---|
public override void Register(GameObject Object) public override bool FireEvent(Event E) |
Info | ||
---|---|---|
You can remove mutations by including a tag with just the Name of the mutation you want with a - in front. For example:
|
Info |
---|
Some steam threads where I discuss mutation modding. http://steamcommunity.com/app/333640/discussions/3/366298942101209876/?tscn=1468516504 http://steamcommunity.com/app/333640/discussions/3/366298942101209876/?tscn=1468516504 |