Need help with stat, class, and combat system.

I am making a small game with a maze to test out a part of a larger project I'm making.

PC and NPCs have 2 Attributes and 2 points to distribute among them:
Physical and Mental
Health is 5+Physical
AC is 4+Mental
Attack modifier is mental
Damage modifier is 1+Physical

Out of this, three possible characters can be made as shown below

  1. Strong Man
    Physical: 2
    Mental: 0
    HP: 7
    AC: 4
    Attack: 1d6
    Damage: 1d6+3(3 being the 1 and the 2 is from physical)

  2. Smart Man
    Physical: 0
    Mental: 2
    HP: 5
    AC: 6
    Attack: 1d6+2
    Damage: 1d6+1

  3. Average Man
    Physical: 1
    Mental: 1
    HP: 6
    AC: 5
    Attack: 1d6+1
    Damage: 1d6+2

Any skill checks for puzzles, traps, or etc will be decided on a Difficulty Check of one of three options:

  1. Easy = 4
  2. Medium = 5
  3. Hard = 6

Example:
Strong man wants to push a heavy box out of his way.
Physical Check: 1d6+2
If Strong man matches the difficulty check or beats it, then he is successful.

Differences between classes

  1. Strong Man can't read words with more than one syllable and may annoy or frighten npcs when talking to them.
  2. Smart Man can't lift very heavy objects, wear heavy armor, or wield heavy weapons. He can read anything in the language he knows and may notice details in the environment that strong man wouldn't, such as alternate routes around a place or hidden passages in a dungeon. Smart Man can also do magic.
  3. Average man won't be great in either side, but can maneuver around the world without the major disadvantages of the other two classes.

I've thought about adding a Social and Dexterity trait so there would be Physical, Mental, Dexterity, and Social, but I think it would over complicate the system I've designed and may should just add a social trait if I add anything else.

Let me know what you think of this system and how I can implement it into my game.

Thanks


Seems simple enough. Although the numbers of HP seem a little low compared to the damage.

As far as implementation goes, are you using Quest? It looks like this should be fairly easy to transform into code.


I don’t know how to code, but I want to put this into quest. The system was originally designed for playing an rpg on a road trip, all you would need is a d6 dice and a phone that can’t write down character stats.


I think the starting point here would probably be to start with your character creation.

You normally want to choose a character before starting the game, so you'd create a blank room to put the player in, and untick the "Show room description when entering a room" checkbox on the game. Then for your game's "start" script, you would have something like this:

options = Split("strong;smart;average")
ShowMenu ("What kind of man would you like to be?", options, false) {
  switch (result) {
    case ("strong") {
      player.physical = 2
      player.mental = 0
    }
    case ("smart") {
      player.physical = 0
      player.mental = 2
    }
    case ("average") {
      player.physical = 1
      player.mental = 1
    }
    default {
      msg ("You selected something that wasn't one of the options, so there must be a typo in my code.")
    }
  }
  player.maxhealth = 5 + player.physical
  player.currenthealth = player.maxhealth
  player.AC = 4 + player.mental
  player.attack = player.mental
  player.damage = 1 + player.physical
  // We enable room descriptions here, so the game doesn't say "You are in a character creation"
  // but it does say "You are in a dungeon" or whatever when we move them to the actual start of the game
  game.showdescriptiononenter = true
  MoveObject (player, first room)
}

That would deal with allowing the player to create their character in the first place.
The last two lines move the player to the starting room, so they can actually start playing; change first room to whatever the name of your first room is.

Can you understand the code well enough there, or does it need extra explanation? I think each line should be fairly self-explanatory; but not sure what level you're at to start with.


This one thing I did not like with playing DnD…
"Example:
Strong man wants to push a heavy box out of his way.
Physical Check: 1d6+2
If Strong man matches the difficulty check or beats it, then he is successful."
With this... A player with 9 strength could (based on dice rolls) move a box that a player with 18 strength could not...
I would be better to place a weight value on the box...
If str<box weight, can't move...
If str>box weight, can move...
Altho, someone smart could move the box if they "thought" of using a lever... Maybe a "mental" roll for this...

Now, after saying all that "none sense"...
Looks like you have an interesting start for a good game.
There are a lot of people here that that can, and will, help you around programming problems...
(Some may be more helpful than others)


There are a couple of good combat codes on here.

Most combat commands look something like this:

