Code-base design approaches

 
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding
View previous topic :: View next topic  
Author Message
gerund



Joined: 24 Nov 2005
Posts: 14

PostPosted: Sun Jun 24, 2007 6:43 am    Post subject: Code-base design approaches Reply with quote

Hi,

I was discussing this topic with someone and I thought I would throw the questions out there to see how others both do it, and think it should be done.

>8 ------ paraphrased email starts ------ >8

Take, for example, a shield that halves all damage dealt to its wearer. Using one model you might create a subscription for all damage events dealt to the wearer of the shield so that when that event came along you could reduce the damage by half.

This raises a bunch of questions:

1) How do you actually go about reducing the damage by half? Do you modify the event directly?

2) How do you guarantee that your 'preemptive' subscription is notified before the 'reactive' subscriptions (like the one that actually applies the
damage) to the player model?

3) How do you manage the necessary subscription changes when the player gives the shield to his buddy, or sells it to a vendor?

>8 ------ paraphrased email ends ------ >8

Any thoughts?
Back to top
View user's profile Send private message
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Mon Jun 25, 2007 2:29 am    Post subject: Reply with quote

I'm not meaning to sound... condescending... but these are fairly easy questions to answer, at least in my opinion.

Assuming that we're talking about development in an "object-oriented" model, we want all objects to be separate from one another, not meshed together into some sort of weird amalgamous blob.

With that said, how it works in the little graphical game project I'm working on (which is really just a MUD with some basic sprites thrown on top)...

Let's say for the sake of argument, that all characters (we call them avatars) are capable of doing some manner of damage, we don't have weapons per say but more like chess pieces, each avatar does a fixed amount of damage based upon a calculation of their total health remaining and blah blah blah. But anyway, when we want an avatar to attack, we call it's do_damage(param) function.

The param is actually just the the avatar to do an attack against. This function then calls the target avatars take_damage(param(s)) function, which is what does the meat and potatoes work of applying damage to the avatar in question.

So, let's take the example of a shield that reduces damage by half (will talk about the finer nuances of this very concept later). At the moment, my avatars do not have inventories as it were, so they don't have armor that affects damage and all that, but if they did...

I would of course, have each avatar keep a list-type container of all the objects that are currently in their possession, perhaps with a separate list or simply object flags for whether or not they are currently worn or in use. So the first thing we would do is calculate how much "base" damage is being done, that is, the raw amount of damage not taking any armor or other "reactive" modifications into account.

