Skip to main content

Defining quests

The state in WTF is explicit, declarative and mostly immutable. You declare all the state your quest will need in a task json configuration. Every quests consists of one Quest configuration, which contains zero or more Frames, which contains zero or more Entities.

Quest configuration

At the global quest configuration level, you set up everything that is not runtime logic: icons, descriptions, rewards, preconditions and requirements, quest givers etc. Every quest configuration describes exactly one quest, though you may define multiple quest givers.

{
"WTF_VERSION": "4.3",
"icon": "ui_iconsTotal_found_thing",
"entities": [],
"rewards": {
"money": 2000,
"goodwill": 40
},
"quest_givers": [
{"Sidorovich": true},
{"Sakharov": true}
]
}

Frames

Think of frames as quest stages in your quest. Multi-frame quests were introduced in WTF 4.3 and are still experimental. As such, I won't document the exact syntax of multi-frame quests.

Every frame describes its set of entities. For a single-frame quests, you may use entities field of quest json to define entities directly. Its lifecycle is kinda funky, I might remove this shortcut in future WTF releases.

Entities

Entity is the smallest piece of your quest. In its essence, it's just a blob of data with an optional Controller. WTF uses Controllers to get the status of the quest.

Conceptually, all entities inside a frame are independent and exist at the same time. Their order only matters for the map marker: PDA task marker will point to the first entity, which Controller status returns RUNNING.

Here's a few quest entities for you:

sid_bribery.json
[
{
"section_name":"drx_sl_quest_item_2",
"id": "init$ igi_helper.give_to_actor(|this.section_name|)",
"release": "del$ alife_release_id(|this.id|) or 1",
"link_id": "package"
},

{
"id": "init$ alife_create('script_zone', |this.pos|, |this.lvid|, |this.gvid|).id",
"release": "del$ alife_release_id(|this.id|) or 1",

"pos": "@$ vector():set(-100, -30, -397)",
"gvid": 449,
"lvid": 162028,
"link_id": "zone"
},

{
"CONTROLLER":"@$ wtf_target_deliver.Deliver",
"id": "init$ |package.id|",
"where": "init$ |zone.id|"
}
]

We have three entities. First entity gives a quest item to the player when quest is accepted and releases it on quest finish. Second entity creates a script_zone server object at given coordinates. Finally, third entity binds it all together with CONTROLLER: wtf_target_deliver.Deliver, which add the logic to the quest.

There is only one controller in this example, but you can have multiple at the same time:

tracking_shot.json
[
{
"section_name":"wpn_igi_ks23_ecolog",
"id": "init$ igi_helper.give_to_actor(|this.section_name|)",
"bullet": "init$ igi_helper.give_to_actor('ammo_23_igi_eco')",
"CONTROLLER":"@$ igi_target_get.Get",
"link_id": "gun"
},
{
"section_name":"simulation_flesh",
"id": "init$ igi_helper.spawn_squad(|this.section_name|, |inputs.smart_id|)",
"HELPERS": ["@$ wtf.ScriptedSquad"],
"CONTROLLER":"@$ igi_target_shoot.Shoot",
"weapon": "wpn_igi_ks23_ecolog"
}
]

Here, normally your PDA marker points to the enemy you need to shoot, but if you drop the weapon, igi_target_get.Get will change status from COMPLETED to RUNNING, and the map marker will move to the weapon instead.

Shaping quest up

There are quite a few values you can configure for your quest that have nothing to do with its logic. You probably should set WTF_VERSION and icon first:

{
"WTF_VERSION": "4.3",
"icon": "ui_iconsTotal_mutant"
}

Unset WTF_VERSION will stop the quest from running, as WTF wouldn't know if it's even compatible.

Quest Givers

To define which quest giver will have your quest, you need to add quest_givers field to the definition:

"quest_givers": [
{"Petrenko": true}
]

Quest givers are defined by sets of tags. What we wrote above means "There is one set of quest givers for this quest, and that's those with tag Petrenko"

Here is how you give your quest to every Medic in the game and every Mechanic in the Bar:

"quest_givers": [
{"Medic": true},
{"Mechanic": true, "Bar": true}
]

You can check tags for every quest giver in gamedata/configs/igi_tasks/base.ltx. Here it is as of WTF 4.3:

