How to store and parse story actions in XML

How to store and parse story actions in XML

I been working on a game in Unity that reads its story (Actions, scene descriptions, NPC's, ect...) from an XML and have been wondering there was a better way to store actions based on player data such as item in an inventory or attribute.
An example would be the player having a light source greater then 5 on hand while entering a dark room.

 You enter a dark room 
 
  and do not have enough light to see it well.
  
 


How would I be able to act on the above logic in C# without hard coding the actions and load dynamically from the XML? Also how should I handle logic in XML if it requires multiple actions or parameters?
For example having a crowbar and the strength greater then 15 to open a door.

 You see a stuck door in front of you.
 
  Your effort to remove the door has failed.
  
   
   
  
 


Because I am rather new to parsing XML I can't think of a way to break the logic out of the XML and use it in code dynamically. I looked over https://stackoverflow.com/questions/372915/game-logic-in-xml-files and really did not seem to answer my question on how to solve it in C#.
Edit:
Spent more time on this and with Blue's answer I was able to come up with a viable solution.
Sample XML
 
  You enter a dark room 
  
   and do you do not have a light source.
  
  
  

Solutions/Answers:

Answer 1:

I would look heavily into state machines and deserializing the XML data into state instances.

You can create class definition for a condition, be that an integer on an item for it’s int brightness = 4; value or a string name = "torch"; in the inventory.

Something along these lines:

public enum ConditionType{
    default,
    itemLevelReq,
    itemEquip,
    playerLevel,
    playerAttribute
}

abstract class Condition{

    abstract ConditionType type;
    string failMessage = "Condition not met";

    public abstract bool IsThisConditionMet();

}

//example concrete condition
class ItemLevelCondition : Condition{

    Condition type = itemLevelReq;
    string itemType;
    int levelReq;

    public ItemLevelCondition(String item, int level, string fail){
        this.itemType = item;
        this.levelReq = level;
        this.failMessage = fail;
    }

    public bool IsThisConditionMet(){
        if(player.items.contains(this.itemType)){
            return player.items[itemType].level >= this.levelReq;
        } else {
            return false;
        }
    }

}

class Scene{
     string description;
     Condition[] requirements;

     public Scene(string description,Condition[] requirements)
     {
         this.description = description;
         this.requirements = requirements;
     }

     public bool AreAllConditionsMet(){
         bool result = true;
         string responseMessage;
         foreach(Condition condition in requirements){
             if(!condition.IsThisConditionMet()){
                 responseMessage += condition.failMessage + "\n";
             }
             result &= condition.IsThisConditionMet();
         }

         Scene.OutputFailMessage();
         return result;
     }

     public void OutputFailMessage(){
         Console.Write(this.responseMessage);
     }
}

Please excuse the roughness but I hope this gives you a decent idea for structure.
Formatting your XML a little better you can then create a parser to create the scenes and the requirements in them, here is an example of both the scenes above in one:

<scene index="5">
 <description>You enter a dark room and feel a door stuck in front of you</description>
 <condition type="itemLevelReq" itemType="light" levelReq="5">
  <failMessage>and do not have enough light to see it well.</text>
 </condition>
 <condition type="playerAttribute" attrType="strength" levelReq="15">
  <failMessage>You are not strong enough.</text>
 </condition>
 <condition type="itemEquip" itemType="crowbar" equipped="true">
  <failMessage>You do not have a crowbar equipped.</text>
 </condition>
</scene>

Here is a snippet of how to do the XML parsing itself:

using System.Collections.Generic;
using System.Xml;
    public static List<Scene> InitialiseScenes()
    {
        List<Scene> scenes = new List<Scene>();

        Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Scenes.xml");

        //This if block verifies the file was loaded into the stream and throws a FileNotFound if it isn't
        if (stream != null)
        {
            StreamReader reader = new StreamReader(stream);

            XmlDocument sceneDoc = new XmlDocument();
            sceneDoc.LoadXml(reader.ReadToEnd());

            string xpathQuery = "/scenes/scene";
            foreach (XmlNode sceneNode in sceneDoc.SelectNodes(xpathQuery))
            {
                //Set up new Champion details
                Scene currentScene;
                List<Condition> conditions = InitialiseConditions(sceneNode.SelectNodes("conditions"));

                currentScene = new Scene(sceneNode.SelectNode("description").InnerText, conditions)

                scenes.Add(currentScene);
            }
        }
        else
        {
            throw new FileNotFoundException("The resource file for the champions data is missing.", "Champions.xml");
        }
        return champions;
    }

    public List<Condition> InitialiseConditions(XmlNodeList nodeList) { 

        //Get conditions from nodes
        List<Condition> result;
        foreach (XmlNode conditionNode in nodeList){
            Condition tmpCondition;

            //TODO: Create list of nodes and use switch statement to load the
            // node into a concrete implementation of the abstract Condition class
            //eg. tmpCondition = new ItemLevelCondition(item, level, fail);

            result.Add(tmpCondition);
        }
    }

I hope this gets you on the right track.

References