Files
Bubberstation/code/modules/explorer_drone/adventure.dm
san7890 ccef887efe Lints Against Unmanaged Local Defines (#74333)
# MAINTAINER - USE THE BUTTON THAT SAYS "MERGE MASTER" THEN SET THE PR
TO AUTO-MERGE! IT'S MUCH EASIER FOR ME TO FIX THINGS BEFORE THEY SKEW
RATHER THAN AFTER THE FACT.

## About The Pull Request

Hey there,

This took a while to do, but here's the gist:

Python file now regexes every file in `/code` except for those that have
some valid reason to be tacking on more global defines. Some of those
reasons are simply just that I don't have the time right now (doing what
you see in this PR took a few hours) to refactor and parse what should
belong and what should be thrown out. For the time being though, this PR
will at least _halt_ people making the mistake of not `#undef`ing any
files they `#define` "locally", or within the scope of a file.

Most people forget to do this and this leads to a lot of mess later on
due to how many variables can be unmanaged on the global level. I've
made this mistake, you've made this mistake, it's a common thing. Let's
automatically check for it so it can be fixed no-stress.

Scenarios this PR corrects:

* Forgetting to undef a define but undeffing others.
* Not undeffing any defines in your file.
* Earmarking a define as a "file local" define, but not defining it.
* Having a define be a "file local" define, but having it be used
elsewhere.
* Having a "local" define not even be in the file that it only shows up
in.
* Having a completely unused define*

(* I kept some of these because they seemed important... Others were
junked.)
## Why It's Good For The Game

If you wanna use it across multiple files, no reason to not make it a
global define (maybe there's a few reasons but let's assume that this is
the 95% case).

Let me know if you don't like how I re-arranged some of the defines and
how you'd rather see it be implemented, and I'd be happy to do that.
This was mostly just "eh does it need it or not" sorta stuff.

I used a pretty cool way to detect if we should use the standardized
GitHub "error" output, you can see the results of that here
https://github.com/san7890/bruhstation/actions/runs/4549766579/jobs/8022186846#step:7:792
## Changelog
Nothing that really concerns players.

(I fixed up all this stuff using vscode, no regexes beyond what you see
in the python script. sorry downstreams)
2023-03-29 10:17:03 -07:00

540 lines
20 KiB
Plaintext

