I'm making a small text browser RPG game using PHP, MySQL and Java Script (and jQuery). All the items are saved in the MySQL database.
Every now and then a character have to make a skill roll (Talk, Climb, Sneak, etc. ), but I have the following problem - some of the items give passive bonuses to some skills. Let's say we have Official Suit item, it gives +1 to Talk rolls and One time use only - automatic success on a Talk roll.
My problem is the following - how can I implement a function for every item, that gives the bonuses or other options when the appropriate roll is made. I want when the player click the Talk option, a function to be run that makes the Talk roll and searches character's inventory for items that give him bonuses to that roll. If it sees that the player have such an item, let's say it's the Official Suit, it runs the item's function which gives the +1 Talk bonus and if the roll fails, the function gives an option to use the special ability of the item for automatic success.
So what is the best way to do this? Keywords to each item or some other way? I can't think of a scalable solution.
Answer
Here is one way to do it:
CalculateCharacterStatEvent
Define a CalculateCharacterStatEvent with properties sender (the Character object that raised the event), stat (the name of the stat that is to be calculated), bonusAbsolute and bonusPercentageBased and some setter functions to manipulate the bonus properties, like increaseBonusAbsolute().
Items and event listeners
Add the item's bonuses in the item's reactToCalculateCharacterStatEvent() method. For example:
public function reactToCalculateCharacterStatEvent($event) {
// The event listener only reacts if the talk skill is calculated
if($event->getStat() == "talk") {
// Increase the item bonus depending on the Character's intelligence
if($event->sender->intelligence < 6) {
$event->increaseBonusAbsolute(1);
} else {
$event->increaseBonusAbsolute(2);
}
}
}
Event listener registration
When you load the items, register the item's event handler reactToCalculateCharacterStatEvent at the Character object, so that it is called whenever the Character object raises a CalculateCharacterStatEvent.
Character class and event raisers
In the Character class, define functions that return character stats, like getAttribute() or getSkillLevel(). At the beginning of your getStat() functions, raise a CalculateCharacterStatEvent. This will give the item's event listeners a chance to respond to the event by changing its bonusAbsolute and bonusPercentage values. Use these values to modify the result of your getStat() methods. For example:
getSkillTalking() {
$event = new CalculateCharacterStatEvent($this, "talking");
$this->raiseEvent($event);
$base = 5; // or some logic to determine the base stats
return $base * $event->getBonusPercentage + $event->getBonusAbsolute();
}
Option to automatically succeed
In order to add functionalities to items, you can just add new event classes, event raisers in the Character class, and new event listeners in the item classes.
For example: you could add an event called FailedSkillCheckEvent and an event listener reactToFailedSkillCheckEvent() in the item classes. When a skill check fails, the Character class raises a FailedSkillCheckEvent. The items's event listeners then have an opportunity to react by adding recovery options to the event object. After raising the FailedSkillCheckEvent, the skill check method continues depending on whether or not there are recovery options listed in the FailedSkillcheckEvent.
Further enhancements
Decorators. This basic pattern can be made more flexible by turning the item's reactTo-methods into a decorator class (Decorator pattern), which can then also be used by other game elements like status effects, passive skills, etc.
Link with data. reactToCalculateCharacterStatEvent() and other event listeners can also be linked to the item's properties so that you can edit the bonuses in a database without having to change any code for bonus assignments. (You can still code unique item behavior if you want to.)
More complex events. In the examples above, the item's event listeners have access to the sender of the event, i.e. the Character object for whom some stat is to be calculated. You could define more complex events that can pass more information to the items's event listeners. For example, you pass an object that represents the enemy of the Character object in a battle context. Your items's bonuses could then depend on the enemy's stats:
// in Character class
getSkillMelee($battle) {
$event = new CalculateCharacterBattleStatEvent($this, $battle->enemy, "melee");
$this->raiseEvent($event);
$base = 5; // or some logic to determine the base stats
return $base * $event->getBonusPercentage + $event->getBonusAbsolute();
}
// in Item class
public function reactToCalculateCharacterBattleStatEvent($event) {
if($event->getStat() == "melee") {
// Increase the item bonus depending on the Character's enemy's intelligence
if($event->enemy->intelligence < 6) {
$event->increaseBonusAbsolute(1);
} else {
$event->increaseBonusAbsolute(2);
}
}
}
No comments:
Post a Comment