LO's Sharp Devs

C# , XNA Game Development Blog. Intentionally more than only for game authors but for C# programmers in general.

Moje zdjęcie
Nazwa:
Lokalizacja: Poland

niedziela, 11 stycznia 2009

[Game Design] Dynamic Quests

I could just not stop myself from extending that idea that I roughly sketched in the previous article.

First - imagine that we have several classes that describe quest(s) "statically" - so how this is presented in Quest Editor.

Therefore we have some Scenario object that is being processed by responsible ScenarioManager class. During the game that manager class founds that some activation (like this is stored in scenario - dialog option, item picked, area entered or whatever) of a new quest happened. It then sends identification number of that quest and pointer to the activator to contained class of QuestsManager to take care of the rest.

Now QM checks the type of the quest and expected result from manager (In many cases it might be specific branch of dialogue, message to be displayed, or player's log entry or all at once. Anyway QM shall also check if quest that is not generic has not been already finished or started - internal integrity check that shall be found during QA process but also left in runtime - especially if game provides custom content. So far it goes normal. Generic quests is a matter for another entry so let us just consider that we just found a pure new dynamic quest started by picking cursed Sword of Slow Death...

In the script we have written that the curse cannot be taken away by normal methods or dispells but requires special treatment. In the quest the item is not dynamic, only the temple and person-to-talk are picked randomly. While there is no direct entry dialogue we must consider serious modification of game world for that quest. So there is no specific result returned to ScenarioManager.

QM orders QuestFactory class to build runtime data for given quest. QF loads static data and first of all creates array of variables that might be used during it initialization script. In our case there is going to happen quite much in that script - first of all it shall check if the activator is really that sword and if the curse flag remains in place. Therefore we are sure that default behaviors of the cursed possessions apply. We then check if expected special script is attached to the Sword's OnSpellCast() event. Last thing is attaching to the player curse script - that is also not a general one.

Curse script is gradually reducing player's endurance (just reducing, any curing spells or potions restore it) and each game hour it displays message - "You feel weaker..." when that happens. Much more interesting is script that is being executed each time the spell is being cast upon the sword. In just allows spells work normally until they have effects of dispell, uncurse, disintegrate, identification or similar (no exact spells, that might be created after quest script but particular effects that we are interested in).

When player tries to remove curse (dispell, uncurse) we return 100% resistance / failure and for FIRST such spell effect we register additional dialog branches for ANY priest or mage in the world (yep, game engine shall support that of course). For desintegrate spell there is 95% chance of failure and same registration of dialogs. If desegregation succeeds - quest and curse are just being removed, but not curse effects that shall be cured normally. For identification spells we display to the player some extra box with message "There is so strong curse on that Sword, that only highly qualified Priest or Mage can know more about it" and then allow standard identification dialog to appear with curse details (or not? SilentFail status? up to the Designer)

Then player have to visit any Mage or Priest and go that dialog branch for the cursed sword. He might be luck enough to ask person proficient enough at first try - then we just jump to the next stage. If not - there is first dynamic modification - we pick accordingly to the interlocutor 15 lvl Mage or Priest he might suggest to us (if our game has living world it may also be that he shall also KNOW that person exists - the he would only point us higher) to talk to. We shall have vast amount of options to define how this randomization shall happen - like localization, availability, if that location was already visited or do we have current entry permission there or just ignore all such obstacles and let the player find solution (by generic quests). We choose them all in Quest Editor and feed randomization engine. If there is NO location or person - engine shall be capable of creating one in game environment dynamically - and such change shall be therefore constant (well, until someone kills the mage...).
Anyway, quest factory then executes ScenarioManager.RegisterKeyElements() with the mage himself and his location. Therefore player will be warned when he tries to lock / kill / destroy object or person that he has quest(s) attached to. Of course player (or in living game world - other NPC or monster) could kill such person and not just being faced immortal character. If so - the quest shall generate a WORKAROUND branch - returning to last mage or other temple and ask again, or finding some scroll with the mage that informs about his master, or whatever. Such things shall be possible to hardcode in quest's script or generated by engine accordingly to similar rules used to generate dynamic branch. For example we shall decide if we just want replacement for current step or way that lead us back to previous one to try again. In our situation it shall be some cynical comment told by avatar - "Well, I just guess that I shall look for another mage..." and reset script few steps back.
For more details - we can then join such us dynamic quest with generic quests - for example our mage knows resolution for our problem and can do that for free but or requires some favor (service or possibly a "kiss" from female character) or component that is required to fulfill the spell. Anything - we can define strict steps in the quest or just define criteria for generic quest generation and wait with baseline until finished.

Let us then imagine that we bring that compound and find mage dead. In traditional scripting (and storyline) it would be intentional event with ready solution - player is supposed to find some track, person or anything that would lead him deeper into the story. This leads dynamic design much more complicated - we shall create workaround that will not interfere with already done parts and will not generate possible infinite loop (let us just imagine that some NPC just gone on his rampage and murders all high level mages...). Probably best solution would be to find yet another mage and continue from there. But how to prevent another generic quest from him? If previous quest was a simple service we might just pay him for casting spell and quest ends. But if we were supposed to find some compound required for spell this gets to be a little harder...

Game shall track therefore all such generic subquest progresses and have additional dialogues to make it smooth - like we just telling new wizard that we have required spell component. This also leads to another idea - that all generic subquests shall be prepared with special care for failures, additional dialogue lines - preferably also with randomization and variatization. A lot of work, carefull and complicated work. But final results might be astonishing!

We can also define maximum or default amount of generic subquests or default quest lines if generic fail... A lot things to consider by the designers.

In the end, after quest finishes all remaining scripts, dialog options that are still bounded to the quest are removed (so after curse is taken out of the sword, except taking out curse spell effect from itself and player, curse flag and scripts there also shall be removed quest id from the sword - all shall be considered by QuestEnds() script). This not touch log /diary entries - these are just moved to "Finished" branch. Therefore old data is no longer wasting place in save and memory.
All KeyElement flags are also removed from objects.

I hope that this article would help one build his own great questing system :)

