From 8e4288e7b62dc4330aee141d160cddd09fda195a Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Sun, 24 Dec 2023 22:14:27 +0100 Subject: [PATCH] feat: LUA definitions for syntax highlighting --- assets/scripts/_test.lua | 39 + assets/scripts/artifacts/deflector_shield.lua | 21 +- .../scripts/artifacts/gigantic_strength.lua | 30 +- assets/scripts/artifacts/gold_converter.lua | 4 +- assets/scripts/artifacts/repulsion_stone.lua | 2 +- assets/scripts/cards/shield_bash.lua | 26 +- assets/scripts/definitions/actor.lua | 14 + assets/scripts/definitions/api.lua | 868 ++++++++++++++++++ assets/scripts/definitions/artifact.lua | 15 + assets/scripts/definitions/base.lua | 28 + assets/scripts/definitions/callbacks.lua | 31 + assets/scripts/definitions/card.lua | 30 + assets/scripts/definitions/enemy.lua | 20 + assets/scripts/definitions/event.lua | 25 + assets/scripts/definitions/status_effect.lua | 34 + assets/scripts/definitions/story_teller.lua | 7 + cmd/definitions/main.go | 90 ++ docs/LUA_API_DOCS.md | 237 ++--- docs/LUA_DOCS.md | 1 + game/lua.go | 132 +-- game/resources.go | 107 ++- game/session.go | 4 + update-docs.sh | 3 +- 23 files changed, 1509 insertions(+), 259 deletions(-) create mode 100644 assets/scripts/_test.lua create mode 100644 assets/scripts/definitions/actor.lua create mode 100644 assets/scripts/definitions/api.lua create mode 100644 assets/scripts/definitions/artifact.lua create mode 100644 assets/scripts/definitions/base.lua create mode 100644 assets/scripts/definitions/callbacks.lua create mode 100644 assets/scripts/definitions/card.lua create mode 100644 assets/scripts/definitions/enemy.lua create mode 100644 assets/scripts/definitions/event.lua create mode 100644 assets/scripts/definitions/status_effect.lua create mode 100644 assets/scripts/definitions/story_teller.lua create mode 100644 cmd/definitions/main.go diff --git a/assets/scripts/_test.lua b/assets/scripts/_test.lua new file mode 100644 index 0000000..963398f --- /dev/null +++ b/assets/scripts/_test.lua @@ -0,0 +1,39 @@ +function assert_chain(tests) + for i, test in ipairs(tests) do + result = test() + if result ~= nil then + return result + end + end + return nil +end + +function assert_status_effect_count(count) + status_effects = get_actor_status_effects(PLAYER_ID) + + -- check if length of status_effects is 1 + if #status_effects ~= count then + return "Expected " .. count .. " status effects, got " .. #status_effects + end + + return nil +end + +function assert_status_effect(type, number) + status_effects = get_actor_status_effects(PLAYER_ID) + + -- find the status effect + for i, guid in ipairs(status_effects) do + instance = get_status_effect_instance(guid) + if instance.type_id == type then + -- check if the stacks are equal to the number + if instance.stacks ~= number then + return "Expected " .. number .. " block, got " .. tostring(block.stacks) + end + + return nil + end + end + + return "Status effect not found" +end \ No newline at end of file diff --git a/assets/scripts/artifacts/deflector_shield.lua b/assets/scripts/artifacts/deflector_shield.lua index 0a2c646..94ad35c 100644 --- a/assets/scripts/artifacts/deflector_shield.lua +++ b/assets/scripts/artifacts/deflector_shield.lua @@ -11,25 +11,8 @@ register_artifact("DEFLECTOR_SHIELD", { return nil end }, - test = function(ctx) + test = function() add_actor_by_enemy("DUMMY") - - status_effects = get_actor_status_effects(PLAYER_ID) - - -- check if length of status_effects is 1 - if #status_effects ~= 1 then - return "Expected 1 status effect, got " .. #status_effects - end - - -- check if the status effect is BLOCK - block = get_status_effect_instance(status_effects[1]) - if block.type_id ~= "BLOCK" then - return "Expected BLOCK status effect, got " .. tostring(block.type_id) - end - - -- check if the block amount is 8 - if block.stacks ~= 8 then - return "Expected 8 block, got " .. tostring(block.stacks) - end + return assert_chain({ assert_status_effect_count(1), assert_status_effect("BLOCK", 8) }) end }); diff --git a/assets/scripts/artifacts/gigantic_strength.lua b/assets/scripts/artifacts/gigantic_strength.lua index 051deda..8b4445c 100644 --- a/assets/scripts/artifacts/gigantic_strength.lua +++ b/assets/scripts/artifacts/gigantic_strength.lua @@ -1,17 +1,17 @@ register_artifact("GIGANTIC_STRENGTH", { - name = "Stone Of Gigantic Strength", - description = "Double all damage dealt.", - price = 250, - order = 0, - callbacks = { - on_damage_calc = function(ctx) - if ctx.source == ctx.owner then - return ctx.damage * 2 - end - return nil - end, - }, - test = function(ctx) + name = "Stone Of Gigantic Strength", + description = "Double all damage dealt.", + price = 250, + order = 0, + callbacks = { + on_damage_calc = function(ctx) + if ctx.source == ctx.owner then + return ctx.damage * 2 + end + return nil + end + }, + test = function() dummy = add_actor_by_enemy("DUMMY") hp_before = get_actor(dummy).hp @@ -19,8 +19,8 @@ register_artifact("GIGANTIC_STRENGTH", { hp_after = get_actor(dummy).hp if hp_after == hp_before - 2 then - return true + return nil end return "Damage was not doubled. Before:" .. hp_before .. " After:" .. hp_after - end + end }) diff --git a/assets/scripts/artifacts/gold_converter.lua b/assets/scripts/artifacts/gold_converter.lua index 5f2fc2e..61acedd 100644 --- a/assets/scripts/artifacts/gold_converter.lua +++ b/assets/scripts/artifacts/gold_converter.lua @@ -12,10 +12,10 @@ register_artifact("GOLD_CONVERTER", { end }, test = function() - dummy = add_actor_by_enemy("DUMMY") + local dummy = add_actor_by_enemy("DUMMY") deal_damage(PLAYER_ID, dummy, 10000) if get_player().gold == 10 then - return true + return nil end return "Expected 10 gold, got " .. get_player().gold end diff --git a/assets/scripts/artifacts/repulsion_stone.lua b/assets/scripts/artifacts/repulsion_stone.lua index 42e186e..22e046f 100644 --- a/assets/scripts/artifacts/repulsion_stone.lua +++ b/assets/scripts/artifacts/repulsion_stone.lua @@ -6,7 +6,7 @@ register_artifact("REPULSION_STONE", { callbacks = { on_damage = function(ctx) if ctx.target == ctx.owner then - heal(ctx.owner, 2) + heal(ctx.owner, ctx.owner, 2) end return nil end diff --git a/assets/scripts/cards/shield_bash.lua b/assets/scripts/cards/shield_bash.lua index edf5811..7ff07bd 100644 --- a/assets/scripts/cards/shield_bash.lua +++ b/assets/scripts/cards/shield_bash.lua @@ -13,9 +13,31 @@ register_card("SHIELD_BASH", { price = 40, callbacks = { on_cast = function(ctx) - local damage = deal_damage(ctx.caster, 4 + ctx.level * 2) + local damage = deal_damage(ctx.caster, ctx.target, 4 + ctx.level * 2) give_status_effect("BLOCK", ctx.caster, damage) return nil end - } + }, + test = function() + dummy = add_actor_by_enemy("DUMMY") + cards = get_cards(PLAYER_ID) + + -- Check if the card is in the player's hand + if not cards[1] then + return "Card not in hand" + end + + card = get_card_instance(cards[1]) + if card.type_id ~= "SHIELD_BASH" then + return "Card has wrong type: " .. card.type_id + end + + cast_card(cards[1], dummy) + + if get_actor(dummy).hp ~= 96 then + return "Expected 96 health, got " .. get_actor_health(dummy) + end + + return assert_chain({ assert_status_effect_count(1), assert_status_effect("BLOCK", 4) }) + end }) diff --git a/assets/scripts/definitions/actor.lua b/assets/scripts/definitions/actor.lua new file mode 100644 index 0000000..2b3e37d --- /dev/null +++ b/assets/scripts/definitions/actor.lua @@ -0,0 +1,14 @@ +---@meta + +---Actor represents a player or enemy. +---@class actor +---@field guid guid +---@field type_id type_id +---@field name string +---@field description string +---@field max_hp number +---@field hp number +---@field gold number +---@field artifacts guid[] +---@field cards guid[] +---@field status_effects guid[] \ No newline at end of file diff --git a/assets/scripts/definitions/api.lua b/assets/scripts/definitions/api.lua new file mode 100644 index 0000000..e3c8cfa --- /dev/null +++ b/assets/scripts/definitions/api.lua @@ -0,0 +1,868 @@ +---@meta + +-- ##################################### +-- Game Constants +-- ##################################### + +--[[ +Status effect decays by all stacks per turn. +--]] +DECAY_ALL = "" + +--[[ +Status effect never decays. +--]] +DECAY_NONE = "" + +--[[ +Status effect decays by 1 stack per turn. +--]] +DECAY_ONE = "" + +--[[ +Represents the event game state. +--]] +GAME_STATE_EVENT = "" + +--[[ +Represents the fight game state. +--]] +GAME_STATE_FIGHT = "" + +--[[ +Represents the merchant game state. +--]] +GAME_STATE_MERCHANT = "" + +--[[ +Represents the random game state in which the active story teller will decide what happens next. +--]] +GAME_STATE_RANDOM = "" + +--[[ +Player actor id for use in functions where the guid is needed, for example: ``deal_damage(PLAYER_ID, enemy_id, 10)``. +--]] +PLAYER_ID = "" + +-- Functions +-- ##################################### +-- Utility +-- ##################################### + +-- Functions +--[[ +Fetches a value from the persistent store +--]] +---@param key string +---@return any +function fetch(key) end + +--[[ +returns a new random guid. +--]] + +---@return guid +function guid() end + +--[[ +Stores a persistent value for this run that will be restored after a save load. Can store any lua basic value or table. +--]] +---@param key string +---@param value any +function store(key, value) end + +-- ##################################### +-- Styling +-- ##################################### + +-- Functions +--[[ +Makes the text background colored. Takes hex values like #ff0000. +--]] +---@param color string +---@param value any +---@return string +function text_bg(color, value) end + +--[[ +Makes the text bold. +--]] +---@param value any +---@return string +function text_bold(value) end + +--[[ +Makes the text foreground colored. Takes hex values like #ff0000. +--]] +---@param color string +---@param value any +---@return string +function text_color(color, value) end + +--[[ +Makes the text italic. +--]] +---@param value any +---@return string +function text_italic(value) end + +--[[ +Makes the text underlined. +--]] +---@param value any +---@return string +function text_underline(value) end + +-- ##################################### +-- Logging +-- ##################################### + +-- Functions +--[[ +Log at **danger** level to player log. +--]] +---@param value any +function log_d(value) end + +--[[ +Log at **information** level to player log. +--]] +---@param value any +function log_i(value) end + +--[[ +Log at **success** level to player log. +--]] +---@param value any +function log_s(value) end + +--[[ +Log at **warning** level to player log. +--]] +---@param value any +function log_w(value) end + +--[[ +Log to session log. +--]] +---@param value, value, value... any +function print(value, value, value...) end + +-- ##################################### +-- Audio +-- ##################################### + +-- Functions +--[[ +Plays a sound effect. If you want to play ``button.mp3`` you call ``play_audio("button")``. +--]] +---@param sound string +function play_audio(sound) end + +--[[ +Start a song for the background loop. If you want to play ``song.mp3`` you call ``play_music("song")``. +--]] +---@param sound string +function play_music(sound) end + +-- ##################################### +-- Game State +-- ##################################### + +-- Functions +--[[ +Gets the ids of all the encountered events in the order of occurrence. +--]] +---@param any +---@return string[] +function get_event_history() end + +--[[ +Gets the fight state. This contains the player hand, used, exhausted and round information. +--]] +---@param any +---@return table +function get_fight() end + +--[[ +Gets the number of stages cleared. +--]] +---@param any +---@return number +function get_fight_round() end + +--[[ +Checks if the event happened at least once. +--]] +---@param event_id type_id +---@return boolean +function had_event(event_id) end + +--[[ +Checks if all the events happened at least once. +--]] +---@param event_ids type_id[] +---@return boolean +function had_events(event_ids) end + +--[[ +Checks if any of the events happened at least once. +--]] +---@param eventIds string[] +---@return boolean +function had_events_any(eventIds) end + +--[[ +Set event by id. +--]] +---@param eventId string +function set_event(eventId) end + +--[[ +Set the current fight description. This will be shown on the top right in the game. +--]] +---@param desc string +function set_fight_description(desc) end + +--[[ +Set the current game state. See globals. +--]] +---@param state string +function set_game_state(state) end + +-- ##################################### +-- Actor Operations +-- ##################################### + +-- Functions +--[[ +Increases the hp value of a actor by a number. Can be negative value to decrease it. This won't trigger any on_damage callbacks +--]] +---@param guid guid +---@param amount number +function actor_add_hp(guid, amount) end + +--[[ +Increases the max hp value of a actor by a number. Can be negative value to decrease it. +--]] +---@param guid guid +---@param amount number +function actor_add_max_hp(guid, amount) end + +--[[ +Creates a new enemy fighting against the player. Example ``add_actor_by_enemy("RUST_MITE")``. +--]] +---@param enemy_id type_id +---@return string +function add_actor_by_enemy(enemy_id) end + +--[[ +Get a actor by guid. +--]] +---@param guid guid +---@return actor +function get_actor(guid) end + +--[[ +Get opponent (actor) by index of a certain actor. ``get_opponent_by_index(PLAYER_ID, 2)`` would return the second alive opponent of the player. +--]] +---@param guid guid +---@param index number +---@return actor +function get_opponent_by_index(guid, index) end + +--[[ +Get the number of opponents (actors) of a certain actor. ``get_opponent_count(PLAYER_ID)`` would return 2 if the player had 2 alive enemies. +--]] +---@param guid guid +---@return number +function get_opponent_count(guid) end + +--[[ +Get the guids of opponents (actors) of a certain actor. If the player had 2 enemies, ``get_opponent_guids(PLAYER_ID)`` would return a table with 2 strings containing the guids of these actors. +--]] +---@param guid guid +---@return guid[] +function get_opponent_guids(guid) end + +--[[ +Get the player actor. Equivalent to ``get_actor(PLAYER_ID)`` +--]] + +---@return actor +function get_player() end + +--[[ +Deletes a actor by id. +--]] +---@param guid guid +function remove_actor(guid) end + +-- ##################################### +-- Artifact Operations +-- ##################################### + +-- Functions +--[[ +Returns the artifact definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance. +--]] +---@param id string +---@return artifact +function get_artifact(id) end + +--[[ +Returns the artifact instance by guid. +--]] +---@param guid guid +---@return artifact_instance +function get_artifact_instance(guid) end + +--[[ +Gives a actor a artifact. Returns the guid of the newly created artifact. +--]] +---@param type_id type_id +---@param actor guid +---@return string +function give_artifact(type_id, actor) end + +--[[ +Removes a artifact. +--]] +---@param guid guid +function remove_artifact(guid) end + +-- ##################################### +-- Status Effect Operations +-- ##################################### + +-- Functions +--[[ +Adds to the stack count of a status effect. Negative values are also allowed. +--]] +---@param guid guid +---@param count number +function add_status_effect_stacks(guid, count) end + +--[[ +Returns the guids of all status effects that belong to a actor. +--]] +---@param actorId string +---@return guid[] +function get_actor_status_effects(actorId) end + +--[[ +Returns the status effect definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance. +--]] +---@param id string +---@return status_effect +function get_status_effect(id) end + +--[[ +Returns the status effect instance. +--]] +---@param effect_guid guid +---@return status_effect_instance +function get_status_effect_instance(effect_guid) end + +--[[ +Gives a status effect to a actor. If count is not specified a stack of 1 is applied. +--]] +---@param type_id string +---@param actor_guid string +---@param count? number +function give_status_effect(type_id, actor_guid, count) end + +--[[ +Removes a status effect. +--]] +---@param guid guid +function remove_status_effect(guid) end + +--[[ +Sets the stack count of a status effect by guid. +--]] +---@param guid guid +---@param count number +function set_status_effect_stacks(guid, count) end + +-- ##################################### +-- Card Operations +-- ##################################### + +-- Functions +--[[ +Tries to cast a card with a guid and optional target. If the cast isn't successful returns false. +--]] +---@param card_guid guid +---@param target_actor_guid? guid +---@return boolean +function cast_card(card_guid, target_actor_guid) end + +--[[ +Returns the card type definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance. +--]] +---@param id type_id +---@return card +function get_card(id) end + +--[[ +Returns the instance object of a card. +--]] +---@param card_guid guid +---@return card_instance +function get_card_instance(card_guid) end + +--[[ +Returns all the card guids from the given actor. +--]] +---@param actor_guid string +---@return guid[] +function get_cards(actor_guid) end + +--[[ +Gives a card. +--]] +---@param card_type_id type_id +---@param owner_actor_id guid +---@return string +function give_card(card_type_id, owner_actor_id) end + +--[[ +Removes a card. +--]] +---@param cardGuid string +function remove_card(cardGuid) end + +--[[ +Upgrade a card without paying for it. +--]] +---@param card_guid guid +---@return boolean +function upgrade_card(card_guid) end + +--[[ +Upgrade a random card without paying for it. +--]] +---@param actor_guid guid +---@return boolean +function upgrade_random_card(actor_guid) end + +-- ##################################### +-- Damage & Heal +-- ##################################### + +-- Functions +--[[ +Deal damage to a enemy from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns the damage that was dealt. +--]] +---@param source guid +---@param target guid +---@param damage number +---@param flat? boolean +---@return number +function deal_damage(source, target, damage, flat) end + +--[[ +Deal damage to multiple enemies from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns a array of damages for each actor hit. +--]] +---@param source guid +---@param targets guid[] +---@param damage number +---@param flat? boolean +---@return number[] +function deal_damage_multi(source, targets, damage, flat) end + +--[[ +Heals the target triggered by the source. +--]] +---@param source guid +---@param target guid +---@param amount number +function heal(source, target, amount) end + +-- ##################################### +-- Player Operations +-- ##################################### + +-- Functions +--[[ +Finishes the player turn. +--]] + +function finish_player_turn() end + +--[[ +Gives the player gold. +--]] +---@param amount number +function give_player_gold(amount) end + +--[[ +Let the player buy the artifact with the given id. This will deduct the price form the players gold and return true if the buy was successful. +--]] +---@param card_id type_id +---@return boolean +function player_buy_artifact(card_id) end + +--[[ +Let the player buy the card with the given id. This will deduct the price form the players gold and return true if the buy was successful. +--]] +---@param card_id type_id +---@return boolean +function player_buy_card(card_id) end + +--[[ +Let the player draw additional cards for this turn. +--]] +---@param amount number +function player_draw_card(amount) end + +--[[ +Gives the player more action points for this turn. +--]] +---@param points number +function player_give_action_points(points) end + +-- ##################################### +-- Merchant Operations +-- ##################################### + +-- Functions +--[[ +Adds another random artifact to the merchant +--]] + +function add_merchant_artifact() end + +--[[ +Adds another random card to the merchant +--]] + +function add_merchant_card() end + +--[[ +Returns the merchant state. +--]] + +---@return table +function get_merchant() end + +--[[ +Returns the maximum value of artifacts and cards that the merchant will sell. Good to scale ``random_card`` and ``random_artifact``. +--]] + +---@return number +function get_merchant_gold_max() end + +-- ##################################### +-- Random Utility +-- ##################################### + +-- Functions +--[[ +Generates a random face. +--]] +---@param category? number +---@return string +function gen_face(category) end + +--[[ +Returns the type id of a random artifact. +--]] +---@param max_price number +---@return type_id +function random_artifact(max_price) end + +--[[ +Returns the type id of a random card. +--]] +---@param max_price number +---@return type_id +function random_card(max_price) end + +-- ##################################### +-- Localization +-- ##################################### + +-- Functions +--[[ +Returns the localized string for the given key. Examples on locals definition can be found in `/assets/locals`. Example: `` +l('cards.MY_CARD.name', "English Default Name")`` +--]] +---@param key string +---@param default? string +---@return string +function l(key, default) end + +-- ##################################### +-- Content Registry +-- ##################################### + +-- Functions +--[[ +Deletes all base game content. Useful if you don't want to include base game content in your mod. + +```lua +delete_base_game() -- delete all base game content +delete_base_game("artifact") -- deletes all artifacts +delete_base_game("card") -- deletes all cards +delete_base_game("enemy") -- deletes all enemies +delete_base_game("event") -- deletes all events +delete_base_game("status_effect") -- deletes all status effects +delete_base_game("story_teller") -- deletes all story tellers + +``` +--]] +---@param type? string +function delete_base_game(type) end + +--[[ +Deletes a card. + +```lua +delete_card("SOME_CARD") +``` +--]] +---@param id type_id +function delete_card(id) end + +--[[ +Deletes an enemy. + +```lua +delete_enemy("SOME_ENEMY") +``` +--]] +---@param id type_id +function delete_enemy(id) end + +--[[ +Deletes an event. + +```lua +delete_event("SOME_EVENT") +``` +--]] +---@param id type_id +function delete_event(id) end + +--[[ +Deletes a status effect. + +```lua +delete_status_effect("SOME_STATUS_EFFECT") +``` +--]] +---@param id type_id +function delete_status_effect(id) end + +--[[ +Deletes a story teller. + +```lua +delete_story_teller("SOME_STORY_TELLER") +``` +--]] +---@param id type_id +function delete_story_teller(id) end + +--[[ +Registers a new artifact. + +```lua +register_artifact("REPULSION_STONE", + { + name = "Repulsion Stone", + description = "For each damage taken heal for 2", + price = 100, + order = 0, + callbacks = { + on_damage = function(ctx) + if ctx.target == ctx.owner then + heal(ctx.owner, 2) + end + return nil + end, + } + } +) +``` +--]] +---@param id type_id +---@param definition artifact +function register_artifact(id, definition) end + +--[[ +Registers a new card. + +```lua +register_card("MELEE_HIT", + { + name = "Melee Hit", + description = "Use your bare hands to deal 5 (+3 for each upgrade) damage.", + state = function(ctx) + return "Use your bare hands to deal " .. highlight(5 + ctx.level * 3) .. " damage." + end, + max_level = 1, + color = "#2f3e46", + need_target = true, + point_cost = 1, + price = 30, + callbacks = { + on_cast = function(ctx) + deal_damage(ctx.caster, ctx.target, 5 + ctx.level * 3) + return nil + end, + } + } +) +``` +--]] +---@param id type_id +---@param definition card +function register_card(id, definition) end + +--[[ +Registers a new enemy. + +```lua +register_enemy("RUST_MITE", + { + name = "Rust Mite", + description = "Loves to eat metal.", + look = "/v\\", + color = "#e6e65a", + initial_hp = 22, + max_hp = 22, + gold = 10, + callbacks = { + on_turn = function(ctx) + if ctx.round % 4 == 0 then + give_status_effect("RITUAL", ctx.guid) + else + deal_damage(ctx.guid, PLAYER_ID, 6) + end + + return nil + end + } + } +) +``` +--]] +---@param id type_id +---@param definition enemy +function register_enemy(id, definition) end + +--[[ +Registers a new event. + +```lua +register_event("SOME_EVENT", + { + name = "Event Name", + description = "Flavor Text... Can include **Markdown** Syntax!", + choices = { + { + description = "Go...", + callback = function() + -- If you return nil on_end will decide the next game state + return nil + end + }, + { + description = "Other Option", + callback = function() return GAME_STATE_FIGHT end + } + }, + on_enter = function() + play_music("energetic_orthogonal_expansions") + + give_card("MELEE_HIT", PLAYER_ID) + give_card("MELEE_HIT", PLAYER_ID) + give_card("MELEE_HIT", PLAYER_ID) + give_card("RUPTURE", PLAYER_ID) + give_card("BLOCK", PLAYER_ID) + give_artifact(get_random_artifact_type(150), PLAYER_ID) + end, + on_end = function(choice) + -- Choice will be nil or the index of the choice taken + return GAME_STATE_RANDOM + end, + } +) +``` +--]] +---@param id type_id +---@param definition event +function register_event(id, definition) end + +--[[ +Registers a new status effect. + +```lua +register_status_effect("BLOCK", { + name = "Block", + description = "Decreases incoming damage for each stack", + look = "Blk", + foreground = "#219ebc", + state = function(ctx) + return "Takes " .. highlight(ctx.stacks) .. " less damage" + end, + can_stack = true, + decay = DECAY_ALL, + rounds = 1, + order = 100, + callbacks = { + on_damage_calc = function(ctx) + if ctx.target == ctx.owner then + add_status_effect_stacks(ctx.guid, -ctx.damage) + return ctx.damage - ctx.stacks + end + return ctx.damage + end + } +}) +``` +--]] +---@param id type_id +---@param definition status_effect +function register_status_effect(id, definition) end + +--[[ +Registers a new story teller. + +```lua +register_story_teller("STORY_TELLER_XYZ", { + active = function(ctx) + if not had_events_any({ "A", "B", "C" }) then + return 1 + end + return 0 + end, + decide = function(ctx) + local stage = get_stages_cleared() + + if stage >= 3 then + set_event("SOME_EVENT") + return GAME_STATE_EVENT + end + + -- Fight against rust mites or clean bots + local d = math.random(2) + if d == 1 then + add_actor_by_enemy("RUST_MITE") + elseif d == 2 then + add_actor_by_enemy("CLEAN_BOT") + end + + return GAME_STATE_FIGHT + end +}) +) +``` +--]] +---@param id type_id +---@param definition story_teller +function register_story_teller(id, definition) end + diff --git a/assets/scripts/definitions/artifact.lua b/assets/scripts/definitions/artifact.lua new file mode 100644 index 0000000..64f1841 --- /dev/null +++ b/assets/scripts/definitions/artifact.lua @@ -0,0 +1,15 @@ +---@meta + +---@class artifact +---@field id? type_id +---@field name? string +---@field description? string +---@field price? number +---@field order? number +---@field callbacks? callbacks +---@field test? fun():nil|string +---@field base_game? boolean + +---@class artifact_instance +---@field guid guid +---@field type_id type_id \ No newline at end of file diff --git a/assets/scripts/definitions/base.lua b/assets/scripts/definitions/base.lua new file mode 100644 index 0000000..0d337be --- /dev/null +++ b/assets/scripts/definitions/base.lua @@ -0,0 +1,28 @@ +---@meta + +---GUID of an actor, artifact, or status effect. References an active instance of the object. +---@alias guid string + +---ID of an actor, artifact, or status effect. References the definition of the object. +---@alias type_id string + +---Game state. Used to determine what the game should be doing at the moment. Can be one of: GAME_STATE_EVENT, GAME_STATE_FIGHT, GAME_STATE_MERCHANT, GAME_STATE_RANDOM +---@alias game_state string + +---Next game state. Used to determine what the game should be doing next. Can be one of: GAME_STATE_EVENT, GAME_STATE_FIGHT, GAME_STATE_MERCHANT, GAME_STATE_RANDOM +---@alias next_game_state string + +---Registered objects. +---@class registered +---@field card { [string]: card } +---@field artifact { [string]: artifact } +---@field event { [string]: event } +---@field story_teller { [string]: story_teller } +---@field status_effect { [string]: status_effect } +registered = { + ["card"] = {}, + ["artifact"] = {}, + ["event"] = {}, + ["story_teller"] = {}, + ["status_effect"] = {}, +} \ No newline at end of file diff --git a/assets/scripts/definitions/callbacks.lua b/assets/scripts/definitions/callbacks.lua new file mode 100644 index 0000000..876d033 --- /dev/null +++ b/assets/scripts/definitions/callbacks.lua @@ -0,0 +1,31 @@ +---@meta + +---Callbacks context table. This table is passed to all callbacks but not all fields are used in all callbacks. +---@class ctx +---@field type_id? type_id +---@field guid? guid +---@field source? guid +---@field target? guid +---@field owner? guid +---@field caster? guid +---@field level? number +---@field damage? number +---@field heal? number +---@field stacks? number +---@field round? number + +---@class callbacks +---@field on_actor_die? fun(ctx:ctx):nil +---@field on_cast? fun(ctx:ctx):nil +---@field on_damage? fun(ctx:ctx):nil +---@field on_damage_calc? fun(ctx:ctx):number +---@field on_heal_calc? fun(ctx:ctx):number +---@field on_init? fun(ctx:ctx):nil +---@field on_pick_up? fun(ctx:ctx):nil +---@field on_player_turn? fun(ctx:ctx):nil +---@field on_remove? fun(ctx:ctx):nil +---@field on_status_add? fun(ctx:ctx):nil +---@field on_status_remove? fun(ctx:ctx):nil +---@field on_status_stack? fun(ctx:ctx):nil +---@field on_turn? fun(ctx:ctx):boolean|nil + diff --git a/assets/scripts/definitions/card.lua b/assets/scripts/definitions/card.lua new file mode 100644 index 0000000..d6630b1 --- /dev/null +++ b/assets/scripts/definitions/card.lua @@ -0,0 +1,30 @@ +---@meta + +---@class card_state_ctx +---@field type_id type_id +---@field guid guid +---@field level number +---@field owner guid + +---Card represents a playable card definition. +---@class card +---@field id? type_id +---@field name string +---@field description string +---@field state? fun(ctx:card_state_ctx):nil +---@field color string +---@field point_cost number +---@field max_level number +---@field does_exhaust? boolean +---@field need_target boolean +---@field price number +---@field callbacks callbacks +---@field test? fun():nil|string +---@field base_game? boolean + +---CardInstance represents an instance of a card owned by some actor. +---@class card_instance +---@field guid guid +---@field type_id type_id +---@field level number +---@field owner guid \ No newline at end of file diff --git a/assets/scripts/definitions/enemy.lua b/assets/scripts/definitions/enemy.lua new file mode 100644 index 0000000..fe6bec6 --- /dev/null +++ b/assets/scripts/definitions/enemy.lua @@ -0,0 +1,20 @@ +---@meta + +---@class enemy_intend_ctx +---@field type_id type_id +---@field guid guid +---@field round number + +---Enemy represents a definition of a enemy that can be linked from a Actor. +---@class enemy +---@field id? type_id +---@field name string +---@field description string +---@field initial_hp number +---@field max_hp number +---@field look string +---@field color string +---@field intend? fun(ctx:enemy_intend_ctx):nil +---@field callbacks callbacks +---@field test? fun():nil|string +---@field base_game? boolean \ No newline at end of file diff --git a/assets/scripts/definitions/event.lua b/assets/scripts/definitions/event.lua new file mode 100644 index 0000000..0565057 --- /dev/null +++ b/assets/scripts/definitions/event.lua @@ -0,0 +1,25 @@ +---@meta + +---@class event_on_enter_ctx +---@field type_id type_id + +---@class event_choice_ctx +---@field type_id type_id +---@field choice number + +---EventChoice represents a possible choice in the Event. +---@class event_choice +---@field description? string +---@field description_fn? fun():nil|string +---@field callback fun(ctx:event_choice_ctx):next_game_state|nil + +---Event represents a encounter-able event. +---@class event +---@field id? string +---@field name string +---@field description string +---@field choices event_choice[] +---@field on_enter? fun(ctx:event_on_enter_ctx):nil +---@field on_end fun(ctx:event_choice_ctx):next_game_state|nil +---@field test? fun():nil|string +---@field base_game? boolean \ No newline at end of file diff --git a/assets/scripts/definitions/status_effect.lua b/assets/scripts/definitions/status_effect.lua new file mode 100644 index 0000000..e306973 --- /dev/null +++ b/assets/scripts/definitions/status_effect.lua @@ -0,0 +1,34 @@ +---@meta + +---@alias decay_type string + +---@class status_effect_state_ctx +---@field type_id type_id +---@field guid guid +---@field stacks number +---@field owner guid + +--- Status effect defintion +---@class status_effect +---@field id? type_id +---@field name string +---@field description string +---@field state fun(ctx:status_effect_state_ctx):nil +---@field look string +---@field foreground string +---@field order? number +---@field can_stack boolean +---@field decay decay_type +---@field rounds number +---@field callbacks callbacks +---@field test? fun():nil|string +---@field base_game? boolean + +--- Status effect instance +---@class status_effect_instance +---@field guid guid +---@field type_id type_id +---@field owner guid +---@field stacks number +---@field rounds_left number +---@field round_entered number diff --git a/assets/scripts/definitions/story_teller.lua b/assets/scripts/definitions/story_teller.lua new file mode 100644 index 0000000..64bb71d --- /dev/null +++ b/assets/scripts/definitions/story_teller.lua @@ -0,0 +1,7 @@ +---@meta + +---@class story_teller +---@field id type_id +---@field active fun():next_game_state +---@field decide fun():number +---@field base_game boolean \ No newline at end of file diff --git a/cmd/definitions/main.go b/cmd/definitions/main.go new file mode 100644 index 0000000..c241b4e --- /dev/null +++ b/cmd/definitions/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "fmt" + "github.com/BigJk/end_of_eden/game" + "github.com/samber/lo" + "sort" + "strings" +) + +func main() { + docs := game.NewSession().LuaDocs() + + // Fetch the globals and functions keys + globals := lo.Keys(docs.Globals) + functions := lo.Keys(docs.Functions) + + // Sort them + sort.Strings(globals) + sort.Strings(functions) + + // Get the sorted categories + cats := lo.Keys(docs.Categories) + sort.SliceStable(cats, func(i, j int) bool { + return docs.Categories[cats[i]].Order < docs.Categories[cats[j]].Order + }) + + // Build definition + builder := strings.Builder{} + builder.WriteString("---@meta\n\n") + for _, key := range cats { + cat := docs.Categories[key] + + builder.WriteString("-- #####################################\n") + builder.WriteString("-- " + cat.Name + "\n") + builder.WriteString("-- #####################################\n\n") + + for _, key := range globals { + glob := docs.Globals[key] + if glob.Category != cat.Name { + continue + } + builder.WriteString(fmt.Sprintf(`--[[ +%s +--]]`, glob.Description)) + builder.WriteString("\n" + glob.Name + " = \"\"\n\n") + } + + builder.WriteString("-- Functions\n") + + for _, key := range functions { + fn := docs.Functions[key] + if fn.Category != cat.Name { + continue + } + builder.WriteString(fmt.Sprintf(`--[[ +%s +--]]`, fn.Description)) + builder.WriteString("\n" + strings.Join(lo.Map(fn.Args, func(item string, index int) string { + isOptional := strings.HasPrefix(item, "(optional) ") + if isOptional { + item = strings.TrimPrefix(item, "(optional) ") + } + + t := "any" + split := strings.Split(item, ":") + if len(split) > 1 { + t = strings.TrimSpace(split[1]) + } + + return "---@param " + strings.TrimSpace(split[0]) + lo.Ternary(isOptional, "?", "") + " " + t + }), "\n")) + if fn.Return != "" { + builder.WriteString("\n---@return " + fn.Return) + } + builder.WriteString("\nfunction " + fn.Name + "(") + builder.WriteString(strings.Join(lo.Map(fn.Args, func(item string, index int) string { + isOptional := strings.HasPrefix(item, "(optional) ") + if isOptional { + item = strings.TrimPrefix(item, "(optional) ") + } + return strings.TrimSpace(strings.Split(item, ":")[0]) + }), ", ")) + builder.WriteString(") end\n\n") + } + } + + // Output docs + fmt.Print(builder.String()) +} diff --git a/docs/LUA_API_DOCS.md b/docs/LUA_API_DOCS.md index de3531f..9a37f8d 100644 --- a/docs/LUA_API_DOCS.md +++ b/docs/LUA_API_DOCS.md @@ -91,7 +91,7 @@ Fetches a value from the persistent store **Signature:** ``` -fetch(key : String) -> Any +fetch(key : string) -> any ``` @@ -103,7 +103,7 @@ returns a new random guid. **Signature:** ``` -guid() -> String +guid() -> guid ``` @@ -115,7 +115,7 @@ Stores a persistent value for this run that will be restored after a save load. **Signature:** ``` -store(key : String, value : Any) -> None +store(key : string, value : any) -> None ``` @@ -136,7 +136,7 @@ Makes the text background colored. Takes hex values like #ff0000. **Signature:** ``` -text_bg(color : String, value) -> String +text_bg(color : string, value : any) -> string ``` @@ -148,7 +148,7 @@ Makes the text bold. **Signature:** ``` -text_bold(value) -> String +text_bold(value : any) -> string ``` @@ -160,7 +160,7 @@ Makes the text foreground colored. Takes hex values like #ff0000. **Signature:** ``` -text_color(color : String, value) -> String +text_color(color : string, value : any) -> string ``` @@ -172,7 +172,7 @@ Makes the text italic. **Signature:** ``` -text_italic(value) -> String +text_italic(value : any) -> string ``` @@ -184,7 +184,7 @@ Makes the text underlined. **Signature:** ``` -text_underline(value) -> String +text_underline(value : any) -> string ``` @@ -205,7 +205,7 @@ Log at **danger** level to player log. **Signature:** ``` -log_d(value) -> None +log_d(value : any) -> None ``` @@ -217,7 +217,7 @@ Log at **information** level to player log. **Signature:** ``` -log_i(value) -> None +log_i(value : any) -> None ``` @@ -229,7 +229,7 @@ Log at **success** level to player log. **Signature:** ``` -log_s(value) -> None +log_s(value : any) -> None ``` @@ -241,7 +241,7 @@ Log at **warning** level to player log. **Signature:** ``` -log_w(value) -> None +log_w(value : any) -> None ``` @@ -274,7 +274,7 @@ Plays a sound effect. If you want to play ``button.mp3`` you call ``play_audio(" **Signature:** ``` -play_audio(sound : String) -> None +play_audio(sound : string) -> None ``` @@ -286,7 +286,7 @@ Start a song for the background loop. If you want to play ``song.mp3`` you call **Signature:** ``` -play_music(sound : String) -> None +play_music(sound : string) -> None ``` @@ -307,7 +307,7 @@ Gets the ids of all the encountered events in the order of occurrence. **Signature:** ``` -get_event_history() -> Array +get_event_history() -> string[] ``` @@ -319,7 +319,7 @@ Gets the fight state. This contains the player hand, used, exhausted and round i **Signature:** ``` -get_fight() -> Table +get_fight() -> table ``` @@ -331,7 +331,7 @@ Gets the number of stages cleared. **Signature:** ``` -get_fight_round() -> Number +get_fight_round() -> number ``` @@ -343,7 +343,7 @@ Checks if the event happened at least once. **Signature:** ``` -had_event(eventId : String) -> Bool +had_event(event_id : type_id) -> boolean ``` @@ -355,7 +355,7 @@ Checks if all the events happened at least once. **Signature:** ``` -had_events(eventIds : Array) -> Bool +had_events(event_ids : type_id[]) -> boolean ``` @@ -367,7 +367,7 @@ Checks if any of the events happened at least once. **Signature:** ``` -had_events_any(eventIds : Array) -> Bool +had_events_any(eventIds : string[]) -> boolean ``` @@ -379,7 +379,7 @@ Set event by id. **Signature:** ``` -set_event(eventId : String) -> None +set_event(eventId : string) -> None ``` @@ -391,7 +391,7 @@ Set the current fight description. This will be shown on the top right in the ga **Signature:** ``` -set_fight_description(desc : String) -> None +set_fight_description(desc : string) -> None ``` @@ -403,7 +403,7 @@ Set the current game state. See globals. **Signature:** ``` -set_game_state(state : String) -> None +set_game_state(state : string) -> None ``` @@ -424,7 +424,7 @@ Increases the hp value of a actor by a number. Can be negative value to decrease **Signature:** ``` -actor_add_hp(guid : String, amount : Number) -> None +actor_add_hp(guid : guid, amount : number) -> None ``` @@ -436,7 +436,7 @@ Increases the max hp value of a actor by a number. Can be negative value to decr **Signature:** ``` -actor_add_max_hp(guid : String, amount : Number) -> None +actor_add_max_hp(guid : guid, amount : number) -> None ``` @@ -448,7 +448,7 @@ Creates a new enemy fighting against the player. Example ``add_actor_by_enemy("R **Signature:** ``` -add_actor_by_enemy(enemyId : String) -> String +add_actor_by_enemy(enemy_id : type_id) -> string ``` @@ -460,7 +460,7 @@ Get a actor by guid. **Signature:** ``` -get_actor(guid : String) -> Table +get_actor(guid : guid) -> actor ``` @@ -472,7 +472,7 @@ Get opponent (actor) by index of a certain actor. ``get_opponent_by_index(PLAYER **Signature:** ``` -get_opponent_by_index(guid : String, index : Number) -> Table +get_opponent_by_index(guid : guid, index : number) -> actor ``` @@ -484,7 +484,7 @@ Get the number of opponents (actors) of a certain actor. ``get_opponent_count(PL **Signature:** ``` -get_opponent_count(guid : String) -> Table +get_opponent_count(guid : guid) -> number ``` @@ -496,7 +496,7 @@ Get the guids of opponents (actors) of a certain actor. If the player had 2 enem **Signature:** ``` -get_opponent_guids(guid : String) -> Table +get_opponent_guids(guid : guid) -> guid[] ``` @@ -508,7 +508,7 @@ Get the player actor. Equivalent to ``get_actor(PLAYER_ID)`` **Signature:** ``` -get_player() -> Table +get_player() -> actor ``` @@ -520,7 +520,7 @@ Deletes a actor by id. **Signature:** ``` -remove_actor(guid : String) -> None +remove_actor(guid : guid) -> None ``` @@ -541,7 +541,7 @@ Returns the artifact definition. Can take either a guid or a typeId. If it's a g **Signature:** ``` -get_artifact(id : String) -> Table +get_artifact(id : string) -> artifact ``` @@ -553,7 +553,7 @@ Returns the artifact instance by guid. **Signature:** ``` -get_artifact_instance(guid : String) -> None +get_artifact_instance(guid : guid) -> artifact_instance ``` @@ -565,7 +565,7 @@ Gives a actor a artifact. Returns the guid of the newly created artifact. **Signature:** ``` -give_artifact(typeId : String, actor : String) -> String +give_artifact(type_id : type_id, actor : guid) -> string ``` @@ -577,7 +577,7 @@ Removes a artifact. **Signature:** ``` -remove_artifact(guid : String) -> None +remove_artifact(guid : guid) -> None ``` @@ -598,7 +598,7 @@ Adds to the stack count of a status effect. Negative values are also allowed. **Signature:** ``` -add_status_effect_stacks(guid : String, count : Number) -> None +add_status_effect_stacks(guid : guid, count : number) -> None ``` @@ -610,7 +610,7 @@ Returns the guids of all status effects that belong to a actor. **Signature:** ``` -get_actor_status_effects(actorId : String) -> Array +get_actor_status_effects(actorId : string) -> guid[] ``` @@ -622,7 +622,7 @@ Returns the status effect definition. Can take either a guid or a typeId. If it' **Signature:** ``` -get_status_effect(id : String) -> Table +get_status_effect(id : string) -> status_effect ``` @@ -634,7 +634,7 @@ Returns the status effect instance. **Signature:** ``` -get_status_effect_instance(effectGuid : String) -> Table +get_status_effect_instance(effect_guid : guid) -> status_effect_instance ``` @@ -646,7 +646,7 @@ Gives a status effect to a actor. If count is not specified a stack of 1 is appl **Signature:** ``` -give_status_effect(typeId : String, actorGuid : String, (optional) count : Number) -> None +give_status_effect(type_id : string, actor_guid : string, (optional) count : number) -> None ``` @@ -658,7 +658,7 @@ Removes a status effect. **Signature:** ``` -remove_status_effect(guid : String) -> None +remove_status_effect(guid : guid) -> None ``` @@ -670,7 +670,7 @@ Sets the stack count of a status effect by guid. **Signature:** ``` -set_status_effect_stacks(guid : String, count : Number) -> None +set_status_effect_stacks(guid : guid, count : number) -> None ``` @@ -691,7 +691,7 @@ Tries to cast a card with a guid and optional target. If the cast isn't successf **Signature:** ``` -cast_card(cardGuid : String, (optional) targetActorGuid : String) -> Bool +cast_card(card_guid : guid, (optional) target_actor_guid : guid) -> boolean ``` @@ -703,7 +703,7 @@ Returns the card type definition. Can take either a guid or a typeId. If it's a **Signature:** ``` -get_card(id : String) -> Table +get_card(id : type_id) -> card ``` @@ -715,7 +715,7 @@ Returns the instance object of a card. **Signature:** ``` -get_card_instance(cardGuid : String) -> Table +get_card_instance(card_guid : guid) -> card_instance ``` @@ -727,7 +727,7 @@ Returns all the card guids from the given actor. **Signature:** ``` -get_cards(actorGuid : String) -> Array +get_cards(actor_guid : string) -> guid[] ``` @@ -739,7 +739,7 @@ Gives a card. **Signature:** ``` -give_card(cardTypeId : String, ownerActorId : String) -> String +give_card(card_type_id : type_id, owner_actor_id : guid) -> string ``` @@ -751,7 +751,7 @@ Removes a card. **Signature:** ``` -remove_card(cardGuid : String) -> None +remove_card(cardGuid : string) -> None ``` @@ -763,7 +763,7 @@ Upgrade a card without paying for it. **Signature:** ``` -upgrade_card(cardGuid : String) -> Bool +upgrade_card(card_guid : guid) -> boolean ``` @@ -775,7 +775,7 @@ Upgrade a random card without paying for it. **Signature:** ``` -upgrade_random_card(actorGuid : String) -> Bool +upgrade_random_card(actor_guid : guid) -> boolean ``` @@ -791,24 +791,24 @@ None ### Functions
deal_damage
-Deal damage to a enemy from one source. If flat is true the damage can't be modified by status effects or artifacts. +Deal damage to a enemy from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns the damage that was dealt. **Signature:** ``` -deal_damage(source : String, target : String, damage : Number, flat : Bool) -> None +deal_damage(source : guid, target : guid, damage : number, (optional) flat : boolean) -> number ```
deal_damage_multi
-Deal damage to multiple enemies from one source. If flat is true the damage can't be modified by status effects or artifacts. +Deal damage to multiple enemies from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns a array of damages for each actor hit. **Signature:** ``` -deal_damage_multi(source : String, targets : Array, damage : Number, flat : Bool) -> None +deal_damage_multi(source : guid, targets : guid[], damage : number, (optional) flat : boolean) -> number[] ```
@@ -820,7 +820,7 @@ Heals the target triggered by the source. **Signature:** ``` -heal(source : String, target : String, amount : Number) -> None +heal(source : guid, target : guid, amount : number) -> None ``` @@ -853,7 +853,7 @@ Gives the player gold. **Signature:** ``` -give_player_gold(amount : Number) -> None +give_player_gold(amount : number) -> None ``` @@ -865,7 +865,7 @@ Let the player buy the artifact with the given id. This will deduct the price fo **Signature:** ``` -player_buy_artifact(artifactId : String) -> Bool +player_buy_artifact(card_id : type_id) -> boolean ``` @@ -877,7 +877,7 @@ Let the player buy the card with the given id. This will deduct the price form t **Signature:** ``` -player_buy_card(cardId : String) -> Bool +player_buy_card(card_id : type_id) -> boolean ``` @@ -889,7 +889,7 @@ Let the player draw additional cards for this turn. **Signature:** ``` -player_draw_card(amount : Number) -> None +player_draw_card(amount : number) -> None ``` @@ -901,7 +901,7 @@ Gives the player more action points for this turn. **Signature:** ``` -player_give_action_points(points : Number) -> None +player_give_action_points(points : number) -> None ``` @@ -946,7 +946,7 @@ Returns the merchant state. **Signature:** ``` -get_merchant() -> Table +get_merchant() -> table ``` @@ -958,7 +958,7 @@ Returns the maximum value of artifacts and cards that the merchant will sell. Go **Signature:** ``` -get_merchant_gold_max() -> Number +get_merchant_gold_max() -> number ``` @@ -979,7 +979,7 @@ Generates a random face. **Signature:** ``` -gen_face((optional) category : Number) -> String +gen_face((optional) category : number) -> string ``` @@ -991,7 +991,7 @@ Returns the type id of a random artifact. **Signature:** ``` -random_artifact(maxPrice : Number) -> String +random_artifact(max_price : number) -> type_id ``` @@ -1003,7 +1003,7 @@ Returns the type id of a random card. **Signature:** ``` -random_card(maxPrice : Number) -> String +random_card(max_price : number) -> type_id ``` @@ -1025,7 +1025,7 @@ l('cards.MY_CARD.name', "English Default Name")`` **Signature:** ``` -l(key : String, (optional) default : String) -> String +l(key : string, (optional) default : string) -> string ``` @@ -1057,7 +1057,7 @@ delete_base_game("story_teller") -- deletes all story tellers **Signature:** ``` -delete_base_game((optional) type : String) -> None +delete_base_game((optional) type : string) -> None ``` @@ -1073,7 +1073,7 @@ delete_card("SOME_CARD") **Signature:** ``` -delete_card(id : String) -> None +delete_card(id : type_id) -> None ``` @@ -1089,7 +1089,7 @@ delete_enemy("SOME_ENEMY") **Signature:** ``` -delete_enemy(id : String) -> None +delete_enemy(id : type_id) -> None ``` @@ -1105,7 +1105,7 @@ delete_event("SOME_EVENT") **Signature:** ``` -delete_event(id : String) -> None +delete_event(id : type_id) -> None ``` @@ -1121,7 +1121,7 @@ delete_status_effect("SOME_STATUS_EFFECT") **Signature:** ``` -delete_status_effect(id : String) -> None +delete_status_effect(id : type_id) -> None ``` @@ -1137,7 +1137,7 @@ delete_story_teller("SOME_STORY_TELLER") **Signature:** ``` -delete_story_teller(id : String) -> None +delete_story_teller(id : type_id) -> None ``` @@ -1168,7 +1168,7 @@ register_artifact("REPULSION_STONE", **Signature:** ``` -register_artifact(id : String, definition : Table) -> None +register_artifact(id : type_id, definition : artifact) -> None ``` @@ -1203,7 +1203,7 @@ register_card("MELEE_HIT", **Signature:** ``` -register_card(id : String, definition : Table) -> None +register_card(id : type_id, definition : card) -> None ``` @@ -1240,7 +1240,7 @@ register_enemy("RUST_MITE", **Signature:** ``` -register_enemy(id : String, definition : Table) -> None +register_enemy(id : type_id, definition : enemy) -> None ``` @@ -1253,7 +1253,7 @@ Registers a new event. register_event("SOME_EVENT", { name = "Event Name", - description = [[Flavor Text... Can include **Markdown** Syntax!]], + description = "Flavor Text... Can include **Markdown** Syntax!", choices = { { description = "Go...", @@ -1288,7 +1288,7 @@ register_event("SOME_EVENT", **Signature:** ``` -register_event(id : String, definition : Table) -> None +register_event(id : type_id, definition : event) -> None ``` @@ -1298,28 +1298,34 @@ register_event(id : String, definition : Table) -> None Registers a new status effect. ```lua -register_artifact("REPULSION_STONE", - { - name = "Repulsion Stone", - description = "For each damage taken heal for 2", - price = 100, - order = 0, - callbacks = { - on_damage = function(ctx) - if ctx.target == ctx.owner then - heal(ctx.owner, 2) - end - return nil - end, - } +register_status_effect("BLOCK", { + name = "Block", + description = "Decreases incoming damage for each stack", + look = "Blk", + foreground = "#219ebc", + state = function(ctx) + return "Takes " .. highlight(ctx.stacks) .. " less damage" + end, + can_stack = true, + decay = DECAY_ALL, + rounds = 1, + order = 100, + callbacks = { + on_damage_calc = function(ctx) + if ctx.target == ctx.owner then + add_status_effect_stacks(ctx.guid, -ctx.damage) + return ctx.damage - ctx.stacks + end + return ctx.damage + end } -) +}) ``` **Signature:** ``` -register_status_effect(id : String, definition : Table) -> None +register_status_effect(id : type_id, definition : status_effect) -> None ``` @@ -1329,28 +1335,39 @@ register_status_effect(id : String, definition : Table) -> None Registers a new story teller. ```lua -register_artifact("REPULSION_STONE", - { - name = "Repulsion Stone", - description = "For each damage taken heal for 2", - price = 100, - order = 0, - callbacks = { - on_damage = function(ctx) - if ctx.target == ctx.owner then - heal(ctx.owner, 2) - end - return nil - end, - } - } +register_story_teller("STORY_TELLER_XYZ", { + active = function(ctx) + if not had_events_any({ "A", "B", "C" }) then + return 1 + end + return 0 + end, + decide = function(ctx) + local stage = get_stages_cleared() + + if stage >= 3 then + set_event("SOME_EVENT") + return GAME_STATE_EVENT + end + + -- Fight against rust mites or clean bots + local d = math.random(2) + if d == 1 then + add_actor_by_enemy("RUST_MITE") + elseif d == 2 then + add_actor_by_enemy("CLEAN_BOT") + end + + return GAME_STATE_FIGHT + end +}) ) ``` **Signature:** ``` -register_story_teller(id : String, definition : Table) -> None +register_story_teller(id : type_id, definition : story_teller) -> None ``` diff --git a/docs/LUA_DOCS.md b/docs/LUA_DOCS.md index 05d53e5..bd93e89 100644 --- a/docs/LUA_DOCS.md +++ b/docs/LUA_DOCS.md @@ -5,6 +5,7 @@ - The [luafun](https://github.com/luafun/luafun) functional library is available by default to provide functions like `map`, `filter`, etc. which are very helpful. Check the [luafun docs](https://luafun.github.io/index.html) for more information. - If you are new to lua: [Learn Lua in 15 Minutes](https://tylerneylon.com/a/learn-lua/) - For usage examples check the game scripts in `./assets/scripts` +- LUA definitions for the API are available in `./assets/scripts/definitions`. If you use Visual Studio Code with this [Lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) extension you should get autocompletion and a lot of type checking out of the box. ## Game API diff --git a/game/lua.go b/game/lua.go index 357ad09..cd318af 100644 --- a/game/lua.go +++ b/game/lua.go @@ -87,19 +87,19 @@ fun = require "fun" d.Category("Utility", "General game constants.", 1) - d.Function("guid", "returns a new random guid.", "String") + d.Function("guid", "returns a new random guid.", "guid") l.SetGlobal("guid", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(NewGuid("LUA"))) return 1 })) - d.Function("store", "Stores a persistent value for this run that will be restored after a save load. Can store any lua basic value or table.", "", "key : String", "value : Any") + d.Function("store", "Stores a persistent value for this run that will be restored after a save load. Can store any lua basic value or table.", "", "key : string", "value : any") l.SetGlobal("store", l.NewFunction(func(state *lua.LState) int { session.Store(state.ToString(1), mapper.ToGoValue(state.Get(2))) return 0 })) - d.Function("fetch", "Fetches a value from the persistent store", "Any", "key : String") + d.Function("fetch", "Fetches a value from the persistent store", "any", "key : string") l.SetGlobal("fetch", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.Fetch(state.ToString(1)))) return 1 @@ -109,31 +109,31 @@ fun = require "fun" d.Category("Styling", "Helper functions for text styling.", 2) - d.Function("text_bold", "Makes the text bold.", "String", "value") + d.Function("text_bold", "Makes the text bold.", "string", "value : any") l.SetGlobal("text_bold", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString("\033[1m" + luhelp2.ToString(state.Get(1), mapper) + "\033[22m")) return 1 })) - d.Function("text_italic", "Makes the text italic.", "String", "value") + d.Function("text_italic", "Makes the text italic.", "string", "value : any") l.SetGlobal("text_italic", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString("\033[3m" + luhelp2.ToString(state.Get(1), mapper) + "\033[23m")) return 1 })) - d.Function("text_underline", "Makes the text underlined.", "String", "value") + d.Function("text_underline", "Makes the text underlined.", "string", "value : any") l.SetGlobal("text_underline", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString("\033[4m" + luhelp2.ToString(state.Get(1), mapper) + "\033[24m")) return 1 })) - d.Function("text_color", "Makes the text foreground colored. Takes hex values like #ff0000.", "String", "color : String", "value") + d.Function("text_color", "Makes the text foreground colored. Takes hex values like #ff0000.", "string", "color : string", "value : any") l.SetGlobal("text_color", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(removeAnsiReset(lipgloss.NewStyle().Foreground(lipgloss.Color(luhelp2.ToString(state.Get(1), mapper))).Render(luhelp2.ToString(state.Get(2), mapper))))) return 1 })) - d.Function("text_bg", "Makes the text background colored. Takes hex values like #ff0000.", "String", "color : String", "value") + d.Function("text_bg", "Makes the text background colored. Takes hex values like #ff0000.", "string", "color : string", "value : any") l.SetGlobal("text_bg", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(removeAnsiReset(lipgloss.NewStyle().Background(lipgloss.Color(luhelp2.ToString(state.Get(1), mapper))).Render(luhelp2.ToString(state.Get(2), mapper))))) return 1 @@ -143,25 +143,25 @@ fun = require "fun" d.Category("Logging", "Various logging functions.", 3) - d.Function("log_i", "Log at **information** level to player log.", "", "value") + d.Function("log_i", "Log at **information** level to player log.", "", "value : any") l.SetGlobal("log_i", l.NewFunction(func(state *lua.LState) int { session.Log(LogTypeInfo, luhelp2.ToString(state.Get(1), mapper)) return 0 })) - d.Function("log_w", "Log at **warning** level to player log.", "", "value") + d.Function("log_w", "Log at **warning** level to player log.", "", "value : any") l.SetGlobal("log_w", l.NewFunction(func(state *lua.LState) int { session.Log(LogTypeWarning, luhelp2.ToString(state.Get(1), mapper)) return 0 })) - d.Function("log_d", "Log at **danger** level to player log.", "", "value") + d.Function("log_d", "Log at **danger** level to player log.", "", "value : any") l.SetGlobal("log_d", l.NewFunction(func(state *lua.LState) int { session.Log(LogTypeDanger, luhelp2.ToString(state.Get(1), mapper)) return 0 })) - d.Function("log_s", "Log at **success** level to player log.", "", "value") + d.Function("log_s", "Log at **success** level to player log.", "", "value : any") l.SetGlobal("log_s", l.NewFunction(func(state *lua.LState) int { session.Log(LogTypeSuccess, luhelp2.ToString(state.Get(1), mapper)) return 0 @@ -199,13 +199,13 @@ fun = require "fun" d.Category("Audio", "Audio helper functions.", 4) - d.Function("play_audio", "Plays a sound effect. If you want to play ``button.mp3`` you call ``play_audio(\"button\")``.", "", "sound : String") + d.Function("play_audio", "Plays a sound effect. If you want to play ``button.mp3`` you call ``play_audio(\"button\")``.", "", "sound : string") l.SetGlobal("play_audio", l.NewFunction(func(state *lua.LState) int { audio.Play(state.ToString(1)) return 0 })) - d.Function("play_music", "Start a song for the background loop. If you want to play ``song.mp3`` you call ``play_music(\"song\")``.", "", "sound : String") + d.Function("play_music", "Start a song for the background loop. If you want to play ``song.mp3`` you call ``play_music(\"song\")``.", "", "sound : string") l.SetGlobal("play_music", l.NewFunction(func(state *lua.LState) int { audio.PlayMusic(state.ToString(1)) return 0 @@ -215,55 +215,55 @@ fun = require "fun" d.Category("Game State", "Functions that modify the general game state.", 5) - d.Function("set_event", "Set event by id.", "", "eventId : String") + d.Function("set_event", "Set event by id.", "", "eventId : string") l.SetGlobal("set_event", l.NewFunction(func(state *lua.LState) int { session.SetEvent(state.ToString(1)) return 0 })) - d.Function("set_game_state", "Set the current game state. See globals.", "", "state : String") + d.Function("set_game_state", "Set the current game state. See globals.", "", "state : string") l.SetGlobal("set_game_state", l.NewFunction(func(state *lua.LState) int { session.SetGameState(GameState(state.ToString(1))) return 0 })) - d.Function("set_fight_description", "Set the current fight description. This will be shown on the top right in the game.", "", "desc : String") + d.Function("set_fight_description", "Set the current fight description. This will be shown on the top right in the game.", "", "desc : string") l.SetGlobal("set_fight_description", l.NewFunction(func(state *lua.LState) int { session.SetFightDescription(state.ToString(1)) return 0 })) - d.Function("get_fight_round", "Gets the fight round.", "Number", "") + d.Function("get_fight_round", "Gets the fight round.", "number", "") l.SetGlobal("get_fight_round", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LNumber(session.GetFightRound())) return 1 })) - d.Function("get_fight_round", "Gets the number of stages cleared.", "Number", "") + d.Function("get_fight_round", "Gets the number of stages cleared.", "number", "") l.SetGlobal("get_stages_cleared", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LNumber(session.GetStagesCleared())) return 1 })) - d.Function("get_fight", "Gets the fight state. This contains the player hand, used, exhausted and round information.", "Table", "") + d.Function("get_fight", "Gets the fight state. This contains the player hand, used, exhausted and round information.", "table", "") l.SetGlobal("get_fight", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetFight())) return 1 })) - d.Function("get_event_history", "Gets the ids of all the encountered events in the order of occurrence.", "Array", "") + d.Function("get_event_history", "Gets the ids of all the encountered events in the order of occurrence.", "string[]", "") l.SetGlobal("get_event_history", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetEventHistory())) return 1 })) - d.Function("had_event", "Checks if the event happened at least once.", "Bool", "eventId : String") + d.Function("had_event", "Checks if the event happened at least once.", "boolean", "event_id : type_id") l.SetGlobal("had_event", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.HadEvent(state.ToString(1)))) return 1 })) - d.Function("had_events", "Checks if all the events happened at least once.", "Bool", "eventIds : Array") + d.Function("had_events", "Checks if all the events happened at least once.", "boolean", "event_ids : type_id[]") l.SetGlobal("had_events", l.NewFunction(func(state *lua.LState) int { var ids []string if err := mapper.Map(state.Get(1).(*lua.LTable), &ids); err != nil { @@ -275,7 +275,7 @@ fun = require "fun" return 1 })) - d.Function("had_events_any", "Checks if any of the events happened at least once.", "Bool", "eventIds : Array") + d.Function("had_events_any", "Checks if any of the events happened at least once.", "boolean", "eventIds : string[]") l.SetGlobal("had_events_any", l.NewFunction(func(state *lua.LState) int { var ids []string if err := mapper.Map(state.Get(1).(*lua.LTable), &ids); err != nil { @@ -291,55 +291,55 @@ fun = require "fun" d.Category("Actor Operations", "Functions that modify or access the actors. Actors are either the player or enemies.", 6) - d.Function("get_player", "Get the player actor. Equivalent to ``get_actor(PLAYER_ID)``", "Table") + d.Function("get_player", "Get the player actor. Equivalent to ``get_actor(PLAYER_ID)``", "actor") l.SetGlobal("get_player", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetPlayer())) return 1 })) - d.Function("get_actor", "Get a actor by guid.", "Table", "guid : String") + d.Function("get_actor", "Get a actor by guid.", "actor", "guid : guid") l.SetGlobal("get_actor", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetActor(state.ToString(1)))) return 1 })) - d.Function("get_opponent_by_index", "Get opponent (actor) by index of a certain actor. ``get_opponent_by_index(PLAYER_ID, 2)`` would return the second alive opponent of the player.", "Table", "guid : String", "index : Number") + d.Function("get_opponent_by_index", "Get opponent (actor) by index of a certain actor. ``get_opponent_by_index(PLAYER_ID, 2)`` would return the second alive opponent of the player.", "actor", "guid : guid", "index : number") l.SetGlobal("get_opponent_by_index", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetOpponentByIndex(state.ToString(1), int(state.ToNumber(2))-1))) return 1 })) - d.Function("get_opponent_count", "Get the number of opponents (actors) of a certain actor. ``get_opponent_count(PLAYER_ID)`` would return 2 if the player had 2 alive enemies.", "Table", "guid : String") + d.Function("get_opponent_count", "Get the number of opponents (actors) of a certain actor. ``get_opponent_count(PLAYER_ID)`` would return 2 if the player had 2 alive enemies.", "number", "guid : guid") l.SetGlobal("get_opponent_count", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LNumber(session.GetOpponentCount(state.ToString(1)))) return 1 })) - d.Function("get_opponent_guids", "Get the guids of opponents (actors) of a certain actor. If the player had 2 enemies, ``get_opponent_guids(PLAYER_ID)`` would return a table with 2 strings containing the guids of these actors.", "Table", "guid : String") + d.Function("get_opponent_guids", "Get the guids of opponents (actors) of a certain actor. If the player had 2 enemies, ``get_opponent_guids(PLAYER_ID)`` would return a table with 2 strings containing the guids of these actors.", "guid[]", "guid : guid") l.SetGlobal("get_opponent_guids", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetOpponentGUIDs(state.ToString(1)))) return 1 })) - d.Function("remove_actor", "Deletes a actor by id.", "", "guid : String") + d.Function("remove_actor", "Deletes a actor by id.", "", "guid : guid") l.SetGlobal("remove_actor", l.NewFunction(func(state *lua.LState) int { session.GetActor(state.ToString(1)) return 0 })) - d.Function("actor_add_max_hp", "Increases the max hp value of a actor by a number. Can be negative value to decrease it.", "", "guid : String", "amount : Number") + d.Function("actor_add_max_hp", "Increases the max hp value of a actor by a number. Can be negative value to decrease it.", "", "guid : guid", "amount : number") l.SetGlobal("actor_add_max_hp", l.NewFunction(func(state *lua.LState) int { session.ActorAddMaxHP(state.ToString(1), int(state.ToNumber(2))) return 0 })) - d.Function("actor_add_hp", "Increases the hp value of a actor by a number. Can be negative value to decrease it. This won't trigger any on_damage callbacks", "", "guid : String", "amount : Number") + d.Function("actor_add_hp", "Increases the hp value of a actor by a number. Can be negative value to decrease it. This won't trigger any on_damage callbacks", "", "guid : guid", "amount : number") l.SetGlobal("actor_add_hp", l.NewFunction(func(state *lua.LState) int { session.ActorAddHP(state.ToString(1), int(state.ToNumber(2))) return 0 })) - d.Function("add_actor_by_enemy", "Creates a new enemy fighting against the player. Example ``add_actor_by_enemy(\"RUST_MITE\")``.", "String", "enemyId : String") + d.Function("add_actor_by_enemy", "Creates a new enemy fighting against the player. Example ``add_actor_by_enemy(\"RUST_MITE\")``.", "string", "enemy_id : type_id") l.SetGlobal("add_actor_by_enemy", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(session.AddActorFromEnemy(state.ToString(1)))) return 1 @@ -349,26 +349,26 @@ fun = require "fun" d.Category("Artifact Operations", "Functions that modify or access the artifacts.", 7) - d.Function("give_artifact", "Gives a actor a artifact. Returns the guid of the newly created artifact.", "String", "typeId : String", "actor : String") + d.Function("give_artifact", "Gives a actor a artifact. Returns the guid of the newly created artifact.", "string", "type_id : type_id", "actor : guid") l.SetGlobal("give_artifact", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(session.GiveArtifact(state.ToString(1), state.ToString(2)))) return 1 })) - d.Function("remove_artifact", "Removes a artifact.", "", "guid : String") + d.Function("remove_artifact", "Removes a artifact.", "", "guid : guid") l.SetGlobal("remove_artifact", l.NewFunction(func(state *lua.LState) int { session.RemoveArtifact(state.ToString(1)) return 0 })) - d.Function("get_artifact", "Returns the artifact definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "Table", "id : String") + d.Function("get_artifact", "Returns the artifact definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "artifact", "id : string") l.SetGlobal("get_artifact", l.NewFunction(func(state *lua.LState) int { art, _ := session.GetArtifact(state.ToString(1)) state.Push(luhelp2.ToLua(state, art)) return 1 })) - d.Function("get_artifact_instance", "Returns the artifact instance by guid.", "", "guid : String") + d.Function("get_artifact_instance", "Returns the artifact instance by guid.", "artifact_instance", "guid : guid") l.SetGlobal("get_artifact_instance", l.NewFunction(func(state *lua.LState) int { _, instance := session.GetArtifact(state.ToString(1)) state.Push(luhelp2.ToLua(state, instance)) @@ -379,7 +379,7 @@ fun = require "fun" d.Category("Status Effect Operations", "Functions that modify or access the status effects.", 8) - d.Function("give_status_effect", "Gives a status effect to a actor. If count is not specified a stack of 1 is applied.", "", "typeId : String", "actorGuid : String", "(optional) count : Number") + d.Function("give_status_effect", "Gives a status effect to a actor. If count is not specified a stack of 1 is applied.", "", "type_id : string", "actor_guid : string", "(optional) count : number") l.SetGlobal("give_status_effect", l.NewFunction(func(state *lua.LState) int { if state.GetTop() == 2 { state.Push(lua.LString(session.GiveStatusEffect(state.ToString(1), state.ToString(2), 1))) @@ -389,37 +389,37 @@ fun = require "fun" return 1 })) - d.Function("remove_status_effect", "Removes a status effect.", "", "guid : String") + d.Function("remove_status_effect", "Removes a status effect.", "", "guid : guid") l.SetGlobal("remove_status_effect", l.NewFunction(func(state *lua.LState) int { session.RemoveStatusEffect(state.ToString(1)) return 0 })) - d.Function("add_status_effect_stacks", "Adds to the stack count of a status effect. Negative values are also allowed.", "", "guid : String", "count : Number") + d.Function("add_status_effect_stacks", "Adds to the stack count of a status effect. Negative values are also allowed.", "", "guid : guid", "count : number") l.SetGlobal("add_status_effect_stacks", l.NewFunction(func(state *lua.LState) int { session.AddStatusEffectStacks(state.ToString(1), int(state.ToNumber(2))) return 0 })) - d.Function("set_status_effect_stacks", "Sets the stack count of a status effect by guid.", "", "guid : String", "count : Number") + d.Function("set_status_effect_stacks", "Sets the stack count of a status effect by guid.", "", "guid : guid", "count : number") l.SetGlobal("set_status_effect_stacks", l.NewFunction(func(state *lua.LState) int { session.SetStatusEffectStacks(state.ToString(1), int(state.ToNumber(2))) return 0 })) - d.Function("get_actor_status_effects", "Returns the guids of all status effects that belong to a actor.", "Array", "actorId : String") + d.Function("get_actor_status_effects", "Returns the guids of all status effects that belong to a actor.", "guid[]", "actorId : string") l.SetGlobal("get_actor_status_effects", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetActorStatusEffects(state.ToString(1)))) return 1 })) - d.Function("get_status_effect", "Returns the status effect definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "Table", "id : String") + d.Function("get_status_effect", "Returns the status effect definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "status_effect", "id : string") l.SetGlobal("get_status_effect", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetStatusEffect(state.ToString(1)))) return 1 })) - d.Function("get_status_effect_instance", "Returns the status effect instance.", "Table", "effectGuid : String") + d.Function("get_status_effect_instance", "Returns the status effect instance.", "status_effect_instance", "effect_guid : guid") l.SetGlobal("get_status_effect_instance", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetStatusEffectInstance(state.ToString(1)))) return 1 @@ -429,51 +429,51 @@ fun = require "fun" d.Category("Card Operations", "Functions that modify or access the cards.", 9) - d.Function("give_card", "Gives a card.", "String", "cardTypeId : String", "ownerActorId : String") + d.Function("give_card", "Gives a card.", "string", "card_type_id : type_id", "owner_actor_id : guid") l.SetGlobal("give_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(session.GiveCard(state.ToString(1), state.ToString(2)))) return 1 })) - d.Function("remove_card", "Removes a card.", "", "cardGuid : String") + d.Function("remove_card", "Removes a card.", "", "cardGuid : string") l.SetGlobal("remove_card", l.NewFunction(func(state *lua.LState) int { session.RemoveCard(state.ToString(1)) return 0 })) - d.Function("cast_card", "Tries to cast a card with a guid and optional target. If the cast isn't successful returns false.", "Bool", "cardGuid : String", "(optional) targetActorGuid : String") + d.Function("cast_card", "Tries to cast a card with a guid and optional target. If the cast isn't successful returns false.", "boolean", "card_guid : guid", "(optional) target_actor_guid : guid") l.SetGlobal("cast_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LBool(session.CastCard(state.ToString(1), state.ToString(2)))) return 1 })) - d.Function("get_cards", "Returns all the card guids from the given actor.", "Array", "actorGuid : String") + d.Function("get_cards", "Returns all the card guids from the given actor.", "guid[]", "actor_guid : string") l.SetGlobal("get_cards", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetCards(state.ToString(1)))) return 1 })) - d.Function("get_card", "Returns the card type definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "Table", "id : String") + d.Function("get_card", "Returns the card type definition. Can take either a guid or a typeId. If it's a guid it will fetch the type behind the instance.", "card", "id : type_id") l.SetGlobal("get_card", l.NewFunction(func(state *lua.LState) int { card, _ := session.GetCard(state.ToString(1)) state.Push(luhelp2.ToLua(state, card)) return 1 })) - d.Function("get_card_instance", "Returns the instance object of a card.", "Table", "cardGuid : String") + d.Function("get_card_instance", "Returns the instance object of a card.", "card_instance", "card_guid : guid") l.SetGlobal("get_card_instance", l.NewFunction(func(state *lua.LState) int { _, instance := session.GetCard(state.ToString(1)) state.Push(luhelp2.ToLua(state, instance)) return 1 })) - d.Function("upgrade_card", "Upgrade a card without paying for it.", "Bool", "cardGuid : String") + d.Function("upgrade_card", "Upgrade a card without paying for it.", "boolean", "card_guid : guid") l.SetGlobal("upgrade_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LBool(session.UpgradeCard(state.ToString(1)))) return 1 })) - d.Function("upgrade_random_card", "Upgrade a random card without paying for it.", "Bool", "actorGuid : String") + d.Function("upgrade_random_card", "Upgrade a random card without paying for it.", "boolean", "actor_guid : guid") l.SetGlobal("upgrade_random_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LBool(session.UpgradeRandomCard(state.ToString(1)))) return 1 @@ -483,7 +483,7 @@ fun = require "fun" d.Category("Damage & Heal", "Functions that deal damage or heal.", 10) - d.Function("deal_damage", "Deal damage to a enemy from one source. If flat is true the damage can't be modified by status effects or artifacts.", "", "source : String", "target : String", "damage : Number", "flat : Bool") + d.Function("deal_damage", "Deal damage to a enemy from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns the damage that was dealt.", "number", "source : guid", "target : guid", "damage : number", "(optional) flat : boolean") l.SetGlobal("deal_damage", l.NewFunction(func(state *lua.LState) int { if state.GetTop() == 3 { state.Push(lua.LNumber(session.DealDamage(state.ToString(1), state.ToString(2), int(state.ToNumber(3)), false))) @@ -493,7 +493,7 @@ fun = require "fun" return 1 })) - d.Function("deal_damage_multi", "Deal damage to multiple enemies from one source. If flat is true the damage can't be modified by status effects or artifacts.", "", "source : String", "targets : Array", "damage : Number", "flat : Bool") + d.Function("deal_damage_multi", "Deal damage to multiple enemies from one source. If flat is true the damage can't be modified by status effects or artifacts. Returns a array of damages for each actor hit.", "number[]", "source : guid", "targets : guid[]", "damage : number", "(optional) flat : boolean") l.SetGlobal("deal_damage_multi", l.NewFunction(func(state *lua.LState) int { var guids []string @@ -520,7 +520,7 @@ fun = require "fun" return 1 })) - d.Function("heal", "Heals the target triggered by the source.", "", "source : String", "target : String", "amount : Number") + d.Function("heal", "Heals the target triggered by the source.", "", "source : guid", "target : guid", "amount : number") l.SetGlobal("heal", l.NewFunction(func(state *lua.LState) int { if state.GetTop() == 3 { state.Push(lua.LNumber(session.Heal(state.ToString(1), state.ToString(2), int(state.ToNumber(3)), false))) @@ -534,31 +534,31 @@ fun = require "fun" d.Category("Player Operations", "Functions that are related to the player.", 11) - d.Function("player_draw_card", "Let the player draw additional cards for this turn.", "", "amount : Number") + d.Function("player_draw_card", "Let the player draw additional cards for this turn.", "", "amount : number") l.SetGlobal("player_draw_card", l.NewFunction(func(state *lua.LState) int { session.PlayerDrawCard(int(state.ToNumber(1))) return 0 })) - d.Function("player_give_action_points", "Gives the player more action points for this turn.", "", "points : Number") + d.Function("player_give_action_points", "Gives the player more action points for this turn.", "", "points : number") l.SetGlobal("player_give_action_points", l.NewFunction(func(state *lua.LState) int { session.PlayerGiveActionPoints(int(state.ToNumber(1))) return 0 })) - d.Function("give_player_gold", "Gives the player gold.", "", "amount : Number") + d.Function("give_player_gold", "Gives the player gold.", "", "amount : number") l.SetGlobal("give_player_gold", l.NewFunction(func(state *lua.LState) int { session.GivePlayerGold(int(state.ToNumber(1))) return 0 })) - d.Function("player_buy_card", "Let the player buy the card with the given id. This will deduct the price form the players gold and return true if the buy was successful.", "Bool", "cardId : String") + d.Function("player_buy_card", "Let the player buy the card with the given id. This will deduct the price form the players gold and return true if the buy was successful.", "boolean", "card_id : type_id") l.SetGlobal("player_buy_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LBool(session.PlayerBuyCard(state.ToString(1)))) return 1 })) - d.Function("player_buy_artifact", "Let the player buy the artifact with the given id. This will deduct the price form the players gold and return true if the buy was successful.", "Bool", "artifactId : String") + d.Function("player_buy_artifact", "Let the player buy the artifact with the given id. This will deduct the price form the players gold and return true if the buy was successful.", "boolean", "card_id : type_id") l.SetGlobal("player_buy_artifact", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LBool(session.PlayerBuyArtifact(state.ToString(1)))) return 1 @@ -574,7 +574,7 @@ fun = require "fun" d.Category("Merchant Operations", "Functions that are related to the merchant.", 12) - d.Function("get_merchant", "Returns the merchant state.", "Table") + d.Function("get_merchant", "Returns the merchant state.", "table") l.SetGlobal("get_merchant", l.NewFunction(func(state *lua.LState) int { state.Push(luhelp2.ToLua(state, session.GetMerchant())) return 1 @@ -592,7 +592,7 @@ fun = require "fun" return 0 })) - d.Function("get_merchant_gold_max", "Returns the maximum value of artifacts and cards that the merchant will sell. Good to scale ``random_card`` and ``random_artifact``.", "Number") + d.Function("get_merchant_gold_max", "Returns the maximum value of artifacts and cards that the merchant will sell. Good to scale ``random_card`` and ``random_artifact``.", "number") l.SetGlobal("get_merchant_gold_max", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LNumber(session.GetMerchantGoldMax())) return 1 @@ -602,7 +602,7 @@ fun = require "fun" d.Category("Random Utility", "Functions that help with random generation.", 13) - d.Function("gen_face", "Generates a random face.", "String", "(optional) category : Number") + d.Function("gen_face", "Generates a random face.", "string", "(optional) category : number") l.SetGlobal("gen_face", l.NewFunction(func(state *lua.LState) int { if state.GetTop() == 1 { state.Push(lua.LString(faces.Global.Gen(int(state.ToNumber(1))))) @@ -612,13 +612,13 @@ fun = require "fun" return 1 })) - d.Function("random_card", "Returns the type id of a random card.", "String", "maxPrice : Number") + d.Function("random_card", "Returns the type id of a random card.", "type_id", "max_price : number") l.SetGlobal("random_card", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(session.GetRandomCard(int(state.ToNumber(1))))) return 1 })) - d.Function("random_artifact", "Returns the type id of a random artifact.", "String", "maxPrice : Number") + d.Function("random_artifact", "Returns the type id of a random artifact.", "type_id", "max_price : number") l.SetGlobal("random_artifact", l.NewFunction(func(state *lua.LState) int { state.Push(lua.LString(session.GetRandomArtifact(int(state.ToNumber(1))))) return 1 @@ -628,7 +628,7 @@ fun = require "fun" d.Category("Localization", "Functions that help with localization.", 14) - d.Function("l", "Returns the localized string for the given key. Examples on locals definition can be found in `/assets/locals`. Example: ``\nl('cards.MY_CARD.name', \"English Default Name\")``", "String", "key : String", "(optional) default : String") + d.Function("l", "Returns the localized string for the given key. Examples on locals definition can be found in `/assets/locals`. Example: ``\nl('cards.MY_CARD.name', \"English Default Name\")``", "string", "key : string", "(optional) default : string") l.SetGlobal("l", l.NewFunction(func(state *lua.LState) int { if state.GetTop() == 1 { state.Push(lua.LString(localization.G(state.ToString(1)))) diff --git a/game/resources.go b/game/resources.go index d99eea4..5cf485c 100644 --- a/game/resources.go +++ b/game/resources.go @@ -68,7 +68,7 @@ func NewResourcesManager(state *lua.LState, docs *ludoc.Docs, logger *log.Logger // Load all local scripts _ = fs.Walk("./assets/scripts", func(path string, isDir bool) error { // Don't load libs - if strings.Contains(path, "scripts/libs") { + if strings.Contains(path, "scripts/libs") || strings.Contains(path, "scripts/definitions") { return nil } @@ -79,6 +79,10 @@ func NewResourcesManager(state *lua.LState, docs *ludoc.Docs, logger *log.Logger panic(err) } + if strings.HasPrefix(string(luaBytes), "---@meta") { + return nil + } + if err := man.luaState.DoString(string(luaBytes)); err != nil { // TODO: error handling panic(err) @@ -313,7 +317,7 @@ func (man *ResourcesManager) defineDocs(docs *ludoc.Docs) { end, } } -)`), "", "id : String", "definition : Table") +)`), "", "id : type_id", "definition : artifact") docs.Function("register_card", fmt.Sprintf("Registers a new card.\n\n```lua\n%s\n```", `register_card("MELEE_HIT", { @@ -334,7 +338,7 @@ func (man *ResourcesManager) defineDocs(docs *ludoc.Docs) { end, } } -)`), "", "id : String", "definition : Table") +)`), "", "id : type_id", "definition : card") docs.Function("register_enemy", fmt.Sprintf("Registers a new enemy.\n\n```lua\n%s\n```", `register_enemy("RUST_MITE", { @@ -357,12 +361,12 @@ func (man *ResourcesManager) defineDocs(docs *ludoc.Docs) { end } } -)`), "", "id : String", "definition : Table") +)`), "", "id : type_id", "definition : enemy") docs.Function("register_event", fmt.Sprintf("Registers a new event.\n\n```lua\n%s\n```", `register_event("SOME_EVENT", { name = "Event Name", - description = [[Flavor Text... Can include **Markdown** Syntax!]], + description = "Flavor Text... Can include **Markdown** Syntax!", choices = { { description = "Go...", @@ -391,47 +395,64 @@ func (man *ResourcesManager) defineDocs(docs *ludoc.Docs) { return GAME_STATE_RANDOM end, } -)`), "", "id : String", "definition : Table") +)`), "", "id : type_id", "definition : event") - docs.Function("register_status_effect", fmt.Sprintf("Registers a new status effect.\n\n```lua\n%s\n```", `register_artifact("REPULSION_STONE", - { - name = "Repulsion Stone", - description = "For each damage taken heal for 2", - price = 100, - order = 0, - callbacks = { - on_damage = function(ctx) - if ctx.target == ctx.owner then - heal(ctx.owner, 2) - end - return nil - end, - } + docs.Function("register_status_effect", fmt.Sprintf("Registers a new status effect.\n\n```lua\n%s\n```", `register_status_effect("BLOCK", { + name = "Block", + description = "Decreases incoming damage for each stack", + look = "Blk", + foreground = "#219ebc", + state = function(ctx) + return "Takes " .. highlight(ctx.stacks) .. " less damage" + end, + can_stack = true, + decay = DECAY_ALL, + rounds = 1, + order = 100, + callbacks = { + on_damage_calc = function(ctx) + if ctx.target == ctx.owner then + add_status_effect_stacks(ctx.guid, -ctx.damage) + return ctx.damage - ctx.stacks + end + return ctx.damage + end } -)`), "", "id : String", "definition : Table") +})`), "", "id : type_id", "definition : status_effect") - docs.Function("register_story_teller", fmt.Sprintf("Registers a new story teller.\n\n```lua\n%s\n```", `register_artifact("REPULSION_STONE", - { - name = "Repulsion Stone", - description = "For each damage taken heal for 2", - price = 100, - order = 0, - callbacks = { - on_damage = function(ctx) - if ctx.target == ctx.owner then - heal(ctx.owner, 2) - end - return nil - end, - } - } -)`), "", "id : String", "definition : Table") + docs.Function("register_story_teller", fmt.Sprintf("Registers a new story teller.\n\n```lua\n%s\n```", `register_story_teller("STORY_TELLER_XYZ", { + active = function(ctx) + if not had_events_any({ "A", "B", "C" }) then + return 1 + end + return 0 + end, + decide = function(ctx) + local stage = get_stages_cleared() - docs.Function("delete_event", fmt.Sprintf("Deletes an event.\n\n```lua\n%s\n```", `delete_event("SOME_EVENT")`), "", "id : String") - docs.Function("delete_card", fmt.Sprintf("Deletes a card.\n\n```lua\n%s\n```", `delete_card("SOME_CARD")`), "", "id : String") - docs.Function("delete_enemy", fmt.Sprintf("Deletes an enemy.\n\n```lua\n%s\n```", `delete_enemy("SOME_ENEMY")`), "", "id : String") - docs.Function("delete_status_effect", fmt.Sprintf("Deletes a status effect.\n\n```lua\n%s\n```", `delete_status_effect("SOME_STATUS_EFFECT")`), "", "id : String") - docs.Function("delete_story_teller", fmt.Sprintf("Deletes a story teller.\n\n```lua\n%s\n```", `delete_story_teller("SOME_STORY_TELLER")`), "", "id : String") + if stage >= 3 then + set_event("SOME_EVENT") + return GAME_STATE_EVENT + end + + -- Fight against rust mites or clean bots + local d = math.random(2) + if d == 1 then + add_actor_by_enemy("RUST_MITE") + elseif d == 2 then + add_actor_by_enemy("CLEAN_BOT") + end + + return GAME_STATE_FIGHT + end +}) +)`), "", "id : type_id", "definition : story_teller") + + docs.Function("delete_event", fmt.Sprintf("Deletes an event.\n\n```lua\n%s\n```", `delete_event("SOME_EVENT")`), "", "id : type_id") + docs.Function("delete_card", fmt.Sprintf("Deletes a card.\n\n```lua\n%s\n```", `delete_card("SOME_CARD")`), "", "id : type_id") + docs.Function("delete_enemy", fmt.Sprintf("Deletes an enemy.\n\n```lua\n%s\n```", `delete_enemy("SOME_ENEMY")`), "", "id : type_id") + docs.Function("delete_status_effect", fmt.Sprintf("Deletes a status effect.\n\n```lua\n%s\n```", `delete_status_effect("SOME_STATUS_EFFECT")`), "", "id : type_id") + docs.Function("delete_story_teller", fmt.Sprintf("Deletes a story teller.\n\n```lua\n%s\n```", `delete_story_teller("SOME_STORY_TELLER")`), "", "id : type_id") docs.Function("delete_base_game", fmt.Sprintf("Deletes all base game content. Useful if you don't want to include base game content in your mod.\n\n```lua\n%s\n```", `delete_base_game() -- delete all base game content delete_base_game("artifact") -- deletes all artifacts @@ -440,5 +461,5 @@ delete_base_game("enemy") -- deletes all enemies delete_base_game("event") -- deletes all events delete_base_game("status_effect") -- deletes all status effects delete_base_game("story_teller") -- deletes all story tellers -`), "", "(optional) type : String") +`), "", "(optional) type : string") } diff --git a/game/session.go b/game/session.go index 856a8fd..ac4800b 100644 --- a/game/session.go +++ b/game/session.go @@ -342,6 +342,10 @@ func (s *Session) loadMods(mods []string) { panic(err) } + if strings.HasPrefix(string(luaBytes), "---@meta") { + return nil + } + if err := s.luaState.DoString(string(luaBytes)); err != nil { s.logLuaError("ModLoader", "", err) } diff --git a/update-docs.sh b/update-docs.sh index efde5fd..410284b 100755 --- a/update-docs.sh +++ b/update-docs.sh @@ -1,3 +1,4 @@ #!/bin/bash -go run ./cmd/docs > ./docs/LUA_API_DOCS.md \ No newline at end of file +go run ./cmd/docs > ./docs/LUA_API_DOCS.md +go run ./cmd/definitions > ./assets/scripts/definitions/api.lua \ No newline at end of file