diff --git a/game/assets/sfx/close_hand.wav b/game/assets/sfx/close_hand.wav new file mode 100644 index 00000000..eda58418 Binary files /dev/null and b/game/assets/sfx/close_hand.wav differ diff --git a/game/assets/sfx/cond_off.wav b/game/assets/sfx/cond_off.wav new file mode 100644 index 00000000..1b5e9803 Binary files /dev/null and b/game/assets/sfx/cond_off.wav differ diff --git a/game/assets/sfx/cond_on.wav b/game/assets/sfx/cond_on.wav new file mode 100644 index 00000000..e0c03dd0 Binary files /dev/null and b/game/assets/sfx/cond_on.wav differ diff --git a/game/assets/sfx/create_card.wav b/game/assets/sfx/create_card.wav new file mode 100644 index 00000000..cd917f6a Binary files /dev/null and b/game/assets/sfx/create_card.wav differ diff --git a/game/assets/sfx/discard-temporary-card.wav b/game/assets/sfx/discard-temporary-card.wav new file mode 100644 index 00000000..40ac43fa Binary files /dev/null and b/game/assets/sfx/discard-temporary-card.wav differ diff --git a/game/assets/sfx/draw_card.wav b/game/assets/sfx/draw_card.wav new file mode 100644 index 00000000..19d27f05 Binary files /dev/null and b/game/assets/sfx/draw_card.wav differ diff --git a/game/assets/sfx/equip_off.wav b/game/assets/sfx/equip_off.wav new file mode 100644 index 00000000..0baacd17 Binary files /dev/null and b/game/assets/sfx/equip_off.wav differ diff --git a/game/assets/sfx/equip_on.wav b/game/assets/sfx/equip_on.wav new file mode 100644 index 00000000..0bd8fd89 Binary files /dev/null and b/game/assets/sfx/equip_on.wav differ diff --git a/game/assets/sfx/gain_focus.wav b/game/assets/sfx/gain_focus.wav new file mode 100644 index 00000000..79246ea0 Binary files /dev/null and b/game/assets/sfx/gain_focus.wav differ diff --git a/game/assets/sfx/get_hp.wav b/game/assets/sfx/get_hp.wav new file mode 100644 index 00000000..54f4b7db Binary files /dev/null and b/game/assets/sfx/get_hp.wav differ diff --git a/game/assets/sfx/get_pack.wav b/game/assets/sfx/get_pack.wav new file mode 100644 index 00000000..7dd2358e Binary files /dev/null and b/game/assets/sfx/get_pack.wav differ diff --git a/game/assets/sfx/get_pp.wav b/game/assets/sfx/get_pp.wav new file mode 100644 index 00000000..61463df2 Binary files /dev/null and b/game/assets/sfx/get_pp.wav differ diff --git a/game/assets/sfx/open-pack.wav b/game/assets/sfx/open-pack.wav new file mode 100644 index 00000000..8e97fff0 Binary files /dev/null and b/game/assets/sfx/open-pack.wav differ diff --git a/game/assets/sfx/open_hand.wav b/game/assets/sfx/open_hand.wav new file mode 100644 index 00000000..a36c2dff Binary files /dev/null and b/game/assets/sfx/open_hand.wav differ diff --git a/game/assets/sfx/select_card.wav b/game/assets/sfx/select_card.wav new file mode 100644 index 00000000..62d1f810 Binary files /dev/null and b/game/assets/sfx/select_card.wav differ diff --git a/game/assets/sfx/shuffle_hand.wav b/game/assets/sfx/shuffle_hand.wav new file mode 100644 index 00000000..e4ff6b91 Binary files /dev/null and b/game/assets/sfx/shuffle_hand.wav differ diff --git a/game/assets/sfx/toggle_card.wav b/game/assets/sfx/toggle_card.wav new file mode 100644 index 00000000..8f9ed838 Binary files /dev/null and b/game/assets/sfx/toggle_card.wav differ diff --git a/game/assets/sfx/weapon_off.wav b/game/assets/sfx/weapon_off.wav new file mode 100644 index 00000000..ef42c67b Binary files /dev/null and b/game/assets/sfx/weapon_off.wav differ diff --git a/game/assets/sfx/weapon_on.wav b/game/assets/sfx/weapon_on.wav new file mode 100644 index 00000000..a724f8c4 Binary files /dev/null and b/game/assets/sfx/weapon_on.wav differ diff --git a/game/assets/texture/tiles.png b/game/assets/texture/tiles.png index 9e516631..96ba825f 100644 Binary files a/game/assets/texture/tiles.png and b/game/assets/texture/tiles.png differ diff --git a/game/database/domains/body/obstacle.json b/game/database/domains/body/obstacle.json index 9c703be9..337d6707 100644 --- a/game/database/domains/body/obstacle.json +++ b/game/database/domains/body/obstacle.json @@ -5,6 +5,6 @@ "faction":"agressive", "fin":-2, "name":"Obstacle", - "res":2, + "res":-1, "extends":false } \ No newline at end of file diff --git a/game/database/domains/card/arcane-burst.json b/game/database/domains/card/arcane-burst.json index 02ad06a3..13580b03 100644 --- a/game/database/domains/card/arcane-burst.json +++ b/game/database/domains/card/arcane-burst.json @@ -2,15 +2,13 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=arc", - "base":1, "center":"=self_pos", "ignore_owner":true, - "mod":80, "name":"damage_on_area", "sfx":"attack-hit", "size":3, - "type":"effect" + "type":"effect", + "value":"=amount" }], "inputs":[{ "aoe-hint":3, @@ -22,11 +20,6 @@ "output":"dummy", "tactical-hint":"harmful", "type":"input" - },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" },{ "name":"self", "output":"self", @@ -41,6 +34,13 @@ "name":"get_body_pos", "output":"self_pos", "type":"operator" + },{ + "attr":"ARC", + "base":1, + "mod":80, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, @@ -48,6 +48,7 @@ "cost":3, "exhaustion":"FULL", "icon":"card-arcane-burst", + "level":4, "name":"Arcane Burst", "set":"ranged_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/auto-fire.json b/game/database/domains/card/auto-fire.json index aec36f25..9910ac7f 100644 --- a/game/database/domains/card/auto-fire.json +++ b/game/database/domains/card/auto-fire.json @@ -9,10 +9,9 @@ "auto_activation":{ "ability":{ "effects":[{ - "attr":"=cor", - "base":0, - "mod":100, + "value":"=amount", "name":"damage_on_target", + "projectile":true, "sfx":"attack-hit", "target":"=target", "type":"effect" @@ -40,10 +39,12 @@ "range":3, "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] }, "trigger":"on_cycle" @@ -57,4 +58,4 @@ }, "icon":false, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/bloodthirst.json b/game/database/domains/card/bloodthirst.json index 94dbb690..ed2fbe9f 100644 --- a/game/database/domains/card/bloodthirst.json +++ b/game/database/domains/card/bloodthirst.json @@ -1,5 +1,6 @@ { "attr":"ANI", + "level":4, "cost":3, "icon":"card-bloodthirst", "name":"Bloodthirst", @@ -8,9 +9,7 @@ "auto_activation":{ "ability":{ "effects":[{ - "attr":"=ani", - "base":2, - "mod":50, + "value":"=amount", "name":"heal", "target":"=self-body", "type":"effect" @@ -25,18 +24,74 @@ "output":"self-body", "type":"operator" },{ - "name":"get_attribute", - "output":"ani", - "type":"operator", - "which":"ANI" + "attr":"ANI", + "base":2, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" }] }, "trigger":"on_kill" }, "charges":12, "operators":[], + "static":[{ + "descr":"Whenever you deal damage, you deal an\nadditional 1 damage for each other\ncreature within 3 tiles of you.", + "op":"damage_on_target", + "replacement-ability":{ + "effects":[{ + "attr":"=attr", + "base":"=base+x", + "mod":"=mod", + "name":"damage_on_target", + "sfx":"attack-hit", + "target":"=target", + "type":"effect", + "value":"=base+x" + }], + "inputs":[{ + "name":"integer", + "output":"value", + "type":"input" + },{ + "name":"body", + "output":"target", + "type":"input" + },{ + "name":"self", + "output":"self", + "type":"operator" + },{ + "actor":"=self", + "name":"get_actor_body", + "output":"self_body", + "type":"operator" + },{ + "body":"=self_body", + "name":"get_body_pos", + "output":"self_pos", + "type":"operator" + },{ + "ignore-owner":true, + "name":"count_nearby_bodies", + "output":"count", + "pos":"=self_pos", + "range":3, + "type":"operator", + "body-type":false + },{ + "lhs":"=value", + "name":"integer_binop", + "op":"+", + "output":"base+x", + "rhs":"=count", + "type":"operator" + }] + } + }], "status-tags":[], "tactical-hint":"helpful", "trigger":"on_turn" } -} \ No newline at end of file +} diff --git a/game/database/domains/card/bone-club-crush.json b/game/database/domains/card/bone-club-crush.json index bba3dc05..3cb890a8 100644 --- a/game/database/domains/card/bone-club-crush.json +++ b/game/database/domains/card/bone-club-crush.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":7, - "mod":20, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target-body", @@ -25,17 +23,20 @@ "pos":"=target-pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":7, + "mod":20, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":1, "icon":"card-bone-club", + "level":6, "name":"Bone Club Crush", "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/bone-club.json b/game/database/domains/card/bone-club.json index a8d9a4cf..7f41d8c2 100644 --- a/game/database/domains/card/bone-club.json +++ b/game/database/domains/card/bone-club.json @@ -1,6 +1,7 @@ { "attr":"COR", "cost":3, + "level":6, "icon":"card-bone-club", "name":"Bone Club", "one_time":true, @@ -24,4 +25,4 @@ "trigger":false, "auto_activation":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/chained-energy.json b/game/database/domains/card/chained-energy.json index 9d220b97..b620aca7 100644 --- a/game/database/domains/card/chained-energy.json +++ b/game/database/domains/card/chained-energy.json @@ -1,6 +1,7 @@ { "attr":"ANI", "cost":1, + "level":4, "desc":"", "icon":"card-chained-energy", "name":"Chained Energy", @@ -10,9 +11,7 @@ "auto_activation":{ "ability":{ "effects":[{ - "attr":"=ani", - "base":0, - "mod":50, + "value":"=amount", "name":"damage_on_target", "projectile":true, "sfx":"attack-hit", @@ -43,10 +42,12 @@ "range":4, "type":"operator" },{ - "name":"get_attribute", - "output":"ani", - "type":"operator", - "which":"ANI" + "attr":"ANI", + "base":0, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" }] }, "trigger":"on_play" diff --git a/game/database/domains/card/chained-surge.json b/game/database/domains/card/chained-surge.json index 7da1a499..42a0586e 100644 --- a/game/database/domains/card/chained-surge.json +++ b/game/database/domains/card/chained-surge.json @@ -11,7 +11,8 @@ }, "attr":"ANI", "cost":1, + "level":8, "icon":"card-chained-surge", "name":"Chained Surge", "set":"support_expert" -} \ No newline at end of file +} diff --git a/game/database/domains/card/change-of-plans.json b/game/database/domains/card/change-of-plans.json index 127cbb84..4ab02a65 100644 --- a/game/database/domains/card/change-of-plans.json +++ b/game/database/domains/card/change-of-plans.json @@ -11,10 +11,11 @@ }, "attr":"ARC", "cost":1, + "level":5, "desc":"Close your eyes and see beyond.", "icon":"card-change-of-plans", "name":"Change of Plans", "set":"support_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/concentration.json b/game/database/domains/card/concentration.json index 1148d0e6..455b559c 100644 --- a/game/database/domains/card/concentration.json +++ b/game/database/domains/card/concentration.json @@ -1,6 +1,7 @@ { "attr":"ANI", "cost":1, + "level":3, "desc":"", "half-exhaustion":true, "icon":"card-concentration", @@ -21,4 +22,4 @@ }, "art":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/dash.json b/game/database/domains/card/dash.json index fb039696..6f25e405 100644 --- a/game/database/domains/card/dash.json +++ b/game/database/domains/card/dash.json @@ -43,8 +43,9 @@ }, "attr":"COR", "cost":1, + "level":3, "desc":"Voooosh", "icon":"card-dash", "name":"Dash", "set":"maneuver_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/disposable-defenses.json b/game/database/domains/card/disposable-defenses.json index d8b5d079..2da69d65 100644 --- a/game/database/domains/card/disposable-defenses.json +++ b/game/database/domains/card/disposable-defenses.json @@ -1,6 +1,7 @@ { "attr":"NONE", "cost":3, + "level":7, "icon":"card-disposable-defenses", "name":"Disposable Defenses", "one_time":true, @@ -15,4 +16,4 @@ "tactical-hint":"helpful", "trigger":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/energy-beam.json b/game/database/domains/card/energy-beam.json index b1286e07..65a49fbc 100644 --- a/game/database/domains/card/energy-beam.json +++ b/game/database/domains/card/energy-beam.json @@ -2,10 +2,8 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=arc", - "base":0, + "value":"=amount", "center":"=target_pos", - "mod":100, "name":"damage_on_area", "sfx":"attack-hit", "size":1, @@ -46,10 +44,12 @@ "pos":"=hitscan", "type":"operator" },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, @@ -61,4 +61,4 @@ "type-description":"", "set":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/energy-shield.json b/game/database/domains/card/energy-shield.json index e1588c14..7bfa0cc0 100644 --- a/game/database/domains/card/energy-shield.json +++ b/game/database/domains/card/energy-shield.json @@ -4,6 +4,7 @@ "icon":"card-energy-shield", "name":"Energy Shield", "set":"armor_advanced", + "level":5, "widget":{ "charges":20, "equipment":{ @@ -14,4 +15,4 @@ "tactical-hint":"helpful", "trigger":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/entangle.json b/game/database/domains/card/entangle.json index 09200b44..1970a229 100644 --- a/game/database/domains/card/entangle.json +++ b/game/database/domains/card/entangle.json @@ -27,7 +27,8 @@ }, "attr":"ANI", "cost":1, + "level":5, "icon":"card-entangle", "name":"Entangle", "set":"maneuver_advanced" -} \ No newline at end of file +} diff --git a/game/database/domains/card/entangled.json b/game/database/domains/card/entangled.json index 4d417648..52ff8355 100644 --- a/game/database/domains/card/entangled.json +++ b/game/database/domains/card/entangled.json @@ -1,6 +1,7 @@ { "attr":"ANI", "icon":"card-entangle", + "level":5, "name":"Entangled", "one_time":true, "widget":{ @@ -15,4 +16,4 @@ "trigger":"on_turn" }, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/fireball.json b/game/database/domains/card/fireball.json index 12625135..88612987 100644 --- a/game/database/domains/card/fireball.json +++ b/game/database/domains/card/fireball.json @@ -2,10 +2,8 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=arc", - "base":0, + "value":"=amount", "center":"=target", - "mod":150, "name":"damage_on_area", "projectile":true, "sfx":"attack-hit", @@ -23,15 +21,18 @@ "type":"input", "empty-tile":false },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":0, + "mod":150, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"ARC", "cost":3, + "level":9, "desc":"Ages go by, and the fireball spell remains the\nbread and butter of arcane artists.", "icon":"card-fireball", "name":"Fireball", @@ -39,4 +40,4 @@ "set":"ranged_expert", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/firebolt.json b/game/database/domains/card/firebolt.json index 74a06035..410ce5a3 100644 --- a/game/database/domains/card/firebolt.json +++ b/game/database/domains/card/firebolt.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=arc", - "base":0, - "mod":50, + "value":"=amount", "name":"damage_on_target", "projectile":true, "sfx":"attack-hit", @@ -28,20 +26,22 @@ "pos":"=tgt", "type":"operator" },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":0, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"ARC", - "cost":2, + "cost":1, + "level":3, "desc":"'Ouch that hurts! - Imp with his face on fire.", "icon":"card-firebolt", "name":"Firebolt", - "pp":4, "set":"ranged_common", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/flash.json b/game/database/domains/card/flash.json index 2933fead..d5c86cf8 100644 --- a/game/database/domains/card/flash.json +++ b/game/database/domains/card/flash.json @@ -31,11 +31,11 @@ }, "attr":"ARC", "cost":2, + "level":3, "desc":"Aaaaaaahhh... Savior of the Universe!", "icon":"card-flash", "name":"Flash", - "pp":0, "type-description":"", "set":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/flurry-of-blows.json b/game/database/domains/card/flurry-of-blows.json index 1426d792..48d193e7 100644 --- a/game/database/domains/card/flurry-of-blows.json +++ b/game/database/domains/card/flurry-of-blows.json @@ -2,25 +2,19 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":5, - "mod":25, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=t1", "type":"effect" },{ - "attr":"=cor", - "base":5, - "mod":25, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=t2", "type":"effect" },{ - "attr":"=cor", - "base":5, - "mod":25, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=t3", @@ -72,16 +66,19 @@ "pos":"=t3pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":5, + "mod":25, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":3, + "level":8, "icon":"card-flurry-of-blows", "name":"Flurry of Blows", "set":"strikes_expert" -} \ No newline at end of file +} diff --git a/game/database/domains/card/greater-jump.json b/game/database/domains/card/greater-jump.json index cc01b949..a1bb1688 100644 --- a/game/database/domains/card/greater-jump.json +++ b/game/database/domains/card/greater-jump.json @@ -10,11 +10,9 @@ "vfx-spd":4, "sfx":false },{ - "attr":"=cor", - "base":4, + "value":"=amount", "center":"=pos", "ignore_owner":true, - "mod":50, "name":"damage_on_area", "sfx":"attack-hit", "size":3, @@ -30,10 +28,12 @@ "tactical-hint":"movement", "type":"input" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":4, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"self", "output":"self", @@ -51,8 +51,8 @@ "desc":"Take THAT gravity!", "icon":"card-jump", "name":"Greater Jump", - "pp":3, + "level":9, "set":"maneuver_expert", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/greater-rush.json b/game/database/domains/card/greater-rush.json index 49c58ff3..fa1fd54e 100644 --- a/game/database/domains/card/greater-rush.json +++ b/game/database/domains/card/greater-rush.json @@ -10,10 +10,8 @@ "vfx-spd":1, "sfx":false },{ - "attr":"=cor", - "base":1, + "value":"=amount", "center":"=damage_pos", - "mod":100, "name":"damage_on_area", "sfx":"attack-hit", "size":1, @@ -55,20 +53,22 @@ "pos":"=target_pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":1, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":2, + "level":6, "desc":"It's rush hour. And I'm not talking about kung-fu.", "icon":"card-rush", "name":"Greater Rush", - "pp":10, "set":"maneuver_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/greater_healing_potion.json b/game/database/domains/card/greater_healing_potion.json index 756c7241..c2dfa142 100644 --- a/game/database/domains/card/greater_healing_potion.json +++ b/game/database/domains/card/greater_healing_potion.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":0, - "base":10, - "mod":100, + "value":10, "name":"heal", "target":"=self_body", "type":"effect" @@ -23,9 +21,10 @@ }, "attr":"NONE", "cost":1, + "level":5, "icon":"card-greater-potion", "name":"Greater Healing Potion", "one_time":true, "set":"consumables_advanced", - "temporary":true -} \ No newline at end of file + "temporary":false +} diff --git a/game/database/domains/card/haste.json b/game/database/domains/card/haste.json index 7281d435..e93acc54 100644 --- a/game/database/domains/card/haste.json +++ b/game/database/domains/card/haste.json @@ -1,6 +1,7 @@ { "attr":"ANI", "cost":5, + "level":8, "desc":"'Gotta go fast!' - A mutated spiked beast motto.", "icon":"card-haste", "name":"Haste", @@ -23,4 +24,4 @@ }, "set":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/heal.json b/game/database/domains/card/heal.json index 7e08478f..21d53cb2 100644 --- a/game/database/domains/card/heal.json +++ b/game/database/domains/card/heal.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=ANI", - "base":0, - "mod":100, + "value":"=amount", "name":"heal", "target":"=self", "type":"effect" @@ -23,10 +21,12 @@ "non-wall":false, "empty-tile":false },{ - "name":"get_attribute", - "output":"ANI", - "type":"operator", - "which":"ANI" + "attr":"ANI", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"get_body_at", "output":"self", @@ -37,11 +37,11 @@ }, "attr":"ANI", "cost":2, + "level":5, "desc":"", "icon":"card-heal", "name":"Heal", - "pp":3, "set":"support_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/healing_potion.json b/game/database/domains/card/healing_potion.json index d9a742e1..79821618 100644 --- a/game/database/domains/card/healing_potion.json +++ b/game/database/domains/card/healing_potion.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=vit", - "base":4, - "mod":100, + "value":4, "name":"heal", "target":"=self_body", "type":"effect" @@ -18,21 +16,16 @@ "name":"get_actor_body", "output":"self_body", "type":"operator" - },{ - "name":"get_body_attribute", - "output":"vit", - "type":"operator", - "which":"VIT" }] } }, "attr":"NONE", "cost":1, + "level":1, "desc":"Gulp. Down the hatch, foxy.", "icon":"card-potion", "name":"Healing Potion", "one_time":true, - "pp":4, "set":"consumables_common", "type-description":"" -} \ No newline at end of file +} diff --git a/game/database/domains/card/hide-vest.json b/game/database/domains/card/hide-vest.json index 75ca3ad3..35fa921a 100644 --- a/game/database/domains/card/hide-vest.json +++ b/game/database/domains/card/hide-vest.json @@ -1,6 +1,7 @@ { "attr":"NONE", "cost":3, + "level":4, "icon":"card-hide-vest", "name":"Hide Vest", "set":"armor_common", @@ -14,4 +15,4 @@ "tactical-hint":"helpful", "trigger":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/hook-n-uppercut.json b/game/database/domains/card/hook-n-uppercut.json index e0a6d70e..53bac096 100644 --- a/game/database/domains/card/hook-n-uppercut.json +++ b/game/database/domains/card/hook-n-uppercut.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":6, - "mod":40, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target-body", @@ -26,16 +24,19 @@ "pos":"=target-pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":6, + "mod":40, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":2, + "level":6, "icon":"card-hook-n-uppercut", "name":"Hook and Uppercut", "set":"strikes_advanced" -} \ No newline at end of file +} diff --git a/game/database/domains/card/illusion_of_darkness.json b/game/database/domains/card/illusion_of_darkness.json index 1d667949..b2b36292 100644 --- a/game/database/domains/card/illusion_of_darkness.json +++ b/game/database/domains/card/illusion_of_darkness.json @@ -30,8 +30,8 @@ "desc":"Goodnight sweet prince.", "icon":"card-illusion-of-darkness", "name":"Illusion of Darkness", - "pp":3, + "level":7, "set":"control_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/impact-grenade.json b/game/database/domains/card/impact-grenade.json index 7160cabd..78b46f7d 100644 --- a/game/database/domains/card/impact-grenade.json +++ b/game/database/domains/card/impact-grenade.json @@ -2,10 +2,8 @@ "art":{ "art_ability":{ "effects":[{ - "attr":0, - "base":5, + "value":5, "center":"=target_pos", - "mod":100, "name":"damage_on_area", "projectile":true, "size":2, @@ -25,8 +23,9 @@ }, "attr":"NONE", "cost":1, + "level":4, "icon":"card-impact-grenade", "name":"Impact Grenade", "one_time":true, "set":"consumables_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/jump.json b/game/database/domains/card/jump.json index 893eb1a5..66ae89ef 100644 --- a/game/database/domains/card/jump.json +++ b/game/database/domains/card/jump.json @@ -10,11 +10,9 @@ "vfx-spd":4, "sfx":false },{ - "attr":"=cor", - "base":1, + "value":"=amount", "center":"=target_pos", "ignore_owner":true, - "mod":50, "name":"damage_on_area", "size":2, "type":"effect" @@ -29,10 +27,12 @@ "tactical-hint":"harmful", "type":"input" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":1, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"self", "output":"self", @@ -47,8 +47,9 @@ }, "attr":"COR", "cost":2, + "level":6, "desc":"Up up up!", "name":"Jump", - "set":"armor_advanced", + "set":"maneuver_advanced", "icon":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/lead-pipe-strike.json b/game/database/domains/card/lead-pipe-strike.json index bc999cbe..49e72dc4 100644 --- a/game/database/domains/card/lead-pipe-strike.json +++ b/game/database/domains/card/lead-pipe-strike.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":7, - "mod":30, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=body", @@ -26,17 +24,20 @@ "pos":"=pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":7, + "mod":30, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":3, + "level":7, "icon":"card-lead-pipe", "name":"Lead Pipe Strike", "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/lead-pipe.json b/game/database/domains/card/lead-pipe.json index 5a87abdf..3f50a7e7 100644 --- a/game/database/domains/card/lead-pipe.json +++ b/game/database/domains/card/lead-pipe.json @@ -1,6 +1,7 @@ { "attr":"COR", "cost":3, + "level":7, "icon":"card-lead-pipe", "name":"Lead Pipe", "set":"weapon_advanced", @@ -18,4 +19,4 @@ "tactical-hint":"helpful", "trigger":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/light-drops.json b/game/database/domains/card/light-drops.json index e17d02cd..ce782856 100644 --- a/game/database/domains/card/light-drops.json +++ b/game/database/domains/card/light-drops.json @@ -1,6 +1,7 @@ { "attr":"NONE", "cost":1, + "level":5, "icon":"card-light-drops", "name":"Light Drops", "one_time":true, @@ -20,4 +21,4 @@ "inputs":[] } } -} \ No newline at end of file +} diff --git a/game/database/domains/card/old-laddle-strike.json b/game/database/domains/card/old-laddle-strike.json index 1a26dcc2..3fd78274 100644 --- a/game/database/domains/card/old-laddle-strike.json +++ b/game/database/domains/card/old-laddle-strike.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":5, - "mod":40, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target_body", @@ -26,18 +24,21 @@ "pos":"=target_pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":5, + "mod":40, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":3, + "level":4, "icon":"card-old-laddle-strike", "name":"Old Laddle Strike", "one_time":true, "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/old-laddle.json b/game/database/domains/card/old-laddle.json index 4667344e..52c60e61 100644 --- a/game/database/domains/card/old-laddle.json +++ b/game/database/domains/card/old-laddle.json @@ -1,6 +1,7 @@ { "attr":"COR", "cost":3, + "level":4, "desc":"A mass-produced weapon.", "icon":"card-old-laddle", "name":"Old Laddle", @@ -27,4 +28,4 @@ "auto_activation":false }, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/plasma-bomb.json b/game/database/domains/card/plasma-bomb.json index 5e4bd351..d9cd3375 100644 --- a/game/database/domains/card/plasma-bomb.json +++ b/game/database/domains/card/plasma-bomb.json @@ -2,10 +2,8 @@ "art":{ "art_ability":{ "effects":[{ - "attr":0, - "base":12, + "value":12, "center":"=target_pos", - "mod":100, "name":"damage_on_area", "projectile":true, "sfx":"attack-hit", @@ -25,8 +23,9 @@ }, "attr":"NONE", "cost":1, + "level":8, "icon":"card-plasma-bomb", "name":"Plasma Bomb", "one_time":true, "set":"consumables_expert" -} \ No newline at end of file +} diff --git a/game/database/domains/card/plated-shield.json b/game/database/domains/card/plated-shield.json index 47305813..e489b5e1 100644 --- a/game/database/domains/card/plated-shield.json +++ b/game/database/domains/card/plated-shield.json @@ -1,6 +1,7 @@ { - "attr":"NONE", + "attr":"COR", "cost":3, + "level":9, "icon":"card-plated-shield", "name":"Plated Shield", "set":"armor_expert", @@ -18,4 +19,4 @@ "tactical-hint":"helpful", "trigger":false } -} \ No newline at end of file +} diff --git a/game/database/domains/card/proximity-detector.json b/game/database/domains/card/proximity-detector.json index 92688db6..346a557b 100644 --- a/game/database/domains/card/proximity-detector.json +++ b/game/database/domains/card/proximity-detector.json @@ -13,10 +13,8 @@ "target":"=body_self", "type":"effect" },{ - "attr":"=arc", - "base":0, + "value":"=amount", "center":"=pos", - "mod":100, "name":"damage_on_area", "sfx":"attack-hit", "size":2, @@ -33,10 +31,12 @@ "output":"pos", "type":"operator" },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] }, "trigger":"on_done" @@ -67,4 +67,4 @@ }, "icon":false, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/push.json b/game/database/domains/card/push.json index ba58ea7e..2d523c14 100644 --- a/game/database/domains/card/push.json +++ b/game/database/domains/card/push.json @@ -60,10 +60,11 @@ }, "attr":"COR", "cost":1, + "level":2, "desc":"Outta my way!", "icon":"card-push", "name":"Push", "set":"control_common", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/rage.json b/game/database/domains/card/rage.json index a1363d2f..6c317d6e 100644 --- a/game/database/domains/card/rage.json +++ b/game/database/domains/card/rage.json @@ -1,6 +1,7 @@ { "attr":"ANI", "cost":2, + "level":5, "desc":"They say Rage is all the rage with the kids.", "icon":"card-rage", "name":"Rage", @@ -23,4 +24,4 @@ "equipment":false }, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/reckless-smash.json b/game/database/domains/card/reckless-smash.json index 866d7801..b05c6edc 100644 --- a/game/database/domains/card/reckless-smash.json +++ b/game/database/domains/card/reckless-smash.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":12, - "mod":50, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target", @@ -29,10 +27,12 @@ "empty-tile":false, "non-wall":false },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":12, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"get_body_at", "output":"target", @@ -52,11 +52,11 @@ }, "attr":"COR", "cost":3, + "level":7, "desc":"They say 'no pain, no gain'.\nI'll give them what they want.", "icon":"card-reckless-smash", "name":"Reckless Smash", - "pp":0, "set":"strikes_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/roundhouse-kick.json b/game/database/domains/card/roundhouse-kick.json index d84e4312..599e3d20 100644 --- a/game/database/domains/card/roundhouse-kick.json +++ b/game/database/domains/card/roundhouse-kick.json @@ -2,11 +2,9 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":6, + "value":"=amount", "center":"=self-pos", "ignore_owner":true, - "mod":60, "name":"damage_on_area", "sfx":"attack-hit", "size":2, @@ -20,10 +18,12 @@ "tactical-hint":"harmful", "type":"input" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":6, + "mod":60, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"self", "output":"self", @@ -43,7 +43,8 @@ }, "attr":"COR", "cost":3, + "level":4, "icon":"card-roundhouse-kick", "name":"Roundhouse Kick", "set":"strikes_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/rush.json b/game/database/domains/card/rush.json index 5f75dd73..f00ce90d 100644 --- a/game/database/domains/card/rush.json +++ b/game/database/domains/card/rush.json @@ -10,10 +10,8 @@ "vfx-spd":1, "sfx":false },{ - "attr":"=cor", - "base":0, + "value":"=amount", "center":"=damage_pos", - "mod":50, "name":"damage_on_area", "sfx":"attack-hit", "size":1, @@ -54,17 +52,20 @@ "pos":"=target_pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":0, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":2, + "level":3, "desc":"Excuse me sir, I've got somewhere to be right now", "icon":"card-rush", "name":"Rush", "set":"maneuver_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/rusty-blaster-shot.json b/game/database/domains/card/rusty-blaster-shot.json index e4f5ba8e..7c9055e8 100644 --- a/game/database/domains/card/rusty-blaster-shot.json +++ b/game/database/domains/card/rusty-blaster-shot.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":0, - "mod":100, + "value":"=amount", "name":"damage_on_target", "projectile":true, "sfx":"attack-hit", @@ -28,17 +26,20 @@ "pos":"=target-pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":1, + "level":6, "icon":"card-blaster", "name":"Blaster Shot", "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/rusty-blaster.json b/game/database/domains/card/rusty-blaster.json index 024b879a..d65ca015 100644 --- a/game/database/domains/card/rusty-blaster.json +++ b/game/database/domains/card/rusty-blaster.json @@ -1,6 +1,7 @@ { "attr":"COR", "cost":5, + "level":6, "desc":"An old but reliable arcane blaster.", "icon":"card-blaster", "name":"Rusty Blaster", @@ -26,4 +27,4 @@ "trigger":false }, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/self-destruct.json b/game/database/domains/card/self-destruct.json index fd54d95c..2d9e4910 100644 --- a/game/database/domains/card/self-destruct.json +++ b/game/database/domains/card/self-destruct.json @@ -9,10 +9,8 @@ "auto_activation":{ "ability":{ "effects":[{ - "attr":"=arc", - "base":0, + "value":"=amount", "center":"=pos", - "mod":100, "name":"damage_on_area", "sfx":"attack-hit", "size":3, @@ -32,10 +30,12 @@ "output":"actor", "type":"operator" },{ - "name":"get_attribute", - "output":"arc", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "body":"=body_self", "name":"get_body_pos", @@ -54,4 +54,4 @@ }, "icon":false, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/sidestep.json b/game/database/domains/card/sidestep.json index 24ce3cfa..68bb6b8d 100644 --- a/game/database/domains/card/sidestep.json +++ b/game/database/domains/card/sidestep.json @@ -33,10 +33,11 @@ }, "attr":"ANI", "cost":2, + "level":3, "desc":"Ooops, excuse me!", "half-exhaustion":true, "icon":"card-sidestep", "name":"Side-step", "set":"maneuver_common", "temporary":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/signet-of-inspiration.json b/game/database/domains/card/signet-of-inspiration.json index 6714bed6..0c7d56c8 100644 --- a/game/database/domains/card/signet-of-inspiration.json +++ b/game/database/domains/card/signet-of-inspiration.json @@ -11,8 +11,9 @@ }, "attr":"NONE", "cost":1, + "level":8, "icon":"card-miracle", "name":"Signet of Inspiration", "one_time":true, "set":"consumables_expert" -} \ No newline at end of file +} diff --git a/game/database/domains/card/sonic-boom.json b/game/database/domains/card/sonic-boom.json index cbf9fb1a..5ef59998 100644 --- a/game/database/domains/card/sonic-boom.json +++ b/game/database/domains/card/sonic-boom.json @@ -2,10 +2,8 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":3, + "value":"=amount", "center":"=damage_pos", - "mod":50, "name":"damage_on_area", "sfx":"attack-hit", "size":1, @@ -46,16 +44,19 @@ "pos":"=hit_pos", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":3, + "mod":50, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":2, + "level":7, "icon":"card-sonic-boom", "name":"Sonic Boom", "set":"ranged_advanced" -} \ No newline at end of file +} diff --git a/game/database/domains/card/soul_robe.json b/game/database/domains/card/soul_robe.json index af1057f7..6f92afeb 100644 --- a/game/database/domains/card/soul_robe.json +++ b/game/database/domains/card/soul_robe.json @@ -1,6 +1,7 @@ { "attr":"ANI", "cost":3, + "level":5, "desc":"", "icon":"card-soul-robe", "name":"Soul Robe", @@ -28,4 +29,4 @@ }, "set":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/spark-rod-aoe.json b/game/database/domains/card/spark-rod-aoe.json index b2fdea6c..b9560f1f 100644 --- a/game/database/domains/card/spark-rod-aoe.json +++ b/game/database/domains/card/spark-rod-aoe.json @@ -2,11 +2,9 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":4, + "value":"=amount", "center":"=target-pos", "ignore_owner":true, - "mod":30, "name":"damage_on_area", "sfx":"attack-hit", "size":3, @@ -20,17 +18,20 @@ "tactical-hint":"harmful", "type":"input" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":4, + "mod":30, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":3, + "level":10, "icon":"card-spark-rod-shockwave", "name":"Spark Blast", "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/spark-rod-target.json b/game/database/domains/card/spark-rod-target.json index e302be09..2172bf23 100644 --- a/game/database/domains/card/spark-rod-target.json +++ b/game/database/domains/card/spark-rod-target.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":6, - "mod":30, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target-body", @@ -27,17 +25,20 @@ "pos":"=target", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":6, + "mod":30, + "name":"effective_power", + "output":"amount", + "type":"operator" }] } }, "attr":"COR", "cost":2, + "level":10, "icon":"card-spark-rod-strike", "name":"Rod Strike", "temporary":true, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/spark_rod.json b/game/database/domains/card/spark_rod.json index 4bdd7bd0..0bf84e34 100644 --- a/game/database/domains/card/spark_rod.json +++ b/game/database/domains/card/spark_rod.json @@ -1,6 +1,7 @@ { "attr":"COR", "cost":3, + "level":10, "desc":"'Why just ~hit~ your enemies when you can also create an eletric explosion around them? Well, Tark Tech answers this dillema with the new Spark Rod 2000*!!\n\n*Spark Rod is not recommended for children' - old and controversial commercial from Tark Tech.", "icon":"card-spark-rod", "name":"Spark Rod 2000", @@ -28,4 +29,4 @@ } }, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/stick_flame.json b/game/database/domains/card/stick_flame.json index 767caaaf..17847ed5 100644 --- a/game/database/domains/card/stick_flame.json +++ b/game/database/domains/card/stick_flame.json @@ -28,6 +28,7 @@ }, "attr":"ARC", "cost":2, + "level":7, "desc":"'Hey Danny, hold this for me, will ya?'.\n\nRobert was surprised Danny didn't sent him an invite for his birthday the week after.", "icon":"card-sticky-flame", "name":"Stick Flame", @@ -35,4 +36,4 @@ "set":"ranged_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/sticky_flame.json b/game/database/domains/card/sticky_flame.json index e51e9bb8..394bdb79 100644 --- a/game/database/domains/card/sticky_flame.json +++ b/game/database/domains/card/sticky_flame.json @@ -1,6 +1,7 @@ { "attr":"ARC", "cost":0, + "level":7, "desc":"Oh man, this is gonna blow...", "name":"Sticky Flame", "one_time":true, @@ -9,9 +10,7 @@ "auto_activation":{ "ability":{ "effects":[{ - "attr":"=ARC", - "base":1, - "mod":100, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=body_self", @@ -22,10 +21,12 @@ "output":"body_self", "type":"input" },{ - "name":"get_attribute", - "output":"ARC", - "type":"operator", - "which":"ARC" + "attr":"ARC", + "base":1, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" }] }, "trigger":"on_done" @@ -40,4 +41,4 @@ }, "icon":false, "set":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/stomp.json b/game/database/domains/card/stomp.json index 9e19aeab..240aa401 100644 --- a/game/database/domains/card/stomp.json +++ b/game/database/domains/card/stomp.json @@ -9,11 +9,9 @@ "size":3, "type":"effect" },{ - "attr":"=ani", - "base":4, + "value":"=amount", "center":"=pos", "ignore_owner":true, - "mod":20, "name":"damage_on_area", "sfx":"attack-hit", "size":3, @@ -32,10 +30,12 @@ "empty-tile":false, "non-wall":false },{ - "name":"get_attribute", - "output":"ani", - "type":"operator", - "which":"ANI" + "attr":"ANI", + "base":4, + "mod":20, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"self", "output":"self", @@ -55,6 +55,7 @@ }, "attr":"ANI", "cost":3, + "level":9, "desc":"", "icon":"card-stomp", "name":"Stomp", @@ -62,4 +63,4 @@ "set":"control_expert", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/strike.json b/game/database/domains/card/strike.json index a562d849..f3694187 100644 --- a/game/database/domains/card/strike.json +++ b/game/database/domains/card/strike.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":2, - "mod":30, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target_body", @@ -24,10 +22,12 @@ "non-wall":false, "empty-tile":false },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":2, + "mod":30, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"get_body_at", "output":"target_body", @@ -38,6 +38,7 @@ }, "attr":"COR", "cost":1, + "level":3, "desc":"", "icon":"card-strike", "name":"Strike", @@ -45,4 +46,4 @@ "type-description":"", "one_time":false, "temporary":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/stunning-blow.json b/game/database/domains/card/stunning-blow.json index 0cd51dae..cbde420a 100644 --- a/game/database/domains/card/stunning-blow.json +++ b/game/database/domains/card/stunning-blow.json @@ -28,8 +28,9 @@ }, "attr":"ANI", "cost":2, + "level":4, "desc":"The best defense is a good offense.\nThe best offense is a good punch.", "icon":"card-stunning-blow", "name":"Stunning Blow", "set":"control_common" -} \ No newline at end of file +} diff --git a/game/database/domains/card/teleport.json b/game/database/domains/card/teleport.json index 52573371..0e52d09f 100644 --- a/game/database/domains/card/teleport.json +++ b/game/database/domains/card/teleport.json @@ -35,6 +35,7 @@ }, "attr":"ARC", "cost":2, + "level":7, "desc":"", "icon":"card-teleport", "name":"Teleport", @@ -42,4 +43,4 @@ "set":"maneuver_advanced", "type-description":"", "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/trained-strike.json b/game/database/domains/card/trained-strike.json index 3c0ae84b..f350e3b8 100644 --- a/game/database/domains/card/trained-strike.json +++ b/game/database/domains/card/trained-strike.json @@ -2,9 +2,7 @@ "art":{ "art_ability":{ "effects":[{ - "attr":"=cor", - "base":0, - "mod":100, + "value":"=amount", "name":"damage_on_target", "sfx":"attack-hit", "target":"=target_body", @@ -33,10 +31,12 @@ "output":"self_body", "type":"operator" },{ - "name":"get_attribute", - "output":"cor", - "type":"operator", - "which":"COR" + "attr":"COR", + "base":0, + "mod":100, + "name":"effective_power", + "output":"amount", + "type":"operator" },{ "name":"get_body_at", "output":"target_body", @@ -54,4 +54,4 @@ "set":false, "temporary":false, "one_time":false -} \ No newline at end of file +} diff --git a/game/database/domains/card/vial-of-essence.json b/game/database/domains/card/vial-of-essence.json index 05ecdd7e..74369de1 100644 --- a/game/database/domains/card/vial-of-essence.json +++ b/game/database/domains/card/vial-of-essence.json @@ -11,8 +11,9 @@ }, "attr":"NONE", "cost":1, + "level":7, "icon":"card-vial-of-essence", "name":"Vial of Essence", "one_time":true, "set":"consumables_advanced" -} \ No newline at end of file +} diff --git a/game/database/domains/drop/heart.json b/game/database/domains/drop/heart.json index d1970f7e..f09324af 100644 --- a/game/database/domains/drop/heart.json +++ b/game/database/domains/drop/heart.json @@ -6,7 +6,8 @@ "mod":100, "name":"heal", "target":"=self-body", - "type":"effect" + "type":"effect", + "value":3 }], "inputs":[{ "name":"self", diff --git a/game/database/resources/sfx/close-hand.json b/game/database/resources/sfx/close-hand.json new file mode 100644 index 00000000..ad176043 --- /dev/null +++ b/game/database/resources/sfx/close-hand.json @@ -0,0 +1,4 @@ +{ + "filename":"close_hand.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/condition-equip.json b/game/database/resources/sfx/condition-equip.json new file mode 100644 index 00000000..30d7f142 --- /dev/null +++ b/game/database/resources/sfx/condition-equip.json @@ -0,0 +1,4 @@ +{ + "filename":"cond_on.wav", + "polyphony":3 +} \ No newline at end of file diff --git a/game/database/resources/sfx/condition-unequip.json b/game/database/resources/sfx/condition-unequip.json new file mode 100644 index 00000000..58fc7333 --- /dev/null +++ b/game/database/resources/sfx/condition-unequip.json @@ -0,0 +1,4 @@ +{ + "filename":"cond_off.wav", + "polyphony":3 +} \ No newline at end of file diff --git a/game/database/resources/sfx/create-equipment.json b/game/database/resources/sfx/create-equipment.json new file mode 100644 index 00000000..cd82c5e3 --- /dev/null +++ b/game/database/resources/sfx/create-equipment.json @@ -0,0 +1,4 @@ +{ + "filename":"create_card.wav", + "polyphony":3 +} \ No newline at end of file diff --git a/game/database/resources/sfx/discard-card.json b/game/database/resources/sfx/discard-card.json new file mode 100644 index 00000000..9e98e279 --- /dev/null +++ b/game/database/resources/sfx/discard-card.json @@ -0,0 +1,4 @@ +{ + "filename":"draw_card.wav", + "polyphony":5 +} \ No newline at end of file diff --git a/game/database/resources/sfx/dissolve.json b/game/database/resources/sfx/dissolve.json new file mode 100644 index 00000000..2d59ecd3 --- /dev/null +++ b/game/database/resources/sfx/dissolve.json @@ -0,0 +1,4 @@ +{ + "filename":"discard-temporary-card.wav", + "polyphony":3 +} \ No newline at end of file diff --git a/game/database/resources/sfx/draw-card.json b/game/database/resources/sfx/draw-card.json new file mode 100644 index 00000000..9e98e279 --- /dev/null +++ b/game/database/resources/sfx/draw-card.json @@ -0,0 +1,4 @@ +{ + "filename":"draw_card.wav", + "polyphony":5 +} \ No newline at end of file diff --git a/game/database/resources/sfx/focus-gain.json b/game/database/resources/sfx/focus-gain.json new file mode 100644 index 00000000..e36ee121 --- /dev/null +++ b/game/database/resources/sfx/focus-gain.json @@ -0,0 +1,4 @@ +{ + "filename":"gain_focus.wav", + "polyphony":6 +} \ No newline at end of file diff --git a/game/database/resources/sfx/get-hp.json b/game/database/resources/sfx/get-hp.json new file mode 100644 index 00000000..40b446cc --- /dev/null +++ b/game/database/resources/sfx/get-hp.json @@ -0,0 +1,4 @@ +{ + "filename":"get_hp.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/get-pack.json b/game/database/resources/sfx/get-pack.json new file mode 100644 index 00000000..310feadc --- /dev/null +++ b/game/database/resources/sfx/get-pack.json @@ -0,0 +1,4 @@ +{ + "filename":"get_pack.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/get-pp.json b/game/database/resources/sfx/get-pp.json new file mode 100644 index 00000000..7d8c9ae6 --- /dev/null +++ b/game/database/resources/sfx/get-pp.json @@ -0,0 +1,4 @@ +{ + "filename":"get_pp.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/open-hand.json b/game/database/resources/sfx/open-hand.json new file mode 100644 index 00000000..7ec7fa33 --- /dev/null +++ b/game/database/resources/sfx/open-hand.json @@ -0,0 +1,4 @@ +{ + "filename":"open_hand.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/open-pack.json b/game/database/resources/sfx/open-pack.json new file mode 100644 index 00000000..2f368245 --- /dev/null +++ b/game/database/resources/sfx/open-pack.json @@ -0,0 +1,4 @@ +{ + "filename":"open-pack.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/select-card.json b/game/database/resources/sfx/select-card.json new file mode 100644 index 00000000..09e3ced9 --- /dev/null +++ b/game/database/resources/sfx/select-card.json @@ -0,0 +1,4 @@ +{ + "filename":"select_card.wav", + "polyphony":5 +} \ No newline at end of file diff --git a/game/database/resources/sfx/shuffle.json b/game/database/resources/sfx/shuffle.json new file mode 100644 index 00000000..125eb72e --- /dev/null +++ b/game/database/resources/sfx/shuffle.json @@ -0,0 +1,4 @@ +{ + "filename":"shuffle_hand.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/toggle-card.json b/game/database/resources/sfx/toggle-card.json new file mode 100644 index 00000000..6a73066d --- /dev/null +++ b/game/database/resources/sfx/toggle-card.json @@ -0,0 +1,4 @@ +{ + "filename":"toggle_card.wav", + "polyphony":4 +} \ No newline at end of file diff --git a/game/database/resources/sfx/wearable-equip.json b/game/database/resources/sfx/wearable-equip.json new file mode 100644 index 00000000..dfc7ad05 --- /dev/null +++ b/game/database/resources/sfx/wearable-equip.json @@ -0,0 +1,4 @@ +{ + "filename":"equip_on.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/wearable-unequip.json b/game/database/resources/sfx/wearable-unequip.json new file mode 100644 index 00000000..58edadc5 --- /dev/null +++ b/game/database/resources/sfx/wearable-unequip.json @@ -0,0 +1,4 @@ +{ + "filename":"equip_off.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/wieldable-equip.json b/game/database/resources/sfx/wieldable-equip.json new file mode 100644 index 00000000..1a60a1e9 --- /dev/null +++ b/game/database/resources/sfx/wieldable-equip.json @@ -0,0 +1,4 @@ +{ + "filename":"weapon_on.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/sfx/wieldable-unequip.json b/game/database/resources/sfx/wieldable-unequip.json new file mode 100644 index 00000000..8c206c2d --- /dev/null +++ b/game/database/resources/sfx/wieldable-unequip.json @@ -0,0 +1,4 @@ +{ + "filename":"weapon_off.wav", + "polyphony":2 +} \ No newline at end of file diff --git a/game/database/resources/tileset/demo.json b/game/database/resources/tileset/demo.json index 37cb85e9..1c14f2ee 100644 --- a/game/database/resources/tileset/demo.json +++ b/game/database/resources/tileset/demo.json @@ -1,10 +1,33 @@ { "mapping":{ - "ALTAR":[240,0,80,160,0,80], - "EXITDOWN":[80,0,80,160,0,80], - "EXITUP":[320,0,80,160,0,80], - "FLOOR":[0,0,80,160,0,80], - "WALL":[160,0,80,160,0,80] + "ALTAR":[{ + "quad":[80,150,80,120,0,0], + "weight":1 + }], + "EXITDOWN":[{ + "quad":[0,150,80,120,0,0], + "weight":1 + }], + "EXITUP":[{ + "quad":[240,90,80,120,0,60], + "weight":1 + }], + "FLOOR":[{ + "quad":[0,0,80,120,0,30], + "weight":10 + },{ + "quad":[80,0,80,120,0,30], + "weight":1 + },{ + "quad":[160,0,80,120,0,30], + "weight":1 + },{ + "quad":[240,0,80,120,0,30], + "weight":0 + },{ + "quad":[320,0,80,210,0,30], + "weight":0 + }] }, "texture":"bare-tiles" } diff --git a/game/database/resources/tileset/otherdemo.json b/game/database/resources/tileset/otherdemo.json index 6a47bf83..51ac6392 100644 --- a/game/database/resources/tileset/otherdemo.json +++ b/game/database/resources/tileset/otherdemo.json @@ -1,10 +1,25 @@ { "mapping":{ - "ALTAR":[240,0,80,160,0,80], - "EXITDOWN":[80,0,80,160,0,80], - "EXITUP":[320,0,80,160,0,80], - "FLOOR":[0,0,80,160,0,80], - "WALL":[160,0,80,160,0,80] + "ALTAR":[{ + "quad":[240,0,80,160,0,80], + "weight":1 + }], + "EXITDOWN":[{ + "quad":[80,0,80,160,0,80], + "weight":1 + }], + "EXITUP":[{ + "quad":[320,0,80,160,0,80], + "weight":1 + }], + "FLOOR":[{ + "quad":[0,0,80,160,0,80], + "weight":1 + }], + "WALL":[{ + "quad":[160,0,80,160,0,80], + "weight":1 + }] }, "texture":"purple-tiles" -} +} \ No newline at end of file diff --git a/game/database/resources/tileset/ruins.json b/game/database/resources/tileset/ruins.json index 44da8b08..fa50b072 100644 --- a/game/database/resources/tileset/ruins.json +++ b/game/database/resources/tileset/ruins.json @@ -1,10 +1,25 @@ { "mapping":{ - "ALTAR":[240,0,80,160,0,80], - "EXITDOWN":[80,160,80,160,0,80], - "EXITUP":[0,160,80,160,0,80], - "FLOOR":[0,0,80,160,0,80], - "WALL":[0,320,80,160,0,80] + "ALTAR":[{ + "quad":[240,0,80,160,0,80], + "weight":1 + }], + "EXITDOWN":[{ + "quad":[80,160,80,160,0,80], + "weight":1 + }], + "EXITUP":[{ + "quad":[0,160,80,160,0,80], + "weight":1 + }], + "FLOOR":[{ + "quad":[0,0,80,160,0,80], + "weight":1 + }], + "WALL":[{ + "quad":[0,320,80,160,0,80], + "weight":1 + }] }, "texture":"tiles-alt" -} +} \ No newline at end of file diff --git a/game/database/schema/card.lua b/game/database/schema/card.lua index 50063114..6ca5fce3 100644 --- a/game/database/schema/card.lua +++ b/game/database/schema/card.lua @@ -1,4 +1,5 @@ +local ABILITY = require 'domain.ability' local DEFS = require 'domain.definitions' local _CARDS = 'domains.card' @@ -14,6 +15,8 @@ return { { id = 'desc', name = "Description", type = 'text' }, { id = 'attr', name = "Type (attr)", type = 'enum', options = DEFS.CARD_ATTRIBUTES }, + { id = 'level', name = "Level", type = 'range', min = 1, + max = 10, default = 1 }, { id = 'cost', name = "Cost", type = 'range', min = 0, max = DEFS.ACTION.MAX_FOCUS }, { id = 'half-exhaustion', name = "Half exhaustion", type = 'boolean' }, @@ -38,6 +41,18 @@ return { options = DEFS.TRIGGERS }, { id = 'trigger-condition', name = "Spend Trigger Condition", type = 'ability', optional = true }, + { + id = 'static', name = "Static Abilities", + type = 'array', schema = { + { id = 'op', name = "Operation or Effect", type = 'enum', + options = ABILITY.allOperationsAndEffects() }, + { id = 'replacement-ability', name = "Condition and Replacement", + type = 'ability', + hint = "When the inputs are met, the operation\n" .. + "or effect are replaced by the effects here" }, + { id = 'descr', name = "Rules Text", type = 'text' }, + } + }, { id = 'operators', name = "Static Attribute Operator", type = 'array', schema = { diff --git a/game/database/schema/tileset.lua b/game/database/schema/tileset.lua index 6fb1cc6f..b700d5ea 100644 --- a/game/database/schema/tileset.lua +++ b/game/database/schema/tileset.lua @@ -5,22 +5,43 @@ return { { id = 'mapping', name = "Mapping", type = 'section', required = true, schema = { - { id = 'FLOOR', name = "Floor Quad #", type = 'vector', - size = 6, range = {0}, - signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} }, - { id = 'WALL', name = "Wall Quad #", type = 'vector', - size = 6, range = {0}, - signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} }, - { id = 'ALTAR', name = "Altar Quad #", type = 'vector', - size = 6, range = {0}, - signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} }, - { id = 'EXITDOWN', name = "Exit down Quad #", type = 'vector', - size = 6, range = {0}, - signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} }, - { id = 'EXITUP', name = "Exit up Quad #", type = 'vector', - size = 6, range = {0}, - signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} }, - }, + { + id = 'FLOOR', name = "Floor Tiles", type = 'array', + schema = { + { id = 'weight', name = "Weight", type = 'integer', range = {0,10} }, + { id = 'quad', name = "Quad #", type = 'vector', + size = 6, range = {0}, + signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} } + } + }, + { + id = 'ALTAR', name = "Altar Tiles", type = 'array', + schema = { + { id = 'weight', name = "Weight", type = 'integer', range = {0,10} }, + { id = 'quad', name = "Quad #", type = 'vector', + size = 6, range = {0}, + signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} } + } + }, + { + id = 'EXITDOWN', name = "Exit Down Tiles", type = 'array', + schema = { + { id = 'weight', name = "Weight", type = 'integer', range = {0,10} }, + { id = 'quad', name = "Quad #", type = 'vector', + size = 6, range = {0}, + signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} } + } + }, + { + id = 'EXITUP', name = "Exit Up Tiles", type = 'array', + schema = { + { id = 'weight', name = "Weight", type = 'integer', range = {0,10} }, + { id = 'quad', name = "Quad #", type = 'vector', + size = 6, range = {0}, + signature = {'ix', 'iy', 'qw', 'qh', 'ox', 'oy'} } + } + } + } } } diff --git a/game/devmode/view/actor_inspector.lua b/game/devmode/view/actor_inspector.lua index d23387dc..4029c5f6 100644 --- a/game/devmode/view/actor_inspector.lua +++ b/game/devmode/view/actor_inspector.lua @@ -1,4 +1,5 @@ +local ACTIONDEFS = require 'domain.definitions.action' local IMGUI = require 'imgui' return function (actor) @@ -18,7 +19,7 @@ return function (actor) if changed then actor:getBody():setHP(newhp) end - IMGUI.Text(("PWRLVL: %d"):format(actor:getPowerLevel())) + IMGUI.Text(("PWRLVL: %.2f"):format(actor:getPowerLevel())) IMGUI.Separator() IMGUI.Text(("COR: %d"):format(actor:getCOR())) IMGUI.Text(("ARC: %d"):format(actor:getARC())) @@ -32,8 +33,14 @@ return function (actor) IMGUI.Text(("FIN: %d"):format(actor:getBody():getFIN())) IMGUI.Text(("RES: %d"):format(actor:getBody():getRES())) IMGUI.Separator() - IMGUI.Text(("Skill: %d"):format(actor:getBody():getSkill())) - IMGUI.Text(("Speed: %d"):format(actor:getBody():getSpeed())) + local focus_per_cycle = actor:getBody():getFocusRegen() + * ACTIONDEFS.CYCLE_UNIT + IMGUI.Text(("Focus Regen: %.2f focus/cycle"):format(focus_per_cycle)) + local turns_per_cycle = actor:getBody():getSpeed() / ACTIONDEFS.MAX_ENERGY + * ACTIONDEFS.CYCLE_UNIT + IMGUI.Text(("Speed: %.2f turns/cycle"):format(turns_per_cycle)) + IMGUI.Text(("Base HP: %.2f"):format(actor:getBody():getBaseMaxHP())) + IMGUI.Text(("Extra HP: %+d%%"):format(actor:getBody():getExtraMaxHP() * 100)) end end diff --git a/game/devmode/view/body_inspector.lua b/game/devmode/view/body_inspector.lua index 5f14365e..8f2a0f2c 100644 --- a/game/devmode/view/body_inspector.lua +++ b/game/devmode/view/body_inspector.lua @@ -27,8 +27,8 @@ return function (body) IMGUI.Text(("FIN: %d"):format(body:getFIN())) IMGUI.Text(("RES: %d"):format(body:getRES())) IMGUI.Separator() - IMGUI.Text(("Skill: %d"):format(body:getSkill())) - IMGUI.Text(("Speed: %d"):format(body:getSpeed())) + IMGUI.Text(("Base HP: %.2f"):format(body:getBaseMaxHP())) + IMGUI.Text(("Extra HP: %+d%%"):format(body:getExtraMaxHP() * 100)) IMGUI.Separator() IMGUI.Text("Widgets:") IMGUI.Indent(20) diff --git a/game/devmode/view/input/ability.lua b/game/devmode/view/input/ability.lua index 26ab83c8..18fe1f3a 100644 --- a/game/devmode/view/input/ability.lua +++ b/game/devmode/view/input/ability.lua @@ -1,4 +1,6 @@ +-- luacheck: no self + local ABILITY = require 'domain.ability' local IMGUI = require 'imgui' local DB = require 'database' @@ -9,6 +11,7 @@ local table = table local ipairs = ipairs local require = require local setfenv = setfenv +local pcall = pcall local _CMDTYPES = { 'inputs', 'effects', @@ -20,6 +23,8 @@ local _idgen = IDGenerator() local AbilityEditor = class:new() +-- luacheck: no self + local function _split(str, max_line_length) local lines = {} local line @@ -43,12 +48,35 @@ function AbilityEditor:instance(obj, _elementspec, _fieldschema) local _ability = _elementspec[_fieldschema.id] or { inputs = {}, effects = {} } - local _selected = nil local _active = not (not _elementspec[_fieldschema.id] and _fieldschema.optional) - local function _delete() - table.remove(_ability[_selected.cmdtype], _selected.idx) + local _cmd_editors = {} + local SPEC_EDITOR = require 'devmode.view.specification_editor' + for _,cmdtype in ipairs(_CMDTYPES) do + _cmd_editors[cmdtype] = {} + end + + local function _bind_delete(cmdtype, i) + return function () + table.remove(_ability[cmdtype], i) + for _, editor in ipairs(_cmd_editors[cmdtype]) do + editor.dirty = true + end + end + end + + local function _editor_for(cmdtype, i) + local cmd = _ability[cmdtype][i] + local editor_list = _cmd_editors[cmdtype] + if not editor_list[i] or editor_list[i].dirty then + local _, _, renderer = SPEC_EDITOR(cmd, cmd.type .. 's/' .. cmd.name, + _CMDTYPES[cmdtype], + _bind_delete(cmdtype, i), nil, + _ability) + editor_list[i] = { render = renderer, dirty = false } + end + return editor_list[i] end local function _commandList(gui, cmdtype) @@ -79,15 +107,10 @@ function AbilityEditor:instance(obj, _elementspec, _fieldschema) view = ("%2d: %s"):format(i, command.name) end IMGUI.PushID(("%s/%s:%d"):format(_ability, cmdtype, i)) - if IMGUI.Selectable(view, - _selected and _selected.cmdtype == cmdtype - and _selected.idx == i) then - _selected = _selected or {} - _selected.cmdtype = cmdtype - _selected.idx = i - gui:push('specification_editor', command, - command.type .. 's/' .. command.name, _CMDTYPES[cmdtype], - _delete, nil, _ability) + local id = ("%s:%i"):format(command.name, i) + if IMGUI.TreeNodeEx_2(id, { "Framed" }, view) then + _editor_for(cmdtype, i).render(gui) + IMGUI.TreePop() end IMGUI.PopID() end @@ -113,7 +136,7 @@ function AbilityEditor:instance(obj, _elementspec, _fieldschema) IMGUI.Unindent(20) end - function input(gui) + function input(gui) -- luacheck: no global if _fieldschema.optional then IMGUI.PushID(_fieldschema.id .. ".check") _active = IMGUI.Checkbox("", _active) @@ -133,18 +156,21 @@ function AbilityEditor:instance(obj, _elementspec, _fieldschema) IMGUI.Text("Preview") IMGUI.Indent(20) IMGUI.PushItemWidth(360) - local descr = ABILITY.preview(_ability, {}, {}) + local ok, descr = pcall(ABILITY.preview,_ability, {}, {}) + if not ok then + descr = "Could not preview ability" + end local text = "" for _, line in ipairs(_split(descr, 40)) do text = text .. line .. "\n" end - IMGUI.InputTextMultiline("", text, 1024, 0, 0, { "ReadOnly" }) + IMGUI.InputTextMultiline("", text, 1024, 0, 40, { "ReadOnly" }) IMGUI.PopItemWidth() IMGUI.Unindent(40) end end - function __operator:call(gui) + function __operator:call(gui) -- luacheck: no global return obj.input(gui) end diff --git a/game/devmode/view/input/reference.lua b/game/devmode/view/input/reference.lua index 1a884cba..cb1e14e6 100644 --- a/game/devmode/view/input/reference.lua +++ b/game/devmode/view/input/reference.lua @@ -1,6 +1,5 @@ local IMGUI = require 'imgui' -local DB = require 'database' local class = require 'lux.class' local setfenv = setfenv @@ -9,14 +8,16 @@ local ipairs = ipairs local pairs = pairs local require = require local type = type +local tostring = tostring local OutputEditor = class:new() +-- luacheck: no self function OutputEditor:instance(obj, _elementspec, _fieldschema) setfenv(1, obj) - function input(gui) + function input(_) -- luacheck: no global IMGUI.PushID(_fieldschema.id) IMGUI.Text(_fieldschema.name) local value, changed = IMGUI.InputText("", _elementspec[_fieldschema.id] @@ -27,7 +28,7 @@ function OutputEditor:instance(obj, _elementspec, _fieldschema) IMGUI.PopID() end - function __operator:call(gui) + function __operator:call(gui) -- luacheck: no global return obj.input(gui) end end @@ -42,11 +43,11 @@ function ValueEditor:instance(obj, _elementspec, _fieldschema, _parent) local inputStr = require 'devmode.view.helpers.string' local function _appendRefs(from, to, match) - for k,item in pairs(from) do + for _,item in pairs(from) do if item == _elementspec then return false end local t = require(('domain.%ss.%s'):format(item.type, item.name)).type if not t or t == match then - table.insert(to, "=" .. item.output) + table.insert(to, "=" .. tostring(item.output)) end end return true @@ -55,6 +56,7 @@ function ValueEditor:instance(obj, _elementspec, _fieldschema, _parent) local function _getRefs() local refs = {} _appendRefs(_parent.inputs, refs, _fieldschema.match) + _appendRefs(_parent.effects, refs, _fieldschema.match) local idx = 0 for i,ref in ipairs(refs) do if ref == _elementspec[_fieldschema.id] then @@ -80,7 +82,7 @@ function ValueEditor:instance(obj, _elementspec, _fieldschema, _parent) _use_ref = false end - function input(gui) + function input(_) -- luacheck: no global IMGUI.PushID(_fieldschema.id) IMGUI.Text(_fieldschema.name) local changed @@ -102,12 +104,12 @@ function ValueEditor:instance(obj, _elementspec, _fieldschema, _parent) if _fieldschema.match == 'integer' or _fieldschema.match == 'string' then IMGUI.SameLine() - _use_ref, changed = IMGUI.Checkbox("Ref##".._fieldschema.id, _use_ref) + _use_ref, _ = IMGUI.Checkbox("Ref##".._fieldschema.id, _use_ref) end IMGUI.PopID() end - function __operator:call(gui) + function __operator:call(gui) -- luacheck: no global return obj.input(gui) end end diff --git a/game/devmode/view/specification_editor.lua b/game/devmode/view/specification_editor.lua index 3ed199cb..f9d72386 100644 --- a/game/devmode/view/specification_editor.lua +++ b/game/devmode/view/specification_editor.lua @@ -12,22 +12,30 @@ return function(elementspec, group_name, title, delete, rename, parent) table.insert(inputs, INPUT(elementspec, fieldschema, parent)) end - return title .. " Editor", 2, function(gui) - - -- meta actions - local spec_meta = getmetatable(elementspec) - if spec_meta and spec_meta.is_leaf and IMGUI.Button("Save##1") then - DB.save(elementspec) + local function _meta_buttons(gui, spec_meta) + if spec_meta and spec_meta.is_leaf then + if IMGUI.Button("Save##1") then + DB.save(elementspec) + end + IMGUI.SameLine() end - IMGUI.SameLine() - if rename and IMGUI.Button("Rename##1") then - gui:push('name_input', title, rename) + if rename then + if IMGUI.Button("Rename##1") then + gui:push('name_input', title, rename) + end + IMGUI.SameLine() end - IMGUI.SameLine() if IMGUI.Button("Delete##1") then delete() return true end + end + + return title .. " Editor", 2, function(gui) + + -- meta actions + local spec_meta = getmetatable(elementspec) + if _meta_buttons(gui, spec_meta) then return true end IMGUI.Spacing() IMGUI.Separator() IMGUI.Spacing() @@ -55,18 +63,7 @@ return function(elementspec, group_name, title, delete, rename, parent) IMGUI.Spacing() IMGUI.Separator() IMGUI.Spacing() - if spec_meta and spec_meta.is_leaf and IMGUI.Button("Save##2") then - DB.save(elementspec) - end - IMGUI.SameLine() - if rename and IMGUI.Button("Rename##2") then - gui:push('name_input', title, rename) - end - IMGUI.SameLine() - if IMGUI.Button("Delete##2") then - delete() - return true - end + if _meta_buttons(gui, spec_meta) then return true end end end diff --git a/game/domain/ability.lua b/game/domain/ability.lua index d750761c..031fadea 100644 --- a/game/domain/ability.lua +++ b/game/domain/ability.lua @@ -4,17 +4,11 @@ local OP = require 'lux.pack' 'domain.operators' local IN = require 'lux.pack' 'domain.inputs' local DB = require 'database' -local _CMDTYPES = { - effect = FX, - inputs = IN, - operators = OP -} - -local function _unref(ref, values) +local function _deref(ref, registers) if type(ref) == 'string' then local n = ref:match '=(.+)' if n then - return values[n] + return registers[n] end end return ref @@ -22,6 +16,20 @@ end local ABILITY = {} +function ABILITY.allOperationsAndEffects() + local t = {} + local n = 1 + for _,option in DB.subschemaTypes('operators') do + t[n] = option + n = n + 1 + end + for _,option in DB.subschemaTypes('effects') do + t[n] = option + n = n + 1 + end + return t +end + function ABILITY.inputsOf(ability) return ipairs(ability.inputs) end @@ -38,72 +46,107 @@ local function _fields(cmd) return DB.schemaFor(cmd.type .. 's/' .. cmd.name) end -local function _unrefFieldValues(cmd, values) - local unrefd_field_values = {} +local function _derefFieldValues(cmd, registers) + local derefd_field_values = {} for _,field in _fields(cmd) do - unrefd_field_values[field.id] = _unref(cmd[field.id], values) + derefd_field_values[field.id] = _deref(cmd[field.id], registers) end - return unrefd_field_values + return derefd_field_values end function ABILITY.checkInputs(ability, actor, inputvalues) - local values = {} + local registers = {} for _,cmd in ipairs(ability.inputs) do + local derefd_field_values = _derefFieldValues(cmd, registers) if cmd.type == 'input' then - local unrefd_field_values = _unrefFieldValues(cmd, values) local inputspec = IN[cmd.name] - if inputspec.isValid(actor, unrefd_field_values, + if inputspec.isValid(actor, derefd_field_values, inputvalues[cmd.output]) then if cmd.output then - values[cmd.output] = inputvalues[cmd.output] + registers[cmd.output] = inputvalues[cmd.output] end else return false end + elseif cmd.type == 'operator' then + registers[cmd.output] = OP[cmd.name].process(actor, derefd_field_values) end end - return true + return true, registers end local _CMDLISTS = { 'inputs', 'effects' } +local _CMDMAP = { operator = OP, effect = FX } + +-- Every helper function used here is either const or mutates only the values +-- it returns. +local _hashAbility, _matches, _matchAbilities, _copySourceAbilities, + _importRegisters, _expandCommands, _redirectOutputs, _markSourceAbilities +--- Executes an ability from an actor using the provided input values. +-- +-- Might match static abilities, causing the expansion of commands. This +-- happens whenever a command has the name indicated by an static ability and +-- its parameter values satisfy the input of that static ability. In this +-- case, the command is substituted by the sequence of effect commands in the +-- static ability. +-- +-- Expanded commands have two nuances. First, registers written to by the +-- input commands of the static ability are imported into the current ability, +-- but name clashes raise an error. Second, expanded commands with output +-- name "result" are redirected to the orignally substituted command's output. function ABILITY.execute(ability, actor, inputvalues) - local values = {} + local registers = {} + local src_abilities_of = {} + local redirected_output = {} for _,cmdlist in ipairs(_CMDLISTS) do - for _,cmd in ipairs(ability[cmdlist]) do + local cmd_stream = {} + for i,cmd in ipairs(ability[cmdlist]) do + cmd_stream[i] = cmd + end + while #cmd_stream > 0 do + local cmd = table.remove(cmd_stream, 1) local value - local type, name = cmd.type, cmd.name - if type == 'input' then + if cmd.type == 'input' then value = inputvalues[cmd.output] - else - local unrefd_field_values = _unrefFieldValues(cmd, values) - if type == 'operator' then - value = OP[name].process(actor, unrefd_field_values) - elseif type == 'effect' then - value = FX[name].process(actor, unrefd_field_values) + elseif _CMDMAP[cmd.type] then + local derefd_field_values = _derefFieldValues(cmd, registers) + local match = _matchAbilities(actor, cmd.name, derefd_field_values, + src_abilities_of[cmd]) + if match then + registers = _importRegisters(registers, cmd, match) + cmd_stream = _expandCommands(cmd_stream, match) + redirected_output = _redirectOutputs(redirected_output, match, cmd) + src_abilities_of = _markSourceAbilities(src_abilities_of, match, cmd) else - return error("Invalid command type") + local process = _CMDMAP[cmd.type][cmd.name].process + value = process(actor, derefd_field_values) end + else + return error("Invalid command type") end if cmd.output then - values[cmd.output] = value + if cmd.output == 'result' and redirected_output[cmd] then + registers[redirected_output[cmd]] = value + else + registers[cmd.output] = value + end end end end end -function _NOPREVIEW() +local function _NOPREVIEW() return nil end -function ABILITY.preview(ability, actor, inputvalues) - local values = {} - local prevs = {} +function ABILITY.preview(ability, actor, inputvalues, capitalize) + local registers = {} for _,cmdlist in ipairs(_CMDLISTS) do for _,cmd in ipairs(ability[cmdlist]) do local prev, value local type, name = cmd.type, cmd.name - local unrefd_field_values = _unrefFieldValues(cmd, values) + local derefd_field_values = _derefFieldValues(cmd, registers) if type == 'input' then value = IN[name].preview or function() return inputvalues[cmd.output] @@ -118,15 +161,100 @@ function ABILITY.preview(ability, actor, inputvalues) end end if cmd.output and value then - values[cmd.output] = value(actor, unrefd_field_values) + registers[cmd.output] = value(actor, derefd_field_values) end - local text = (prev or _NOPREVIEW)(actor, unrefd_field_values) + local text = (prev or _NOPREVIEW)(actor, derefd_field_values) if text then - table.insert(values, text) + table.insert(registers, text) + end + end + end + local preview = table.concat(registers, ". ") .. "." + if capitalize then + return preview:gsub("^(%w)", string.upper) + else + return preview + end +end + +-- Helper functions from here on + +function _hashAbility(match) + local hash = tostring(match.ability) .. tostring(match.source) + return hash +end + +function _matches(actor, match, field_values, src_abilities) + local ability = match.ability + if not (src_abilities and src_abilities[_hashAbility(match)]) then + return ABILITY.checkInputs(ability, actor, field_values) + end + return false +end + +function _matchAbilities(actor, cmd_name, field_values, src_abilities) + for _, widget in actor:getBody():eachWidget() do + for _, static_ability in widget:getStaticAbilities() do + if static_ability['op'] == cmd_name then + local match = { + ability = static_ability['replacement-ability'], + source = widget + } + local ok, new_values = _matches(actor, match, field_values, + src_abilities) + if ok then + match.new_values = new_values + return match + end end end end - return table.concat(values, ". ") .. "." +end + +function _copySourceAbilities(src_abilities) + local copy = {} + for k, v in pairs(src_abilities or {}) do + copy[k] = v + end + return copy +end + +local _OVERWRITE_MSG = [[ +WARNING: register "%s" overwritten by expansion of ability + from card %s on command %s!]] + +function _importRegisters(registers, cmd, match) + for k, v in pairs(match.new_values) do + if registers[k] then + print(_OVERWRITE_MSG:format(k, match.source:getName(), cmd.name)) + end + registers[k] = v + end + return registers +end + +function _expandCommands(cmd_stream, match) + for i, expanded_cmd in ipairs(match.ability['effects']) do + table.insert(cmd_stream, i, expanded_cmd) + end + return cmd_stream +end + +function _redirectOutputs(redirected_output, match, cmd) + for _, expanded_cmd in ipairs(match.ability['effects']) do + redirected_output[expanded_cmd] = cmd['output'] + end + return redirected_output +end + +function _markSourceAbilities(src_abilities_of, match, cmd) + for _, expanded_cmd in ipairs(match.ability['effects']) do + local src_abilities = _copySourceAbilities(src_abilities_of[cmd]) + src_abilities[_hashAbility(match)] = true + src_abilities_of[expanded_cmd] = src_abilities + end + return src_abilities_of end return ABILITY + diff --git a/game/domain/actor.lua b/game/domain/actor.lua index ed1b27b9..62bf5bd0 100644 --- a/game/domain/actor.lua +++ b/game/domain/actor.lua @@ -279,8 +279,23 @@ function Actor:isHandFull() return #self.hand >= DEFS.HAND_LIMIT end +function Actor:canPlayCard(card) + local attr = card:getRelatedAttr() + local level + if attr ~= DEFS.CARD_ATTRIBUTES.NONE then + level = self:getAttribute(attr) + else + level = math.max(self:getAttribute(DEFS.PRIMARY_ATTRIBUTES.COR), + self:getAttribute(DEFS.PRIMARY_ATTRIBUTES.ARC)) + level = math.max(self:getAttribute(DEFS.PRIMARY_ATTRIBUTES.ANI), + level) + end + return level >= card:getLevel() and + self:getFocus() >= card:getCost() +end + function Actor:getFocus() - return self.focus + return math.floor(self.focus) end function Actor:getBufferSize() @@ -570,9 +585,27 @@ function Actor:grabDrops(tile) if ABILITY.checkInputs(dropspec.ability, self, inputvalues) then table.remove(drops, i) n = n-1 - coroutine.yield('report', { - sfx = 'get-item' - }) + + for _, effect in ipairs(dropspec.ability.effects) do + local name = effect.name + if name == "give_pack" then + coroutine.yield('report', { + sfx = 'get-pack' + }) + elseif name == "reward_pp" then + coroutine.yield('report', { + sfx = 'get-pp' + }) + elseif name == "heal" then + coroutine.yield('report', { + sfx = 'get-hp' + }) + else + coroutine.yield('report', { + sfx = 'get-item' + }) + end + end ABILITY.execute(dropspec.ability, self, inputvalues) else i = i+1 @@ -582,6 +615,7 @@ end function Actor:tick() self.energy = self.energy + self:getSPD() + self:gainFocus(self:getBody():getFocusRegen()) end function Actor:ready() @@ -626,7 +660,6 @@ function Actor:discardHand() end function Actor:beginTurn() - self:gainFocus(ACTIONDEFS.FOCUS_PER_TURN) while self:getHandSize() < DEFS.HAND_LIMIT and self:canDrawCard() do self:drawCard() end @@ -691,7 +724,7 @@ function Actor:getPowerLevel() for _,value in pairs(self.upgrades) do lvl = value + lvl end - return lvl + return lvl / 100 end return Actor diff --git a/game/domain/body.lua b/game/domain/body.lua index c8c73305..475b653f 100644 --- a/game/domain/body.lua +++ b/game/domain/body.lua @@ -167,12 +167,25 @@ function Body:getSpeed() return APT.SPEED(self:getSPD(), self:getFIN()) end -function Body:getSkill() - return APT.SKILL(self:getSKL(), self:getEFC()) +function Body:getFocusRegen() + return APT.FOCUS_REGEN(self:getSKL(), self:getEFC()) / 100 +end + +function Body:getBaseMaxHP() + local power_level = 3 + local actor = self:getActor() + if actor then + power_level = actor:getPowerLevel() + end + return APT.BASE_HP(power_level, self:getRES()) +end + +function Body:getExtraMaxHP() + return APT.EXTRA_HP(self:getVIT()) / 10 end function Body:getMaxHP() - return APT.HP(self:getVIT(), self:getRES()) + return math.floor(self:getBaseMaxHP() * (1 + self:getExtraMaxHP())) end function Body:getConsumption() -- luacheck: no self diff --git a/game/domain/card.lua b/game/domain/card.lua index d0aaa63b..8ecd3bc3 100644 --- a/game/domain/card.lua +++ b/game/domain/card.lua @@ -1,5 +1,6 @@ local ABILITY = require 'domain.ability' +local TRIGGERS = require 'domain.definitions.triggers' local ACTIONSDEFS = require 'domain.definitions.action' local DB = require 'database' local GameElement = require 'domain.gameelement' @@ -54,6 +55,10 @@ function Card:getRelatedAttr() return self:getSpec('attr') end +function Card:getLevel() + return self:getSpec('level') or 1 +end + function Card:getOwner() return Util.findId(self.owner_id) end @@ -116,6 +121,10 @@ function Card:getWidgetTriggerCondition() return self:getSpec('widget')['trigger-condition'] end +function Card:getStaticAbilities() + return ipairs(self:getSpec('widget')['static'] or {}) +end + function Card:getStaticOperators() return ipairs(self:getSpec('widget')['operators'] or {}) end @@ -207,41 +216,54 @@ local _EPQ_TYPENAMES = { function Card:getEffect() local effect = "" local inputs = { self = self:getOwner() } + effect = effect .. "Lv " .. self:getLevel() .. " " if self:isTemporary() then effect = effect .. "Temporary " elseif self:isOneTimeOnly() then effect = effect .. "Single-Use " end if self:isArt() then - effect = effect .. ("Art (%d focus)\n\n"):format(self:getCost()) - .. ABILITY.preview(self:getArtAbility(), self:getOwner(), inputs) + effect = effect .. "Art\n\n" + effect = effect .. ABILITY.preview(self:getArtAbility(), self:getOwner(), + inputs, true) elseif self:isWidget() then local place = self:getWidgetPlacement() if place then effect = effect .. _EPQ_TYPENAMES[place] else effect = effect .. "Condition" end - effect = effect .. (" (%d focus"):format(self:getCost()) local charges = self:getWidgetCharges() if charges > 0 then local trigger = self:getWidgetTrigger() - effect = effect .. (", %d charges%s"):format( + effect = effect .. (" (%d charges%s)"):format( charges, trigger and "/" .. trigger or "" ) end - effect = effect .. ")" - local auto = self:getWidgetTriggeredAbility() if auto then - local ability, trigger = auto.ability, auto.trigger - effect = effect .. ("\n\nTrigger [%s]: "):format(trigger) - .. ABILITY.preview(ability, self:getOwner(), inputs) + do -- static abilities + local abs, n = {}, 0 + for _,ab in self:getStaticAbilities() do + n = n + 1 + abs[n] = ab.descr ~= "" and ab.descr + or "Missing static ability description." + end + if n > 0 then + effect = effect .. "\n\n" .. table.concat(abs, "\n\n") + end end - local ops, n = {}, 0 - for _,op in self:getStaticOperators() do - n = n + 1 - ops[n] = ("%s %s%d"):format(op.attr, op.op, op.val) + do -- static operators + local ops, n = {}, 0 + for _,op in self:getStaticOperators() do + n = n + 1 + ops[n] = ("You get %s %s%d"):format(op.attr, op.op, op.val) + end + if n > 0 then + effect = effect .. "\n\n" .. table.concat(ops, ", ") .. "." + end end - if n > 0 then - effect = effect .. "\n\n" .. table.concat(ops, ", ") .. "." + local auto = self:getWidgetTriggeredAbility() if auto then + local ability, trigger = auto.ability, TRIGGERS.WORDING[auto.trigger] + effect = effect .. ("\n\n%s, "):format(trigger) + .. ABILITY.preview(ability, self:getOwner(), inputs) end -- TODO: describe created cards local equip = self:getSpec('widget').equipment diff --git a/game/domain/definitions/aptitude.lua b/game/domain/definitions/aptitude.lua index 848fc598..41362b98 100644 --- a/game/domain/definitions/aptitude.lua +++ b/game/domain/definitions/aptitude.lua @@ -29,16 +29,20 @@ function APT.ATTR_LEVEL(owner, which) return lv-1 end -function APT.HP(vit, res) - return math.floor((3 + res) * vit) +function APT.BASE_HP(power_level, res) + return math.floor(power_level * (2 + res/2)) +end + +function APT.EXTRA_HP(vit) + return math.floor(vit) end function APT.SPEED(spd, fin) return math.floor(10 + fin + spd/2) end -function APT.SKILL(skl, efc) - return math.floor(skl + efc) +function APT.FOCUS_REGEN(skl, efc) + return math.floor(3 + efc + skl) end return APT diff --git a/game/domain/definitions/attribute.lua b/game/domain/definitions/attribute.lua index ad708fd3..1f1f67e0 100644 --- a/game/domain/definitions/attribute.lua +++ b/game/domain/definitions/attribute.lua @@ -5,8 +5,8 @@ ATTR.BASE_SPD = 10 ATTR.INITIAL_UPGRADE = 100 ATTR.INFLUENCE = { - SKL = {'COR', 'ARC'}, - SPD = {'ARC', 'ANI'}, + SPD = {'COR', 'ARC'}, + SKL = {'ARC', 'ANI'}, VIT = {'ANI', 'COR'} } diff --git a/game/domain/definitions/colors.lua b/game/domain/definitions/colors.lua index 69842688..c2a5b568 100644 --- a/game/domain/definitions/colors.lua +++ b/game/domain/definitions/colors.lua @@ -6,14 +6,14 @@ local COLORS = {} COLORS.NEUTRAL = Color.fromInt {0xff, 0xff, 0xff, 0xff} COLORS.TRANSP = Color.fromInt {0xff, 0xff, 0xff, 0x00} COLORS.SEMITRANSP = Color.fromInt {0xff, 0xff, 0xff, 0x80} -COLORS.BLACK = Color.fromInt {0x00, 0x00, 0x00, 0xff} +COLORS.BLACK = Color.fromInt {0x06, 0x06, 0x08, 0xff} COLORS.VOID = Color.fromInt {0, 0, 0, 0} COLORS.HALF_VISIBLE = Color.fromInt {0x80, 0x80, 0x80, 0xff} COLORS.LIGHT_GRAY = Color:new {.7, .7, .7, 1} COLORS.GRAY = Color.fromInt {0x4a, 0x54, 0x62, 0xff} COLORS.DARK = Color.fromInt {0x1f, 0x1f, 0x1f, 0xff} COLORS.DARKER = Color.fromInt {12, 12, 12, 255} -COLORS.BACKGROUND = Color.fromInt {50, 80, 80, 255} +COLORS.BACKGROUND = COLORS.BLACK COLORS.EXIT = Color.fromInt {0x77, 0xba, 0x99, 0xff} COLORS.FLOOR1 = Color.fromInt {25, 73, 95, 0xff} COLORS.FLOOR2 = Color.fromInt {25, 73, 95 + 20, 0xff} @@ -23,16 +23,16 @@ COLORS.HUD_BG = Color:new {12/256, 12/256, 12/256, 1} COLORS.EMPTY = Color:new {0.2, .15, 0.05, 1} COLORS.WARNING = Color:new {1, 0.8, 0.2, 1} COLORS.VALID = Color:new {0, 0.7, 1, 1} +COLORS.INVALID = Color.fromInt {0x3b, 0x17, 0x25, 0xff} COLORS.NOTIFICATION = Color.fromInt {0xD9, 0x53, 0x4F, 0xff} COLORS.SUCCESS = Color.fromInt {0x33, 0xAA, 0x3F, 0xff} -COLORS.STASH = Color.fromInt {0x41, 0x6e, 0x8e, 0xff} COLORS.PLAY = Color.fromInt {0xa3, 0x78, 0x71, 0xff} -COLORS.COR = Color.fromInt {0xbe, 0x76, 0x3a, 0xff} -COLORS.ARC = Color.fromInt {0x6e, 0x60, 0xaa, 0xff} -COLORS.ANI = Color.fromInt {0x77, 0xb9, 0x55, 0xff} -COLORS.NONE = Color.fromInt {0x77, 0x77, 0x77, 0xff} +COLORS.COR = Color.fromInt {0xf9, 0xa3, 0x1b, 0xff} +COLORS.ARC = Color.fromInt {0x79, 0x3a, 0x80, 0xff} +COLORS.ANI = Color.fromInt {0x14, 0xa0, 0x2e, 0xff} +COLORS.NONE = Color.fromInt {0x6d, 0x75, 0x8d, 0xff} COLORS.PP = Color.fromInt {0x28, 0x5c, 0xc4, 255} COLORS.FOCUS = Color.fromInt {0xbc, 0x4a, 0x9b, 0xff} diff --git a/game/domain/definitions/routemap.lua b/game/domain/definitions/routemap.lua index 237466df..124304c8 100644 --- a/game/domain/definitions/routemap.lua +++ b/game/domain/definitions/routemap.lua @@ -17,14 +17,14 @@ ROUTEMAP.initial_nodes = { { ZONES.B, SYMBOLS.V }, --{ ZONES.B, SYMBOLS.V }, --{ ZONES.B, SYMBOLS.V }, - { ZONES.C, SYMBOLS.V }, - { ZONES.C, SYMBOLS.V }, - { ZONES.C, SYMBOLS.V }, --{ ZONES.C, SYMBOLS.V }, --{ ZONES.C, SYMBOLS.V }, - --{ ZONES.D, SYMBOLS.v }, - --{ ZONES.D, SYMBOLS.v }, - --{ ZONES.D, SYMBOLS.v }, + --{ ZONES.C, SYMBOLS.V }, + --{ ZONES.C, SYMBOLS.V }, + --{ ZONES.C, SYMBOLS.V }, + { ZONES.D, SYMBOLS.v }, + { ZONES.D, SYMBOLS.v }, + { ZONES.D, SYMBOLS.v }, --{ ZONES.D, SYMBOLS.v }, --{ ZONES.D, SYMBOLS.v }, --{ ZONES.E, SYMBOLS.v }, diff --git a/game/domain/definitions/triggers.lua b/game/domain/definitions/triggers.lua index ede220bf..347c6cd5 100644 --- a/game/domain/definitions/triggers.lua +++ b/game/domain/definitions/triggers.lua @@ -3,29 +3,32 @@ return { "on_tick", "on_cycle", "on_turn", - "on_use", - "on_any_use", "on_hit", "on_done", "on_place", "on_play", "on_leave", - "on_act", - "on_focus_end", "on_kill", ON_TICK = 'on_tick', ON_CYCLE = 'on_cycle', ON_TURN = 'on_turn', - ON_USE = 'on_use', - ON_ANY_USE = 'on_any_use', ON_HIT = 'on_hit', ON_DONE = 'on_done', ON_PLACE = 'on_place', ON_PLAY = 'on_play', ON_LEAVE = 'on_leave', - ON_ACT = 'on_act', - ON_FOCUS_END = 'on_focus_end', ON_KILL = 'on_kill', + WORDING = { + on_tick = "Every tick", + on_cycle = "Every cycle", + on_turn = "In each of your turns", + on_hit = "Whenever you take damage", + on_done = "When this condition ends", + on_place = "Whenever you receive a widget", + on_play = "Whenever you play a card", + on_leave = "Whenever you lose a widget", + on_kill = "Whenever you kill something", + } } diff --git a/game/domain/effects/consume_cards.lua b/game/domain/effects/consume_cards.lua index f05494a6..683bd012 100644 --- a/game/domain/effects/consume_cards.lua +++ b/game/domain/effects/consume_cards.lua @@ -7,7 +7,7 @@ FX.schema = { } function FX.preview(actor, fieldvalues) - return ("Consume up to %s cards"):format(fieldvalues['card_list']) + return ("consume up to %s cards"):format(fieldvalues['card_list']) end function FX.process (actor, fieldvalues) diff --git a/game/domain/effects/damage_on_area.lua b/game/domain/effects/damage_on_area.lua index 0ab468b4..423011bf 100644 --- a/game/domain/effects/damage_on_area.lua +++ b/game/domain/effects/damage_on_area.lua @@ -1,16 +1,13 @@ local TILE = require 'common.tile' -local ATTR = require 'domain.definitions.attribute' local FX = {} FX.schema = { { id = 'center', name = "Target position", type = 'value', match = 'pos' }, { id = 'size', name = "Area Size", type = 'value', match = 'integer', range = {1} }, - { id = 'base', name = "Base Power", type = 'integer', range = {0,100} }, - { id = 'attr', name = "Scaling Factor", type = 'value', match = 'integer' }, - { id = 'mod', name = "%Mod", type = 'integer', range = {1,10000}, - default = 100 }, + { id = 'value', name = "value", type = 'value', match = 'integer', + range = {0,100} }, { id = 'ignore_owner', name = "Ignore Owner", type = 'boolean'}, { id = 'projectile', name = "Is projectile?", type = 'boolean' }, { id = 'sfx', name = "SFX", type = 'enum', @@ -18,17 +15,15 @@ FX.schema = { optional = true }, } -function FX.preview (actor, fieldvalues) - local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod - local attr_value = actor.getAttribute and actor:getAttribute(attr) or 3 - local amount = ATTR.EFFECTIVE_POWER(base, attr_value, mod) +function FX.preview (_, fieldvalues) + local value = fieldvalues['value'] local size = fieldvalues['size'] - 1 + local center = fieldvalues['center'] if size > 0 then - return ("Deal %d (%d + %2d%% %s) damage on a %s-radius area around %s") - :format(amount, base, mod, attr, size, fieldvalues['center']) + return ("deal %s damage on a %s-radius area around %s") + :format(value, size, center) else - return ("Deal %d (%d + %2d%% %s) damage at %s") - :format(amount, base, mod, attr, fieldvalues['center']) + return ("deal %s damage at %s"):format(value, center) end end @@ -36,11 +31,8 @@ function FX.process (actor, fieldvalues) local sector = actor:getBody():getSector() local ci, cj = unpack(fieldvalues['center']) local size = fieldvalues['size'] - local base = fieldvalues['base'] - local attr = fieldvalues['attr'] - local mod = fieldvalues['mod'] local ignore_owner = fieldvalues['ignore_owner'] - local amount = ATTR.EFFECTIVE_POWER(base, attr, mod) + local value = fieldvalues['value'] if fieldvalues['projectile'] then coroutine.yield('report', { type = 'projectile', @@ -53,7 +45,7 @@ function FX.process (actor, fieldvalues) local body = sector:getBodyAt(i, j) if body then if (not ignore_owner or body ~= actor:getBody()) and TILE.dist(i,j,ci,cj) <= size - 1 then - local result = body:takeDamageFrom(amount, actor) + local result = body:takeDamageFrom(value, actor) coroutine.yield('report', { type = 'take_damage', source = actor, diff --git a/game/domain/effects/damage_on_target.lua b/game/domain/effects/damage_on_target.lua index ad0a122a..25e645f4 100644 --- a/game/domain/effects/damage_on_target.lua +++ b/game/domain/effects/damage_on_target.lua @@ -1,47 +1,46 @@ -local ATTR = require 'domain.definitions.attribute' local FX = {} FX.schema = { { id = 'target', name = "Target", type = 'value', match = 'body' }, - { id = 'base', name = "Base Power", type = 'integer', range = {0,100} }, - { id = 'attr', name = "Scaling Factor", type = 'value', match = 'integer' }, - { id = 'mod', name = "%Mod", type = 'integer', default = 100, - range = {1,10000} }, + { id = 'value', name = "value", type = 'value', match = 'integer', + range = {0,100} }, { id = 'projectile', name = "Is projectile?", type = 'boolean' }, { id = 'sfx', name = "SFX", type = 'enum', options = 'resources.sfx', optional = true }, + { id = 'output', name = "Label", type = 'output' } } -function FX.preview (actor, fieldvalues) - local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod - local attr_value = actor.getAttribute and actor:getAttribute(attr) or 3 - local amount = ATTR.EFFECTIVE_POWER(base, attr_value, mod) - return ("Deal %d (%d + %2d%% %s) damage to %s") - :format(amount, base, mod, attr, fieldvalues.target) +function FX.preview (_, fieldvalues) + local value = fieldvalues['value'] + local target = fieldvalues['target'] + return ("deal %s damage to %s"):format(value, target) end function FX.process (actor, fieldvalues) - local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod - local amount = ATTR.EFFECTIVE_POWER(base, attr, mod) - local result = fieldvalues.target:takeDamageFrom(amount, actor) + local value = fieldvalues['value'] + local target = fieldvalues['target'] if fieldvalues['projectile'] then coroutine.yield('report', { type = 'projectile', actor = actor, - target = { fieldvalues['target']:getPos() }, + target = { target:getPos() }, }) end + local result = target:takeDamageFrom(value, actor) + coroutine.yield('report', { type = 'take_damage', source = actor, - body = fieldvalues['target'], + body = target, amount = result.dmg, sfx = fieldvalues.sfx, }) + + return result end return FX diff --git a/game/domain/effects/destroy_body.lua b/game/domain/effects/destroy_body.lua index a46acb77..217146ff 100644 --- a/game/domain/effects/destroy_body.lua +++ b/game/domain/effects/destroy_body.lua @@ -7,7 +7,7 @@ FX.schema = { } function FX.preview() - return "Destroy target body" + return "destroy target body" end function FX.process (actor, fieldvalues) diff --git a/game/domain/effects/draw_card.lua b/game/domain/effects/draw_card.lua index 5a4374a2..c7f9d270 100644 --- a/game/domain/effects/draw_card.lua +++ b/game/domain/effects/draw_card.lua @@ -7,7 +7,7 @@ FX.schema = { } function FX.preview(actor, fieldvalues) - return ("Draw %s cards"):format(fieldvalues['amount']) + return ("draw %s cards"):format(fieldvalues['amount']) end function FX.process (actor, fieldvalues) diff --git a/game/domain/effects/gain_focus.lua b/game/domain/effects/gain_focus.lua index b56883dd..27edec5f 100644 --- a/game/domain/effects/gain_focus.lua +++ b/game/domain/effects/gain_focus.lua @@ -7,7 +7,7 @@ FX.schema = { } function FX.preview(_, fieldvalues) - return ("Gain %s Focus"):format(fieldvalues['amount']) + return ("gain %s Focus"):format(fieldvalues['amount']) end function FX.process (actor, fieldvalues) diff --git a/game/domain/effects/give_pack.lua b/game/domain/effects/give_pack.lua index bb96ac18..b74c7935 100644 --- a/game/domain/effects/give_pack.lua +++ b/game/domain/effects/give_pack.lua @@ -7,7 +7,7 @@ FX.schema = { } function FX.preview() - return "Get card pack" + return "get card pack" end function FX.process (actor, fieldvalues) diff --git a/game/domain/effects/heal.lua b/game/domain/effects/heal.lua index 512b06e7..eb79cc01 100644 --- a/game/domain/effects/heal.lua +++ b/game/domain/effects/heal.lua @@ -1,33 +1,25 @@ -local ATTR = require 'domain.definitions.attribute' - local FX = {} FX.schema = { { id = 'target', name = "Target", type = 'value', match = 'body' }, - { id = 'base', name = "Base Power", type = 'integer', range = {0,100} }, - { id = 'attr', name = "Scaling Factor", type = 'value', match = 'integer' }, - { id = 'mod', name = "% Mod", type = 'value', match = 'integer', - range = {1} }, + { id = 'value', name = "value", type = 'value', match = 'integer', + range = {0,100} } } -function FX.preview(actor, fieldvalues) - local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod - local attr_value = actor.getAttribute and actor:getAttribute(attr) or 3 - local amount = ATTR.EFFECTIVE_POWER(base, attr_value, mod) - return ("Heal %d (%d + %2d%% %s( hit points for %s") - :format(amount, base, mod, attr, fieldvalues['target']) +function FX.preview(_, fieldvalues) + return ("heal %s hit points to %s") + :format(fieldvalues['value'], fieldvalues['target']) end function FX.process(_, fieldvalues) - local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod local target = fieldvalues['target'] - local amount = ATTR.EFFECTIVE_POWER(base, attr, mod) - local effective_amount = target:heal(amount) + local value = fieldvalues['value'] + local effective_value = target:heal(value) coroutine.yield('report', { type = 'heal', body = target, - amount = effective_amount, + amount = effective_value, }) end diff --git a/game/domain/effects/lose_life.lua b/game/domain/effects/lose_life.lua index 14115995..59f77bae 100644 --- a/game/domain/effects/lose_life.lua +++ b/game/domain/effects/lose_life.lua @@ -14,7 +14,7 @@ FX.schema = { -- can be for self-damaging attacks, as well as effects like poison function FX.preview(actor, fieldvalues) - local str = ("Lose %s%% hit points"):format(fieldvalues['percentage']) + local str = ("lose %s%% hit points"):format(fieldvalues['percentage']) if fieldvalues['stay_alive'] then str = str .. " (non-lethal)" end diff --git a/game/domain/effects/make_body.lua b/game/domain/effects/make_body.lua index 0778ed92..b73dd97a 100644 --- a/game/domain/effects/make_body.lua +++ b/game/domain/effects/make_body.lua @@ -22,7 +22,7 @@ FX.schema = { function FX.preview(_, fieldvalues) local name = DB.loadSpec('body', fieldvalues['bodyspec'])['name'] - local str = ("Create %s"):format(name) + local str = ("create %s"):format(name) local widgets = fieldvalues['widgets'] if widgets and #widgets > 0 then str = str .. " with " diff --git a/game/domain/effects/move_to.lua b/game/domain/effects/move_to.lua index 4ca76e02..893434ff 100644 --- a/game/domain/effects/move_to.lua +++ b/game/domain/effects/move_to.lua @@ -14,7 +14,7 @@ FX.schema = { } function FX.preview(_, fieldvalues) - return ("Move %s to position %s"):format(fieldvalues['body'], + return ("move %s to position %s"):format(fieldvalues['body'], fieldvalues['pos']) end diff --git a/game/domain/effects/place_widget.lua b/game/domain/effects/place_widget.lua index 91912cae..17a4152e 100644 --- a/game/domain/effects/place_widget.lua +++ b/game/domain/effects/place_widget.lua @@ -12,7 +12,7 @@ FX.schema = { function FX.preview(_, fieldvalues) local name = DB.loadSpec('card', fieldvalues['card'])['name'] - return ("Cause %s to %s"):format(name, fieldvalues['body']) + return ("cause %s to %s"):format(name, fieldvalues['body']) end function FX.process(actor, fieldvalues) @@ -21,10 +21,9 @@ function FX.process(actor, fieldvalues) card:setOwner(actor) body:placeWidget(card) coroutine.yield('report', { - type = 'text_rise', - text_type = 'status', + type = 'place_widget_card', body = body, - string = card:getName(), + card = card, sfx = fieldvalues.sfx, }) end diff --git a/game/domain/effects/place_widget_on_area.lua b/game/domain/effects/place_widget_on_area.lua index 1478c933..8e4f33d6 100644 --- a/game/domain/effects/place_widget_on_area.lua +++ b/game/domain/effects/place_widget_on_area.lua @@ -16,7 +16,7 @@ function FX.preview(_, fieldvalues) local name = DB.loadSpec('card', fieldvalues['card'])['name'] local size = fieldvalues['size'] - 1 local center = fieldvalues['center'] - return ("Cause %s on %s-radius area around %s"):format(name, size, center) + return ("cause %s on %s-radius area around %s"):format(name, size, center) end function FX.process (actor, fieldvalues) @@ -33,10 +33,9 @@ function FX.process (actor, fieldvalues) card:setOwner(actor) body:placeWidget(card) coroutine.yield('report', { - type = 'text_rise', - text_type = 'status', + type = 'place_widget_card', body = body, - string = card:getName(), + card = card, sfx = fieldvalues.sfx, }) end diff --git a/game/domain/effects/reward_pp.lua b/game/domain/effects/reward_pp.lua index b919eb26..2605f825 100644 --- a/game/domain/effects/reward_pp.lua +++ b/game/domain/effects/reward_pp.lua @@ -10,7 +10,7 @@ FX.schema = { } function FX.preview(_, fieldvalues) - return ("Give %s PP"):format(fieldvalues['amount']) + return ("give %s PP"):format(fieldvalues['amount']) end function FX.process (actor, fieldvalues) diff --git a/game/domain/inputs/enum.lua b/game/domain/inputs/enum.lua new file mode 100644 index 00000000..e62ac528 --- /dev/null +++ b/game/domain/inputs/enum.lua @@ -0,0 +1,15 @@ + +local INPUT = {} + +INPUT.schema = { + { id = 'output', name = "Label", type = 'output' } +} + +INPUT.type = 'enum' + +function INPUT.isValid(_, _, _) + return true +end + +return INPUT + diff --git a/game/domain/inputs/integer.lua b/game/domain/inputs/integer.lua new file mode 100644 index 00000000..3c6977b7 --- /dev/null +++ b/game/domain/inputs/integer.lua @@ -0,0 +1,15 @@ + +local INPUT = {} + +INPUT.schema = { + { id = 'output', name = "Label", type = 'output' } +} + +INPUT.type = 'integer' + +function INPUT.isValid(_, _, _) + return true +end + +return INPUT + diff --git a/game/domain/inputs/is_same_enum.lua b/game/domain/inputs/is_same_enum.lua new file mode 100644 index 00000000..ccfa9f81 --- /dev/null +++ b/game/domain/inputs/is_same_enum.lua @@ -0,0 +1,17 @@ + +local INPUT = {} + +INPUT.schema = { + { id = 'lhs', name = "Left value", type = 'value', match = 'enum' }, + { id = 'rhs', name = "Right value", type = 'string' }, + { id = 'output', name = "Label", type = 'output' }, +} + +INPUT.type = 'boolean' + +function INPUT.isValid(_, fieldvalues, _) + return fieldvalues['lhs'] == fieldvalues['rhs'] +end + +return INPUT + diff --git a/game/domain/inputs/is_same_integer.lua b/game/domain/inputs/is_same_integer.lua new file mode 100644 index 00000000..bc2f1db1 --- /dev/null +++ b/game/domain/inputs/is_same_integer.lua @@ -0,0 +1,17 @@ + +local INPUT = {} + +INPUT.schema = { + { id = 'lhs', name = "Left value", type = 'value', match = 'integer' }, + { id = 'rhs', name = "Right value", type = 'value', match = 'integer' }, + { id = 'output', name = "Label", type = 'output' }, +} + +INPUT.type = 'boolean' + +function INPUT.isValid(_, fieldvalues, _) + return fieldvalues['lhs'] == fieldvalues['rhs'] +end + +return INPUT + diff --git a/game/domain/maneuver/play_card.lua b/game/domain/maneuver/play_card.lua index 80c7eb1d..9df356bd 100644 --- a/game/domain/maneuver/play_card.lua +++ b/game/domain/maneuver/play_card.lua @@ -28,7 +28,7 @@ end function PLAYCARD.validate(actor, inputvalues) local card = _card(actor, inputvalues) - return actor:getFocus() >= card:getCost() and + return actor:canPlayCard(card) and (not card:isArt() or ABILITY.checkInputs(card:getArtAbility(), actor, inputvalues)) end diff --git a/game/domain/operators/effective_power.lua b/game/domain/operators/effective_power.lua new file mode 100644 index 00000000..9d82b1d1 --- /dev/null +++ b/game/domain/operators/effective_power.lua @@ -0,0 +1,37 @@ + +--- Calculate the effective power of an effect given a base value, the +-- associated attribute, and the modifying factor. + +local DEFS = require 'domain.definitions' +local ATTR = require 'domain.definitions.attribute' + +local OP = {} + +OP.schema = { + { id = 'base', name = "Base Power", type = 'integer', range = {0,100} }, + { id = 'attr', name = "Attribute", type = 'enum', + options = DEFS.ALL_ATTRIBUTES }, + { id = 'mod', name = "% Mod", type = 'value', match = 'integer', + range = {1,1000} }, + { id = 'output', name = "Label", type = 'output' } +} + +OP.type = 'integer' + +function OP.process(actor, fieldvalues) + local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod + local attr_value = actor:getAttribute(attr) + return ATTR.EFFECTIVE_POWER(base, attr_value, mod) +end + +function OP.preview(actor, fieldvalues) + local base, attr, mod = fieldvalues.base, fieldvalues.attr, fieldvalues.mod + local amount = "" + if actor.id then -- is it a valid actor? + amount = ("%d "):format(OP.process(actor, fieldvalues)) + end + return ("%s(%d + %2d%% %s)"):format(amount, base, mod, attr) +end + +return OP + diff --git a/game/gamestates/animations/create_equipment_card.lua b/game/gamestates/animations/create_equipment_card.lua index 3af0b726..908ce7d0 100644 --- a/game/gamestates/animations/create_equipment_card.lua +++ b/game/gamestates/animations/create_equipment_card.lua @@ -2,6 +2,7 @@ local TweenValue = require 'view.helpers.tweenvalue' local CardView = require 'view.card' local Util = require "steaming.util" +local PLAYSFX = require 'helpers.playsfx' local vec2 = require 'cpml' .vec2 local ANIM = require 'common.activity' () @@ -26,6 +27,7 @@ function ANIM:script(route, view, report) view.action_hud.handview:addCard(cardview) action_hud:disableCardInfo() cardview:setPosition(widgetview.position:unpack()) + PLAYSFX("create-equipment") self.wait(delay:set(0.2)) cardview:register("HUD_FX") _slideDown(widgetview, self) diff --git a/game/gamestates/animations/draw_card.lua b/game/gamestates/animations/draw_card.lua index 6fdbe9a3..4cf3ce9a 100644 --- a/game/gamestates/animations/draw_card.lua +++ b/game/gamestates/animations/draw_card.lua @@ -3,6 +3,7 @@ local TweenValue = require 'view.helpers.tweenvalue' local CardView = require 'view.card' +local PLAYSFX = require 'helpers.playsfx' local ANIM = require 'common.activity' () @@ -15,6 +16,7 @@ function ANIM:script(route, view, report) local hand = action_hud.handview hand:addCard(cardview) cardview:register("HUD") + PLAYSFX("draw-card") cardview:setPosition(frontbuffer:getTopCardPosition():unpack()) action_hud:disableCardInfo() self.wait(delay:set(0.2)) diff --git a/game/gamestates/animations/place_widget_card.lua b/game/gamestates/animations/place_widget_card.lua new file mode 100644 index 00000000..211d1c20 --- /dev/null +++ b/game/gamestates/animations/place_widget_card.lua @@ -0,0 +1,58 @@ + +-- luacheck: globals MAIN_TIMER + +local COLORS = require 'domain.definitions.colors' +local CardView = require 'view.card' +local VIEWDEFS = require 'view.definitions' +local RisingText = require 'view.sector.risingtext' +local vec2 = require 'cpml' .vec2 + +local ANIM = require 'common.activity' () + +function ANIM:script(route, view, report) + local action_hud = view.action_hud + if report.body == route.getControlledActor():getBody() then + local cardview = CardView(report.card) + local w, h = VIEWDEFS.VIEWPORT_DIMENSIONS() + cardview:register("HUD_FX") + + cardview:setPosition(w/2, h/2) + local dock = action_hud:getDockFor(cardview.card) + local destination = dock:getAvailableSlotPosition() + local mode = dock:getCardMode() + + local offset = vec2(0, -2*VIEWDEFS.CARD_H) + + if dock:getCardMode() == 'cond' then + dock:updateConditionsPositions(dock:getConditionsCount() + 1) + elseif dock:getCardMode() == 'equip' then + dock:updateDockPosition(true) + end + + cardview:addTimer("slide", MAIN_TIMER, "tween", .6, cardview, + {position = destination + offset}, 'out-cubic', + function() + cardview:setMode(mode) + cardview:addTimer("wait", MAIN_TIMER, "after", .1, + function() + action_hud.handview.cardinfo:lockCard() + action_hud:disableCardInfo() + cardview:addTimer("final_slide", MAIN_TIMER, "tween", .6, + cardview, {position = destination}, + 'out-cubic', + function() + dock:addCard(cardview) + self.resume() + end) + end) + end) + + + self.wait() + else + local bodyview = view.sector:getBodyView(report.body) + RisingText(bodyview, report.card:getName(), COLORS.WARNING):play() + end +end + +return ANIM diff --git a/game/gamestates/animations/play_widget_card.lua b/game/gamestates/animations/play_widget_card.lua index ccbdacc1..04dc688f 100644 --- a/game/gamestates/animations/play_widget_card.lua +++ b/game/gamestates/animations/play_widget_card.lua @@ -2,6 +2,7 @@ local Util = require "steaming.util" local TweenValue = require 'view.helpers.tweenvalue' local VIEWDEFS = require 'view.definitions' +local PLAYSFX = require 'helpers.playsfx' local vec2 = require 'cpml' .vec2 local ANIM = require 'common.activity' () @@ -43,6 +44,16 @@ function ANIM:script(route, view, report) cardview:setMode(mode) cardview:addTimer("wait", MAIN_TIMER, "after", .1, function() + if dock:getCardMode() == 'cond' then + PLAYSFX('condition-equip') + elseif dock:getCardMode() == 'equip' then + local placement = cardview.card:getWidgetPlacement() + if placement == "wieldable" then + PLAYSFX('wieldable-equip') + elseif placement == "wearable" then + PLAYSFX('wearable-equip') + end + end action_hud.handview.cardinfo:lockCard() action_hud:disableCardInfo() cardview:addTimer("final_slide", MAIN_TIMER, "tween", .6, diff --git a/game/gamestates/animations/shuffle_buffers.lua b/game/gamestates/animations/shuffle_buffers.lua index 5c8350c5..553f4d55 100644 --- a/game/gamestates/animations/shuffle_buffers.lua +++ b/game/gamestates/animations/shuffle_buffers.lua @@ -1,6 +1,7 @@ -- luacheck: globals MAIN_TIMER local TweenValue = require 'view.helpers.tweenvalue' +local PLAYSFX = require 'helpers.playsfx' local ANIM = require 'common.activity' () @@ -11,6 +12,7 @@ function ANIM:script(route, view, report) local frontbuffer = view.frontbuffer local backbuffer = view.backbuffer local d = .8 + PLAYSFX 'shuffle' backbuffer:changeSide(d, frontbuffer, report.actor) self.wait(delay:set(d-.1)) end diff --git a/game/gamestates/character_build.lua b/game/gamestates/character_build.lua index 969a17f5..d1bdf225 100644 --- a/game/gamestates/character_build.lua +++ b/game/gamestates/character_build.lua @@ -73,10 +73,10 @@ function state:update(dt) PLAYSFX('back-menu', .05) _view:cancel() elseif DIRECTIONALS.wasDirectionTriggered(_NEXT) then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) _view:selectPrev() elseif DIRECTIONALS.wasDirectionTriggered(_PREV) then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) _view:selectNext() end diff --git a/game/gamestates/consume_cards.lua b/game/gamestates/consume_cards.lua index d1436120..4a8fcb1d 100644 --- a/game/gamestates/consume_cards.lua +++ b/game/gamestates/consume_cards.lua @@ -86,13 +86,17 @@ function state:update(_) }) else if DIRECTIONALS.wasDirectionTriggered('LEFT') then + PLAYSFX('select-card', .05) _prev() elseif DIRECTIONALS.wasDirectionTriggered('RIGHT') then + PLAYSFX('select-card', .05) _next() elseif (DIRECTIONALS.wasDirectionTriggered('UP') or DIRECTIONALS.wasDirectionTriggered('DOWN')) then + PLAYSFX('toggle-card', .05) _toggle() elseif INPUT.wasActionPressed('CANCEL') then + PLAYSFX('back-menu', .05) _cancel() end end diff --git a/game/gamestates/open_pack.lua b/game/gamestates/open_pack.lua index 263142fb..efeef4b7 100644 --- a/game/gamestates/open_pack.lua +++ b/game/gamestates/open_pack.lua @@ -59,6 +59,8 @@ end local function _cancel() if _status == "choosing_pack" then _leave = true + else + PLAYSFX('denied', .03) end end @@ -127,14 +129,18 @@ function state:update(_) }) else if _status == "choosing_pack" and _card_list_view:usedHoldbar() then + PLAYSFX 'open-pack' _confirm() elseif DIRECTIONALS.wasDirectionTriggered('LEFT') then + PLAYSFX('select-card', .05) _prev() elseif DIRECTIONALS.wasDirectionTriggered('RIGHT') then + PLAYSFX('select-card', .05) _next() elseif _status == "choosing_card" and (DIRECTIONALS.wasDirectionTriggered('UP') or DIRECTIONALS.wasDirectionTriggered('DOWN')) then + PLAYSFX('toggle-card', .05) _toggle() elseif INPUT.wasActionPressed('CANCEL') then _cancel() diff --git a/game/gamestates/pick_widget_slot.lua b/game/gamestates/pick_widget_slot.lua deleted file mode 100644 index 0f4eeaab..00000000 --- a/game/gamestates/pick_widget_slot.lua +++ /dev/null @@ -1,74 +0,0 @@ - -local INPUT = require 'input' -local DIRECTIONALS = require 'infra.dir' -local DEFS = require 'domain.definitions' -local PLAYSFX = require 'helpers.playsfx' -local PickWidgetView = require 'view.pickwidget' -local Draw = require "draw" - -local state = {} - -local _view -local _selection -local _validate -local _target -local _leave - - -local function _prev() - _selection = (_selection - 2) % _target:getBody():getWidgetCount() + 1 -end - -local function _next() - _selection = _selection % _target:getBody():getWidgetCount() + 1 -end - -local function _confirm() - if _validate(_selection) then - _view:fadeOut() - SWITCHER.pop({ picked_slot = _selection }) - end -end - -local function _cancel() - _view:fadeOut() - PLAYSFX('back-menu', .05) - SWITCHER.pop({}) -end - -function state:enter(from, actor, validator) - _target = actor - _validate = validator - _selection = 1 - _leave = actor:getBody():getWidgetCount() <= 0 - - if not _leave then - _view = PickWidgetView(actor) - _view:register("HUD") - _view:fadeIn() - end -end - -function state:update(dt) - if _leave then - (_view and _view.fadeOut or DEFS.NULL_METHOD)(_view) - SWITCHER.pop({}) - else - if DIRECTIONALS.wasDirectionTriggered('UP') then - _prev() - elseif DIRECTIONALS.wasDirectionTriggered('DOWN') then - _next() - elseif INPUT.wasActionPressed('CONFIRM') then - _confirm() - elseif INPUT.wasActionPressed('CANCEL') then - _cancel() - end - _view:setSelection(_selection) - end -end - -function state:draw() - Draw.allTables() -end - -return state diff --git a/game/gamestates/play.lua b/game/gamestates/play.lua index 87bbb91d..6e26a768 100644 --- a/game/gamestates/play.lua +++ b/game/gamestates/play.lua @@ -175,8 +175,9 @@ end function state:update(_) --FIXME:this doesn't need to happen every update (I think) - if _route.getControlledActor() or _player then - _view.sector:updateFov(_route.getControlledActor() or _player) + _player = _player or _route.getControlledActor() or _route.getPlayerActor() + if _player then + _view.sector:updateFov(_player) else return error("missing player") end @@ -184,7 +185,7 @@ function state:update(_) if _next_action then _playTurns(unpack(_next_action)) end - _view.sector:lookAt(_route.getControlledActor() or _player) + _view.sector:lookAt(_player) end function state:resume(from, args) diff --git a/game/gamestates/settings.lua b/game/gamestates/settings.lua index 9c73ea95..b84cd080 100644 --- a/game/gamestates/settings.lua +++ b/game/gamestates/settings.lua @@ -68,11 +68,11 @@ function state:update(dt) _save = false SWITCHER.pop() elseif DIRECTIONALS.wasDirectionTriggered("UP") then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) _selection = (_selection - 2 + _fieldcount) % _fieldcount + 1 _view:setFocus(_selection) elseif DIRECTIONALS.wasDirectionTriggered("DOWN") then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) _selection = (_selection % _fieldcount) + 1 _view:setFocus(_selection) elseif DIRECTIONALS.wasDirectionTriggered("LEFT") then diff --git a/game/gamestates/start_menu.lua b/game/gamestates/start_menu.lua index 88c92b63..0ef22334 100644 --- a/game/gamestates/start_menu.lua +++ b/game/gamestates/start_menu.lua @@ -109,10 +109,10 @@ function state:update(dt) PLAYSFX('back-menu', .05) MENU.cancel() elseif DIRECTIONALS.wasDirectionTriggered('UP') then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) MENU.prev() elseif DIRECTIONALS.wasDirectionTriggered('DOWN') then - PLAYSFX('select-menu', .1) + PLAYSFX('select-menu', .05) MENU.next() end end diff --git a/game/gamestates/user_turn.lua b/game/gamestates/user_turn.lua index fb31b0f9..33a22d7f 100644 --- a/game/gamestates/user_turn.lua +++ b/game/gamestates/user_turn.lua @@ -191,7 +191,7 @@ end _ACTION[DEFS.ACTION.PLAY_CARD] = function(card_index) local actor = _route.getControlledActor() local card = actor:getHandCard(card_index) - if actor:getFocus() >= card:getCost() then + if actor:canPlayCard(card) then PLAYSFX('ok-menu', .05) _useAction(DEFS.ACTION.PLAY_CARD, { card_index = card_index }) else diff --git a/game/resources/tileset.lua b/game/resources/tileset.lua index 54bc9472..a61f9757 100644 --- a/game/resources/tileset.lua +++ b/game/resources/tileset.lua @@ -4,22 +4,39 @@ local TileSet = {} local _cache = {} local function _initTileset(info, texture) - local g = love.graphics + local g = love.graphics -- luacheck: globals love local w, h = texture:getDimensions() local mapping = info.mapping local quads = {} local offsets = {} + local weights = {} if mapping then - for name, dim in pairs(mapping) do + for name, alternates in pairs(mapping) do local tile = SCHEMATICS[name] - quads[tile] = g.newQuad(dim[1], dim[2], dim[3], dim[4], w, h) - offsets[tile] = { dim[5], dim[6] } + quads[tile] = {} + offsets[tile] = {} + local raw_weights = {} + local total_weight = 0 + weights[tile] = {} + for i, data in ipairs(alternates) do + local dim = data.quad + quads[tile][i] = g.newQuad(dim[1], dim[2], dim[3], dim[4], w, h) + offsets[tile][i] = { dim[5], dim[6] } + raw_weights[i] = data.weight + total_weight = total_weight + data.weight + end + local acc = 0 + for i, weight in ipairs(raw_weights) do + acc = acc + weight / total_weight + weights[tile][i] = acc + end end end return { texture = info.texture, quads = quads, offsets = offsets, + weights = weights } end diff --git a/game/view/card.lua b/game/view/card.lua index 738efcfc..9ffa2289 100644 --- a/game/view/card.lua +++ b/game/view/card.lua @@ -205,7 +205,11 @@ function CardView:draw() _title_font:set() local cardname = self.card:getName() local namewidth = _title_font:getWidth(cardname) - g.setColor(COLORS.NEUTRAL * Color:new{1,1,1,self.alpha}) + if self.card:getOwner() and self.card:getOwner():canPlayCard(self.card) then + g.setColor(COLORS.NEUTRAL * Color:new{1,1,1,self.alpha}) + else + g.setColor(COLORS.INVALID * Color:new{1,1,1,self.alpha}) + end g.printf(cardname, x + round((w - namewidth)/2), round(y-pd-_title_font:getHeight()), namewidth, "center") @@ -244,7 +248,7 @@ function CardView:draw() g.translate(x, y) --Draw card info g.setColor(0x20/255, 0x20/255, 0x20/255, self.alpha*self.info_alpha) - local type_str = self.card:getType() + local type_str = self.card:getType() .. " " .. self.card:getLevel() g.printf(type_str, pd, h - pd - _card_font:getHeight()/2, typewidth, "left") _info_font.set() @@ -300,7 +304,7 @@ end function _draw_hexagon(mode, x, y, r) local v = vec2(r, 0) local points = {} - for i = 1, 6 do + for _ = 1, 6 do table.insert(points,x + v.x) table.insert(points,y + v.y) v = vec2.rotate(v, math.pi/3) diff --git a/game/view/dissolvecard.lua b/game/view/dissolvecard.lua index 3c2f05e0..ab09a552 100644 --- a/game/view/dissolvecard.lua +++ b/game/view/dissolvecard.lua @@ -26,9 +26,9 @@ function Dissolve:init(cardview, duration) self.deferred = function () end - --PLAYSFX 'dissolve' TODO add a sfx for this self:register('HUD_FX') + PLAYSFX 'dissolve' self:addTimer("start", MAIN_TIMER, "tween", duration, self, { offset = -_MAX_OFFSET }, 'in-quad', function () self:kill(); return self.deferred() end) diff --git a/game/view/gameplay/actionhud/buffer.lua b/game/view/gameplay/actionhud/buffer.lua index e132ca40..8704f675 100644 --- a/game/view/gameplay/actionhud/buffer.lua +++ b/game/view/gameplay/actionhud/buffer.lua @@ -124,7 +124,7 @@ function BufferView:getTopCardPosition(index_offset) end function BufferView:update(dt) - local actor = self.route.getControlledActor() + local actor = self.route.getPlayerActor() if self.side == 'front' then self.button:setCost(actor:getBody():getConsumption()) self.button:update(dt) diff --git a/game/view/gameplay/actionhud/focusbar.lua b/game/view/gameplay/actionhud/focusbar.lua index 310fc018..eb81b182 100644 --- a/game/view/gameplay/actionhud/focusbar.lua +++ b/game/view/gameplay/actionhud/focusbar.lua @@ -1,5 +1,5 @@ --- luacheck: SWITCHER GS globals love +-- luacheck: globals love SWITCHER GS MAIN_TIMER local FONT = require 'view.helpers.font' local COLORS = require 'domain.definitions.colors' @@ -93,8 +93,7 @@ function FocusBar:update(dt) self.explosions[i]:update(dt) end - local _OFF_SPD = 2.5 - self.actor = self.route.getControlledActor() + self.actor = self.route.getPlayerActor() --update fade-in local maxfocus = ACTIONDEFS.MAX_FOCUS @@ -107,6 +106,14 @@ function FocusBar:update(dt) self.explosions[i]:emit(40) end) end + elseif focus > self.previous_focus then + for i = focus, self.previous_focus + 1, -1 do + self:addTimer(nil, MAIN_TIMER, "after", (i-1)*.05, + function() + PLAYSFX('focus-gain', .05) + self.explosions[i]:emit(20) + end) + end end self.previous_focus = focus for i = 1, maxfocus do @@ -201,7 +208,6 @@ function _newExplosionSource() particles:setColors(COLORS.NEUTRAL, COLORS.TRANSP) particles:setSizes(3) particles:setEmissionArea('ellipse', 0, 0, 0, false) - particles:setTangentialAcceleration(-256) return particles end diff --git a/game/view/gameplay/actionhud/hand/init.lua b/game/view/gameplay/actionhud/hand/init.lua index ff40fa68..cce9ad41 100644 --- a/game/view/gameplay/actionhud/hand/init.lua +++ b/game/view/gameplay/actionhud/hand/init.lua @@ -5,6 +5,7 @@ local COLORS = require 'domain.definitions.colors' local FONT = require 'view.helpers.font' local CardView = require 'view.card' local CardInfo = require 'view.gameplay.actionhud.hand.cardinfo' +local PLAYSFX = require 'helpers.playsfx' local VIEWDEFS = require 'view.definitions' local PROFILE = require 'infra.profile' local Class = require "steaming.extra_libs.hump.class" @@ -79,6 +80,7 @@ function HandView:getFocus() end function HandView:moveFocus(dir) + PLAYSFX('select-card', .06) if dir == "LEFT" then self.focus_index = (self.focus_index - 2) % (#self.hand) + 1 elseif dir == "RIGHT" then @@ -94,11 +96,13 @@ function HandView:activate() if not PROFILE.getTutorial("use_card") then SWITCHER.push(GS.TUTORIAL_HINT, "use_card") end + PLAYSFX('open-hand') self.active = true self.focus_index = math.max(1, math.min(#self.hand, self.focus_index)) end function HandView:deactivate() + PLAYSFX('close-hand') self.active = false end diff --git a/game/view/gameplay/actionhud/init.lua b/game/view/gameplay/actionhud/init.lua index 4303c10e..47d76256 100644 --- a/game/view/gameplay/actionhud/init.lua +++ b/game/view/gameplay/actionhud/init.lua @@ -1,27 +1,28 @@ -- luacheck: globals MAIN_TIMER, no self -local DIRECTIONALS = require 'infra.dir' -local LONG_WALK = require 'view.helpers.long_walk' -local ADJACENCY = require 'view.helpers.adjacency' -local INPUT = require 'input' -local DEFS = require 'domain.definitions' -local VIEWDEFS = require 'view.definitions' -local HandView = require 'view.gameplay.actionhud.hand' -local Minimap = require 'view.gameplay.actionhud.minimap' -local EquipmentDock = require 'view.gameplay.actionhud.equipmentdock' -local ConfirmHint = require 'view.gameplay.actionhud.controlhints.confirm' -local CancelHint = require 'view.gameplay.actionhud.controlhints.cancel' -local OpenPacksHint = require 'view.gameplay.actionhud.controlhints.openpacks' -local ShowStatsHint = require 'view.gameplay.actionhud.controlhints.showstats' +local DIRECTIONALS = require 'infra.dir' +local LONG_WALK = require 'view.helpers.long_walk' +local ADJACENCY = require 'view.helpers.adjacency' +local INPUT = require 'input' +local DEFS = require 'domain.definitions' +local VIEWDEFS = require 'view.definitions' +local PLAYSFX = require 'helpers.playsfx' +local HandView = require 'view.gameplay.actionhud.hand' +local Minimap = require 'view.gameplay.actionhud.minimap' +local EquipmentDock = require 'view.gameplay.actionhud.equipmentdock' +local ConfirmHint = require 'view.gameplay.actionhud.controlhints.confirm' +local CancelHint = require 'view.gameplay.actionhud.controlhints.cancel' +local OpenPacksHint = require 'view.gameplay.actionhud.controlhints.openpacks' +local ShowStatsHint = require 'view.gameplay.actionhud.controlhints.showstats' local ToggleHintsHint = require 'view.gameplay.actionhud.controlhints.togglehints' -local ConditionDock = require 'view.gameplay.actionhud.conditiondock' -local FocusBar = require 'view.gameplay.actionhud.focusbar' -local TurnPreview = require 'view.gameplay.actionhud.turnpreview' -local CardView = require 'view.card' -local Util = require "steaming.util" -local Class = require "steaming.extra_libs.hump.class" -local ELEMENT = require "steaming.classes.primitives.element" +local ConditionDock = require 'view.gameplay.actionhud.conditiondock' +local FocusBar = require 'view.gameplay.actionhud.focusbar' +local TurnPreview = require 'view.gameplay.actionhud.turnpreview' +local CardView = require 'view.card' +local Util = require "steaming.util" +local Class = require "steaming.extra_libs.hump.class" +local ELEMENT = require "steaming.classes.primitives.element" local _INFO_LAG = 0.65 -- seconds local _MARGIN = 20 @@ -243,16 +244,19 @@ end function ActionHUD:removeWidgetCard(card) if self.weardock:getCard() and self.weardock:getCard().card == card then + PLAYSFX("wearable-unequip") return self.weardock:removeCard() end if self.wielddock:getCard() and self.wielddock:getCard().card == card then + PLAYSFX("wieldable-unequip") return self.wielddock:removeCard() end for i = 1, self.conddock:getConditionsCount() do local condition = self.conddock:getCard(i) if condition and condition.card == card then + PLAYSFX("condition-unequip") return self.conddock:removeCard(i) end end diff --git a/game/view/helpers/card.lua b/game/view/helpers/card.lua index f444dc54..a82bc035 100644 --- a/game/view/helpers/card.lua +++ b/game/view/helpers/card.lua @@ -1,19 +1,13 @@ local FONT = require 'view.helpers.font' local TEXTURE = require 'view.helpers.texture' -local RES = require 'resources' -local APT = require 'domain.definitions.aptitude' local COLORS = require 'domain.definitions.colors' -local round = require 'common.math' .round --CARDVIEW PROPERTIES-- local _title_font = FONT.get("TextBold", 20) local _text_font = FONT.get("Text", 20) -local _info_font = FONT.get("Text", 18) -local _card_font = FONT.get("Text", 12) local _card_base -local _neutral_icon local CARD = {} @@ -28,8 +22,11 @@ end --Draw the description of a card. function CARD.drawInfo(card, x, y, width, alpha, player_actor, no_desc) alpha = alpha or 1 - local g = love.graphics + local g = love.graphics -- luacheck: globals love local cr, cg, cb = unpack(COLORS.NEUTRAL) + if not (card:getOwner() and card:getOwner():canPlayCard(card)) then + cr, cg, cb = unpack(COLORS.INVALID) + end g.push() diff --git a/game/view/pickwidget.lua b/game/view/pickwidget.lua deleted file mode 100644 index 5f767b8f..00000000 --- a/game/view/pickwidget.lua +++ /dev/null @@ -1,101 +0,0 @@ - -local RES = require 'resources' -local DEFS = require 'domain.definitions' -local Color = require 'common.color' -local FONT = require 'view.helpers.font' -local Class = require "steaming.extra_libs.hump.class" -local ELEMENT = require "steaming.classes.primitives.element" - -local PickWidgetView = Class{ - __includes = { ELEMENT } -} - -local _FONT_NAME = "Text" -local _FONT_SIZE = 20 -local _BLOCK_HEIGHT = 48 -local _MARGIN = 16 -local _PADDING = 4 -local _FMT = "%s [%d/%d%s]" -local _TRIGGERS = { - [DEFS.TRIGGERS.ON_USE] = " uses", - [DEFS.TRIGGERS.ON_TURN] = " turns", - [DEFS.TRIGGERS.ON_TICK] = " ticks", -} - -local _width, _height -local _font -local _alpha - -local function _initGraphicValues() - local g = love.graphics - _width, _height = g.getDimensions() - _font = _font or FONT.get(_FONT_NAME, _FONT_SIZE) -end - -function PickWidgetView:init(target_actor) - ELEMENT.init(self) - - self.target = target_actor - self.selection = 1 - self.alpha = 0 - - _initGraphicValues() -end - -function PickWidgetView:setSelection(n) - self.selection = n -end - -function PickWidgetView:draw() - local g = love.graphics - g.setColor(0, 0, 0, self.alpha*0.5) - g.rectangle("fill", 0, 0, _width, _height) - g.push() - - g.translate(_width/8, _height/2-2*(_BLOCK_HEIGHT+_MARGIN)) - -- draw stuff - local strs = {} - local width = 0 - for index, widget in self.target:getBody():eachWidget() do - strs[index] = _FMT:format(widget:getName(), - widget:getWidgetCharges() - widget:getUsages(), - widget:getWidgetCharges(), - _TRIGGERS[widget:getWidgetTrigger()] or "" - ) - width = math.max(width, _font:getWidth(strs[index])) - end - for index, info_str in ipairs(strs) do - local selected = self.selection == index - if selected then - g.setColor(Color.fromInt(0xff, 0xff, 0xff, self.alpha*0xff)) - else - g.setColor(Color.fromInt(0x16, 0x16, 0x16, self.alpha*0xff)) - end - g.rectangle("fill", 0, 0, width+8*_PADDING, _BLOCK_HEIGHT) - _font:set() - if selected then - g.setColor(Color.fromInt(0x00, 0x00, 0x00, self.alpha*0xff)) - else - g.setColor(Color.fromInt(0xff, 0xff, 0xff, self.alpha*0xff)) - end - g.printf(info_str, 4*_PADDING, _PADDING, width) - g.translate(0, _BLOCK_HEIGHT + _MARGIN) - end - - g.pop() -end - -function PickWidgetView:fadeOut() - self:removeTimer("widget_picker_fade", MAIN_TIMER) - self:addTimer("widget_picker_fade", MAIN_TIMER, "tween", - .2, self, { alpha = 0 }, "out-quad", - function () self:destroy() end) -end - -function PickWidgetView:fadeIn() - self:removeTimer("widget_picker_fade", MAIN_TIMER) - self:addTimer("widget_picker_fade", MAIN_TIMER, "tween", - .25, self, { alpha = 1 }, "out-quad") -end - -return PickWidgetView diff --git a/game/view/sector.lua b/game/view/sector.lua index 4e569065..573e3c54 100644 --- a/game/view/sector.lua +++ b/game/view/sector.lua @@ -347,7 +347,7 @@ function SectorView:draw() if body then table.insert(draw_bodies, body) table.insert(all_bodies, body) - local player = self.route.getControlledActor():getBody() + local player = self.route.getPlayerActor():getBody() local player_i, player_j = player:getPos() local body_i, body_j = body:getPos() if body:getDialogue() then diff --git a/game/view/sector/mesh/wall.lua b/game/view/sector/mesh/wall.lua index b9a6e9bf..275d707c 100644 --- a/game/view/sector/mesh/wall.lua +++ b/game/view/sector/mesh/wall.lua @@ -1,5 +1,5 @@ -local VIEWDEFS = require 'view.definitions' +local COLORS = require 'domain.definitions.colors' local vec3 = require 'cpml' .vec3 local _WALL_H = 80 @@ -33,7 +33,7 @@ local function _appendFace(mesh, base) mesh.faces[n+i] = base + idx end end - + local function _appendQuad(mesh, color, v1, v2, v3, v4) local base = mesh.count local pos = _tov3(mesh.pos) @@ -62,6 +62,14 @@ function WallMesh:addSide(color, v1, v2, b1, b2) end end +function WallMesh:addBottom(v1, v2, v3, v4, extra, ...) + v1, v2, v3, v4 = _tov3(v1), _tov3(v2), _tov3(v3), _tov3(v4 or v3) + _appendQuad(self, COLORS.BLACK, v1, v2, v3, v4) + if extra then + return self:addBottom(v3, v4, extra, ...) + end +end + function WallMesh:addTop(color, v1, v2, v3, v4, extra, ...) local height = vec3(0,0,-1)*_WALL_H v1, v2, v3, v4 = _tov3(v1), _tov3(v2), _tov3(v3), _tov3(v4 or v3) diff --git a/game/view/sector/tilemap.lua b/game/view/sector/tilemap.lua index 78d17644..3d13f613 100644 --- a/game/view/sector/tilemap.lua +++ b/game/view/sector/tilemap.lua @@ -26,16 +26,15 @@ local TILEMAP = {} local _sector local _tile_batch -local _tile_offset -local _tile_quads +local _tileset +local _variations local _fovmask local _tilemask function TILEMAP.init(sector, tileset) local texture = RES.loadTexture(tileset.texture) _tile_batch = love.graphics.newSpriteBatch(texture, 512, "stream") - _tile_offset = tileset.offsets - _tile_quads = tileset.quads + _tileset = tileset _sector = sector _fovmask = love.graphics.newCanvas(_VIEW_W * _TILE_W, _VIEW_H * _TILE_H) _FXSHADER = _FXSHADER or love.graphics.newShader(_FXCODE) @@ -53,6 +52,14 @@ function TILEMAP.init(sector, tileset) ) _tilemask = love.graphics.newImage(data) end + _variations = {} + local rng = love.math.newRandomGenerator(0) -- always same seed + for i = 1, #_sector.tiles do + _variations[i] = {} + for j = 1, #_sector.tiles[i] do + _variations[i][j] = rng:random() + end + end end local _SIDES = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } } @@ -120,6 +127,8 @@ function TILEMAP.drawAbyss(g) g.pop() end + + function TILEMAP.drawFloor(g) _tile_batch:clear() for i, j in CAM:tilesInRange() do @@ -129,8 +138,18 @@ function TILEMAP.drawFloor(g) local tile_type = (tile.type == SCHEMATICS.WALL) and SCHEMATICS.FLOOR or tile.type local x, y = j*_TILE_W, i*_TILE_H - _tile_batch:add(_tile_quads[tile_type], x, y, - 0, 1, 1, unpack(_tile_offset[tile.type])) + local variation = _variations[ti][tj] + local idx = 1 + for _, threshold in ipairs(_tileset.weights[tile_type]) do + if variation < threshold then + break + else + idx = math.min(idx + 1, #_tileset.weights[tile_type]) + end + end + local quad = _tileset.quads[tile_type][idx] + local offset = _tileset.offsets[tile_type][idx] + _tile_batch:add(quad, x, y, 0, 1, 1, unpack(offset)) end end diff --git a/game/view/sector/wall.lua b/game/view/sector/wall.lua index 6d522b95..b9a9cf22 100644 --- a/game/view/sector/wall.lua +++ b/game/view/sector/wall.lua @@ -23,10 +23,12 @@ local _TOPRIGHT = vec2(_TILE_W, 0) local _BOTLEFT = vec2(0, _TILE_H) local _BOTRIGHT = vec2(_TILE_W, _TILE_H) -local _BACK_COLOR = {31/256, 44/256, 38/256, 0.4} -local _FRONT_COLOR = {31/256, 44/256, 38/256, 1} -local _BORDER_COLOR = {43/256, 100/256, 112/256, 1} -local _TOP_COLOR = {0.2, 0.2, 0.2, 0.6} +local _BACK_COLOR = {0x5b/256, 0x31/256, 0x38/256, 0.4} +local _FRONT_COLOR = {0x5b/256, 0x31/256, 0x38/256, 1} +local _FRONT_BRIGHT_COLOR = {0x8e/256, 0x52/256, 0x52/256, 1} +local _FRONT_DARK_COLOR = {0x42/256, 0x24/256, 0x33/256, 1} +local _BORDER_COLOR = {0xba/256, 0x75/256, 0x6a/256, 1} +local _TOP_COLOR = {0x14/256, 0x10/256, 0x13/256, 0.6} local _W, _H @@ -117,29 +119,36 @@ function WALL.load(sector) -- top if _empty(neighbors, 1, 2) then + wall:addBottom(_rect(_GRID_W, _TILE_W - _GRID_W, + _MARGIN_H + _BORDER_H, _GRID_H)) wall:addSide(_BACK_COLOR, vec2(_GRID_W, _MARGIN_H), vec2(_TILE_W - _GRID_W, _MARGIN_H), vec2(0, _BORDER_H)) wall:addTop(_TOP_COLOR, _rect(_GRID_W, _TILE_W - _GRID_W, _MARGIN_H + _BORDER_H, _GRID_H)) else + wall:addBottom(_rect(_GRID_W, _TILE_W - _GRID_W, 0, + _GRID_H)) wall:addTop(_TOP_COLOR, _rect(_GRID_W, _TILE_W - _GRID_W, 0, _GRID_H)) end -- topleft if _walled(neighbors, 2, 1) and _empty(neighbors, 1, 2) then -- straight left + wall:addBottom(_CORNER_HOR()) wall:addSide(_BACK_COLOR, vec2(0, _MARGIN_H), vec2(_GRID_W, _MARGIN_H), vec2(0, _BORDER_H)) wall:addTop(_TOP_COLOR, _CORNER_HOR()) elseif _walled(neighbors, 1, 2) and _empty(neighbors, 2, 1) then -- straight up + wall:addBottom(_CORNER_VER()) wall:addSide(nil, vec2(_MARGIN_W, 0), vec2(_MARGIN_W, _GRID_H), vec2(_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _CORNER_VER()) elseif _empty(neighbors, 2, 1) and _empty(neighbors, 1, 2) then -- outer corner + wall:addBottom(_CORNER_OUT()) wall:addSide(_BACK_COLOR, vec2(_MARGIN_W, _GRID_H), vec2(_GRID_W, _MARGIN_H), vec2(_BORDER_W, 0), vec2(0, _BORDER_H)) @@ -147,28 +156,33 @@ function WALL.load(sector) elseif _walled(neighbors, 2, 1) and _walled(neighbors, 1, 2) and _empty(neighbors, 1, 1) then -- inner corner + wall:addBottom(_CORNER_INN()) wall:addSide(_BACK_COLOR, vec2(0, _MARGIN_H), vec2(_MARGIN_W, 0), vec2(0, _BORDER_H), vec2(_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _CORNER_INN()) else + wall:addBottom(_CORNER_ALL()) wall:addTop(_TOP_COLOR, _CORNER_ALL()) end -- topright if _walled(neighbors, 2, 3) and _empty(neighbors, 1, 2) then -- straight right + wall:addBottom(_xform(_TOPRIGHT, -1, 1, _CORNER_HOR())) wall:addSide(_BACK_COLOR, vec2(_TILE_W - _GRID_W, _MARGIN_H), vec2(_TILE_W, _MARGIN_H), vec2(0, _BORDER_H)) wall:addTop(_TOP_COLOR, _xform(_TOPRIGHT, -1, 1, _CORNER_HOR())) elseif _walled(neighbors, 1, 2) and _empty(neighbors, 2, 3) then -- straight up + wall:addBottom(_xform(_TOPRIGHT, -1, 1, _CORNER_VER())) wall:addSide(nil, vec2(_TILE_W - _MARGIN_W, 0), vec2(_TILE_W - _MARGIN_W, _GRID_H), vec2(-_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_TOPRIGHT, -1, 1, _CORNER_VER())) elseif _empty(neighbors, 1, 2) and _empty(neighbors, 2, 3) then -- outer corner + wall:addBottom(_xform(_TOPRIGHT, -1, 1, _CORNER_OUT())) wall:addSide(_BACK_COLOR, vec2(_TILE_W - _MARGIN_W, _GRID_H), vec2(_TILE_W - _GRID_W, _MARGIN_H), vec2(-_BORDER_W, 0), vec2(0, _BORDER_H)) @@ -176,27 +190,35 @@ function WALL.load(sector) elseif _walled(neighbors, 1, 2) and _walled(neighbors, 2, 3) and _empty(neighbors, 1, 3) then -- inner corner + wall:addBottom(_xform(_TOPRIGHT, -1, 1, _CORNER_INN())) wall:addSide(_BACK_COLOR, vec2(_TILE_W, _MARGIN_H), vec2(_TILE_W - _MARGIN_W, 0), vec2(0, _BORDER_H), vec2(-_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_TOPRIGHT, -1, 1, _CORNER_INN())) else + wall:addBottom(_xform(_TOPRIGHT, -1, 1, _CORNER_ALL())) wall:addTop(_TOP_COLOR, _xform(_TOPRIGHT, -1, 1, _CORNER_ALL())) end -- left if _empty(neighbors, 2, 1) then local border = vec2(_BORDER_W,0) + wall:addBottom(_rect(_MARGIN_W + _BORDER_W, _GRID_W, + _GRID_H, _TILE_H - _GRID_H)) wall:addSide(nil, vec2(_MARGIN_W, _GRID_H), vec2(_MARGIN_W, _TILE_H - _GRID_H), border) wall:addTop(_TOP_COLOR, _rect(_MARGIN_W + _BORDER_W, _GRID_W, _GRID_H, _TILE_H - _GRID_H)) else + wall:addBottom(_rect(0, _GRID_W, _GRID_H, + _TILE_H - _GRID_H)) wall:addTop(_TOP_COLOR, _rect(0, _GRID_W, _GRID_H, _TILE_H - _GRID_H)) end -- middle do + wall:addBottom(_rect(_GRID_W, _TILE_W - _GRID_W, _GRID_H, + _TILE_H - _GRID_H)) wall:addTop(_TOP_COLOR, _rect(_GRID_W, _TILE_W - _GRID_W, _GRID_H, _TILE_H - _GRID_H)) end @@ -204,6 +226,9 @@ function WALL.load(sector) -- right if _empty(neighbors, 2, 3) then local border = vec2(-_BORDER_W,0) + wall:addBottom(_rect(_TILE_W - _GRID_W, + _TILE_W - (_MARGIN_W + _BORDER_W), + _GRID_H, _TILE_H - _GRID_H)) wall:addSide(nil, vec2(_TILE_W - _MARGIN_W, _GRID_H), vec2(_TILE_W - _MARGIN_W, _TILE_H - _GRID_H), border) @@ -211,12 +236,17 @@ function WALL.load(sector) _TILE_W - (_MARGIN_W + _BORDER_W), _GRID_H, _TILE_H - _GRID_H)) else + wall:addBottom(_rect(_TILE_W - _GRID_W, _TILE_W, _GRID_H, + _TILE_H - _GRID_H)) wall:addTop(_TOP_COLOR, _rect(_TILE_W - _GRID_W, _TILE_W, _GRID_H, _TILE_H - _GRID_H)) end -- front if _empty(neighbors, 3, 2) then + wall:addBottom(_rect(_GRID_W, _TILE_W - _GRID_W, + _TILE_H - _GRID_H, + _TILE_H - (_MARGIN_H + _BORDER_H))) wall:addSide(_FRONT_COLOR, _BOTLEFT + vec2(_GRID_W, -_MARGIN_H), _BOTRIGHT - vec2(_GRID_W, _MARGIN_H), vec2(0, -_BORDER_H)) @@ -224,6 +254,8 @@ function WALL.load(sector) _TILE_H - _GRID_H, _TILE_H - (_MARGIN_H + _BORDER_H))) else + wall:addBottom(_rect(_GRID_W, _TILE_W - _GRID_W, + _TILE_H - _GRID_H , _TILE_H)) wall:addTop(_TOP_COLOR, _rect(_GRID_W, _TILE_W - _GRID_W, _TILE_H - _GRID_H , _TILE_H)) end @@ -231,60 +263,74 @@ function WALL.load(sector) -- bottomleft if _walled(neighbors, 2, 1) and _empty(neighbors, 3, 2) then -- straight left + wall:addBottom(_xform(_BOTLEFT, 1, -1, _CORNER_HOR())) wall:addSide(_FRONT_COLOR, _BOTLEFT - vec2(0, _MARGIN_H), _BOTLEFT + vec2(_GRID_W, -_MARGIN_H), vec2(0, -_BORDER_H)) wall:addTop(_TOP_COLOR, _xform(_BOTLEFT, 1, -1, _CORNER_HOR())) elseif _walled(neighbors, 3, 2) and _empty(neighbors, 2, 1) then -- straight down + wall:addBottom(_xform(_BOTLEFT, 1, -1, _CORNER_VER())) wall:addSide(nil, _BOTLEFT + vec2(_MARGIN_W, -_GRID_H), _BOTLEFT + vec2(_MARGIN_W, 0), vec2(_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_BOTLEFT, 1, -1, _CORNER_VER())) elseif _empty(neighbors, 2, 1) and _empty(neighbors, 3, 2) then -- outer corner - wall:addSide(_FRONT_COLOR, _BOTLEFT + vec2(_MARGIN_W, -_GRID_H), - _BOTLEFT + vec2(_GRID_W, -_MARGIN_H), - vec2(_BORDER_W, 0), vec2(0, -_BORDER_H)) + wall:addBottom(_xform(_BOTLEFT, 1, -1, _CORNER_OUT())) + wall:addSide(_FRONT_BRIGHT_COLOR, + _BOTLEFT + vec2(_MARGIN_W, -_GRID_H), + _BOTLEFT + vec2(_GRID_W, -_MARGIN_H), + vec2(_BORDER_W, 0), vec2(0, -_BORDER_H)) wall:addTop(_TOP_COLOR, _xform(_BOTLEFT, 1, -1, _CORNER_OUT())) elseif _walled(neighbors, 2, 1) and _walled(neighbors, 3, 2) and _empty(neighbors, 3, 1) then -- inner corner - wall:addSide(_FRONT_COLOR, _BOTLEFT + vec2(0, -_MARGIN_H), - _BOTLEFT + vec2(_MARGIN_W, 0), - vec2(0, -_BORDER_H), vec2(_BORDER_W, 0)) + wall:addBottom(_xform(_BOTLEFT, 1, -1, _CORNER_INN())) + wall:addSide(_FRONT_DARK_COLOR, _BOTLEFT + vec2(0, -_MARGIN_H), + _BOTLEFT + vec2(_MARGIN_W, 0), + vec2(0, -_BORDER_H), + vec2(_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_BOTLEFT, 1, -1, _CORNER_INN())) else + wall:addBottom(_xform(_BOTLEFT, 1, -1, _CORNER_ALL())) wall:addTop(_TOP_COLOR, _xform(_BOTLEFT, 1, -1, _CORNER_ALL())) end -- bottomright if _walled(neighbors, 2, 3) and _empty(neighbors, 3, 2) then -- straight right + wall:addBottom(_xform(_BOTRIGHT, -1, -1, _CORNER_HOR())) wall:addSide(_FRONT_COLOR, _BOTRIGHT - vec2(0, _MARGIN_H), _BOTRIGHT - vec2(_GRID_W, _MARGIN_H), vec2(0, -_BORDER_H)) wall:addTop(_TOP_COLOR, _xform(_BOTRIGHT, -1, -1, _CORNER_HOR())) elseif _walled(neighbors, 3, 2) and _empty(neighbors, 2, 3) then -- straight down + wall:addBottom(_xform(_BOTRIGHT, -1, -1, _CORNER_VER())) wall:addSide(nil, _BOTRIGHT - vec2(_MARGIN_W, _GRID_H), _BOTRIGHT - vec2(_MARGIN_W, 0), vec2(-_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_BOTRIGHT, -1, -1, _CORNER_VER())) elseif _empty(neighbors, 2, 3) and _empty(neighbors, 3, 2) then -- outer corner - wall:addSide(_FRONT_COLOR, _BOTRIGHT - vec2(_MARGIN_W, _GRID_H), - _BOTRIGHT - vec2(_GRID_W, _MARGIN_H), - vec2(-_BORDER_W, 0), vec2(0, -_BORDER_H)) + wall:addBottom(_xform(_BOTRIGHT, -1, -1, _CORNER_OUT())) + wall:addSide(_FRONT_DARK_COLOR, _BOTRIGHT - vec2(_MARGIN_W, _GRID_H), + _BOTRIGHT - vec2(_GRID_W, _MARGIN_H), + vec2(-_BORDER_W, 0), + vec2(0, -_BORDER_H)) wall:addTop(_TOP_COLOR, _xform(_BOTRIGHT, -1, -1, _CORNER_OUT())) elseif _walled(neighbors, 2, 3) and _walled(neighbors, 3, 2) and _empty(neighbors, 3, 3) then -- inner corner - wall:addSide(_FRONT_COLOR, _BOTRIGHT - vec2(0, _MARGIN_H), - _BOTRIGHT - vec2(_MARGIN_W, 0), - vec2(0, -_BORDER_H), vec2(-_BORDER_W, 0)) + wall:addBottom(_xform(_BOTRIGHT, -1, -1, _CORNER_INN())) + wall:addSide(_FRONT_BRIGHT_COLOR, _BOTRIGHT - vec2(0, _MARGIN_H), + _BOTRIGHT - vec2(_MARGIN_W, 0), + vec2(0, -_BORDER_H), + vec2(-_BORDER_W, 0)) wall:addTop(_TOP_COLOR, _xform(_BOTRIGHT, -1, -1, _CORNER_INN())) else + wall:addBottom(_xform(_BOTRIGHT, -1, -1, _CORNER_ALL())) wall:addTop(_TOP_COLOR, _xform(_BOTRIGHT, -1, -1, _CORNER_ALL())) end end diff --git a/game/view/startmenu.lua b/game/view/startmenu.lua index a7497011..be7f610b 100644 --- a/game/view/startmenu.lua +++ b/game/view/startmenu.lua @@ -1,3 +1,6 @@ + +-- luacheck: globals love VERSION + --DEPENDENCIES-- local RES = require 'resources' local FONT = require 'view.helpers.font' @@ -11,16 +14,14 @@ local StartMenuView = Class{ __includes = { ELEMENT } } -local _TITLE_TEXT = "backdoor" local _LH = 1.5 -local _TILE_W, _TILE_H = 80, 80 +local _TILE_W = 80 local _SCROLL_THRESHOLD = 6 local _TITLE_FONT_SIZE = 48 local _MENU_FONT_SIZE = 24 local _VERSION_FONT_SIZE = 16 local _CONTROLS_FONT_SIZE = 24 -local _FADE_TIME = .5 --Logo consts and variables local _LOGO_BG_PARTS = 11 @@ -59,8 +60,6 @@ local function _initLogo() _LOGO_BG_MAG_MIN end _LOGO_TEXT = RES.loadTexture('logo-text') - _LOGO_BG_WIDTH = _LOGO_BG[1]:getWidth() - _LOGO_BG_HEIGHT = _LOGO_BG[1]:getHeight() end local function _renderTitleLogo(g) @@ -97,7 +96,7 @@ local function _renderOptions(g, q, selection, scrolltop) local count = 0 while not q.isEmpty() do local item_text = q.pop() - local text_color = COLORS.BACKGROUND + local text_color = COLORS.NONE count = count + 1 if count >= scrolltop and count < scrolltop + _SCROLL_THRESHOLD then if selection == count then @@ -185,7 +184,7 @@ function StartMenuView:draw() end -function StartMenuView:update(dt) +function StartMenuView:update(dt) -- luacheck: no self _logo_rotation = (_logo_rotation + _LOGO_ROTATION_SPEED*dt) for i = 2, _LOGO_BG_PARTS do