// json field definitions bit verbose but i've had it with the typos
#define ADVENTURE_NAME_FIELD "adventure_name"
#define ADVENTURE_STARTING_NODE_FIELD "starting_node"
#define ADVENTURE_REQUIRED_SITE_TRAITS_FIELD "required_site_traits"
#define ADVENTURE_SCAN_BAND_MODS_FIELD "scan_band_mods"
#define ADVENTURE_LOOT_FIELD "loot_categories"
#define ADVENTURE_STARTING_QUALITIES_FIELD "starting_qualities"
#define ADVENTURE_DEEP_SCAN_DESCRIPTION "deep_scan_description"
#define ADVENTURE_NODES_FIELD "nodes"
#define ADVENTURE_TRIGGERS_FIELD "triggers"
#define ADVENTURE_VERSION_FIELD "version"
#define NODE_NAME_FIELD "name"
#define NODE_DESCRIPTION_FIELD "description"
#define NODE_IMAGE_FIELD "image"
#define NODE_RAW_IMAGE_FIELD "raw_image"
#define NODE_CHOICES_FIELD "choices"
#define NODE_ON_ENTER_EFFECTS_FIELD "on_enter_effects"
#define NODE_ON_EXIT_EFFECTS_FIELD "on_exit_effects"
#define CHOICE_KEY_FIELD "key"
#define CHOICE_NAME_FIELD "name"
#define CHOICE_ON_SELECTION_EFFECT_FIELD "on_selection_effects"
#define CHOICE_REQUIREMENTS_FIELD "requirements"
#define CHOICE_EXIT_NODE_FIELD "exit_node"
#define CHOICE_DELAY_FIELD "delay"
#define CHOICE_DELAY_MESSAGE_FIELD "delay_message"
#define EFFECT_TYPE_FIELD "effect_type"
#define EFFECT_QUALITY_FIELD "quality"
#define EFFECT_VALUE_FIELD "value"
#define EFFECT_VALUE_VALUE_TYPE_FIELD "value_type"
#define TRIGGER_NAME_FIELD "name"
#define TRIGGER_REQUIREMENTS_FIELD "requirements"
#define TRIGGER_ON_TRIGGER_EFFECTS_FIELD "on_trigger_effects"
#define TRIGGER_TARGET_NODE_FIELD "target_node"
#define REQ_GROUP_REQUIREMENTS_FIELD "requirements"
#define REQ_GROUP_GROUP_TYPE_FIELD "group_type"
#define REQ_QUALITY_FIELD "quality"
#define REQ_VALUE_FIELD "value"
#define REQ_OPERATOR_FIELD "operator"
#define CURRENT_ADVENTURE_VERSION 1
/// All possible adventures in raw form
GLOBAL_LIST_EMPTY(explorer_drone_adventure_db_entries)
/// Loads all adventures from DB
/proc/load_adventures()
. = list()
if(!SSdbcore.Connect())
GLOB.explorer_drone_adventure_db_entries = .
return
var/datum/db_query/Query = SSdbcore.NewQuery("SELECT id,adventure_data,uploader,timestamp,approved FROM [format_table_name("text_adventures")]")
if(!Query.Execute())
qdel(Query)
return
while(Query.NextRow())
var/datum/adventure_db_entry/entry = new()
entry.id = Query.item[1]
entry.raw_json = Query.item[2]
entry.uploader = Query.item[3]
entry.timestamp = Query.item[4]
entry.approved = Query.item[5]
entry.extract_metadata()
. += entry
qdel(Query)
GLOB.explorer_drone_adventure_db_entries = .
/datum/adventure_db_entry
/// db id or null for freshly created adventures
var/id
/// actual adventure json string
var/raw_json
/// ckey of last change user.
var/uploader
/// Time of last change.
var/timestamp
/// Unapproved adventures won't be used for exploration sites.
var/approved = FALSE
/// Was the adventure used for exploration site this round.
var/placed = FALSE
//Variables below are extracted from the JSON
/// json version
var/version
/// adventure name
var/name
/// required site traits to use this adventure
var/list/required_site_traits
/// Check if the adventure usable for given exploration site traits
/datum/adventure_db_entry/proc/valid_for_use(list/site_traits)
if(!raw_json || version != CURRENT_ADVENTURE_VERSION || placed)
return FALSE
if(required_site_traits && length(required_site_traits - site_traits) != 0)
return FALSE
return TRUE
/// Updates this entry from db, if possible.
/datum/adventure_db_entry/proc/refresh()
if(id)
//Check if our timestamp is fresh, if not update local and stop
var/datum/db_query/SelectQuery = SSdbcore.NewQuery("SELECT adventure_data,uploader,timestamp,approved FROM [format_table_name("text_adventures")] WHERE id = :id",list("id" = id))
if(!SelectQuery.warn_execute() || !SelectQuery.NextRow())
qdel(SelectQuery)
return
raw_json = SelectQuery.item[1]
uploader = SelectQuery.item[2]
timestamp = SelectQuery.item[3]
approved = SelectQuery.item[4]
extract_metadata()
qdel(SelectQuery)
return
// No ID, nothing to be done.
/// Pushes this entry changes to DB
/datum/adventure_db_entry/proc/save()
if(id)
//We're up to date, update db instead
var/datum/db_query/UpdateQuery = SSdbcore.NewQuery("UPDATE [format_table_name("text_adventures")] SET adventure_data = :adventure_data,uploader = :uploader,approved = :approved WHERE id = :id AND timestamp < NOW()",
list("id" = id, "adventure_data" = raw_json, "uploader" = usr.ckey, "approved" = approved))
UpdateQuery.warn_execute()
qdel(UpdateQuery)
else
// Create new entry
var/datum/db_query/InsertQuery = SSdbcore.NewQuery("INSERT INTO [format_table_name("text_adventures")] (adventure_data, uploader) VALUES (:raw_json, :uploader)", list("raw_json" = raw_json, "uploader" = usr.ckey))
if(!InsertQuery.warn_execute())
qdel(InsertQuery)
return FALSE
id = InsertQuery.last_insert_id
qdel(InsertQuery)
refresh()
/// Deletes the local AND db entry.
/datum/adventure_db_entry/proc/remove()
if(id)
var/datum/db_query/DelQuery = SSdbcore.NewQuery("DELETE FROM [format_table_name("text_adventures")] WHERE id = :id", list("id" = id))
if(!DelQuery.warn_execute())
qdel(DelQuery)
return FALSE
log_admin("[key_name(usr)] deleted text adventure with id : [id], name : [name]")
qdel(DelQuery)
GLOB.explorer_drone_adventure_db_entries -= src
qdel(src)
return TRUE
/// Extracts fields that are used by adventure browser / generation before instantiating
/datum/adventure_db_entry/proc/extract_metadata()
if(!raw_json)
CRASH("Trying to extract metadata from empty adventure")
var/list/json_data = json_decode(raw_json)
if(!islist(json_data))
CRASH("Invalid JSON for adventure with db id:[id]")
version = json_data[ADVENTURE_VERSION_FIELD] || 0
name = json_data[ADVENTURE_NAME_FIELD]
required_site_traits = json_data[ADVENTURE_REQUIRED_SITE_TRAITS_FIELD]
/// Creates new adventure instance
/datum/adventure_db_entry/proc/create_adventure()
if(version != CURRENT_ADVENTURE_VERSION)
CRASH("Trying to instance outdated adventure version")
return try_loading_adventure()
/// Parses adventure JSON and returns /datum/adventure instance on success
/datum/adventure_db_entry/proc/try_loading_adventure()
var/list/json_data = json_decode(raw_json)
if(!islist(json_data))
CRASH("Invalid JSON in adventure with id:[id], name:[name]")
//Basic validation of required fields, don't even bother loading if they are missing.
var/static/list/required_fields = list(ADVENTURE_NAME_FIELD,ADVENTURE_STARTING_NODE_FIELD,ADVENTURE_NODES_FIELD)
for(var/field in required_fields)
if(!json_data[field])
CRASH("Adventure id:[id], name:[name] missing [field] value")
var/datum/adventure/loaded_adventure = new
//load properties
loaded_adventure.starting_node = json_data[ADVENTURE_STARTING_NODE_FIELD]
loaded_adventure.name = json_data[ADVENTURE_NAME_FIELD]
loaded_adventure.required_site_traits = json_data[ADVENTURE_REQUIRED_SITE_TRAITS_FIELD]
loaded_adventure.band_modifiers = json_data[ADVENTURE_SCAN_BAND_MODS_FIELD]
loaded_adventure.loot_categories = json_data[ADVENTURE_LOOT_FIELD]
loaded_adventure.starting_qualities = json_data[ADVENTURE_STARTING_QUALITIES_FIELD]
loaded_adventure.deep_scan_description = json_data[ADVENTURE_DEEP_SCAN_DESCRIPTION]
for(var/list/node_data in json_data[ADVENTURE_NODES_FIELD])
var/datum/adventure_node/node = try_loading_node(node_data)
if(node)
if(loaded_adventure.nodes[node.id])
CRASH("Duplicate [node.id] node in id:[id], name:[name] adventure")
loaded_adventure.nodes[node.id] = node
loaded_adventure.triggers = json_data[ADVENTURE_TRIGGERS_FIELD]
if(!loaded_adventure.validate())
CRASH("Validation failed for id:[id], name:[name] adventure")
return loaded_adventure
/datum/adventure_db_entry/proc/try_loading_node(node_data)
if(!islist(node_data))
CRASH("Invalid adventure node data in id:[id], name:[name] adventure.")
var/datum/adventure_node/fresh_node = new
fresh_node.id = node_data[NODE_NAME_FIELD]
fresh_node.description = node_data[NODE_DESCRIPTION_FIELD]
fresh_node.image_name = node_data[NODE_IMAGE_FIELD]
fresh_node.raw_image = node_data[NODE_RAW_IMAGE_FIELD]
fresh_node.choices = list()
for(var/list/choice_data in node_data[NODE_CHOICES_FIELD])
fresh_node.choices[choice_data[CHOICE_KEY_FIELD]] = choice_data
fresh_node.on_enter_effects = node_data[NODE_ON_ENTER_EFFECTS_FIELD]
fresh_node.on_exit_effects = node_data[NODE_ON_EXIT_EFFECTS_FIELD]
return fresh_node
/// text adventure instance, holds data about nodes/choices/etc and of current play state.
/datum/adventure
/// Adventure name, this organization only, not visible to users
var/name
/// Node the adventure will start at
var/starting_node
/// Required site traits for the adventure to appear
var/list/required_site_traits = list()
/// Modifiers to band scan values
var/list/band_modifiers = list()
/// Loot table ids used as reward for finishing the adventure succesfully.
var/list/loot_categories = list()
/// Nodes for this adventure, represent single scene.
var/list/nodes = list()
/// Triggers for this adventure, checked after quality changes to cause instantenous results
var/list/triggers = list()
/// List of starting quality values, these will be set before first node is encountered.
var/list/starting_qualities = list()
///Keeps track firing of triggers until stop state to prevent loops
var/list/trigger_loop_safety = list()
/// Opional description shown after site deep scan
var/deep_scan_description
// State tracking variables
/// Current active adventure node
var/datum/adventure_node/current_node
/// Last other node than this one. Used by GO_BACK_NODE
var/previous_node_id
/// Assoc list of quality name = value
var/list/qualities
/// Delayed state properties. If not null, means adventure is in delayed action state and will contain list(delay_time,delay_message)
var/list/delayed_action
/// Basic sanity checks to ensure broken adventures are not used.
/datum/adventure/proc/validate()
///Check all nodes have choices
for(var/node_id in nodes)
var/datum/adventure_node/node = nodes[node_id]
if(!length(node.choices))
return FALSE
return TRUE
/datum/adventure/proc/start_adventure()
initialize_qualities()
previous_node_id = starting_node
navigate_to_node(starting_node)
/// Finish adventure
/datum/adventure/proc/end_adventure(result)
SEND_SIGNAL(src,COMSIG_ADVENTURE_FINISHED,result)
/datum/adventure/proc/initialize_qualities()
qualities = starting_qualities || list()
SEND_SIGNAL(src,COMSIG_ADVENTURE_QUALITY_INIT,qualities)
/datum/adventure/proc/navigate_to_node(node_id)
if(current_node)
if(current_node.on_exit(src)) //Trigger on exit caused node change <- I don't really see much use for this so might want to warn about it ?
return
if(current_node.id != previous_node_id)
previous_node_id = current_node.id
if(handle_special_nodes(node_id))
return
if(!nodes[node_id])
stack_trace("Invalid adventure node navigation from node [current_node.id]")
current_node = nodes[node_id]
current_node.on_enter(src)
/// Handles special node ID's
/datum/adventure/proc/handle_special_nodes(node_id)
switch(node_id)
if(FAIL_NODE)
end_adventure(ADVENTURE_RESULT_DAMAGE)
return TRUE
if(FAIL_DEATH_NODE)
end_adventure(ADVENTURE_RESULT_DEATH)
return TRUE
if(WIN_NODE)
end_adventure(ADVENTURE_RESULT_SUCCESS)
return TRUE
if(GO_BACK_NODE)
if(previous_node_id)
navigate_to_node(previous_node_id)
return TRUE
else
return FALSE
else
return FALSE
/datum/adventure/proc/select_choice(choice_id)
if(!current_node || !islist(current_node.choices[choice_id]))
return
var/list/choice_data = current_node.choices[choice_id]
if(!check_requirements(choice_data[CHOICE_REQUIREMENTS_FIELD]))
return
if(choice_data[CHOICE_ON_SELECTION_EFFECT_FIELD])
if(apply_adventure_effect(choice_data[CHOICE_ON_SELECTION_EFFECT_FIELD],src))
return //Trigger forced node change.
var/exit_id = choice_data[CHOICE_EXIT_NODE_FIELD]
if(!exit_id)
CRASH("No exit node for choice [choice_id] in adventure [name]")
if(choice_data[CHOICE_DELAY_FIELD])
var/delay_message = choice_data[CHOICE_DELAY_MESSAGE_FIELD]
var/delay_time = choice_data[CHOICE_DELAY_FIELD]
if(!isnum(delay_time))
CRASH("Invalid delay in adventure [name]")
SEND_SIGNAL(src,COMSIG_ADVENTURE_DELAY_START,delay_time,delay_message)
delayed_action = list(delay_time,delay_message)
addtimer(CALLBACK(src, PROC_REF(finish_delay),exit_id),delay_time)
return
navigate_to_node(exit_id)
/datum/adventure/proc/finish_delay(exit_id)
delayed_action = null
navigate_to_node(exit_id)
SEND_SIGNAL(src,COMSIG_ADVENTURE_DELAY_END)
/datum/adventure/ui_data(mob/user)
. = ..()
.["description"] = current_node?.description
.["image"] = current_node?.image_name
.["raw_image"] = current_node?.raw_image
.["choices"] = current_node?.get_available_choices(src)
/datum/adventure_node
/// Unique identifier for this node
var/id
/// The actual displayed text
var/description
/// Preset image name, exclusive with raw_image
var/image_name
/// Image in base64 form. Exclusive with image_name
var/raw_image
/// All possible choices from this node, associative list of choice_id -> choice_data
var/list/choices
/// Effects fired when navigating to this node.
var/list/on_enter_effects
/// Effects fired when leaving this node.
var/list/on_exit_effects
/// Pauses adventure for this long after the choice
var/delay
/// This will show when the delay is happening.
var/delay_message
/datum/adventure_node/proc/on_enter(datum/adventure/context)
if(on_enter_effects)
if(context.apply_adventure_effect(on_enter_effects))
return TRUE
/datum/adventure_node/proc/on_exit(datum/adventure/context)
if(on_exit_effects)
if(context.apply_adventure_effect(on_exit_effects))
return TRUE
/datum/adventure_node/proc/get_available_choices(datum/adventure/context)
. = list()
for(var/choice_key in choices)
var/list/choice_data = choices[choice_key]
if(context.check_requirements(choice_data[CHOICE_REQUIREMENTS_FIELD]))
. += list(list("key" = choice_key,"text" = choice_data[CHOICE_NAME_FIELD]))
///Applies changes encoded in effect data and processes triggers, returns TRUE if the change forced node change.
/datum/adventure/proc/apply_adventure_effect(list/effect_data,process_triggers=TRUE)
if(!islist(effect_data))
CRASH("Invalid effect data [json_encode(effect_data)] in adventure [name]")
for(var/list/effect_group in effect_data)
var/effect_keyword = effect_group[EFFECT_TYPE_FIELD]
var/list/quality_name = effect_group[EFFECT_QUALITY_FIELD]
var/value = process_adventure_value(effect_group[EFFECT_VALUE_FIELD])
switch(effect_keyword)
if(ADVENTURE_EFFECT_TYPE_REMOVE) //remove quality doesn't care about value for now
qualities -= quality_name
if(ADVENTURE_EFFECT_TYPE_ADD)
if(!isnum(value))
CRASH("Invalid add quality effect value in effect [json_encode(effect_data)] in adventure [name]")
if(!qualities[quality_name])
qualities[quality_name] = 0
qualities[quality_name] += value
if(ADVENTURE_EFFECT_TYPE_SET)
qualities[quality_name] = value
else
CRASH("Invalid effect keyword in effect [json_encode(effect_data)] in adventure [name]")
///Check Triggers
if(process_triggers)
for(var/list/trigger_data in triggers)
if(!check_requirements(trigger_data[TRIGGER_REQUIREMENTS_FIELD]))
continue
if(LAZYACCESS(trigger_loop_safety,trigger_data[TRIGGER_NAME_FIELD]))
stack_trace("Loop in trigger processing detected in adventure [name]")
continue
LAZYADD(trigger_loop_safety,trigger_data[TRIGGER_NAME_FIELD])
if(trigger_data[TRIGGER_ON_TRIGGER_EFFECTS_FIELD])
apply_adventure_effect(trigger_data[TRIGGER_ON_TRIGGER_EFFECTS_FIELD],FALSE) //Let's keep this simple
if(trigger_data[TRIGGER_TARGET_NODE_FIELD])
navigate_to_node(trigger_data[TRIGGER_TARGET_NODE_FIELD])
return TRUE
//We're out of trigger processing
LAZYCLEARLIST(trigger_loop_safety)
return FALSE
/// Extracts raw value from special value objects
/datum/adventure/proc/process_adventure_value(raw_value)
if(islist(raw_value))
var/list/value_as_list = raw_value
switch(value_as_list[EFFECT_VALUE_VALUE_TYPE_FIELD])
if(ADVENTURE_QUALITY_TYPE_RANDOM)
return rand(value_as_list[ADVENTURE_RANDOM_QUALITY_LOW_FIELD],value_as_list[ADVENTURE_RANDOM_QUALITY_HIGH_FIELD])
else
CRASH("Invalid special value type in adventure [name]")
else
return raw_value
/// Checks if current qualities satisfy passed in requirements
/datum/adventure/proc/check_requirements(raw_requirements)
if(!islist(raw_requirements))
return TRUE
var/list/req_groups = raw_requirements
// Top level list - can contain either req groups or single requirements and is AND type group
for(var/list/group_data in req_groups)
if(group_data[REQ_GROUP_REQUIREMENTS_FIELD]) //It's a group
if(!check_requirement_group(group_data))
return FALSE
else //It's a single requirement
if(!check_single_requirement(group_data))
return FALSE
return TRUE
/// Recursively validates group requirements.
/datum/adventure/proc/check_requirement_group(raw_group_data)
if(!islist(raw_group_data))
CRASH("Invalid group requirement in adventure [name]")
var/list/group_data = raw_group_data
var/group_type = group_data[REQ_GROUP_GROUP_TYPE_FIELD]
var/list/group_elements = group_data[REQ_GROUP_REQUIREMENTS_FIELD]
switch(group_type)
if("OR") //Just one out of subgroups/reqs need to be true for this to return true
for(var/list/subgroup_data in group_elements)
if(subgroup_data[REQ_GROUP_REQUIREMENTS_FIELD]) //It's a group
if(check_requirement_group(subgroup_data))
return TRUE
else //It's a single requirement
if(check_single_requirement(subgroup_data))
return TRUE
return FALSE
if("AND") //All subgroups/reqs need to be true for this to return true
for(var/list/subgroup_data in group_elements)
if(subgroup_data[REQ_GROUP_REQUIREMENTS_FIELD]) //It's a group
if(!check_requirement_group(subgroup_data))
return FALSE
else //It's a single requirement
if(!check_single_requirement(subgroup_data))
return FALSE
return TRUE
else
CRASH("Invalid requirement group in adventure [name]")
//Checks if unit requirement {"quality": "a","op": "==","value": "something"} is met.
/datum/adventure/proc/check_single_requirement(raw_requirement)
var/qkey = raw_requirement[REQ_QUALITY_FIELD]
var/qval = raw_requirement[REQ_VALUE_FIELD]
switch(raw_requirement[REQ_OPERATOR_FIELD])
if("==")
return qualities[qkey] == qval
if("!=")
return qualities[qkey] != qval
if(">")
return qualities[qkey] > qval
if(">=")
return qualities[qkey] >= qval
if("<=")
return qualities[qkey] <= qval
if("<")
return qualities[qkey] < qval
if("exists")
return qkey in qualities
#undef ADVENTURE_VERSION_FIELD
#undef CURRENT_ADVENTURE_VERSION
#undef ADVENTURE_NAME_FIELD
#undef ADVENTURE_STARTING_NODE_FIELD
#undef ADVENTURE_REQUIRED_SITE_TRAITS_FIELD
#undef ADVENTURE_SCAN_BAND_MODS_FIELD
#undef ADVENTURE_LOOT_FIELD
#undef ADVENTURE_STARTING_QUALITIES_FIELD
#undef ADVENTURE_DEEP_SCAN_DESCRIPTION
#undef ADVENTURE_NODES_FIELD
#undef ADVENTURE_TRIGGERS_FIELD
#undef NODE_NAME_FIELD
#undef NODE_DESCRIPTION_FIELD
#undef NODE_IMAGE_FIELD
#undef NODE_RAW_IMAGE_FIELD
#undef NODE_CHOICES_FIELD
#undef NODE_ON_ENTER_EFFECTS_FIELD
#undef NODE_ON_EXIT_EFFECTS_FIELD
#undef CHOICE_KEY_FIELD
#undef CHOICE_NAME_FIELD
#undef CHOICE_ON_SELECTION_EFFECT_FIELD
#undef CHOICE_REQUIREMENTS_FIELD
#undef CHOICE_EXIT_NODE_FIELD
#undef CHOICE_DELAY_FIELD
#undef CHOICE_DELAY_MESSAGE_FIELD
#undef EFFECT_TYPE_FIELD
#undef EFFECT_QUALITY_FIELD
#undef EFFECT_VALUE_FIELD
#undef EFFECT_VALUE_VALUE_TYPE_FIELD
#undef TRIGGER_NAME_FIELD
#undef TRIGGER_REQUIREMENTS_FIELD
#undef TRIGGER_ON_TRIGGER_EFFECTS_FIELD
#undef TRIGGER_TARGET_NODE_FIELD
#undef REQ_GROUP_REQUIREMENTS_FIELD
#undef REQ_GROUP_GROUP_TYPE_FIELD
#undef REQ_QUALITY_FIELD
#undef REQ_VALUE_FIELD
#undef REQ_OPERATOR_FIELD