feat: add source-owned combat mechanic programs
This commit is contained in:
+151
-28
@@ -369,30 +369,123 @@ CREATE TABLE IF NOT EXISTS talent_tiers (
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(talent_id, tier)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS talent_triggers (
|
||||
CREATE TABLE IF NOT EXISTS conditional_effect_rules (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
supports_uptime INTEGER NOT NULL DEFAULT 0 CHECK(supports_uptime IN (0, 1)),
|
||||
min_uptime REAL,
|
||||
max_uptime REAL,
|
||||
calculation_script TEXT,
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
source_type TEXT NOT NULL CHECK(source_type IN (
|
||||
'talent','os_protocol_talent','skill_chip_talent','specialization_tree_rank'
|
||||
)),
|
||||
source_id TEXT NOT NULL,
|
||||
configured INTEGER NOT NULL DEFAULT 0 CHECK(configured IN (0,1)),
|
||||
script_version INTEGER NOT NULL DEFAULT 1 CHECK(script_version>0),
|
||||
simulation_readiness TEXT NOT NULL DEFAULT 'ready' CHECK(simulation_readiness IN (
|
||||
'ready','requires_assumptions','captured_only'
|
||||
)),
|
||||
scenario_inputs_json TEXT NOT NULL DEFAULT '[]',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(source_type,source_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS conditional_effect_state_pools (
|
||||
id TEXT PRIMARY KEY,
|
||||
rule_id TEXT NOT NULL REFERENCES conditional_effect_rules(id) ON DELETE CASCADE,
|
||||
state_key TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
state_kind TEXT NOT NULL DEFAULT 'stack' CHECK(state_kind IN (
|
||||
'flag','count','stack','duration','scalar','target_mark','resource'
|
||||
)),
|
||||
state_scope TEXT NOT NULL DEFAULT 'agent' CHECK(state_scope IN ('agent','target')),
|
||||
initial_value REAL NOT NULL DEFAULT 0,
|
||||
minimum_value REAL,
|
||||
maximum_value REAL NOT NULL DEFAULT 1 CHECK(maximum_value>0),
|
||||
best_case_value REAL,
|
||||
duration_seconds REAL CHECK(duration_seconds IS NULL OR duration_seconds>0),
|
||||
expiry_policy TEXT NOT NULL DEFAULT 'clear_all' CHECK(expiry_policy IN ('clear_all','decrement_one','none')),
|
||||
refresh_policy TEXT NOT NULL DEFAULT 'refresh' CHECK(refresh_policy IN ('refresh','extend','ignore')),
|
||||
parameters_json TEXT NOT NULL DEFAULT '{}',
|
||||
sort_order INTEGER NOT NULL CHECK(sort_order>=1),
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(rule_id,state_key),
|
||||
UNIQUE(rule_id,sort_order),
|
||||
CHECK(minimum_value IS NULL OR maximum_value>=minimum_value),
|
||||
CHECK(best_case_value IS NULL OR minimum_value IS NULL OR best_case_value>=minimum_value),
|
||||
CHECK(best_case_value IS NULL OR best_case_value<=maximum_value)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS conditional_effect_state_pools_rule_idx
|
||||
ON conditional_effect_state_pools(rule_id,sort_order);
|
||||
CREATE TABLE IF NOT EXISTS conditional_effect_clauses (
|
||||
id TEXT PRIMARY KEY,
|
||||
rule_id TEXT NOT NULL REFERENCES conditional_effect_rules(id) ON DELETE CASCADE,
|
||||
clause_key TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
event_kind TEXT NOT NULL,
|
||||
recipe_key TEXT,
|
||||
recipe_parameters_json TEXT NOT NULL DEFAULT '{}',
|
||||
conditions_json TEXT NOT NULL DEFAULT '{"kind":"true"}',
|
||||
reducer_json TEXT NOT NULL DEFAULT '{"kind":"none"}',
|
||||
weight_expression_json TEXT,
|
||||
emission_kind TEXT NOT NULL DEFAULT 'each_match' CHECK(emission_kind IN (
|
||||
'each_match','threshold_crossed','while_true','interval_elapsed','value_changed'
|
||||
)),
|
||||
state_pool_id TEXT REFERENCES conditional_effect_state_pools(id) ON DELETE SET NULL,
|
||||
mutations_json TEXT NOT NULL DEFAULT '[]',
|
||||
cooldown_seconds REAL CHECK(cooldown_seconds IS NULL OR cooldown_seconds>0),
|
||||
output_branch TEXT NOT NULL DEFAULT 'active',
|
||||
sort_order INTEGER NOT NULL CHECK(sort_order>=1),
|
||||
active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0,1)),
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(rule_id,clause_key),
|
||||
UNIQUE(rule_id,sort_order)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS conditional_effect_clauses_event_idx
|
||||
ON conditional_effect_clauses(event_kind,rule_id);
|
||||
CREATE TABLE IF NOT EXISTS conditional_effect_outcomes (
|
||||
id TEXT PRIMARY KEY,
|
||||
rule_id TEXT NOT NULL REFERENCES conditional_effect_rules(id) ON DELETE CASCADE,
|
||||
clause_id TEXT REFERENCES conditional_effect_clauses(id) ON DELETE CASCADE,
|
||||
state_pool_id TEXT REFERENCES conditional_effect_state_pools(id) ON DELETE SET NULL,
|
||||
effect_key TEXT NOT NULL,
|
||||
variant_key TEXT NOT NULL DEFAULT 'base',
|
||||
outcome_key TEXT NOT NULL DEFAULT 'active',
|
||||
application_kind TEXT NOT NULL DEFAULT 'active_modifier' CHECK(application_kind IN (
|
||||
'active_modifier','direct_damage','restore_health','restore_armor','restore_ammo','resource_cost','marker'
|
||||
)),
|
||||
effect_scope TEXT NOT NULL DEFAULT 'self' CHECK(effect_scope IN (
|
||||
'self','equipped_weapon','target','allies','self_and_allies','assigned_ability','all_skills'
|
||||
)),
|
||||
stat_attribute_id TEXT REFERENCES stat_attributes(id),
|
||||
value REAL NOT NULL,
|
||||
value_expression_json TEXT,
|
||||
value_basis TEXT NOT NULL DEFAULT 'flat' CHECK(value_basis IN (
|
||||
'flat','max_health_percent','current_health_percent','weapon_base_percent'
|
||||
)),
|
||||
value_scaling TEXT NOT NULL DEFAULT 'per_state_unit' CHECK(value_scaling IN ('flat','per_state_unit')),
|
||||
unit TEXT,
|
||||
damage_basis TEXT CHECK(damage_basis IS NULL OR damage_basis IN ('flat','weapon_base_percent')),
|
||||
application_phase TEXT NOT NULL DEFAULT 'while_active' CHECK(application_phase IN (
|
||||
'while_active','on_event','after_event','on_enter','on_exit'
|
||||
)),
|
||||
combat_timing TEXT NOT NULL DEFAULT 'current' CHECK(combat_timing IN ('pre_event','current')),
|
||||
resource_kind TEXT CHECK(resource_kind IS NULL OR resource_kind IN ('health','armor','ammo')),
|
||||
min_state_value REAL,
|
||||
max_state_value REAL,
|
||||
description_slot INTEGER CHECK(description_slot IS NULL OR description_slot>=1),
|
||||
sort_order INTEGER NOT NULL CHECK(sort_order>=1),
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(rule_id,variant_key,outcome_key,sort_order),
|
||||
CHECK(min_state_value IS NULL OR min_state_value>=0),
|
||||
CHECK(max_state_value IS NULL OR max_state_value>=0),
|
||||
CHECK(min_state_value IS NULL OR max_state_value IS NULL OR max_state_value>=min_state_value),
|
||||
CHECK(
|
||||
(supports_uptime = 0 AND min_uptime IS NULL AND max_uptime IS NULL)
|
||||
OR
|
||||
(supports_uptime = 1 AND min_uptime IS NOT NULL AND max_uptime IS NOT NULL
|
||||
AND min_uptime >= 0 AND max_uptime <= 100 AND min_uptime <= max_uptime)
|
||||
(application_kind='active_modifier' AND stat_attribute_id IS NOT NULL AND damage_basis IS NULL)
|
||||
OR (application_kind='direct_damage' AND damage_basis IS NOT NULL)
|
||||
OR application_kind IN ('restore_health','restore_armor','restore_ammo','resource_cost','marker')
|
||||
)
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS talent_triggers_name_nocase_idx ON talent_triggers(name COLLATE NOCASE);
|
||||
CREATE TABLE IF NOT EXISTS talent_tier_triggers (
|
||||
talent_tier_id TEXT NOT NULL REFERENCES talent_tiers(id) ON DELETE CASCADE,
|
||||
trigger_id TEXT NOT NULL REFERENCES talent_triggers(id),
|
||||
PRIMARY KEY(talent_tier_id, trigger_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS conditional_effect_outcomes_rule_idx
|
||||
ON conditional_effect_outcomes(rule_id,variant_key,outcome_key,sort_order);
|
||||
CREATE TABLE IF NOT EXISTS talent_tier_effects (
|
||||
id TEXT PRIMARY KEY,
|
||||
talent_tier_id TEXT NOT NULL REFERENCES talent_tiers(id) ON DELETE CASCADE,
|
||||
@@ -604,11 +697,6 @@ CREATE TABLE IF NOT EXISTS os_protocol_talents (
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS os_protocol_talents_name_nocase_idx ON os_protocol_talents(name COLLATE NOCASE);
|
||||
CREATE TABLE IF NOT EXISTS os_protocol_talent_triggers (
|
||||
talent_id TEXT NOT NULL REFERENCES os_protocol_talents(id) ON DELETE CASCADE,
|
||||
trigger_id TEXT NOT NULL REFERENCES talent_triggers(id),
|
||||
PRIMARY KEY(talent_id, trigger_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS os_protocol_talent_effects (
|
||||
id TEXT PRIMARY KEY,
|
||||
talent_id TEXT NOT NULL REFERENCES os_protocol_talents(id) ON DELETE CASCADE,
|
||||
@@ -655,11 +743,6 @@ CREATE TABLE IF NOT EXISTS skill_chip_talents (
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS skill_chip_talents_name_nocase_idx ON skill_chip_talents(name COLLATE NOCASE);
|
||||
CREATE TABLE IF NOT EXISTS skill_chip_talent_triggers (
|
||||
talent_id TEXT NOT NULL REFERENCES skill_chip_talents(id) ON DELETE CASCADE,
|
||||
trigger_id TEXT NOT NULL REFERENCES talent_triggers(id),
|
||||
PRIMARY KEY(talent_id, trigger_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS skill_chip_talent_effects (
|
||||
id TEXT PRIMARY KEY,
|
||||
talent_id TEXT NOT NULL REFERENCES skill_chip_talents(id) ON DELETE CASCADE,
|
||||
@@ -857,6 +940,26 @@ CREATE TABLE IF NOT EXISTS specialization_abilities (
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(specialization_id,name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS specialization_ability_attacks (
|
||||
ability_id TEXT PRIMARY KEY REFERENCES specialization_abilities(id) ON DELETE CASCADE,
|
||||
base_damage REAL NOT NULL CHECK(base_damage>=0),
|
||||
damage_type TEXT NOT NULL CHECK(damage_type IN ('Blast','Pierce','Shredding')),
|
||||
delivery TEXT NOT NULL CHECK(delivery IN ('direct','periodic')),
|
||||
hits_per_activation INTEGER NOT NULL DEFAULT 1 CHECK(hits_per_activation>0),
|
||||
tick_interval_seconds REAL CHECK(tick_interval_seconds IS NULL OR tick_interval_seconds>0),
|
||||
damage_duration_seconds REAL CHECK(damage_duration_seconds IS NULL OR damage_duration_seconds>0),
|
||||
cast_seconds REAL NOT NULL DEFAULT 0 CHECK(cast_seconds>=0),
|
||||
target_cap INTEGER NOT NULL DEFAULT 1 CHECK(target_cap>0),
|
||||
charge_count INTEGER NOT NULL DEFAULT 1 CHECK(charge_count>0),
|
||||
charge_policy TEXT NOT NULL DEFAULT 'none' CHECK(charge_policy IN ('none','independent','full_set')),
|
||||
updated_at TEXT NOT NULL,
|
||||
CHECK(
|
||||
(delivery='direct' AND tick_interval_seconds IS NULL AND damage_duration_seconds IS NULL)
|
||||
OR
|
||||
(delivery='periodic' AND tick_interval_seconds IS NOT NULL AND damage_duration_seconds IS NOT NULL)
|
||||
),
|
||||
CHECK(charge_policy<>'none' OR charge_count=1)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS specialization_abilities_specialization_idx ON specialization_abilities(specialization_id,name);
|
||||
CREATE TABLE IF NOT EXISTS specialization_ability_effects (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -1010,6 +1113,26 @@ CREATE TABLE IF NOT EXISTS attribute_calculation_profiles (
|
||||
CHECK(hard_cap IS NULL OR hard_cap>=0),
|
||||
CHECK(soft_cap IS NULL OR hard_cap IS NULL OR hard_cap>=soft_cap)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS skill_attribute_calculation_profiles (
|
||||
id TEXT PRIMARY KEY,
|
||||
revision_id TEXT NOT NULL REFERENCES calculation_revisions(id) ON DELETE CASCADE,
|
||||
stat_attribute_id TEXT NOT NULL REFERENCES stat_attributes(id),
|
||||
stage_key TEXT NOT NULL CHECK(stage_key IN (
|
||||
'flat_damage','engineering','skill_damage','critical_chance','critical_damage',
|
||||
'multishot_chance','multishot_damage','final_damage',
|
||||
'cooldown_recovery','duration'
|
||||
)),
|
||||
operator TEXT NOT NULL CHECK(operator IN ('add','multiply')),
|
||||
weight REAL NOT NULL DEFAULT 1,
|
||||
soft_cap REAL,
|
||||
hard_cap REAL,
|
||||
curve_type TEXT NOT NULL DEFAULT 'none' CHECK(curve_type IN ('none','power','smoothstep')),
|
||||
curve_parameter REAL,
|
||||
UNIQUE(revision_id,stat_attribute_id,stage_key),
|
||||
CHECK(soft_cap IS NULL OR soft_cap>=0),
|
||||
CHECK(hard_cap IS NULL OR hard_cap>=0),
|
||||
CHECK(soft_cap IS NULL OR hard_cap IS NULL OR hard_cap>=soft_cap)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS calculation_calibration_cases (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user