From there, I would (assuming that we're not dealing with specific body parts and such here) loop through the inventory and check if any of the items therein were of type armor and calculate their modification score until I arrived at a total at the end of my inventory.

You then subtract (or add) your modification from your base damage, and apply it to the health points or whatever scoring system of your avatar, check to see if he's dead or not, and conclude the "round".

I think that pretty much sums up all of your questions, but I'll try and explain each as a pointed list briefly for better illustrative measure:

1. No, you do not modify the calling event of doing damage, you modify the damage dealt to the avatar/character/mob after determining what modifications you need to make.

2. The answer to #1 answers pretty illicitly #2, by first calculating your base damage, then calculating your modifications, apply modifications to base damage and THEN do the damage. In this way, you can always be sure that things are happening as they should (hopefully).

3. By subscription changes, I'll assume that you mean making sure that once the player no longer has the shield, the modification is no longer applicable to that player, steps #1 and #2 also answer this third question. If a shield (or other piece of armor) is given away, it is removed from the player's inventory, thus, when modification is next calculated for that player, it will reflect him no longer having the shield because it is now in someone else's inventory.

Hope this helps,

Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Author Message
gerund



Joined: 24 Nov 2005
Posts: 14

PostPosted: Tue Jun 26, 2007 11:28 am    Post subject: Reply with quote

Vopisk wrote:
I'm not meaning to sound... condescending... but these are fairly easy questions to answer, at least in my opinion.


You're not. While it is easy to answer, there are actually a wide range of ways you could do this. From not having an event driven mechanism (one variant of which you gave) to doing it via the event subscriptions (as the questions were couched).

Vopisk wrote:

From there, I would (assuming that we're not dealing with specific body parts and such here) loop through the inventory and check if any of the items therein were of type armor and calculate their modification score until I arrived at a total at the end of my inventory.

You then subtract (or add) your modification from your base damage, and apply it to the health points or whatever scoring system of your avatar, check to see if he's dead or not, and conclude the "round".

I think that pretty much sums up all of your questions, but I'll try and explain each as a pointed list briefly for better illustrative measure:

1. No, you do not modify the calling event of doing damage, you modify the damage dealt to the avatar/character/mob after determining what modifications you need to make.

2. The answer to #1 answers pretty illicitly #2, by first calculating your base damage, then calculating your modifications, apply modifications to base damage and THEN do the damage. In this way, you can always be sure that things are happening as they should (hopefully).

3. By subscription changes, I'll assume that you mean making sure that once the player no longer has the shield, the modification is no longer applicable to that player, steps #1 and #2 also answer this third question. If a shield (or other piece of armor) is given away, it is removed from the player's inventory, thus, when modification is next calculated for that player, it will reflect him no longer having the shield because it is now in someone else's inventory.

Hope this helps


It absolutely does, I find it very interesting. To me it validates the event driven approach the questions were couched in terms of. I would consider them functionally equivalent. Something which is in a location to be asked when there is the opportunity for modification, basically has its ability to modify the value hard-coded. In your case, by a property on the shield I assume, and in the case of the event system, by a function coded onto the specific shield subclass.

If I had to choose between the two approaches, I would take one similar to yours. I say that because my personal interest lies in facilitating data-driven development. Someone who either doesn't have the chops to write code, can't be trusted to or just wants an easier way, can author functionality by just adding a property to a type of object. However, there are drawbacks to this approach, for instance there come to be a lot of properties the content authorers can use and they need to be well documented with respect to what types of objects they work on and when.

But I think data-driven approaches can be taken in many directions beyond this. For instance, if you make a generic property modification layer which is used for fetching definitive values, then you can just have something like:

Code:

actualDamageDone = weapon.damage * target.damageProtectionFactor


And the shield when wielded will have registered itself as modifying the 'damageProtectionFactor' property on the target. And the player might have a ring which is cursed which reduces the damage any weapon the attacking player is wielding, which registers itself as modifying the 'damage' property on any weapon they have wielded.

But while this reduces the need for modification boilerplate in any part of the code which needs to give the chance for things to involve modifiers, the problem still remains that you accrue properties which the content authorers need to be aware of the existance of, and how they can be properly used.

Anyway, thanks for the reply! This is something I have been thinking about a lot lately and a topic of great interest to me.
Back to top
View user's profile Send private message
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Tue Jun 26, 2007 2:52 pm    Post subject: Reply with quote

Happy to help.

Your equation pretty well sums up exactly what I was trying to say, but I would still council that you check both weapon.damage and target.damageProtectionFactor each round. Why? Well, because, in between rounds a weapon may become duller because a powerful strike was just blocked by an iron tower shield, which chipped the blade and thus reduced it's killing efficiency, or the said tower shield may have taken damage due to the strike and thereby be offering less protection.

If you're not one for the "weapons and armor become realistically damaged and even break during combat" school. Then you can easily just set these values upon wearing/wielding and removal of the weapons and armor and just beat the two together each round until someone dies as well. It all depends on your approach to the situation.

However, I would modify the equation also to look something like this:

actualDamageDone = weapon.damage * strike.precision/accuracy/whatever * target.damageProtectionFactor

Because I like to think that how well you swing the sword has some small thing to do with how much pain you inflict. Good luck with your project and feel free to ask any further questions. If I can't answer them, I'm sure one of the other lurkers around here can.

-Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Author Message
Vaeshir



Joined: 26 Jun 2007
Posts: 2
Location: Seattle, WA

PostPosted: Tue Jun 26, 2007 5:05 pm    Post subject: Reply with quote

I would avoid systems like the one you've described if non-technical people are going to be implementing game behavior.

Take, for example, the following behaviors:
    * A magical sword that, instead of dealing damage produces a cloud of butterflies when it strikes a foe.
    * A holy sword that cannot be swung unless its bearer is of good alignment.

Unless you anticipated these sorts of use cases you would need to make some changes in order to support them. You could alter your system so that it supports these kinds of behaviors, but the problem is that you would be required to make code changes. What you want is for your game designers to be able to implement this additional behavior using only scripts. A 'property modification layer', or something similar would give game designers great flexibility in changing the variables that are included in the damage calculation, but it does not allow them to change the rules that govern the behavior of the objects.

What you really want is a more generic 'rule definition layer'.

gerund wrote:
I say that because my personal interest lies in facilitating data-driven development.


I see no reason why event-based are not suitable for data-driven development. You could implement a system in which game designers define two types of data: The objects themselves that contain game state (swords, shields, armor), and the rules that govern the behavior of those objects. For the game objects themselves you can implement a simple, database-like CRUD system. For the game rules you would probably want to write a domain specific language for the game designers to use.

For example:
Code:
ON event.type IS damage
   IF event.target WEARS shield
   THEN SET event.damage TO event.damage / shield.protection


This sort of system is great because it satisfies the 'open/closed' principle; it possible to add additional game behavior without having to modify the existing scripts. Game designers can add additional behavior without modifying the existing game rules. For exmaple, implementing a cursed room in which all damage is doubled would be as simple as adding another rule:

Code:
ON event.type IS damage
   IF cursed_room IS event.source.location
   THEN SET event.damage TO event.damage * room.damage_amplifier


When a damage event is fired, both rules would be applied to it resulting in an overall damage equal to the damage of the sword multiplied by damage amplifier of the room divided by the protection of the shield.
Back to top
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Wed Jun 27, 2007 12:14 am    Post subject: Reply with quote

Interesting take on the matter Vaeshir, I can see the benefits of such a system rather clearly. Being able to easily override default behavior and assign custom behavior to objects, rooms, people or whatever else is a neat idea.

The only issue I see here is in terms of balancing, (I know I'm about to get the "hire trustworthy people" lecture, but oh well...). What I mean is that unless you have the game sandboxed (where development occurs on a separate port/server and changes are migrated), it could be pretty easy for a builder or other development type to accidentally implement a weapon, armor or mob that pretty much runs rampant through the game and causes massive havoc before an admin has a chance to come around and bring it under control.

It's as easy as having your multiplication mixed up with division, or multiplying by the wrong variable, so a player gets a Sword of Enhanced Damage that is broken and actually does so much damage in a single swing that he can take down anything in the game, other players, mobs, etc... This player might be the upstanding type who says, oh, this sword is most definitely broken, let me report it and not use it, or he might be the type to leave you with a MUD full of ghosts. Just one of those things to consider when thinking about giving such power into the hands of those who are working for you.

That said, I still think your idea is a good one, I just felt I should throw out that little "be careful" warning. The holy sword issue really doesn't have any impact on the system that I previously proposed, it's easy to check, either upon wielding or for each combat round what the character's alignment is and subsequently either let them attack or not attack, I was stripping things down to bare basics above to just show the issues asked about in the OP.

The Sword of a Thousand Butterflies however... I'm not sure that one fits in with the above and is certainly a thing worth thinking about, which I'm off to do now.

-Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Author Message
Vaeshir



Joined: 26 Jun 2007
Posts: 2
Location: Seattle, WA

PostPosted: Wed Jun 27, 2007 3:05 am    Post subject: Reply with quote

Vopisk wrote:
It's as easy as having your multiplication mixed up with division, or multiplying by the wrong variable, so a player gets a Sword of Enhanced Damage that is broken and actually does so much damage in a single swing that he can take down anything in the game, other players, mobs, etc... This player might be the upstanding type who says, oh, this sword is most definitely broken, let me report it and not use it, or he might be the type to leave you with a MUD full of ghosts. Just one of those things to consider when thinking about giving such power into the hands of those who are working for you.

That's definitely a concern (although isn't the specific pitfall of overpowered items possible in both models?). I would also be really worried about debugging. As your world grows you'll likely have more and more rule sets participating in the resolution of each event. It could get really difficult to figure out what's going on if something goes wrong. That's the price you pay for flexibility, I suppose.
Back to top
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Wed Jun 27, 2007 11:35 am    Post subject: Reply with quote

Yeah, you're right about the level of complex abstraction you would get by allowing individual items to be so free-form scripted, with rules for specific rooms, entire zones, individuals, their weapons and their armor. It could definitely become a problem to track down a pesky bug.

And yes, over-powered weapons and armor are a possibility in both systems, but my point kinda ties in with that above, it can be a lot harder to find when something might be attached to a single, isolated instance of an object rather than on all objects of X "type".

-Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Author Message
gerund



Joined: 24 Nov 2005
Posts: 14

PostPosted: Thu Jun 28, 2007 7:25 am    Post subject: Reply with quote

Vaeshir wrote:
I would avoid systems like the one you've described if non-technical people are going to be implementing game behavior.


That is true if it is the only system which everything is based on. But for me it would be only one component of a larger system which, as it happens, is rule inspired.

Vaeshir wrote:

Take, for example, the following behaviors:
    * A magical sword that, instead of dealing damage produces a cloud of butterflies when it strikes a foe.
    * A holy sword that cannot be swung unless its bearer is of good alignment.

Unless you anticipated these sorts of use cases you would need to make some changes in order to support them. You could alter your system so that it supports these kinds of behaviors, but the problem is that you would be required to make code changes. What you want is for your game designers to be able to implement this additional behavior using only scripts. A 'property modification layer', or something similar would give game designers great flexibility in changing the variables that are included in the damage calculation, but it does not allow them to change the rules that govern the behavior of the objects.

What you really want is a more generic 'rule definition layer'.


Allowing the game designers to create new behaviours outside the scope of what can be done through the property modifications they can set up is definitely beneficial. But one thing you might notice is that the examples you give are oriented towards immediate results. This is a downside to a rule-based approach, where everything needs to be posited in terms of 'given a certain eventuality, do the following'. Now of course you can make the rule layer more extensive, but this just takes you closer and closer to having the game designers using a complicated programming language. But complication doesn't have to be done badly, so that isn't bad unless it is made badly.

Vaeshir wrote:

gerund wrote:
I say that because my personal interest lies in facilitating data-driven development.


I see no reason why event-based are not suitable for data-driven development. You could implement a system in which game designers define two types of data: The objects themselves that contain game state (swords, shields, armor), and the rules that govern the behavior of those objects. For the game objects themselves you can implement a simple, database-like CRUD system. For the game rules you would probably want to write a domain specific language for the game designers to use.

For example:
Code:
ON event.type IS damage
   IF event.target WEARS shield
   THEN SET event.damage TO event.damage / shield.protection


This sort of system is great because it satisfies the 'open/closed' principle; it possible to add additional game behavior without having to modify the existing scripts. Game designers can add additional behavior without modifying the existing game rules. For exmaple, implementing a cursed room in which all damage is doubled would be as simple as adding another rule:

Code:
ON event.type IS damage
   IF cursed_room IS event.source.location
   THEN SET event.damage TO event.damage * room.damage_amplifier


When a damage event is fired, both rules would be applied to it resulting in an overall damage equal to the damage of the sword multiplied by damage amplifier of the room divided by the protection of the shield.


I personally think that modifications are still best handled by an abstraction layer, and when I see them structured as duration-less as they are applying their effect immediately in an event, it seems like they have been forced to fit into the rules model in the only way they can.

Now admittedly, a rules layer can be built upon to handle different cases, like for instance registering its effect when a situation arises and reverting the effect when the situation is no longer true.

I'd be interested to hear your (or anyone else's) thoughts on that?

Cheers.
Back to top
View user's profile Send private message
Author Message
gerund



Joined: 24 Nov 2005
Posts: 14

PostPosted: Thu Jun 28, 2007 7:44 am    Post subject: Reply with quote

Vaeshir wrote:
Vopisk wrote:
It's as easy as having your multiplication mixed up with division, or multiplying by the wrong variable, so a player gets a Sword of Enhanced Damage that is broken and actually does so much damage in a single swing that he can take down anything in the game, other players, mobs, etc... This player might be the upstanding type who says, oh, this sword is most definitely broken, let me report it and not use it, or he might be the type to leave you with a MUD full of ghosts. Just one of those things to consider when thinking about giving such power into the hands of those who are working for you.

That's definitely a concern (although isn't the specific pitfall of overpowered items possible in both models?). I would also be really worried about debugging. As your world grows you'll likely have more and more rule sets participating in the resolution of each event. It could get really difficult to figure out what's going on if something goes wrong. That's the price you pay for flexibility, I suppose.


