A simple role-playing game, written with C# and WPF.
Lesson details: https://soscsrpg.com/
Please submit feature requests and bugs to: https://github.com/SOSCSRPG/SOSCSRPG/issues
Scott's Open Source C# RPG
Home Page: https://soscsrpg.com
License: MIT License
A simple role-playing game, written with C# and WPF.
Lesson details: https://soscsrpg.com/
Please submit feature requests and bugs to: https://github.com/SOSCSRPG/SOSCSRPG/issues
Check that functions and other properties don't directly access another property's backing variable (unless there is a specific reason for doing that).
This happens when the player is killed and sent back to the Home location where normally the CurrentMonster in GameSession would be set to null. I believe we have a race condition where sometimes the currentBattle object somehow becomes null before the currentMonster object does and so when we go through the CurrentMonster setter, we hit a NullReferenceException.
Steps to reproduce the behavior:
(very intermittent)
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=GameEngine
StackTrace:
at GameEngine.ViewModels.GameSession.set_CurrentMonster(Monster value) in \Engine\ViewModels\GameSession.cs:line 55
Messages not showing up for consuming items after a battle (need to re-connect message handler?)
Rapid clicking in trading screen causes items row order to switch
When cloning GameItems, we need to also clone their Action objects, to prevent problems with event subscriptions.
Change it to something like the below (adding in whatever is needed to handle different types of GameItems and Actions):
Weapon clonedWeapon = new Weapon(ItemID, Name, Price, MinimumDamage, MaximumDamage, DamageType, WeaponSpeed, MissRate);
clonedWeapon.Action = new AttackWithWeapon(clonedWeapon);
When loading a new game, the MessageBroker does not remove subscriptions from the previous GameSession object.
Fix this, so we don't have this type of error coming up again.
The Z key will throw an exception if pressed in the absence of a monster, so I have slightly amended the code at line 250 – 253 of GameSession.cs to:
public void AttackCurrentMonster()
{
if (CurrentMonster == null || CurrentLocation.GetMonster() == null)
{
RaiseMessage(“No monsters to attack here!”);
return;
}
RNGCryptoServiceProvider is being deprecated. Replace with new technique:
public static int GetNumberBetween(int minimumValue, int maximumValue)
{
// Need to add one to maximumValue, because otherwise,
// this function will never generate a value that matches the maximumValue.
// For example: to get a value from 1 to 10 (inclusive),
// The code must (effectively) call: RandomNumberGenerator.GetInt32(1, 11);
return RandomNumberGenerator.GetInt32(minimumValue, maximumValue + 1);
}
Describe the bug
Typo:
Change the hard-coded “18” value we were passing into the base constructor for the dexterity to “new LiChange the hard-coded “18” value we were passing into the base constructor for the dexterity to “new List()”.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Should be:
Change the hard-coded “18” value we were passing into the base constructor for the dexterity to “new List()”.
Make sure combat functions do not run from keypress, if there is not a current monster/battle.
For things like the ItemQuantity class, consider using a struct.
Made from a project note. it a very dirty solution, but it is a WIP
`
namespace MonsterCreator
{
using System.Collections.Generic;
using System.IO;
using System.Xml;
public static class BuilderExtensions
{
public static MonsterBuilder CreateMonster(this MonsterBuilder builder, string monsterName, int MaximumHitPoints, string WeaponId, int RewardXP, int Gold,
string ImageName, int Dexterity, IEnumerable<(string ID, int Percentage)> lootBag)
{
builder.Monster = builder.XmlFile.CreateElement("Monster");
builder.Monster.SetAttribute("ID", (builder.Monsters.ChildNodes.Count + 1).ToString());
builder.Monster.SetAttribute("Name", monsterName);
builder.Monster.SetAttribute(nameof(MaximumHitPoints), MaximumHitPoints.ToString());
builder.Monster.SetAttribute(nameof(WeaponId), WeaponId);
builder.Monster.SetAttribute(nameof(RewardXP), RewardXP.ToString());
builder.Monster.SetAttribute(nameof(Gold), Gold.ToString());
builder.Monster.SetAttribute(nameof(ImageName), ImageName);
var dex = builder.XmlFile.CreateElement(nameof(Dexterity));
dex.InnerText = Dexterity.ToString();
builder.Monster.AppendChild(dex);
var lootItems = builder.XmlFile.CreateElement("LootItems");
foreach ((string ID, int Percentage) in lootBag)
{
var item = builder.XmlFile.CreateElement("LootItem");
item.SetAttribute(nameof(ID), ID);
item.SetAttribute(nameof(Percentage), Percentage.ToString());
lootItems.AppendChild(item);
}
builder.Monster.AppendChild(lootItems);
builder.Monsters.AppendChild(builder.Monster);
builder.Monster = null;
builder.XmlFile.Save(".\\GameData\\Monsters.xml");
return builder;
}
}
public class MonsterBuilder
{
private const string MONSTER_DATA_FILENAME = ".\\GameData\\Monsters.xml";
private const string BaseNode = "/Monsters";
internal readonly XmlDocument XmlFile = new XmlDocument();
internal XmlElement Monsters { get; }
internal XmlElement Monster { get; set; }
public MonsterBuilder()
{
if (File.Exists(MONSTER_DATA_FILENAME))
{
XmlFile.Load(MONSTER_DATA_FILENAME);
if (!string.IsNullOrEmpty(BaseNode))
{
if (XmlFile.SelectSingleNode(BaseNode).NodeType == XmlNodeType.Element)
{
Monsters = (XmlElement)XmlFile.SelectSingleNode(BaseNode);
}
}
}
}
}
}
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Engine.Models;
namespace MonsterCreator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//Range of Hit Points
public ObservableCollection<int> HitPoints = new ObservableCollection<int>(Enumerable.Range(1, 25));
// Complete collection of Monsters so far.
public ObservableCollection<Monster> Monsters = new ObservableCollection<Monster>();
public ObservableCollection<(string ItemName, int ID, int Percentage)> Loots = new ObservableCollection<(string, int, int)>
{
("Rusty Sword", 1002, 25),
("Snake fang", 1501, 35),
("Rat Claw", 1502, 35),
("Spider fang", 1503, 35),
("Granola bar", 2001, 50),
("Oats", 3001, 50),
("Honey", 3002, 50),
("Raisins", 3003, 50)
};
public MainWindow()
{
InitializeComponent();
MonsterHP.ItemsSource = HitPoints;
MonsterXP.ItemsSource = HitPoints;
MonsterXP.SelectedIndex = 0;
MonsterHP.SelectedIndex = 0;
Weapons.ItemsSource = Loots.Where(x => x.ID > 1500 && x.ID < 1505).Select(x => x.ItemName);
Weapons.SelectedIndex = 0;
Gold1.ItemsSource = HitPoints;
Gold1.SelectedIndex = 0;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MonsterBuilder builder = new MonsterBuilder();
textBox1.Text = (builder.Monsters.ChildNodes.Count + 1).ToString();
builder.CreateMonster(
MonsterName.Content.ToString(),
MonsterHP.SelectedIndex + 1,
Loots.FirstOrDefault(x => x.ItemName == Weapons.Text).ID.ToString(),
MonsterXP.SelectedIndex + 1,
int.Parse(Gold1.Text),
"",
10,
Loots.Select(x => (x.ID.ToString(), x.Percentage))
);
}
}
}
`
XAML
`
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MonsterCreator"
xmlns:System="clr-namespace:System;assembly=System.Runtime" x:Class="MonsterCreator.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="0,0,-3,0" HorizontalAlignment="Right" Width="800">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="16*"/>
<RowDefinition Height="0*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Label x:Name="Monster_Creator" Content="SOSCSRPG Monster Creator 0.1a" HorizontalAlignment="Left" Height="24" Margin="308,10,0,0" VerticalAlignment="Top" Width="184" Grid.ColumnSpan="2"/>
<Grid HorizontalAlignment="Center" Height="384" Margin="0,34,0,0" VerticalAlignment="Top" Width="380" Grid.RowSpan="4">
<TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="7,29,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="106" Height="25"/>
<ComboBox x:Name="MonsterHP" HorizontalAlignment="Left" Height="25" Margin="7,87,0,0" VerticalAlignment="Top" Width="106" />
<Label x:Name="MonsterName" Content="Name" HorizontalAlignment="Left" Height="24" VerticalAlignment="Top" Width="86" Margin="8,0,0,0"/>
<Label x:Name="MonsterHitPoints" Content="Hit Points" HorizontalAlignment="Left" Height="24" Margin="8,60,0,0" VerticalAlignment="Top" Width="86"/>
<Label x:Name="MonsterId" Content="ID" HorizontalAlignment="Left" Height="23" Margin="127,1,0,0" VerticalAlignment="Top" Width="85"/>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="25" Margin="127,29,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="105" IsEnabled="False"/>
<Label x:Name="Expierence" Content="Expierence" HorizontalAlignment="Left" Height="25" Margin="127,59,0,0" VerticalAlignment="Top" Width="85"/>
<ComboBox x:Name="MonsterXP" HorizontalAlignment="Left" Height="25" Margin="127,86,0,0" VerticalAlignment="Top" Width="106" />
<Label x:Name="Weapon" Content="Weapon" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="84"/>
<ComboBox x:Name="Weapons" HorizontalAlignment="Left" Margin="7,141,0,0" VerticalAlignment="Top" Width="106"/>
<Label x:Name="Gold" Content="Gold" HorizontalAlignment="Left" Margin="127,114,0,0" VerticalAlignment="Top" Width="75"/>
<ComboBox x:Name="Gold1" HorizontalAlignment="Left" Margin="127,141,0,0" VerticalAlignment="Top" Width="105"/>
<Button x:Name="button" Content="Create Monster" HorizontalAlignment="Left" Height="30" Margin="7,240,0,0" VerticalAlignment="Top" Width="106" Click="Button_Click"/>
</Grid>
</Grid>
</Window>
`
Example appended to file
<Monster ID="4" Name="Name" MaximumHitPoints="8" WeaponId="1502" RewardXP="8" Gold="4" ImageName=""> <Dexterity>10</Dexterity> <LootItems> <LootItem ID="1002" Percentage="25" /> <LootItem ID="1501" Percentage="35" /> <LootItem ID="1502" Percentage="35" /> <LootItem ID="1503" Percentage="35" /> <LootItem ID="2001" Percentage="50" /> <LootItem ID="3001" Percentage="50" /> <LootItem ID="3002" Percentage="50" /> <LootItem ID="3003" Percentage="50" /> </LootItems> </Monster>
This is very rough draft, so improvements and eventual push will come
If you sell the pointy stick at another vendor before going back to turn in the quest you don’t get the error.
Currently the ComboBox in MainWindow for the consumable items only show single items.
That makes for a huge list when there are lots of consumable items in the inventory.
Having multiple of the same consumable items only show once with a quantity concatenation would shorten the list of ComboBox items.
New feature
Add a function to let programmers call a function to roll an N-sided die, X number of times.
See: this comment
Add to (?)
Most OSS projects have a CONTRIBUTING.md file to describe the process and guidelines for making contributions to the project.
Describe the solution you'd like
We should have a CONTRIBUTING.md for this project.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.