gamedata/configs/igi_tasks/base.ltx
[npc_tags]
agr_smart_terrain_1_6_army_mechanic_stalker = Mechanic, Agroprom, Army
agr_1_6_medic_army_mlr = Medic, Agroprom, Army
agr_smart_terrain_1_6_near_2_military_colonel_kovalski = Leader, Agroprom, Army, Kuznetsov
; Bar
bar_visitors_stalker_mechanic = Mechanic, Bar, Duty
bar_dolg_medic = Medic, Bar, Duty
bar_visitors_barman_stalker_trader = Barman, Trader, Loner, Bar, Barkeep
bar_dolg_leader = Trader, Bar, Duty, Voronin
bar_dolg_general_petrenko_stalker = Leader, Bar, Duty, Petrenko
snitch = Bar, Loner, Snitch
; Darkscape
dasc_tech_mlr = Mechanic, Darkscape, Loner
; Dark Valley
val_smart_terrain_7_3_bandit_mechanic_stalker = Mechanic, DarkValley, Bandit
bandit_main_base_medic_mlr = Medic, DarkValley, Bandit
zat_b7_bandit_boss_sultan = Leader, DarkValley, Bandit, Sultan
val_smart_terrain_7_4_bandit_trader_stalker = Trader, DarkValley, Bandit, Olivius
; Dead City
cit_killers_merc_mechanic_stalker = Mechanic, DeadCity, Mercenary
cit_killers_merc_medic_stalker = Medic, DeadCity, Mercenary
cit_killers_merc_trader_stalker = Leader, Trader, DeadCity, Mercenary, Dushman
cit_killers_merc_barman_mlr = Barman, Trader, DeadCity, Mercenary, Aslan
; Escape
esc_smart_terrain_5_7_loner_mechanic_stalker = Mechanic, Escape, Loner
army_south_mechan_mlr = Mechanic, Escape, Army
esc_m_trader = Trader, Leader, Escape, Loner, Sidorovich
esc_2_12_stalker_wolf = TaskGiver, Loner, Escape, Wolf
esc_2_12_stalker_nimble = Trader, Loner, Escape, Nimble
esc_3_16_military_trader = Trader, Army, Escape
esc_2_12_stalker_fanat = TaskGiver, Loner, Escape, Fanatic
; Garbage
hunter_gar_trader = Hunter, Loner, Garbage, Trader, Butcher
baraholka_trader = Trader, Loner, Garbage
baraholka_trader_night = Trader, Loner, Garbage, NightTrader
; Jupiter
jup_b217_stalker_tech = Mechanic, Loner, Jupiter
jup_cont_mech_bandit = Mechanic, Bandit, Jupiter
mechanic_monolith_jup_depo = Mechanic, Monolith, Jupiter
jup_a6_stalker_medik = Medic, Loner, Jupiter
drx_sl_jup_a6_freedom_leader = Leader, Freedom, Jupiter, Loki
jup_b6_scientist_tech = Mechanic, Ecolog, Jupiter, Tukarev
jup_b220_trapper = Hunter, Loner, Jupiter, Trapper
jup_b19_freedom_yar = TaskGiver, Freedom, Jupiter, Yar
jup_b6_scientist_nuclear_physicist = Leader, Ecolog, Jupiter, Hermann
; Marsh
mar_base_stalker_tech = Mechanic, ClearSky, Marsh
mar_smart_terrain_base_doctor = Medic, ClearSky, Marsh
mar_smart_terrain_base_stalker_leader_marsh = Leader, ClearSky, Marsh, Cold
mar_base_owl_stalker_trader = Trader, ClearSky, Marsh, Spore
mar_base_stalker_barmen = Barman, Trader, ClearSky, Marsh, Librarian
; Army Warehouses
mil_smart_terrain_7_7_freedom_mechanic_stalker = Mechanic, Freedom, AW
mil_freedom_medic = Medic, Freedom, AW
mil_smart_terrain_7_7_freedom_leader_stalker = Leader, Freedom, AW, Lukash
mil_smart_terrain_7_10_freedom_trader_stalker = Trader, Freedom, AW, Skinflint
; Pripyat 2
pri_monolith_monolith_mechanic_stalker = Mechanic, Monolith, Pripyat2
merc_pri_a18_mech_mlr = Mechanic, Mercenary, Pripyat2
mechanic_monolith_kbo = Mechanic, Monolith, Pripyat2
pri_monolith_monolith_trader_stalker = Trader, Monolith, Pripyat2, Rabbit
lider_monolith_haron = Leader, Monolith, Pripyat2, Haron
monolith_eidolon = TaskGiver, Monolith, Pripyat2, Eidolon
merc_pri_grifon_mlr = Leader, Mercenary, Pripyat2, Griffin
; Red Forest
red_greh_tech = Mechanic, Greh, RedForest
; Truck Cemetery
trucks_cemetery_bandit_mechanic = Mechanic, Bandit, TruckCemetery
; Yantar
mechanic_army_yan_mlr = Mechanic, Army, Yantar
yan_stalker_sakharov = Leader, Ecolog, Yantar, Sakharov
; Zaton
zat_a2_stalker_mechanic = Mechanic, Loner, Zaton
zat_stancia_mech_merc = Mechanic, Mercenary, Zaton
zat_tech_mlr = Mechanic, Loner, Zaton
zat_b22_stalker_medic = Medic, Loner, Zaton
zat_a2_stalker_barmen = Barman, Trader, Leader, Loner, Zaton, Beard
zat_stancia_trader_merc = Trader, Mercenary, Zaton

Preconditions and Requirements

There are three ways your quest may fail Setup phase: failed preconditions, failed requirements and ?$ macro returning nil. The consequence of all of these is your task not showing up in the task list.

Preconditions and Requirements are structurally the same thing and differ only semantically. Preconditions are intended to be optional and can be disabled in MCM; requirements are not optional and will always be evaluated. To add a precondition to your quest, add a array called preconditions (or requirements) to your quest configuration:

orders_army.json
{
"preconditions": [
"$ get_actor_true_community() == 'army'"
]
...
}

After Setup phase macro evaluation, preconditions array is just an array of booleans; if any boolean is false, preconditions will fail.

Description

WTF generates text keys for your quests automatically. For a quest located in configs/igi_tasks/tasks/MyMod/my_task.json and task giver bar_dolg_general_petrenko_stalker, WTF tests two keys:

igi_task_text_mymod_my_task_bar_dolg_general_petrenko_stalker
igi_task_text_mymod_my_task

Other than that, WTF follows vanilla conventions, transforming keys to:

title = $KEY_name
descr = $KEY_text
job_descr = $KEY_about
task_complete_descr = $KEY_finish

Dynamic description

Other than static text, you can show some text in dynamic description part. As of WTF 4.3, it allows for keys locations, targets and factions. Rewards will be picked up from reward definition automatically. This config:

"description": {
"locations": ["Red Forest"],
"targets": ["Bad people", "Good people"],
"factions": ["$ db.actor:character_community()"]
}

looks like this in game:

game description

Rewards

Rewards are quite simple, you can define goodwill and money, either as number, $ macro or @$ macro:

"rewards": {
"money": "@$ 2000 + 400 * |squad.squad_size|",
"goodwill": 30
},