But is it really? All I see when I think about a rules layer, is the ability to be even more flexible when it comes to the use of it. Now, given that the rules layer is persisted in a way which can be reasoned over, you now have code as data where it would have been text in a file before.

It is possible to analyse this code, data-mine it and show reports.

Let's say that you version control all rules, and you have the ability to say that at the time of the last update from the development server to the live server, you were at revision X. The development server has since had further development to revision Y. You should be able to say, for all rules between revision X and Y:
  • Show me all the new rules.
  • Show me all the modified rules.
  • Show me all the people who worked on new rules or modified rules and what rules they touched.
  • Break down all the elements used in new or modified rules and index the relevant rules under each element involved in them. Then for instance, you might be able to see that 12 rules were relating to damage and verify them by eye.
I hope that illustrates the idea.

And for debugging I would hope an implementation would be able to detect invocation of side-effects. So when you have damage and you fire all the rules which are tied to it, you can make a list of all those which applied side effects and those which didn't, and be able to say if needed what change each made. Normally you would just fire the rules and let them do their thing. And given something going wrong, you could insert some flag which when a condition arose, it would record the full information about the firing of rules.

Now while I have done data-mining on a rules-like "code as data" language, and I have a fair idea of all the things which I can achieve with it, based on what I have achieved with it. I have never written my own rules-based language. But I have played with OpenCyc and read quite a bit and done a few similar things. Perhaps I am talking crazy talk Smile In which case feel free to put me in my place.
Back to top
View user's profile Send private message
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Thu Jun 28, 2007 2:51 pm    Post subject: Reply with quote