sobota, 10 stycznia 2009

[Game Design] Synthetic voices part. 1

I consider that topic realization as far future, but would share my idea with the industry - maybe someone already started that and would like some bright review on the topic :)

Currently we have two realizations of voice acting in games - there are no voices in games (cheap productions) or voices are recorder from (professional) actors. While for simpler games it's possible to do that easily (not so much text to record) it's getting harder for adventure or RPG games - there is so much text that voiced is only part of it, or eventually dialogs are very limited and considerably short (see Oblivion or Fallout 3).

Anyway it's still A LOT to record - not even mentioning mastering that to have normalized volume output - from many actors, record same sentences from different actors, or record several similar sentences from one actor for different situations or even mix of two. The serious drawback is that therefore some dynamic texts that could be visible in dialogs (for example changing rank of the hero when he is being addressed to) are or skipped at all or only written in captions. This also makes writing dialogs and texts at all harder - designers have to consider all those limitations.

Another limitation is localization and internationalization support - while English without conjugation, declination and sex independent sentences is quite charming for that - localizing dialogs that do not consider differences is pain in the ass. Some dialogs that might appear in game are prepared dependently of the sex of hero - but not all, and this leads into even more voices to record. And only consider that sex of both sides of one dialog can vary...

This limits also creation of "generic" or "dynamic" quests. The first category could be incorporated into advanced roguelike games - where same quest line could be modified only with different locations, items or people names to get new quests of similar type. The second one could be used to increase playability factor by assigning limited quests to different people, places or items for each new game (or when key person or item is no longer available - this could help the game to fight so unnatural existence of immortal people in Fallout 3 or Oblivion, without ruining quest plot). Again - in English this is very easy. Consider some classical dialog line like:

I think that for more information about that Ring of Destruction you might ask John Bussack up there in Rovannon.

Fine, let us imagine that considerable dialog script looks like:

I think that for more information about that [Item(CurrentQuestItem(3)).Name] you might ask [Person(CurrentQuestPerson(1)).Name] up there in [Location(CurrentQuestLocation(2)).Name].

Complicated? Not so. But there is no information about sex of person that says that what would led into more complicated script.

Let us consider now translating this into Polish (language that uses postfixes to determine exact language forms). And consider that we have already implemented library that will do all conjugations and declinations automatically (or basing on dictionary - it doesn't matter now).

Wydaje mi się, że aby uzyskać informacje o tym [Decline(Item(CurrentQuestItem(3)).Name, Declinator.Locative, NounNumber.Singular] [ConjugateForSex("powinien", PlayerSex(), VerbNumber.Singular, VerbPerson.Second, VerbMode.Supposition, VerbTime.Past)] [Conjugate("pytać", VerbMode.Fulfillment, VerbPerson.Infinitive)] [Decline(Person(CurrentQuestPerson(1)).Name, Declinator.Accusative, NounNumber.Singular] w [Decline(Location(CurrentQuestLocation(2)).Name, Declinator.Locative, NounNumber.Singular].

Uhh... hard one, isn't it? I would therefore reconsider all conjugation grammar and just write the sentence splitter - or in the code or directly storing 2-4 versions of the sentence for each combination of interlocutors' sex. In first example it could look something like (sentence is constructed so sex of person that talks doesn't matter so we care only of the sex of addressed person):

Wydaje mi się, że aby uzyskać informacje o tym [Decline(Item(CurrentQuestItem(3)).Name, Declinator.Locative, NounNumber.Singular] [IF(PlayerSex(), Sex.Male)]powinieneś[ELSE]powinnaś[ENDIF] spytać[Decline(Person(CurrentQuestPerson(1)).Name, Declinator.Accusative, NounNumber.Singular] w [Decline(Location(CurrentQuestLocation(2)).Name, Declinator.Locative, NounNumber.Singular].

Or even such IF could be made for whole sentence for better readability. Expected result might be something like (for first example it of course depends on gramatization engine) - if player character is male:

Wydaje mi się, że aby uzyskać informacje o tym Pierścieiu Zagłady powinieneś spytać Johna Bussacka w Rovannon.

This of course do not takes information that form of "o tym" is dependent of the "sex"of the ring (both in English and in Polish - this is masculine) that would considerably complicate the script. Therefore I suppose that creation of such dynamic sentences is a far future (until very good translation supporting tools - here this would be great if script is being generated from EXAMPLE translation and supported by handy list of usable items obtained form original sentence). So I think this is still a far future, not even mentioning recording dynamic voices for all this things, or even mastering them so such dynamic sentences built from different sound parts sound correctly. Some resolution may be such construction of translations that are independent of all this changing forms and only switch the dependently of the sex. But suspected results most of the time will not sound very natural.

What about when voice of the person just not "fits" to how this person looks like? The exact timbre of the person depends on many different elements, but construction of the skull bays is one of the most important - this is resonance box of human being. Therefore we subliminally expect person of given features or body build to sound in some way or another. And when he or she sounds different - we are surprised. How therefore align same sentence to different people? They shall not sound the same!

In the next part of this article I will share with you some concept I have to deal with that voice recording problem.

Etykiety: