Giter VIP home page Giter VIP logo

mud-backend's People

Contributors

matt-jordan avatar

Watchers

 avatar  avatar

mud-backend's Issues

Conversations: Don't start a conversation if you're under attack or otherwise indisposed

Right now, any text that triggers a conversation will start up a conversation. However, if a Character is in certain states - fighting or resting or what have you - it should probably not do that.

$ say hi pia kung

Pia Kung says, "I can't talk right now, I'm being attacked by {{character}}"
$ say hi pia kung

Pia Kung snarls at you, "You will die for attacking me!"

We should think of some verbs to describe the interactions (snarl, shout, scream, etc.) as well as some pithy one-liners. It should also depend if you're the attacker (in which case, they're more likely to be mean) vs someone just trying to chat about the weather while their life is in mortal peril.

Door: Lock and unlock

I'm bored and tired of typing, leave me alone.

[north] (door)

$ unlock door

You unlock the door.

Everyone else:

> so and so unlocks the door

Lock would be the same. Things we need to make sure happen:

  1. Locking/unlocking when the door has no lock
  2. Locking/unlocking when the door is in the wrong state (lock when locked; unlocked when unlocked, either when open)

Add default attacks to `CharacterModel` and the combat system

Right now, everyone is just punching each other. While rats don't have weapons, they do bite. So do cats. Bears likely have a few claw attacks plus a bite. And so on.

Effectively, every type of character should have some default attacks associated with them that are used when they don't have a weapon. This likely needs to get stored on the model, as an Animal instance is too generic to define the difference between a rat and a bear.

Quests: THE BASICS

Quests are going to be a thing, yo. So let's do the simplest quest we can think of: find a thing and bring it back.

Quests need to tell users what to do when you're chatting with people:

"Hey so-and-so! I'd like you to bring me back [a rat pelt].

The square brackets tell you what to bring back. Eventually if you have that item, you'll need to give it to them:

$ give a rat pelt to Foobar

You give a rat pelt to Foobar

"Thanks so-and-so! That's just what I wanted!"

You have completed quest "Rats!" (50 exp)

(Or something like that)

While you're on a quest, it can be tricky to remember wtf you're supposed to do:

$ quests

You are on the following quests: [1]
 * Rat pelt: Find [a rat pelt] and give it to [Foobar]

When we think about expressing this in config, we could do something like this:

 "quests": [
    {
      "loadId": "quest-0",
      "version": 1,
      "name": "Rat pelt",
      "maxCompletions": 1
      "stages": [
        {
          "rewards": [{
            "type": "experience",
            "amount": 1 // encounter
          }],
          "actions": [{
          "type": "giveItem",
          "inanimateId": "rat-pelt", // We don't want to use a real inanimate ID here, as the inanimate may go away
          "characterId": "Foobar" // We don't want to use a real ID here, as the character may die and get respawned
          "transitionText": "Thanks {character}! That's just what I wanted!"
           }]
         }
      ]
    }
  ]

note: I think we shouldn't use ID when it isn't a generated ID. Instead, we should switch human readable identifiers that are re-used across spawns to 'tags'. It's not great since things can usually have more than one tag........ but a lot of times I'll use {thing}Id in code to reference the ID that is for a particular thing's actual ID, and calling it a characterId here is bad.

Probably not tag. That's not good. It is an ID.

We use load as a predecessor when it's a human readable ID to be used during load. Maybe we should do something similar here?

Maybe ref, in that it's a handle that should last. (This is weak but oh maybe okay)

Note that each stage is done in order, and each stage is a list of things to do in parallel.

This will take a lot of state data. We'll want to keep track of quests that are done each character.

Note that we haven't said yet how quests start. The most obvious way is when you talk to characters, which means we need conversation.

That should be done before this one.

[Fighter] Parry

Skilled fighters should have the ability for their weapons to provide a defensive bonus. If hit, there should be a chance that increases with skill that the Fighter can deflect the attack away with their main weapon.