No, you're right, if you use some manner of SVN repository to keep your files up-to-date and keep track of updates, then it's fairly easy to roll-back and figure out where something went wrong. However, the suggested "issue" if you will, was that an overpowered weapon or armor or nerfed mob or something could be inserted into the game and have widespread fallout before you're able to review it by eye, assuming that one or a small, select group of people would be in charge of screening new updates.

For example, if the weapon is over-powered, you might find yourself with two or three max-level characters that were newbies the day before because they found or were given one of these swords, or their over-powered suit of armor allowed them to walk into the dragon's lair and take what they felt like at their leisure, while confidently ignoring the Dragon's fire breath attacks. Thus giving them far more loot than they should ever have at their low level.

What do you do in these cases? It is the developer who designed this flawed sword or armor in the first place, the players were just using a tool given them in the game. Do you take back what the players made during that time period? Say, all their experience and/or gold, but what about what they COULD have gotten if they didn't have the sword/armor? As you can probably see, it's a slippery slope and one that needs to be thought about BEFORE allowing developers this kind of control over your world.

One of my current projects is an LP, where the system pretty much works as suggested, items are just coded in C, so you can basically add whatever functionality you want. I could write a sword that just calls the die() function of the target, I would be insane, cause I'd be dropped faster than a hot potato, but I think it makes my point. You're waving around a double-edged sword when you implement free-form development outside of a structured "rules" system, but the rewards can be equally as great as the dangers.

-Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Author Message
gerund



Joined: 24 Nov 2005
Posts: 14

PostPosted: Fri Jun 29, 2007 7:43 am    Post subject: Reply with quote

Vopisk wrote:
What do you do in these cases? It is the developer who designed this flawed sword or armor in the first place, the players were just using a tool given them in the game. Do you take back what the players made during that time period? Say, all their experience and/or gold, but what about what they COULD have gotten if they didn't have the sword/armor? As you can probably see, it's a slippery slope and one that needs to be thought about BEFORE allowing developers this kind of control over your world.


What I was wanting to suggest in my other post but got a bit lost in doing so, was that when you can analyse the effect of code (without executing it) you have the ability to make the slope less slippery.

For instance, all modifications to the damage attribute can be found and indexed. Then create a high level overview, perhaps of the distribution of values the attribute is being modified by. If it looks suspicious, then the code in question can be drilled down to.

Or various ranges of property modifications can be flagged as possibly questionable. And also low-level functions like 'die'. Then when new changes are analysed, code paths can be followed down and if anything questionable is hit, flag the changes as needing review.

Of course, there are limits to what can be detected. When you have a property layer handling placement of modifications abstractly, and things which modify things are getting modified, it can become complicated to reasonably work out what is questionable.

The key aspect is that by being able to analyse the intent of new content, the work involved in reviewing that content can be reduced. And I hope I have illustrated it well enough this time.

