Although I had to make assumptions on how your quest system would function, it feels this is doathat the fact that MongoDB supports a dynamic schema.
How about the following sample schema?
User: {
id: ObjectId,
username: string,
coins: integer
}
Character: {
id: ObjectId.
name: string,
exp: integer,
level: integer,
hp_capacity: integer,
hp_current: integer,
attack: integer,
defence: integer,
spawned: boolean
}
UserOwnedCharacter: {
...Character,
user_id: ObjectId
}
// Can be embedded as an array in the user collection.
UserOwnedQuest: {
id: ObjectId,
user_id: ObjectId,
// either
discovered: boolean,
in_progress: boolean,
completed: boolean
// or
state: string
}
Quest: {
id: ObjectId,
quest_boss_id: ObjectId,
// either
on_begin_gameplay_prerequisite_id: ObjectId,
on_begin_gameplay_effect_id: ObjectId,
on_complete_gameplay_prerequisite_id: ObjectId,
on_complete_gameplay_effect_id: ObjectId,
// or
on_begin_gameplay_prerequisite: {data},
on_begin_gameplay_effect: {data},
on_complete_gameplay_prerequisite: {data},
on_complete_gameplay_effect: {data},
title: string
}
Gameplay Prerequisite: {
id: ObjectId,
"mechanicType": [mechanicPrereq1, mechanicPrereq2, ..., mechanicPrereqN],
...
}
Mechanic Prerequisite: {
id: ObjectId,
equal: {
attribute: any,
...
},
greaterThan: {
attribute: numeric,
...
}
greaterThanOrEqual: {
attribute: numeric,
...
},
lessThan: {
attribute: numeric,
...
},
lessThanOrEqual: {
attribute: numeric,
...
}
}
Gameplay Effect: {
id: ObjectId,
"mechanicType": [mechanicEffect1, mechanicEffect2, ..., mechanicEffectN]
}
Mechanic Effect: {
id: ObjectId,
set: {
attribute: any,
...
},
add: {
attribute: numeric,
...
}
}
Example:
User 1: {
id: "User1",
coins: 100,
...
}
User Early Level Prerequisite: {
id: "UserAtEarlyLevel",
greaterThan: { "level": 2 },
lessThan: { "level": 5 }
}
User Has Coins 100: {
id: "UserHasCoins",
greaterThanOrEqual: { "coins": 100 }
}
User Add Coins 500 Effect: {
id: "UserAddCoins500",
add: { "coins": 500 }
}
User Remove Coins 100 Effect: {
id: "UserRemoveCoins100",
add: { "coins": -100 }
}
Boss 1: {
id: "Boss1",
...
}
User1 Good Guy 1: {
id: "GoodGuy1",
...
}
User1 Good Guy 2: {
id: "GoodGuy1",
...
}
Character Spawned Prerequisite: {
id: "CharSpawned",
equal: { "spawned": true }
}
Character Kill Prerequisite: {
id: "CharKill",
equal: { "hp_current": 0 }
}
Character EXP Effect: {
id: "CharGainExperience100",
add: { "exp": 100 }
}
Character Damage Effect: {
id: "CharDamage50",
add: { "hp_current": -50 }
}
Character Kill Effect: {
id: "CharKill",
set: { "hp_current": 0 }
}
Gameplay Prerequisite: {
id: "Boss1Spawned",
character: {
"Boss1": [Character Spawned Prerequisite]
},
user: {
"this": [User Early Level Prerequisite, User Has Coins 100]
}
}
Gameplay User Consume Coins Effect: {
id: "Boss1Killed",
user: {
"this": [User Remove Coins 100]
}
}
Gameplay Boss1 Killed Prerequisite: {
id: "Boss1Killed",
character: {
"Boss1": [Character Kill Prerequisite]
},
user: {
"this": [User Early Level Prerequisite, User Add Coins 500]
}
}
Quest {
id: "FirstQuest",
quest_boss_id: "Boss1",
on_begin_gameplay_prerequisite: Gameplay Prerequisite 1,
on_begin_gameplay_effect: Gameplay User Consume Coins Effect,
on_complete_gameplay_prerequisite: Gameplay Boss1 Killed Prerequisite,
on_complete_gameplay_effect: User Add Coins 500 Effect,
title: "Kill the boss to get the bounty"
}
It can be expanded to get as complex as you want to.
Now for this to work, you will need to:
- query the DB for the data
- Glue them together in memory and run the prerequisites and effects
- update the in-memory objects in the DB when necessary
You will have to take care of caching those data into memory and saving when necessary.
Good luck!
Wow, that was long...