Saturday, 27 September 2014

C# Source Code Post #3

As promised, here's the third exciting installment of C# Source Code!

Decided to try out some new formatting to make reading the code easier, let me know what you think.

So today we will be looking at Player.cs, this class was referenced in InitLoad.cs somewhere I believe, but it's basically the class that defines the Character the player controls.

Well hey, ain't that much easier to read? :D

Alrighty, let's get stuck in!

The start of this is pretty typical stuff, default using statements, a using statement for Game.Items (that's for the next source post :3)
Then we get this:


What the hell is this thing!?
Well Jeff, I'm glad you asked, but please vacate the cavities of my empty brain.
This is called a "Label", it's something I never covered in my C# tutorials,  but basically it allows various properties to be assigned to a method, class, or other stuff.
In this case, we're assigning the "Serializable()" property to the entire class.

This basically makes it work in such a way that the XML Serializer mentioned in InitLoad.cs can take an instance of the Player class and Serialize it correctly.

Next up more basic stuff, fields, properties, stat mods.
Wait, these stat mods have some mathemagiks to them, what is this sorcery!?

The basic formula used for the Stat mods comes directly from good ol' DnD (That's Dungeons and Dragons).
Your Stat Mod affects various aspects of the game, for example a higher Strength Stat Mod makes you deal more damage.

The formula is as follows:

(Stat - 10) / 2

So if your stat was 16, your modifier would be 3.
Note that due to rounding in integers a stat level of 15 would also result in a modifier of 3, this is intended.

Here's a quick chart:

So as you can see, every 2 points past 10 increases the modifier by 1.

Next up more boring fields, and then a List.

public List<int> Inv;

I don't think I've mentioned this much before, but every item has a unique ID. This list simply lists all the IDs that are in the player's inventory.

Several equipment fields that store the ID of the item in that equipment slot.

Then one crazy-ass property:

Well 2 crazy-ass properties, Dmg and AtkSpd.

The first is how much damage you deal per hit, the second is how many attacks you do per second.

But what's with all the math!?
Damage is calculated a pretty awkward way, firstly, it makes a variable called val and sets it to 0.
Then it makes an Item variable called it, doesn't initialize it.
It then checks ItemIDList, which is a Dictionary List from InitLoad.cs, for the ID stored in the right hand using

InitLoad.ItemIDList.TryGetValue(RHand, out it);

This basically tries to get the item associated with that ID, but it doesn't return an Item instance, it returns true or false, true if it successfully fetches the item, false if it doesn't.
"out it" means it has a secondary output, which it outputs to the arg you specify, in this case it, the Item variable we made.

Next it has to ensure that you're not holding a null item.

if (it != null && it.Name != "NullItem")

There are 2 ways the item can be null:
1) The instance is simply null
2) It is an instance of the item, but it has no stats and it's name is "NullItem"
We check for both, if it is neither, we continue to make sure it's a weapon.

This is a pain in the ass, because ItemIDList stores plain Items, not specific types of items.
ItemEquipmentWeapon extends ItemEquipment, which extends Item, we need to make sure that the item we have is definitely a weapon.

if (it.GetType() == typeof(ItemEquipmentWeapon))

it.GetType() is a default method associated with any object, it returns a Type value.
However ItemEquipmentWeapon isn't a Type it self, it's a class. we need to also get the Type of the class (which returns a Type version of ItemEquipmentWeapon, just as it.GetType() will if "it" is a weapon)
Then it's a matter of making sure their types are the same.
If so we continue.

ItemEquipmentWeapon itw = it as ItemEquipmentWeapon;

Wait whut?
The variable "it" is an item, we know that. We also know that it is a weapon, but it is not stored in that variable as a weapon, therefore we cannot call any Weapon specific functions from "it".
To get around this, we use a cast ("as ItemEquipmentWeapon"). If "it" wasn't a weapon, this cast would crash the program, hence the if statement checking that "it" is a weapon.

"itw" is identical in value to "it", however itw stores it as a weapon, not just an item.
We need this because we need to access the StatMod property and the Dmg property, which are specific to weapons.
it.StatMod will error, because it is an item, not necessarily a weapon.
itw.StatMod will not error.

val =0;

I set the variable to 0 again, even though it's value hasn't changed yet.

val += itw.Dmg;

Simple enough, get the value of the Dmg property from the weapon, add it to 0 and store it in val.

Now we check the StatMod of the weapon.

the StatMod property defines what player stat the weapon focuses on. The majority of weapons focus on Strength or Dexterity.

Whichever stat is focuses on, the player's Stat modifier for that stat (see above) is added to the damage.

This means a very weak character with a Strength of 8 would have difficulty using a Club because it is a Strength based weapon, and a Strength of 8 gives you a -1 Stat Modifier, and thus a -1 to your damage with all strength based weapons.

However if a character had a Strength of 16, they would receive a +3 to the damage of the Club.

That's basically all the switch statement does.

Then we have an else.
This else refers to the item being null.

Basically, if you have nothing equipped in your main hand, your damage is your Strength Modifier + Dexterity Modifier / 2.

The Average of your Str and Dex modifiers.

So if you're a minotaur, and have a Strength of 18, but a Dexterity of 10, your unarmed damage will be 2 (4 + 0 = 4, 4 / 2 = 2)
However if you were an elf, and had a Strength of only 8, but a Dexterity of 18, your unarmed damage would still be 2 (-1 + 4 = 3, 3 / 2 = 1.5, rounded to 2).

It's at this point at the code I intended to have the following:

if(val < 1) val = 1;

All this does is make sure val can be no less than 1, so you will always do at least 1 damage with your fists.

However I forgot to include this, because as we have already established, I'm stupid.

Next up, attack speed.

This is a bit shorter, and uses concepts we're familiar with.

Firstly however, I'd like to explain how attack speed is calculated and used.

Default attack speed is 100. 100 equates to 1 attack per second.
Higher value = higher speed, so 120 is 1.2 attacks per second.

It's really quite simple, AtkSpd / 100 = Attacks per second

Now, back to the code.

We have the bits we're familiar with by now, that get the equipped item, make sure it's not null, make sure it's a weapon etc etc.

Then we have val += itw.AtkSpeed;

This just sets val to the attack speed of the weapon.

else val = 100;

If no weapon is equipped, attack speed is 100 (1 per sec)

Now, there's still a lot more to go over, but unfortunately that will have to wait until next time.

I will be posting these at LEAST once a week, every saturday, but may also post them at other times, so check back daily!

No comments:

Post a Comment