Vopisk wrote:
One of my current projects is an LP, where the system pretty much works as suggested, items are just coded in C, so you can basically add whatever functionality you want. I could write a sword that just calls the die() function of the target, I would be insane, cause I'd be dropped faster than a hot potato, but I think it makes my point. You're waving around a double-edged sword when you implement free-form development outside of a structured "rules" system, but the rewards can be equally as great as the dangers.


An abstracted layer (perhaps rules-based) above the lower level language (perhaps LPC) can allow pretty much everything that the lower level language can. Unless the abstracted layer is intentionally limited, badly designed or not designed/intended to allow analysis, use of the lower level language would actually be detrimental because what it did was define content ouside of that which could be validated and analysed. I talk in terms of an abstracted layer, because rules to me would only be part of a wider system of functionality abstracted above a lower level language.

What I am trying to say is that sticking with LPC is not necessarily more rewarding depending on how the abstracted layer was implemented.

In fact, what this reminds me of is Inform 7. That is a powerful tool (rules based to some extent) which is translated to a lower level language (Inform 6). I imagine something similar could be done within an LP driver, where a custom language translated to LPC. You can even allow embedded snippets of the base language when the overlaying one is not precise enough, as Inform 7 does with Inform 6.

Anyway, I hope I have managed to be clearer and more on point.
Back to top
View user's profile Send private message
Author Message
Vopisk



Joined: 22 Aug 2005
Posts: 99
Location: Golden Valley, Arizona, USA

PostPosted: Fri Jun 29, 2007 12:02 pm    Post subject: Reply with quote

You've made good points with all your posts Gerund, but I think I better get the gist of what you're trying to say this time around. I have acknowledged before that there are ways that either system (scripted or rules-based I'll call them) can be borked beyond hope and someone is left to pick up the pieces, and I do agree that scripting allows much greater freedom in developer design than rigid rules, where something new must be added by the supreme authority (sys admin?) before they can be put into play.

Anyway, not really too much to add to this at this point, just wanted to point out that I did understand your argument. Have a good day. Smile

-Vopisk
Back to top
View user's profile Send private message AIM Address MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2002 phpBB Group
BBTech Template by © 2003-04 MDesign