enhancement: Add experience gathering

When we do certain activities, we should gain experience. We'll want to be a bit prescriptive here with our formula, but basically, when something is greater than your level you should get a bigger bonus; equal; and smaller. Probably a +2/+1/0/-1/-2.

It shouldn't just be combat; completing quests (eventually to be added) should also have a level associated with it.

Add resting with healing

Since we're now taking damage, we have to have a way for a player to regen hitpoints. Entering the 'rest' command.

When a player is resting, the following should happen:

  1. On each tick, if resting, the player heals some HP. Each tick could be a bit variable, i.e., they don't heal on every tick but some modulo of it, but either way, they start to heal.
  2. The player can no longer move. They can use other observational commands.
  3. The player is 'vulnerable'. This is an interesting flag to set, but effectively if something attacks them it should 1/ auto-hit and 2/ probably hurt a lot.

Resting is canceled by 'standing'.

People should be able to tell that a player is resting both by looking at them, as well as by observational messages broadcast to a channel.

enhancement: Add the concept of skills

Classes introduce the notion of who has skills and when do they get them.

At its most basic, we should add skills for the combat weapons and defense types.

Combat Weapons

  • Piercing
  • Slashing
  • Bashing

Defense

  • Shields
  • Armor
  • Defense

We may want to add other things over time.

Factions not set on player creation

Amongst many other things, factions are not set when you first create a player character. This means that the first quest that you would get (Rat Extermination) you won't be able to see, as Pia Kung will think you suck too much to give it to you.

Which is correct: if a PC lowers their faction score a lot, they shouldn't get the quest.

Really, what we need is a 'default player kit' that gives players their base faction scores, some lousy equipment, and a few gold coins.

[Adventurer's Guild Quest]: Add a quest that teaches a user how to play the game

The best way to learn is by doing... and we should give new characters a quest to learn from.

  • The quest should only be available when you're level 1
  • You should get a nice prize at the end (probably the Ring of the Adventurer)

Step 1: Movement and interactions

  • Tell them how to move around, look at things, open doors
  • Go to the next room pick up an item that was generated for them, and return it

Step 2: Combat

  • Have a training dummy that they can beat up. It should have enough HP that it takes a few rounds to 'kill'
  • Return the 'head of the training dummy' in its corpse to complete the stage

Step 3: ...?

Killing characters leaves their model orphaned

When a playable character (Character with a transport) kills an NPC (Character), we do remove them from the game and create a corpse. However, nothing removes the underlying CharacterModel. Given enough time, this is a bit of clutter.

At the same time, we don't want to remove playable characters, which are those CharacterModels that have an accountId associated with them. So we should add some safety checks to prevent that from happening.

Conversations: Random messages will trigger conversation

We only want to trigger conversation when someone talks to NPCs. Currently, this is triggering off of messages sent to a room, which can include informational stuff and not just spoken messages. For example, if we examine the NPC:

$ examine pia kung
Amonsul examines pia kung

Pia Kung says, "blah blah blah"

We need to update this so it only triggers on actual conversation.

Add a 'score' command

While we send hp/mana/energy back all the time to give players a HUD about their most vital stats, most of a character's stats aren't displayed in any way. We should allow characters to see how they're progressing in the game and their vital stats.

$ score

You are a fighter [level 2] (x of y) exp. You are [text description] (health/mana/energy).
You are exceptionally strong (X str), etc.
Skills:
 observation 1    etc.

Door: Open doors

When you have a closed door, you need to be able to open it:

[north] (door)

$ open door

You open the door.

The rest of the room should see this:

> so and so opens the door.

In the destination room, we wouldn't be able to see who did it, but we would see that it happens:

> door opens.

Of course, if things don't work, we should be told so:

north (door)

$ open door

The door is already open.
[north] (door)

$ open door

The door is locked.

[Priest] Add the healing prayer (water)

The prayer 'healing' should convert mana to hp.

Base regen rates are:

      this.attributes.hitpoints.regen = 0;
      this.attributes.manapoints.regen = Math.max(
        this.getAttributeModifier('intelligence'),
        this.getAttributeModifier('wisdom'),
        1);
      this.attributes.energypoints.regen = 5 + this.getAttributeModifier('constitution');

That means:

hp: 0
mana: 1 - 4
energy: 5 - 9

So for mana to hp regen, we should probably have a ratio of 5:1. That means if we're resting, with no regen modifiers, we'll still (slowly) drain out of mana, which is probably 'right' if you have no skill.

If chant improves, we should remove a percentage of the mana cost, rounding down, to a minimum of 1. So until you hit 20, you get nothing, but then the mana cost goes down to 4.

Likewise, as 'healing' prayer improves, we should add to the hp. This probably should go up in 'bursts': 1 - 20 adds +1; 21 - 40 adds +2; 41 - 60 adds +4; 60 - 80 adds +8; 81 - 100 adds +16.

(Of course, you can only get to 50 skill points anyway, but whatever).

That means we'd go from 5 mp for 1 hp at Level 1 with no skills to 1 mp for 17 hp at max. And you'd probably not even lose the mp with other things anyway, so huzzah for perma healing.

The hp healed should likely be halved for party members, rounding down. So until you can get to skill 20, it has no effect on party members (or level 4).

Somewhat flakey tests when checking messages sent to a room

A lot of our unit tests check for messages that have been sent to a room. When we check for those messages, we really don't care about the number of messages that have been sent - we generally just want to see if a message was sent that matches what we expect.

Unfortunately, this often isn't as deterministic as we'd like. Every now and again one of the so and so enters the room messages will get picked up due to normal out of order kinds of things, and a test will fail due to having more messages (and in a different order) than it expected.

We could use a test helper that makes it easy to check if a matching message was sent to a room.

Social: Add emoting

Something along the lines of:

$ emote takes a bow
> Hrothgar takes a bow

This shouldn't be subjected to languages.

Add armor class reduction to damage

Armor is currently useless, in that we don't look at the armorclass to reduce damage. That's not ideal: we want boots to provide some protection from those biting rats. Steel toed boots are even better.

When a character hits a particular location, we should look at the armor the defender is wearing there and apply it to reduce the incoming damage.

Social: Add 'shout'

This is the equivalent of 'say', except that it blasts it across the area.

Because we'll want some color markdown (same for emotes), we should add a new JSON type for this:

{ type: 'SocialMessage', subtype: 'shout', message: 'blah' }

Something like this.

Add `put` command

While we can currently get items that are on the floor of a room or inside of a container, we don't have the equivalent ability to put an item inside of a container. That makes using a good backpack rather challenging.

We should have the ability to put items inside of a container that we're carrying or that is on our person, e.g.,

put longsword in backpack

Add locations / percentages to how characters hit other characters

The combat system I have in mind has armor class being applied on each location as a means of damage reduction. Creatures have more or less likelihood to land hits on different locations based on the difference in their sizes. This gives us a lot of incentive to get armor in all locations, and provides a weird element of 'realism' as rats slowly nibble your toes to death.

  • Size differential -2: Feet (70%), legs (30%)
  • Size differential -1: Feet (40%), legs (30%), body (12%), back (12%), hands (6%)
  • Size differential 0: Feet (5%), legs (20%), body (35%), back (10%), arms (10%), hands (5%), neck (5%), head (10%)
  • Size Differential 1: Feet (1%), legs (15%), body (40%), back (15%), arms (10%), hands (2%), neck (5%), head (12%)
  • Size differential 2: body (53%), back (15%), arms (10%), hands (2%), neck (5%), head (15%)

Improve handling of playable character deaths

When a playable Character dies, we should disconnect the socket. But someone could easily just Login again. We need to do a few things here:

  1. Add a isDead flag to CharaterModel so that we can easily tell that a playable character is dead.
  2. Filter out CharacterModel when logging in so the command fails gracefully.

We may want to also add some safety checks that fail a load if someone tries to create a Character with a CharacterModel that has the isDead flag set as well.

[Fighter] Shield Bash

There's usually a big upside to fighting with two weapons, even with the defensive bonus of having a shield. Bashing someone with your shield gives shield armed fighters a bit more damage output. It should:

  1. Overlap with kick - that is, you shouldn't be able to do both simultaneously
  2. Do some damage to an opponent based on the shield itself (AC to damage + effects, etc.)
  3. Have a stun effect chance

Door: Examine doors

Examining doors should tell you more about it:

[north] (door)

$ examine door

A door. It looks heavy.
The door is closed and locked.

This should also support directions to look at specific doors when there are multiples, e.g. ,examine north.door.

Doors: Block movement if a door is closed

While we have Doors, they don't do anything. First step in making them do something is to block movement:

[north] (door)
$ move north

You cannot move north through door.

There's really no reason to show that to the rest of the room.

Improved combat messages

Currently combat messages are sent as plain text from the backend to the frontend. In order for the frontend to know to decorate combat messages - such as changing the color to red - we'll need to send them as JSON with some new attributes.

Doors: Prevent looking through doors

When you look in a direction, you should only be able to do so if there's nothing blocking you:

[north] (door)

$ look north

You cannot see through door.

Support monetary rewards

Currently, the only reward we have is a faction bonus. Characters who complete a quest should have the ability to get a monetary reward.

Add Error handling to command handling

When we don't process a message sent by a client, that should trigger an Error message that the command wasn't understood. We should look to see if a command isn't generated and fallback to an Error message in that case.

It's arguable that all of the Error messages should be generated in this way, as it would potentially let us markup an Error response so that it can be displayed in a more interesting fashion. We should at least entertain this, as right now we're just slamming Strings back over the socket in a variety of locations.

[Fighter] Implement Cleave

There's probably going to have to be some tweaks to how attacks get set up for this to work... and we may want to think about that in the notion of enemy parties. Anyway.

The idea here is that a sufficiently powerful fighter should have the ability to let their attacks 'carry' through when they kill an enemy. That is:

  • Fighter hits and kills enemy A
  • Fighter's attack carries through and hits enemy B. If it kills enemy B, it continues through to enemy C, etc. until there are no more enemies
  • If Fighter doesn't kill enemy B, then their attacks continue on in that round with enemy B

Cleave - as a skill - obviously has some percentage chance of working when you kill someone.

For this to be useful though, there has to be a 'list' of people to hit, which means multiple active combats for a person (which would significantly change the CombatManager) - alternatively, we only have Cleave work in a Party situation (which is probably where it makes the most sense).

[Priest] Add the ability to chant

Priests should do most of their 'spells' through chanting, which - while active - drains mana in exchange for some effect. Those effects can impact either them or the party, and do not limit their ability to interact in other ways (such as attacking).

$ chant healing
You begin to chant the healing prayer.

Simply using chant should tell you what you are chanting.

$ chant
You are chanting the healing prayer

or

$ chant
You are not chanting anything

To stop chanting - which will happen when you run out of mana anyway - you can just use 'chant off'.

$ chant off
You stop chanting the healing prayer.

Even if chanting has no effect - such as your HP being full - it should still drain mana. There are two ways to improve:

  • The chant skill should have a chance to reduce the amount of mana used for the effect
  • The actual prayer should improve the effect, but not the mana cost.

Door: close the door

When you have an open door, you need to be able to close it:

[north] door

$ close door

You close the door.

The rest of the room should see this:

> so and so closes the door.

In the destination room, we wouldn't be able to see who did it, but we would see that it happens:

> door closes.

Of course, if things don't work, we should be told so:

[north] (door)

$ close door

The door is already closed.

Run-away spawns

When the game starts up, spawners aren't recognizing that they already have characters associated with them. This leads to them re-generating new characters. Those characters are tracked okay, but given enough game restarts, you end up with quite a few NPCs running around doing things.

I'm not sure if this is related to spawners with a greater spawn count than 1, or if it's an ordering thing.

Quests: Spawning a boss

We should support a 'boss' getting spawned when someone accepts a quest. That should go something like this:

  1. When you accept the quest, the monster is spawned
  2. You go and kill the thing
  3. Profit

If someone does #2 first, then the quest should fail.

Social: Add 'say' command

We want the ability to say things to people that are in the same room as us. By defaults, we should be able to say things in common:

$ say hey there
> Hrothgar says "hey there"

If you know a language, you should be able to speak in it:

language goblin
> You are now speaking in goblin
say hey there
> Hrothgar says in goblin "hey there"

But if you don't know goblin:

> Hrothgar says "difa yasl"

We can do a skill check per word and replace it with some phonetic differences based on the language. So we'll need a 'language class' that interprets phrases based on folks skill checks.

(Should be fun!)

Note that your language should impact all things that you say or shout.

Everyone know 'common' by default. We can get better at learning languages by hearing them spoken (slow) and an INT check or by study with a book, but that part can come later.

Doors: Allow looking at doors

When you're looking at things, it should include doors as an object:

[north] (door)

$ look at door

A door. It looks heavy.

There's some trickiness we'll have to handle when there are multiple doors:

[south] (door) [north] (door)

$ look at door

That should just pick the first one in the list, but how do you select which door? Normally we would use 0.door or 1.door, but that indexing doesn't work.

Instead, we should support {direction}.door as a way to index it. This won't work with a container based approach, but we should be able to handle it inside the Look function.

Update Examine with level comparisons

Currently, the Examine command will, based on your observation skills, give you back some basic information about the thing you're inspecting:

a rat

$ examine rat

It's a small rodent. It is uninjured.

We should include a level comparison between the character and the rat. It shouldn't take a very high observation skill to make a comparison here... unless an opposing skill check allows a character to hide their level.

[Fighter]: Double attack command

A couple of ways we could do double attack:

  1. If your current attack hits, you get another swing
  2. A flat 2 attacks per weapon
  3. A flat 2 attacked with the main weapon

A part of me likes the idea of it being #1, but applied to both weapons. That pulls down the damage curve slightly, and when it does happen has a slightly more out-sized effect.

Likewise, we probably need to make the penalty for dual wielding a thing, but we can do that on another issue.

Corpses that never decay

Corpses that are loaded via Inanimate::load and should de-populate don't fade away. This is likely due to how we're counting down using timestamps as opposed to a monotonically decreasing counter - or how we're generally managing it via timestamps. Because time is weird.

Conversations: Support faction checks

If someone has a good enough rating with a faction, conversations should flow as normal. Otherwise, people shouldn't want to talk to you. If you're the equivalent of a mass-murderer, offering you a cup of tea would be weird.

$ say hi pia kung

Pia Kung glowers at you.

This likely need 1/ emoting (we should add that so we can trigger that as an action vs saying things) and 2/ some standard faction checks.

[Fighter]: Dual wield/ambidexterity

Right now, you can dual wield with no penalty. That's probably a bad thing, as two weapons can throw out a ton of damage.

I'm not entirely sure dual wielding is working right now anyway, but that's beside the point.

If you're dual wielding, you should have a penalty with the 'off-hand' weapon. Getting better at dual wield should, over time, reduce that penalty.

Ambidexterity should also, over time, further reduce that penalty by setting the 'off-hand' penalty to be equal to the main hand.

For example:

Base penalty: -4 main / -8 offhand
Dual wield: % chance to reduce penalty to -2 main / -4 offhand
Ambidexterity: % chance to reduce offhand to same as main (-4 base, -2 w/ dual)

Add a utility that finds and reports orphaned items in collections

As we're developing the game, it's pretty easy to leave things orphaned in the database. We should have a utility script to create a list of orphaned items in Rooms, Characters, Weapons, Armor, Spawners, and Inanimates.

Starting from areas:

  • List all rooms
    • List all spawners
    • List all inanimates
      • List all inanimates in inanimates recursively
    • List all Characters
      • List all inanimates on Characters
        • List all inanimates in inanimates recursively

Starting from Characters that have an accountId:

  • Do the same action that was done on Character (if not already done)

Anything not found in this process is likely an orphan.

Add money

When you complete a quest, you need to get paid for it:

You have completed Rat Extermination!
You have received 50 gold coins from Pia Kung

We don't have to implement spending money just yet, but we may as well keep track of it. We could go super complicated here with weight, monetary types, etc. - but that's a lot. And mostly it just serves to make things annoying. So let's not make things more annoying than they should be:

  1. Players have gold (single currency type). We'll leave it open for other currencies, but just implement the basic one for now.
  2. Gold will start off weightless. We can add a weight to it later if we feel like it.
  3. You can see your gold in your inventory.
  4. You can give gold, drop gold, pick up gold just like an item, albeit a slightly special one.

Update `look` command to be able to look inside containers

Currently, look lets you look in directions, at the room you're in, or at specific objects. However, we don't look inside containers currently.

We should update look so that if you look inside of something, it lists out the contents.

look in backpack -> list of items in the backpack OR the word "nothing" (or something similar)

Combat messages are sent only between participants and not to the room

Currently, when two characters are fighting we'll send messages to the attacker and defender, but not the rest of the participants in the room. That's not what we want - we want combat to be 'visible' to everyone else, but with different messages. Effectively the attacker/defender should get one set of messages ('you hit', 'so-and-so hits you') but a third set delivered to everyone else ('So-and-so hits so-and-so').

We can pretty easily do that with the existing Room:sendImmediate function, but it only lets us supress a single character in the room from receiving the message. This worked back when the character was the originator, but it doesn't work when we want to deliver it to all but 2 characters.

This will take a bit of updating, as we'll need to filter it out and switch from a direct comparison to some list manipulations.

Conversations: A simple conversation engine

There's a couple of ways we could do conversations:

  1. EQ style. You 'hail' the NPC, which initiates the converstaion. You then 'tell' specific words to them. This keeps someone else from hijacking the conversation, and all conversations are 1:1.
    • I don't love this. You lose what littler immersion we have. It is easy to keep track of the states however.
  2. DF style. Conversations are 'public', but are established between two characters and are generally maintained until someone ends it (or walks away). Walking away is rude, but may or may not be a negative hit. Responses are all numbered.
    • Parts of this are cool, particularly the way it models bi-directional communication. it's probably a bit tricky to model. But we can also add states to the conversation... and we can reset it.

I'm leaning towards DF style, where saying 'hello' and the NPC name triggers a conversation with them. For NPCs with the same name, we can make it use the standard collection look up (first match and/or 0. or 1.).

(I actually really like this, even if it's going to be a lot of work)

Pseudo-JSON:

conversation: [
    {
         "state": {
             "name": "etc-1",
             "text": "Hello {{character}}. {{times == 0 ? It's nice to meet you : It's nice to see you again}}. I'd love to talk to you about {{transitions_or_list}}.
         }
         "transitions": [{
             "name": "rats",
             "next_state": "etc-2"
         }]
    }
]

We're going to need a pseudo-templating engine here. A jinja2 style kinda thing will work well where the inputs are the character and the conversation's state. I don't think we want to use jinja2 or json-template; it'd probably work but to some extent I want to add 'commands' into the strings that do useful things, e.g., transitions_or_list would grab all the keywords out of the transitions and turn them into "[rats], [mail], or [a crazy adventure]". (or whatever the transitions happen to be)

We can add more of these over time as we build more interesting conversations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.