if (not HasBoolean(object, "dead")) {
  msg ("That's not something you can attack.")
}
else if (object.dead) {
  msg ("That one is knocked out.")
}
else {
  if (player.equipped = null) {
    DoAttack (player, player, object, false)
    attackturnscript
  }
  else {
    DoAttack (player, player.equipped, object, false)
    attackturnscript
  }
}

And then the player attack funtion would look something like this:

if (firearm) {
  damageatt = "firearmdamage"
  attackatt = "firearmattack"
  weapon.ammo = weapon.ammo - 1
}
else {
  damageatt = "damage"
  attackatt = "attack"
}
roll = GetRandomInt(1, 20) + GetInt(weapon, attackatt) - target.defence
if (HasInt(weapon, damageatt)) {
  damage = GetInt(weapon, damageatt)
}
else {
  damage = DiceRoll(GetString(weapon, damageatt))
}
damage = damage * (100 - target.armour) / 100
if (damage < 1) {
  damage = 1
}
if (roll > 15) {
  damage = damage * 3
  AttackReport (weapon.critdesc, attacker, target, damage)
  target.hitpoints = target.hitpoints - damage
}
else if (roll > 5) {
  AttackReport (weapon.attackdesc, attacker, target, damage)
  target.hitpoints = target.hitpoints - damage
}
else {
  AttackReport (weapon.missdesc, attacker, target, 0)
}

I can sort of read the code, I did some programming with C++ in college.

While we're discussing the code, I was considering possibly adding to this system.

There's no mechanics for adding armor or weapons. If armor is implemented currently to the system it will make the characters OP.

What do you all think of expanding from 2 attributes to 4?

Physical
Mental
Agility
Social

I'm not sure how many points for the player to give between them since 4 might be too small.
I'm also worried that I'll over complicate the system so maybe when this is finished it could be hidden for the most part from the players and the player only sees the narrative output of what they did.


I think 4 attributes would be fine.

If you're using more attributes, obviously that means there's more points to go around (4 sounds good); so the menu could be unwieldy. In that case, I'd recommend moving some of the code out of the start script.

If you want to hide the actual numbers, you could come up with descriptions for each stat level.

So your start script would look more like:

player.stat_descriptions = NewDictionary()
dictionary add (player.stat_descriptions, "physical", Split("weaker than anybody;as strong as most people around me;one of the strongest guys in my village;stronger than anyone else in the world"))
dictionary add (player.stat_descriptions, "mental", Split("as dumb as a bag of rocks;able to read and write;top of my class in school;a world-famous genius"))
dictionary add (player.stat_descriptions, "agility", Split("clumsy and slow;fast enough to catch a ball;a champion athlete;faster than a speeding bullet"))
dictionary add (player.stat_descriptions, "social", Split("that guy with no friends;a popular guy;the life of every party;the most awesome guy in the world"))
player.stat_points_remaining = 4
// It might be easier to use a "changed" script. These run automatically whenever a stat is changed
//   so it's easier if you want to add a level-up system in future
player.changedphysical => {
  player.maxhealth = 5 + player.physical
  // if something happens that reduces a player's physical, we probably
  //   don't want it to heal them
  if (player.physical > oldvalue or player.currenthealth > player.maxhealth) {
    player.currenthealth = player.maxhealth
  }
  player.damage = 1 + player.physical
}
player.changedmental => {
  player.AC = 4 + player.mental
  player.attack = player.mental
}
player.physical = 0
player.mental = 0
player.agility = 0
player.social = 0
// Then show the menu
do (character_creation_turnscript, "script")

(I assumed that you're giving the player 4 stat points, and that the maximum for each stat is 3. If you want the maximum to still be 2, just remove the last entry from each list of descriptions)

Then in the "start" room, you'd put a turnscript named character_creation_turnscript (don't forget to enable it). This runs every turn until the player has finished choosing options:

if (player.stat_points_remaining <= 0) {
  game.showdescriptiononenter = true
  MoveObject (player, first room)
}
else {
  options = NewStringDictionary()
  foreach (key, player.stat_descriptions) {
    descriptions = DictionaryItem (player.stat_descriptions, key)
    if (ListCount (descriptions) > GetInt(player, key) + 1) {
      dictionary add (options, key, ListItem (descriptions, GetInt(player, key) + 1))
    }
  }
  msg ("You can train {player.stat_points_remaining} times before your quest begins.")
  ShowMenu ("You can become…", options, false) {
    player.stat_points_remaining = player.stat_points_remaining - 1
    stat = GetInt (player, result)
    set (player, result, stat + 1)
  }
}

Once you've got character creation sorted, you'll probably want to make some functions to handle the dice rolling.
As your game grows, there's a chance you might decide to change the system. To use different dice, maybe, or implement a lucky charm that gives a player a reroll on their next skill check. This is why it's useful to create functions; so that when you come to make a change like that, you only need to make the change in one place.

So, here's a simple function:

<function name="SkillCheck" type="boolean" parameters="character, stat, difficulty">
  roll = GetRandomInt (1, 6)
  stat_points = GetInt (character, stat)
  if (stat_points + roll >= difficulty) {
    return (true)
  }
  else {
    return (false)
  }
</function>

(I could have made the script for that function a single line, return (GetRandomInt(1,6)+GetInt(character,stat) >= difficulty), but I thought it might be a good idea to give you code that's a little easier to read)

Then when you're building your dungeon, you could for example have a heavy box with a "push" verb:

if (SkillCheck ("physical", 5)) {
  msg ("You push the box across the floor a little.")
  this.hasbeenmoved = true
  // any other code you want to run goes here
}
else {
  msg ("You push the box as hard as you can, but it won't shift.")
}

Maybe the box is blocking a doorway. So you'd have an exit with the "run script" checkbox ticked, and the script:

if (GetBoolean (heavy box, "hasbeenmoved")) {
  MoveObject (player, this.to)
}
else {
  msg ("I can't go that way. A large box is blocking my path.")
}

Hopefully these simple examples are easy enough to follow. If you've done programming before, you shouldn't have any trouble picking up Quest's scripting language. If you have any trouble, I'll do my best to help.

I was going to show some example combat code as well, but I'm being called away from the computer now. I can give suggestions later if you need some help. For now, here's an example of an attack-handling function (which would be called by a command for the player, and probably a turnscript for any enemies):

<function name="DoAttack" parameters="attacker, target">
  if (SkillCheck (attacker, "attack", GetInt (target, "AC"))) {
    dmg = GetRandomInt (1, 6) + GetInt (attacker, "damage")
    msg (CapFirst (WriteVerb (attacker, "attack")) + " " + GetDisplayName (target) + ", and inflicts "+dmg+" points of damage.")
    target.currenthealth = target.currenthealth - dmg
  }
  else {
    msg (CapFirst (WriteVerb (attacker, "attack")) + " " + GetDisplayName (target) + ", but misses.")
  }
</function>

As far as armour goes, if you're worried about it being OP, you could have it work as a probability. For example, armour might have a random chance (⅙ or ⅓) of reducing the damage from an attack by 1.


being able to do the coding is one thing, being able to game design is another, and being able to balance the game mechanics and the game as a whole, is yet even a far greater challenge

unfortunately, you just got to practice and get experience with game designing and balancing, I don't think there's really any guide book out there for it (at least not that I've found), and/or use other games and their mechanics, as a guide.

However many in-game attributes/stats you got, they need to have a specific purpose of mechanic that you want in your game, of course.

so, it might be better to think of the mechanic/system/feature you want in the game, and design the code, Attributes (VARIABLES), and scripting, around that

also, keep it simple, as you can always go back and expand and/or change upon it later

I myself am trying to learn game designing and game balancing for my first time too (I never did D&D stuff), and I struggle just without the coding of whatever I want to do, sighs... (am still working on character creation for my massive ambitious TES:skyrim-oblivion-morrowind level of rpg that I'll never ever ever get even remotely to finishing... laughs)


Forgive me for being a noob. Thank you everyone who has helped me with this and I need some further help with implementation of the code.

I want to make two test games, one with the 2 attribute system and the other with the 4 attribute system.

I'm not sure where to put what code where into my game, I'll be starting a fresh game for each system to test them out. So from a fresh start where do I put what code where?

I want to make sure the code posted above is not being added to each other or if they are separate whole sets of coding.

Thanks


The code I posted for the 4-attribute and 2-attribute character creation systems is a complete character creation system; so you should only need one of those.

The 2-attribute version doesn't change the player's attack/damage/health if your physical or mental stats change later. If you want to do that, you'd need to include the blocks that start with player.changedphysical => { and changedmental => { from the other version.

The SkillCheck and DoAttack functions should probably be the same in either version.

If you're using the combat script, you'll also want to give the player object a script attribute named changedcurrenthealth to check if they're dead:

if (this.currenthealth > this.maxhealth) {
  this.currenthealth = this.maxhealth
}
else if (this.currenthealth < 0) {
  msg ("You're dead.")
  finish()
}

If you need any help with other parts of it, I'll be happy to help. Hopefully you can follow the code, and see what each line is doing.


Where do I paste this code? In game or under player?


The changedcurrenthealth script?
It should be a script attribute on the player object.
I believe that in the desktop version the player object has an "Attributes" tab where you can add this.

If you're using the online version of Quest, you would need to put it in either the start script, or the player's initialisation script, with an extra player.changedcurrenthealth => { at the start.


Sorry for my ignorance of Quest, I haven't scripted on a game engine before.

This code, the first that was written, can you give me step by step instructions on how to implement it into a new game?
options = Split("strong;smart;average")
ShowMenu ("What kind of man would you like to be?", options, false) {
switch (result) {
case ("strong") {
player.physical = 2
player.mental = 0
}
case ("smart") {
player.physical = 0
player.mental = 2
}
case ("average") {
player.physical = 1
player.mental = 1
}
default {
msg ("You selected something that wasn't one of the options, so there must be a typo in my code.")
}
}
player.maxhealth = 5 + player.physical
player.currenthealth = player.maxhealth
player.AC = 4 + player.mental
player.attack = player.mental
player.damage = 1 + player.physical
// We enable room descriptions here, so the game doesn't say "You are in a character creation"
// but it does say "You are in a dungeon" or whatever when we move them to the actual start of the game
game.showdescriptiononenter = true
MoveObject (player, first room)
}


(hope I'm not misunderstanding you)
Step-by-step:

  1. Create a new room called "start" or similar (so that the player can't see anything until they've done character creation)
  2. Move the player object into that room.
  3. On the game object's "descriptions" tab, until the option marked "Show room description when entering a room"
  4. Go to the "scripts" tab, and look at the 'start' script; this will be run as soon as the game starts
  5. Click the "code view" button and paste in the script
  6. In the line MoveObject (player, first room), change first room to the name of the room that you want the player to appear in once they've chosen their character.

That should be all you need for that one.


@ paiyaku:

if you want some help in learning quest and its coding more:

http://textadventures.co.uk/forum/general/topic/ljjm32av4e2t9ot49k478g/help#710be61e-eae1-4af1-8363-520cc718ba1c

ask if you need help with anything


Thank you for the help everyone. I spent sometime going over my stat system for 4 attributes and I think I’ve got something pretty good now.

Let me know what you all think.

**4 points to spend between the 4 ability scores:
Physical
Mental
Agility
Social

Physical
Health: 5+Physical
Melee Attack: dice+Physical
Melee Damage: dice+1+Physical

Mental
Magical Defense: Mental
Magical Attacks: dice+Mental
Magical Damage: dice+1+Mental

Agility
Unarmored AC: 4+Agility
Ranged Attack: dice+agility
Ranged Damage: dice+1+agility

Social:
Bartering: item price - social
Performance: dice+social
Speechcraft: dice+1+social

Ability/skill check dice:
1d6: rolling 1 is automatic fail and rolling 6 is automatic success within the physical ability of the character.

Attack dice:
1d6 - rolling 1 is automatic fail and rolling 6 doubles the damage number rolled.

Damage Dice:
1 - unarmed
1d2 - improvised
1d4 - common weapons
1d6 - uncommon weapons
1d8 - rare weapons

Melee/Ranged Attack is against Armor/Unarmored Class
Damage is against HP
Magic Attack is against Armor and if attacker hits the magic defense of the victim reduces the damage taken.**


just in case you don't know already...

there's a few built-in Randomization Functions:

  1. DiceRoll ("NUMBER_OF_DIEdNUMBER_OF_SIDES_ON_DIE") // self-explanatory (what happens when you roll X Die with X number of sides ??? --- that's how this Function/Script behaves)

  2. GetRandomInt (MIN_INTEGER_VALUE,MAX_INTEGER_VALUE) // it randomly selects a number (integer) from the min value to the max value

  3. GetRandomDouble () // it randomly (automatically) selects from 0.1 to 0.9, so that's why there's no parameters for it

  4. RandomChance (INTEGER_VALUE) // Value must be an integer from 0 to 100 // Value is the percent chance of it being 'TRUE', and thus: 100-Value, is the chance of it being 'FALSE')


you can do quite some neat stuff with these and Lists, for example an item drop system:

you have a list of items that can be dropped

the 'GetRandomInt' selects the item to be dropped, from the list of droppable items

and then the 'RandomChance' determines whether the selected item is actually dropped or not


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums