Frogboy Frogboy

Elemental: Making a Quest part 2

Elemental: Making a Quest part 2

image

Yesterday, I wrote the general outline of how to make a quest.

Today, we’ll get into the nitty gritty:

My QuestPackage has these objects in it:

  1. The Quest Definition
  2. The Quest Location
  3. The Goodie Hut (Quest Destination)
  4. Tile Design of the Location
  5. Tile Design of the Destination (the goodie hut)

Items 4 and 5 are generated by the tile editor in the workshop, I just pasted them in.

The Quest Definition

I.                    Quest  Definition

a.       Display Name

b.      Repeatable (will it be spawned multiple times? 1 yes, 0 no)

c.       TriggerChance (% odds that it will be triggered when the trigger condition is met)

d.      Image (PNG of the image)

e.      QuestClass (Minor or Major. Completing a Major quest ends the game)

f.        TriggerType (What causes this quest to occur, we support the Location as well as other triggers such as population, turns, etc. This can be used to create random events which we’ll talk about in the future)

g.       TriggerOrigin (where does the event occur?)

h.      SpawnRating (how advances is the quest on a scale from 1 to 10)

i.         Description

j.        ShortTextAccept

k.       ShortTextDeny

l.         RewardText (dialog title for your reward)

m.    RewardImage (picture of what you’re getting)

n.      SuccessText (text that comes up when the quest is complete)

o.      GameModifier (message the game to do something)

                                                               i.      ModType  (with the corresponding Attribute options)

1.       GiveItem (attribute is name of item)

2.       Unit (StrVal provides the key and if necessary <Value> provides the amount)

a.       TransferUnitStat

b.      StealUnitStat

c.       Lifesteal

d.      IncreaseDecreaseUnitStats

e.      AdjustUnitStat

f.        AdjustCasterUnitStat

g.       UnlockUnitAbility

h.      CharmTarget

i.         CurHealth

j.        CurMana

k.       ManaBurn

l.         GiveExperience

m.    UnitJoinArmy

n.      TargetMovesBack

o.      SummonUnit (UnitClass provides class name, StrVal provides title)

3.       Player

a.       Treasury

b.      SpellPointBonus

c.       AbilityBonus

d.      EssenceBonusForAllChampions

e.      UnlockResource

f.        UnlockImprovement

g.       UnlockTech

h.      UnlockUnitAction

i.         UnlockCityAction

j.        UnlockSpellbook

k.       UnlockDiplomacyWndAbility

l.         RaiseResourceCap

m.    UpgradeCityWalls

n.      ExposeCity

o.      ExposeSovereign

p.      ExposeGoodieHut

q.      SpawnQuestLocations

r.        UpdateSpawnRating

                                                                                                                                       i.      NPC

                                                                                                                                     ii.      CREATURE

                                                                                                                                    iii.      QUEST

                                                                                                                                   iv.      GOODIEHUT

                                                                                                                                     v.      CRYSTAL

                                                                                                                                   vi.      FOOD

                                                                                                                                  vii.      METAL

                                                                                                                                viii.      SHARD

                                                                                                                                   ix.      GOLD

s.       UpdateRecruitables

                                                                                                                                       i.      SPIDERS

                                                                                                                                     ii.      SHRILLS

                                                                                                                                    iii.      DRATH

                                                                                                                                   iv.      DARKLINGS

                                                                                                                                     v.      UMBERDROTHS

                                                                                                                                   vi.      DROTA

                                                                                                                                  vii.      DRAGONS

                                                                                                                                viii.      DEMONS

t.        MarriageProposal

4.       Map

a.  TransportUnit

b.  PlaceEnvironment

c.  PlaceTerrain

d.  GreaterRaiseLand

e.  RaiseLand

f.  LowerLand

g.  SetEnvironment

h.      ReviveLand

i.         DestroyObjects

j.        RandomTerraform

k.       SummonUnit

l.         CreateGoodieHut

m.    CreateResourceHoard

n.      CreateWorldProp

o.      Reveal

p.      BlockTile

5.       City

a.       SummonRandomGuardian

b.      PlaceEnvironmentOnCity

p.      QuestObjectiveDef

                                                               i.      ObjectiveID (defining its numerical ID)

                                                             ii.      NextObjectiveID (telling it where to go next or -1 if this ends the quest)

                                                            iii.      Description

                                                           iv.      GameModifier

                                                             v.      QuestConditionDef (what determines whether this quest is complete?)

1.       Class (Success of Failure)

2.       Type (what type of condition is it)

a.       ClearGoodieHut (TextData then used to say which goodiehut)

b.      KillMonster (TextData used to identify which monster)

c.       UnitKilled

d.      BuildImprovement

e.      ReturnItemToCapital

f.        ReturnItemToQuestLocation

g.       CheckForItem

h.      ReturnItemToOriginCity

i.         UnitLevelUp

j.        UnitEntersOriginCity

3.       Faction (if applicable)

4.       Flag (AllConditionsMet forces all conditions to be met for it to be a successful quest, RevealTarget is useful for showing the player where the target is)

QuestLocationType

This is used to define the tile that will be used as the quest location. You can (and probably should) use existing quest location types.

GoodieHutType

This is used if you want your quest to spawn a goodie hut to send the player to. You could always just do the “bring me 5 wolf pelts back to me and I’ll give you gold” type quest instead and make sure you are spawning wolves that have the item WolfPelt as their treasure.

Download

To download the full quest here it is:

http://dl.dropbox.com/u/8051911/Quest_UrgentMessage.zip

You will need to unzip the XML file into your elemental\data\english\core quests directory

(in the future, I have put in the request that a packaged quest can just go into the user’s quest directory)

Other Notes

The hardest thing about making quests right now is the difficulty in testing them. One typo in a quest can make it just not work. This is why I’m lobbying internally (or externally) to get a quest editor made that eases this but will require more documentation. As you can see from above, the quest system is powerful but we’ve only scratched the surface so far.

138,718 views 47 replies
Reply #26 Top

Quoting Frogboy, reply 5

Code: c++

