Wednesday, June 27, 2012
Tuesday, June 26, 2012
Saturday, June 23, 2012
How to pick up loot
Putting items directly into the inventory.
Pro:
Picking them up from the ground.
Pro:
Open a window to pick from when clicking on a carcass
Pro:
Contra:
I think I will first implement the "put directly into inventory" method, because everything I need to code for that also needs to be coded for the other methods.
Pro:
- Very easy to implement
- No choice not to pick up items
- Players might find ultra-rare items and not even notice it before checking their inventory
- No way for the players to directly control who gets loot in a party
Picking them up from the ground.
Pro:
- Enables drop-trading
- you can see what other players around you find
- Adrenalin rushes when you see something valuable drop
- Enables mob/item interaction
- Either Inventory icons must be designed in a way that they look OK both in the inventory and on the ground, or every item needs an additional floor sprite
- Enables drop-stealing
- Items on ground can be unreachable or overlooked
- A lot of netcode traffic is used for communicating drop position
Open a window to pick from when clicking on a carcass
Pro:
- Convenient to decide what to pick up, especially for parties
- When killing a lot of enemies at once, checking them all for loot can be a chore
- Additional click required to pick up items
I think I will first implement the "put directly into inventory" method, because everything I need to code for that also needs to be coded for the other methods.
Thursday, June 21, 2012
About items
Items are what makes MMORPGs worth playing.
They appeal to the basic human instinct to gather and to hoard.
They are a much greater token of achievement than levels and stats alone.
They are a great source of reward. I still fondly remember the dopamine rushes I experienced in Ragnarok Online every time one of the many ultra-rare 0.01% drops appeared on my screen.
They enable an economy. An exciting game inside the game which drives itself without any actual work by the developer.
Milestone 7 turned my program into a game. But Milestone 8 will make it worth playing.
Milestone 7 finished
I hereby declare Milestone 7 finished. I finished this milestone much quicker than I thought, but that was rather because I was quite active lately, not because it wasn't much work. The planning decision to make a whole milestone out of the mob AI was definitely justified.
I didn't implement all the planned monster strategies, but I didn't plan to do so anyway. I created a solid framework which allows me to create new strategies with minimal effort. This will surely come in handy in the future. Even now the AI is already passable, and without much effort I can make some awesome things.
The next big chunk will be items.
I didn't implement all the planned monster strategies, but I didn't plan to do so anyway. I created a solid framework which allows me to create new strategies with minimal effort. This will surely come in handy in the future. Even now the AI is already passable, and without much effort I can make some awesome things.
The next big chunk will be items.
Monday, June 18, 2012
Respawning server-side
I implemented respawning on the server-side. The client still needs a button to do this.
Currently respawning fills your HP and sends you back to the starting location. A mechanic for saving a different spawn location will be needed, but this will be postponed to Milestone 9.
I also implemented the /death and /revive chat commands.
Something which is also a bit annoying is that there is no way to tell if a player is alive or dead just by looking at them. I need to use a different sprite for dead players.
Currently respawning fills your HP and sends you back to the starting location. A mechanic for saving a different spawn location will be needed, but this will be postponed to Milestone 9.
I also implemented the /death and /revive chat commands.
Something which is also a bit annoying is that there is no way to tell if a player is alive or dead just by looking at them. I need to use a different sprite for dead players.
Saturday, June 16, 2012
Monster attacking
Monsters can now attack player characters (and - theoretically - each other when I would implement a target strategy for that). They only do one damage with every attack for now, but it's a start. I still need to handle player death. When that's done, I practically have a playable game.
Sunday, June 10, 2012
Angel and Imp
I brushed up my rusty pixel art skills and created two placeholder monster sprites. The angel looks pretty cute already, but the imp needs some work.
Angel
Magical creatures of pure good. They strictly adhere to the moral rules written in their "Holy Codex" which encompass pureness, chastity, humility, abstinence, kindness and peacefulness. The last one with one notable exception: Anyone who does not adhere to the rules of the Codex is considered a sinner, and sinners must be opposed with all means necessary. Destroying the sin is a cause which justifies all means necessary. The angels prefer to make a sinner repent and abandon their sinful ways, but when this turns out to be a futile attempt, they often decide to destroy the sin by destroying the sinner.
At first, other creatures usually consider the berating of the angels about their "sinful ways" amusing at best and annoying at worst. But it is foolish to not take them seriously. Angels are not allowed to bluff or lie. When they say that your adherence to a sinful life will have "dread consequences", they mean it.
Angels are also intelligent, educated, organized, polite and well-spoken. As the self-proclaimed moral guardians of the kingdom, they are very interested in politics. The angels openly trusting someone has a very positive influence on the public opinion. That's why many politicians employ some angels as officials for image reasons. Besides, they are smart, diligent, hard-working and frequently even work for free. Unfortunately, closeness to the angels has the disadvantage that any "dirty business" must be hidden from them at all cost, because they will not hesitate to make it public, abandon you, or even outright attack you when they doubt your moral integrity.
Fallen Angel
An angel which willingly commits a sin, or which enjoys performing a sinful act when forced to do it, immediately transforms into a fallen angel. In contrast to angels, they are hedonist creatures whose only concern is their own well-being. They only cooperate with others as long as it gives them direct gain or pleasure, and they will abandon any ties to others as soon as they become a burden. That's why most fallen angels are solitary creatures.Ironically, they are often less dangerous than their good counterparts. They don't care much about the business of others, unless it directly interferes with them. Although fallen angels do not hesitate to use violence to get what they want, they will usually back off when the resistance they have to bother with outweighs the potential gain.
But still, when there is something they really want, they will not have any moral qualms about using any means necessary to get it. There is also a faction of fallen angels which can indeed be very dangerous: Those who discovered the pleasures of sadism and domination. A fallen angel who enjoys to cause suffering is someone you don't want to meet.
Imp
These evil creatures strive on the hate and anger of other creatures. They need hate of others to survive. When nobody hates an imp, they starve to death. To get people to be angry on them they will use insults, practical jokes or even violence. They can be considered the "bullies" of the kingdom. Fortunately, they are small and not very powerful, so they are more of a nuisance than a real threat. But being a nuisance is a skill they trained to perfection.The best way to deal with them is either by ignoring them, or by trying to have a positive attitude towards them. While hate of others is food for them, affection is pure poison and will drive them away. Considering them cute, feeling sorry for them that they must be mean to survive or believing that they are really nice beneath their outer shell is a sure way to drive them away.
Saturday, June 9, 2012
Monster database, spawn areas and roaming strategy
I just implemented:
- Spawn areas defined in map files
- Reading monster properties from a JSON database file
- The roaming strategies RoamMap and RoamArea
- The spawn strategies ReplaceSingle and ReplaceAll
Oh, and the JSON parser need to be made more stable. When they miss some value, they spit out a stack trace. They should use a reasonable default and output a warning instead.
Monster strategy
I thought about how I could implement monster strategy.
On one hand, I want monsters to have many different behavior patterns to give players a varying game experience. This screams like an application for the Strategy pattern. But I also want to keep my Controller pattern where monsters are controlled from the outside. That's because I want some monsters to act as teams and be aware of what other monsters around them are doing.
So I decided that every spawn area shall have its own MonsterController, which in turn gets four different strategies assigned to it:
Here are some example strategies for each category:
Every monster type has a default strategy for each category. But spawn areas can manually override them. So you can have, for example, a demon castle where some demons patrol the surrounding, two demons guard the front gate, a group which ambushs any players who gets past the guards and some which roam the interior.
- SpawnStrategy: When and where it spawns mobs
- TargetStrategy: How it decides which monsters attack which players
- RoamingStrategy: Behavior of monsters without an attack target
- AttackStrategy: Behavior of monsters which have an attack target
Here are some example strategies for each category:
Spawn | ReplaceSingle | Respawns dead mobs until the population reached a certain value |
ReplaceTeam | When all mobs have died, respawn them all. | |
Ambush | Like ReplaceTeam, but only spawn them when a player is in a specific area. | |
Target | null | never choose an attack target |
Closest | Chooses the target closest to the monster | |
ClosestTeam | Chooses the target closest to any controlled monster | |
LastAttacker | Chooses the last combatant who attacked the monster | |
LastAttackerTeam | Chooses the last combatant who attacked any monster of the team | |
BestAttacker | Chooses the combatant who did most damage to monster | |
BestAttackerTeam | Chooses the combatant who did most damage to all monsters of the team | |
Roaming | null | do not move when not in combat |
Guard | Return to spawn position when not in combat | |
Map | Move randomly around the whole map | |
Area | Move randomly around the spawn area | |
Team | Move randomly to positions around the center of the team | |
Patrol | Move along a predefined set of waypoints | |
PatrolTeam | Move along a predefined set of waypoints, wait until everyone has reached the waypoint | |
Attack | null | never attack, never move when in combat |
Stationary | Use a random attack which is in range | |
Pursuit | Choose random attack. When in range, use it. When not in range, move into range. | |
Stalk | Choose random attack, move close to maximum range, use it. | |
Flee | Don't attack. Try to hold a minimum distance to target. |
Every monster type has a default strategy for each category. But spawn areas can manually override them. So you can have, for example, a demon castle where some demons patrol the surrounding, two demons guard the front gate, a group which ambushs any players who gets past the guards and some which roam the interior.
Milestone 6 finished
Now only skills the character possesses are listed. That was my last ToDo for milestone 6.
Next milestone will be Milestone 7: The Revenge Of The Monsters.
Next milestone will be Milestone 7: The Revenge Of The Monsters.
Potential solutions for my reverse proxy problem
Apache Websocket module:
https://github.com/disconnect/apache-websocket/blob/master/README.mdOnly seems to be able to redirect the websocket to a local binary module, not a backend server via network. Well, I could program my own module to do that, but then I could just write the whole proxy server from scratch.
Make my own
When I would write my own proxy server, I could design it completely to fit my needs. I could add some custom features, like ip-banning people from within the game or adding fake latency and jitter for testing lag compensation.Using nginx as reverse proxy with this mod:
http://www.letseehere.com/reverse-proxy-web-socketsNginx was engineered purely as a reverse proxy, so it would very likely be more efficient than Apache anyway.
HAProxy
https://jfarcand.wordpress.com/2011/10/06/configuring-haproxy-for-websocket/http://stackoverflow.com/a/4737648
HAProxy is another dedicated reverse proxy application. And as far as I can tell from these articles, WebSocket is supported out-of-the-box.
Friday, June 8, 2012
Apache mod_proxy can't websocket
Today I tried to set up a simplified version of the network setup I described using some VirtualBox virtual machines running Ubuntu Server. It just had three machines instead of the planned six: the reverse proxy, a gameserver which also ran the MongoDB, and a LAMP server with the client files.
It turned out, apache configured as reverse proxy can not route WebSocket transparently. It strips the Upgrade line from the http headers, sabotaging the handshake.
Now I have to find another proxy server which is able to handle WebSocket.
Or maybe I just write my own reverse proxy. It can't be that difficult. Listen to socket, wait for HTTP header. when it has Upgrade:websocket, forward the tcp stream to the application server, when it hasn't, forward it to the web server. It should be possible to hack together in C in an afternoon and it will most likely be much less bloated than using the humongous Apache HTTP Server.
It turned out, apache configured as reverse proxy can not route WebSocket transparently. It strips the Upgrade line from the http headers, sabotaging the handshake.
Now I have to find another proxy server which is able to handle WebSocket.
Or maybe I just write my own reverse proxy. It can't be that difficult. Listen to socket, wait for HTTP header. when it has Upgrade:websocket, forward the tcp stream to the application server, when it hasn't, forward it to the web server. It should be possible to hack together in C in an afternoon and it will most likely be much less bloated than using the humongous Apache HTTP Server.
Thursday, June 7, 2012
No quest log clutter
The problem with many RPGs of today - both single-player and multi-player - is that they figuratively bombard the player with quests. When you come to a new town you can quickly fill your quest log with 10 or so unrelated things to do. The order in which to do them is left to you. When you are like me, you prioritize all these quests after practical concerns: minimizing travel time, prioritizing quests with rewards I need, or do those first with the lowest level requirement.
The problem with that is that it really kills the narration of each individual quest. Adventuring and storytelling is replaced with managing a checklist. How can you expect the player to follow ten story arcs simultaneously?
For that reason I think that it would be better to abandon the quest log for a mission system like the GTA series. I give you lots of quests to choose from, and you are free to do them in any order you like. But you can only have one active quest at a time. You can abort a quest when you are stuck, but then you have to start it from the beginning. Quests won't be that long, so you won't have to redo too much. Longer storylines will consist of a series of many consequitve quests. The next quest of the series should be offered right after the previous, so that it's clear that they belong together. They still give you the option to decline for now and pursue other quests first.
That way you will be able to fully immerse yourself in the story of a quest without being distracted by the twenty other quests on your questlog.
But what about sidequests? Little surprise challenges along the way? These should also have a space, but they need to be designed in a way that they can be done in the direct vicinity so that you aren't taken too far away from the quest you pursue at the moment.
How will this look in practice? Quest givers will still be marked with different icons telling you 1. if they offer a quest of a new line or the continuation of an existing one (shape) and 2. the length of the quest line (color). These icons will be visible while being on a different quest, but you won't be able to interact with the quest givers yet.
Quest lengths:
quick: a single quest which can be done in the direct vicinity of the quest giver. These can be taken without interrupting an on-going quest because they will be too short to distract too much.
short: a single quest which requires some travelling.
medium: 2-3 consecutive quests, or one with a very long travelling distance and/or multiple optional sidequests along the way.
long: 4-6 consecutive quests, or less but with long travel distances
epic: 7 or more stations, might include planned interruptions where the next quest giver won't be obvious right away or which have "nested" quests - quests which require that other questlines (which will be integrated into the narration) have to be completed in-between.
Example for an epic quests with nesting: 1. find out about an artefact which is broken into three pieces, 2- complete three separate medium-length quests to collect the pieces, 3. reconstruct the artefact 4. use it to destroy a boss monster.
The problem with that is that it really kills the narration of each individual quest. Adventuring and storytelling is replaced with managing a checklist. How can you expect the player to follow ten story arcs simultaneously?
For that reason I think that it would be better to abandon the quest log for a mission system like the GTA series. I give you lots of quests to choose from, and you are free to do them in any order you like. But you can only have one active quest at a time. You can abort a quest when you are stuck, but then you have to start it from the beginning. Quests won't be that long, so you won't have to redo too much. Longer storylines will consist of a series of many consequitve quests. The next quest of the series should be offered right after the previous, so that it's clear that they belong together. They still give you the option to decline for now and pursue other quests first.
That way you will be able to fully immerse yourself in the story of a quest without being distracted by the twenty other quests on your questlog.
But what about sidequests? Little surprise challenges along the way? These should also have a space, but they need to be designed in a way that they can be done in the direct vicinity so that you aren't taken too far away from the quest you pursue at the moment.
How will this look in practice? Quest givers will still be marked with different icons telling you 1. if they offer a quest of a new line or the continuation of an existing one (shape) and 2. the length of the quest line (color). These icons will be visible while being on a different quest, but you won't be able to interact with the quest givers yet.
Quest lengths:
quick: a single quest which can be done in the direct vicinity of the quest giver. These can be taken without interrupting an on-going quest because they will be too short to distract too much.
short: a single quest which requires some travelling.
medium: 2-3 consecutive quests, or one with a very long travelling distance and/or multiple optional sidequests along the way.
long: 4-6 consecutive quests, or less but with long travel distances
epic: 7 or more stations, might include planned interruptions where the next quest giver won't be obvious right away or which have "nested" quests - quests which require that other questlines (which will be integrated into the narration) have to be completed in-between.
Example for an epic quests with nesting: 1. find out about an artefact which is broken into three pieces, 2- complete three separate medium-length quests to collect the pieces, 3. reconstruct the artefact 4. use it to destroy a boss monster.
Wednesday, June 6, 2012
Stat increase buttons
I added buttons for spending status points to increase stats. The skill display must be made a bit more dynamic. Those hardcoded skill names got to go in exchange for dynamic names obtained from netcode so that it doesn't list skills the player hasn't learned yet.
Tuesday, June 5, 2012
Added stat points
I added status points and the netcode to increase stats.
Currently, the collected status points are equal to the collected skill exp. But I intend to decouple that, so that some monsters give better skill exp while others give more stat points. Also, most quests will give only stat points, because giving skill exp would only make sense when the quest focuses on the training of that specific skill.
The client still needs buttons for increasing stats and I need to communicate the costs for doing so.
Currently, the collected status points are equal to the collected skill exp. But I intend to decouple that, so that some monsters give better skill exp while others give more stat points. Also, most quests will give only stat points, because giving skill exp would only make sense when the quest focuses on the training of that specific skill.
The client still needs buttons for increasing stats and I need to communicate the costs for doing so.
Friday, June 1, 2012
Some bugfixes
Yesterday I fixed a long-standing bug which was setting the players position to an illegal value of "-Infinity : -Infinity".
I also added filtering of HTML tags from the chat console on the client. Using HTML markup in chat might have had some useful applications, but the risk that players find a way to abuse this feature to screw with each others interface or even inject XSS code is just too big. I could have filtered user input on the server, but 1. I don't want the server to assume that the presentation layer is rendering HTML and 2. I am not sure I would catch any case where a user-supplied string ends up in the chat console.
To make up for this and allow some markup in chat, like bold text, colors, graphical smilies or hyperlinks, I could later add a custom markup language like BBCode. Links will require some additional filtering. I don't want people to click on javascript: links in the chat.
I also added filtering of HTML tags from the chat console on the client. Using HTML markup in chat might have had some useful applications, but the risk that players find a way to abuse this feature to screw with each others interface or even inject XSS code is just too big. I could have filtered user input on the server, but 1. I don't want the server to assume that the presentation layer is rendering HTML and 2. I am not sure I would catch any case where a user-supplied string ends up in the chat console.
To make up for this and allow some markup in chat, like bold text, colors, graphical smilies or hyperlinks, I could later add a custom markup language like BBCode. Links will require some additional filtering. I don't want people to click on javascript: links in the chat.
Subscribe to:
Posts (Atom)