else if( _tcsicmp( szStat, _T("TriggerType") ) == 0 )
{
    if( _tcsicmp( szValue, _T("GoodieHut") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_GOODIE_HUT );
    else if( _tcsicmp( szValue, _T("CityPopulation") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_CITY_POPULATION );
    else if( _tcsicmp( szValue, _T("TotalPopulation") ) == 0 )
...  

 

End of Frogboy's quote

Ummm.... if that is representative of the XML parsing code, I think I know why it takes a long time to load them... :omg:

Reply #27 Top

Quoting LeeLament, reply 26

Quoting Frogboy, reply 5
Code: c++

else if( _tcsicmp( szStat, _T("TriggerType") ) == 0 )
{
    if( _tcsicmp( szValue, _T("GoodieHut") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_GOODIE_HUT );
    else if( _tcsicmp( szValue, _T("CityPopulation") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_CITY_POPULATION );
    else if( _tcsicmp( szValue, _T("TotalPopulation") ) == 0 )
...  

 


Ummm.... if that is representative of the XML parsing code, I think I know why it takes a long time to load them...
End of LeeLament's quote

That's not XML parsing. That's looking at the already read in object.  We use an STL XML parser.

Reply #28 Top

Good to know, much relieved :-)  If I have more than a dozen or so strings to test like that I usually put most all the strings in the code into a red-black or AVL tree and then assign them all a unique number as a code, then I can just use switch statements everywhere.  The string tests are not repeated over and over again.  In some case I use ternary search trees as well. http://en.wikipedia.org/wiki/Ternary_search_tree

Part of my routine grind is to run VTune on the company's software and identify the performance bottlenecks.

Reply #29 Top

Quoting LeeLament, reply 28
Part of my routine grind is to run VTune on the company's software and identify the performance bottlenecks.
End of LeeLament's quote

Brad, I think someone is volunteering his services... ;P

If he's not, I have rope.

Reply #30 Top

QuestConditionDef and Triggers... do they have equivalents for non-quest stuff? I could totally USE something like that to create abilities.

Reply #31 Top

Quoting Gravedancer, reply 29


Quoting LeeLament,
reply 28
Part of my routine grind is to run VTune on the company's software and identify the performance bottlenecks.

Brad, I think someone is volunteering his services...
If he's not, I have rope.
End of Gravedancer's quote

Just trying to help.  If you mostly spend your days analyzing DMP files (crashes) and code that is responsible for performance bottlenecks, then you can kind of spot code leading to acces violations and code inefficienies on sight.  Especially the simpler cases, such as MANY _stricmp in a row!  But I digress...:blush:

I have been, all the same, following these discussions with keen interest.  It is all quite fascinating.

 

Reply #32 Top

 

Hey Frogboy, how can I have have a quest choice or objective result in spawning a unit on the map? I can use gamemodifier to create a goodiehut, or summonunit to do a standard summon that adds a unit to your stack, but I don't see a straightforward "PlaceUnit" type element within gamemodifier. And the 'encounter' thing seems to always just produce a tactical battle. 

 I was able to kind of fake it by spawning a goodiehut that looks like a unit, and then use the 'encounter' tag to have it launch a battle with the appropriate unit. But this just simulates a stationary unit, I don't think a goodiehut can wander, or is there a way to get it to wander?

 

I want to be able to get a unit to spawn within a certain radius of the questdestination, and then give it a wanderingradius. 

Reply #33 Top

Quoting Gravedancer, reply 24

Quoting Anthony_Christianson, reply 19Now, on to creating the UI for the wizard.
Wow.

I hate to ask but I'm going to anyways... how long did it take you to come up with that code?
End of Gravedancer's quote


Just a quick note about .NET and xml, the built in xml libraries and serialization are extremely handy for quickly developing a application that handles serialization and deserialization of some xml type. The bigger problem as usual is creating the gui, the xml definition itself in the code is basically made in the time it takes you to type the xml classes =P

On that note do you have XSD files for the xml files in elemental? Would spare some typing, must say I haven't looked though.

Reply #34 Top

My 2 cents...

I really hate XML parsing (and text file parsing in general) in realtime :annoyed: . It find it too cumbersome and inefficient. If i want to parse a text file, i usually make an external parsing tool that takes the text file and converts it into binary form. Then in realtime i would load the binary file.

It's faster, memory efficient and avoids string manipulation in the main app. The downside is that you always have to run the tool after every change you make, plus if rules change i'll have to adapt both the tool and the main app. 

But i'm a hardware, not software, engineer so i tend to work on memories <<1GB (or preferably no external memory at all) and execution speed is uber-critical, so the extra hassle seems logical.

It's probably a small overhead for today's PCs though, so maybe my whole point is a waste of words  :grin:

Reply #35 Top

Ok, can I get a question about the AI and modding in general (quests, monsters, NPCs, etc) answered as I'm very concerned, Frogboy?

 

If we mod in all of this stuff, will the AI be able to use it, so if we make a complicated quest, will the AI understand it, if we have 2 modded quests, one offering a sword of +1 and one a sword of +2 will the AI be able to value the second one more than the first and be able to take that into its considerations on the resources/time it must expend on each quest before making a reasoned decision?

 

Does this extend to all other modding, for example adding new creatures, adding new spells and factions - will the AI be able to use them? Because if not then I'm worried that I bought a game primarily for single-player but the biggest attraction (modding) is really only useful for multiplayer.

 

Thanks Brad. :) 

 

PS: Great game so far and am really looking forwards to the more MoM-esque magic system.

Reply #36 Top

Ok I'm not really talking for Stardock here but from what I remember the AI will be able to use modded content as long as it's properly setup.

 

Reply #37 Top

Can we have nested accept and deny statements to simulate a dialogue tree?

Reply #38 Top

Quoting Xython, reply 23
The hardest thing about making quests right now is the difficulty in testing them. One typo in a quest can make it just not work. This is why I’m lobbying internally (or externally) to get a quest editor made that eases this but will require more documentation. As you can see from above, the quest system is powerful but we’ve only scratched the surface so far.

Are you able to release an XSD file so we at least can validate the structure, if not the actual values? Relative work should be significantly less for a pretty sizable initial benefit.
End of Xython's quote

That code took about 30 minutes.  I already have the Wizard Shell from a previous project so now it is just creating the wizard UI steps and flow. Also, without a firm grasp on the allowed schema, I can only facilitate the quests examples that I have examples of.

I am thinking the UI will have the following flow

  1. Load Existing or Create new Quest
  2. Quest Definition 1 (Technical) Name, Triggers, Spawn, etc
  3. Quest Definition 2 (Display) Description, Accept, Deny, Reward Text
  4. Game Modifier Rewards
  5. Pref (Start) Quest Location (Name, Description, Rarity, Images, TileDesign)
  6. Quest Objectives (Game Modifier, GoodieHut, TileDesign, Quest Objective Condition)
  7. Repeat Step 6 until all objectives are entered
  8. Save

Unfortunately, there are still a lot of unknowns that I need resolved before the Wizard will be all inclusive of what can be done.

Reply #39 Top

Quoting Anthony_Christianson, reply 38

Quoting Xython, reply 23The hardest thing about making quests right now is the difficulty in testing them. One typo in a quest can make it just not work. This is why I’m lobbying internally (or externally) to get a quest editor made that eases this but will require more documentation. As you can see from above, the quest system is powerful but we’ve only scratched the surface so far.

Are you able to release an XSD file so we at least can validate the structure, if not the actual values? Relative work should be significantly less for a pretty sizable initial benefit.


That code took about 30 minutes.  I already have the Wizard Shell from a previous project so now it is just creating the wizard UI steps and flow. Also, without a firm grasp on the allowed schema, I can only facilitate the quests examples that I have examples of.

I am thinking the UI will have the following flow


Load Existing or Create new Quest
Quest Definition 1 (Technical) Name, Triggers, Spawn, etc
Quest Definition 2 (Display) Description, Accept, Deny, Reward Text
Game Modifier Rewards
Pref (Start) Quest Location (Name, Description, Rarity, Images, TileDesign)
Quest Objectives (Game Modifier, GoodieHut, TileDesign, Quest Objective Condition)
Repeat Step 6 until all objectives are entered
Save

Unfortunately, there are still a lot of unknowns that I need resolved before the Wizard will be all inclusive of what can be done.
End of Anthony_Christianson's quote

 

Sounds good.  thanks for tackling this.   If you decide to go open source, there are others (like me) that would be happy to help with something.   Otherwise, keep going, knowing that we appreciate your efforts.  Good Job!

Reply #40 Top

Quoting LeeLament, reply 28
Good to know, much relieved   If I have more than a dozen or so strings to test like that I usually put most all the strings in the code into a red-black or AVL tree and then assign them all a unique number as a code, then I can just use switch statements everywhere.  The string tests are not repeated over and over again.  In some case I use ternary search trees as well. http://en.wikipedia.org/wiki/Ternary_search_tree

Part of my routine grind is to run VTune on the company's software and identify the performance bottlenecks.
End of LeeLament's quote

Just use a (good) hash table. It's constant time and you are already hashing the strings anyway.

(I'm referring to your quoted example ;))

 

 

 

Reply #41 Top

Hate to ask the dumb question, but can anyone get the quest as provided in the zip file to actually work in a game.  I've set up a test map just as outlined, but when ever I actually move onto the quest location, nothing happens, no quest, no pop-up, nothing.    Have I done something wrong?   BTW, I did notice I had to put the quest inot the MyGames/Elemental/Quests folder for it to show up in the Cartographers Workshop area.

Reply #42 Top

Quoting Frogboy, reply 27

Quoting LeeLament, reply 26
Quoting Frogboy, reply 5
Code: c++

else if( _tcsicmp( szStat, _T("TriggerType") ) == 0 )
{
    if( _tcsicmp( szValue, _T("GoodieHut") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_GOODIE_HUT );
    else if( _tcsicmp( szValue, _T("CityPopulation") ) == 0 )
        this->SetTriggerType( QUEST_TRIGGER_CITY_POPULATION );
    else if( _tcsicmp( szValue, _T("TotalPopulation") ) == 0 )
...  

 


Ummm.... if that is representative of the XML parsing code, I think I know why it takes a long time to load them...

That's not XML parsing. That's looking at the already read in object.  We use an STL XML parser.
End of Frogboy's quote

That's even worse! ;)

Parsing can be slow, but once parsed objects are supposed to be faster, otherwise the parsing is pointless. Don't be alarmed though, string operations are pretty fast nowadays, and unless this is checked for thousands of objects several times each second, it doesn't matter, but here is how it should look with fully parsed values:


Code: c++

if (szStat == TriggerType)this->setTriggertType( szValue );

End of quote

Then again maybe I should shut up, and let the thread focus on making quests. The few speed issues I've seen are all in the UI, and not really in world processing.

Reply #43 Top

Great post Chief :) . I'm loving the grand and detailed quests we'll be able to make with the editor you have in store. Doing it in the XML is awesome too. A few questions if I may:

1. Will we have quest chains that have multiple outcomes (aside from fight/not fight) ?

2. Will there be quests that can be based solely on the faction that gets to the quest first, or based on whether or not it's a Kingdom or Empire that completes the quest first?

3. In multi-player, can there be quests that work as a "Race to Finish" the quest for Multiple Sovereigns? Example:

A Quest location on the map is gone to by two different Sovereigns. The quest is to find the lair of a powerful beast, kill it, and then bring the item the beast has back to the quest location. That's the standard part, the not so standard part is that Two Different Sovereign's could both go to the quest location and activate the same quest. The quest would Not close off once one Sovereign got the quest, but instead would be available to all the Sovereigns and the first one to get the item back to the quest location wins. That way they are in direct competition to finish the quest first and bring the item back. Perhaps one Sovereign could even wait for their competition to kill the beast to get the item, then attack the other Sovereign to get the item form him/her without having to fight the beast.

4. Can there be quest chains where the outcome can be random based on how other parts of the chain were finished? Example:

A Quest Chain has 4 separate parts. Each part of the cain has multiple ways it can be finished. When you complete the final part in the chain, the outcome of the quest/adventure is calculated by adding together the different outcomes of the previous steps in the chain to come up with a unique finish to the quest based on those variables?

I'm hoping this tool will be as powerful as you say and be able to do a lot more than "fetch the item and bring it back" type quests. Keep up the great work :)

 

Reply #44 Top

Frogboy, for your poll about what we'd like to see, would you be willing to add an additional vote option?  Namely I'd like to see improvements to the interface as outlined in another player's well laid out post here:  https://forums.elementalgame.com/393693

Stability and general gameplay mechanics aside, I feel that as I'm playing I'm not able to get to the relevant information I want as easily as it should be.  If this is already being taken care of in this patch then ignore this request.  Otherwise I feel like this should be the next area taken care of after instating multiplayer.  Thank you.

Sorry I had to post it in this thread, but it seems your other post had replies disabled as far as I could tell.

Reply #45 Top

Quoting Carewolf, reply 42

That's even worse!

Parsing can be slow, but once parsed objects are supposed to be faster, otherwise the parsing is pointless. Don't be alarmed though, string operations are pretty fast nowadays, and unless this is checked for thousands of objects several times each second, it doesn't matter, but here is how it should look with fully parsed values:
End of Carewolf's quote

I may be wrong, but I think that part of the code is showing how the parsed xml is being used to create the objects themselves... it has to be strings at this point. It would only be done once on load, after that the object's own variables have all the information required during normal runtime.

Reply #46 Top

@Raven X,

Right now I am using the flags feature to get the reseult of different quest options and outcomes. I think that is there are a string of 4 quests and the previous three all provide either a unit or an item, you can then use a flag that requres all or some of those items and will give you a different choice list/options based on that.

The problem is that a quest can't recognize a previous quest.

Reply #47 Top

Hi men, you are skilled! please how can i put a NPC reward?

 

Instead of a item after success, put one Champion on army.

 

thanks!