mirror of
https://github.com/BigJk/end_of_eden.git
synced 2026-02-06 10:48:09 +00:00
feat: correct seeding
This commit is contained in:
parent
98da619522
commit
275460002e
@ -33,7 +33,7 @@ function choose_weighted(choices, weights)
|
||||
total_weight = total_weight + weight
|
||||
end
|
||||
|
||||
local random = math.random() * total_weight
|
||||
local random = random() * total_weight
|
||||
for i, weight in ipairs(weights) do
|
||||
random = random - weight
|
||||
if random <= 0 then
|
||||
@ -83,27 +83,39 @@ end
|
||||
---@param tags string[]
|
||||
---@return artifact[]
|
||||
function find_artifacts_by_tags(tags)
|
||||
return find_by_tags(registered.artifact, tags)
|
||||
local found = find_by_tags(registered.artifact, tags)
|
||||
table.sort(found, function(a, b) return a.id:upper() < b.id:upper() end)
|
||||
return found
|
||||
end
|
||||
|
||||
---find_cards_by_tags find all cards with the given tags.
|
||||
---@param tags string[]
|
||||
---@return card[]
|
||||
function find_cards_by_tags(tags)
|
||||
return find_by_tags(registered.card, tags)
|
||||
local found = find_by_tags(registered.card, tags)
|
||||
table.sort(found, function(a, b) return a.id:upper() < b.id:upper() end)
|
||||
return found
|
||||
end
|
||||
|
||||
---find_events_by_tags find all events with the given tags.
|
||||
---@param tags string[]
|
||||
---@return event[]
|
||||
function find_events_by_tags(tags)
|
||||
return find_by_tags(registered.event, tags)
|
||||
local found = find_by_tags(registered.event, tags)
|
||||
--table.sort(found, function(a, b) return a.id:upper() < b.id:upper() end)
|
||||
return found
|
||||
end
|
||||
|
||||
---choose_weighted_by_price choose a random item from the given list, weighted by price.
|
||||
---@param items artifact|card
|
||||
---@return string
|
||||
function choose_weighted_by_price(items)
|
||||
table.sort(items, function(a, b)
|
||||
if a.id == nil then
|
||||
return a.type_id < b.type_id
|
||||
end
|
||||
return a.id < b.id
|
||||
end)
|
||||
return choose_weighted(
|
||||
fun.iter(items):map(function(item) return item.id or item.type_id end):totable(),
|
||||
fun.iter(items):map(function(item) return item.price end):totable()
|
||||
|
||||
@ -41,6 +41,16 @@ function fetch(key) end
|
||||
---@return guid
|
||||
function guid() end
|
||||
|
||||
--- Returns a random number between 0 and 1
|
||||
---@return number
|
||||
function random() end
|
||||
|
||||
--- Returns a random number between min and max
|
||||
---@param min number
|
||||
---@param max number
|
||||
---@return number
|
||||
function random_int(min, max) 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
|
||||
|
||||
@ -6,7 +6,7 @@ function cast_random(guid, target)
|
||||
if #cards == 0 then
|
||||
print("can't cast_random with zero cards available!")
|
||||
else
|
||||
cast_card(cards[math.random(#cards)], target)
|
||||
cast_card(cards[random_int(0, #cards)], target)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ register_enemy("CYBER_SLIME", {
|
||||
|
||||
add_actor_by_enemy("CYBER_SLIME_MINION")
|
||||
add_actor_by_enemy("CYBER_SLIME_MINION")
|
||||
if math.random() < 0.25 then
|
||||
if random() < 0.25 then
|
||||
add_actor_by_enemy("CYBER_SLIME_MINION")
|
||||
end
|
||||
return nil
|
||||
|
||||
@ -13,10 +13,10 @@ It seems to be eating the metal from the walls. It looks at you and after a few
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("RUST_MITE")
|
||||
if math.random() < 0.25 then
|
||||
if random() < 0.25 then
|
||||
add_actor_by_enemy("RUST_MITE")
|
||||
end
|
||||
if math.random() < 0.15 then
|
||||
if random() < 0.15 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
@ -41,10 +41,10 @@ It looks at you and says "Corpse. Clean. Engage.".
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("CLEAN_BOT")
|
||||
if math.random() < 0.25 then
|
||||
if random() < 0.25 then
|
||||
add_actor_by_enemy("CLEAN_BOT")
|
||||
end
|
||||
if math.random() < 0.15 then
|
||||
if random() < 0.15 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
@ -66,10 +66,10 @@ It seems to be waiting for its prey to come closer and there is no way around it
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("CYBER_SPIDER")
|
||||
if math.random() < 0.25 then
|
||||
if random() < 0.25 then
|
||||
add_actor_by_enemy("CYBER_SPIDER")
|
||||
end
|
||||
if math.random() < 0.15 then
|
||||
if random() < 0.15 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
@ -93,10 +93,10 @@ As you explore the facility, you hear a high-pitched whirring sound. A drone equ
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("LASER_DRONE")
|
||||
if math.random() < 0.10 then
|
||||
if random() < 0.10 then
|
||||
add_actor_by_enemy("LASER_DRONE")
|
||||
end
|
||||
if math.random() < 0.15 then
|
||||
if random() < 0.15 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
@ -120,7 +120,7 @@ As you delve deeper into the facility, you notice a bright glow emanating from a
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("PLASMA_GOLEM")
|
||||
if math.random() < 0.05 then
|
||||
if random() < 0.05 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
@ -144,7 +144,7 @@ As you explore the facility, you come across a strange cybernetic slime. It seem
|
||||
description = "Fight!",
|
||||
callback = function()
|
||||
add_actor_by_enemy("CYBER_SLIME")
|
||||
if math.random() < 0.10 then
|
||||
if random() < 0.10 then
|
||||
add_actor_by_enemy("REPAIR_DRONE")
|
||||
end
|
||||
return GAME_STATE_FIGHT
|
||||
|
||||
@ -183,7 +183,7 @@ You find a room with a strange device in the middle. It seems to be some kind of
|
||||
:filter(function(card)
|
||||
return card.does_consume
|
||||
end):totable()
|
||||
if math.random() < 0.5 then
|
||||
if random() < 0.5 then
|
||||
local choosen = choose_weighted_by_price(possible_artifacts)
|
||||
if choosen then
|
||||
give_artifact(choosen, PLAYER_ID)
|
||||
@ -232,7 +232,7 @@ You find a old automatic workstation. You are able to get it working again. You
|
||||
return nil
|
||||
end
|
||||
|
||||
local choosen = cards[math.random(#cards)]
|
||||
local choosen = cards[random_int(0, #cards)]
|
||||
upgrade_card(choosen)
|
||||
deal_damage(PLAYER_ID, PLAYER_ID, 2, true)
|
||||
|
||||
|
||||
@ -262,11 +262,11 @@ end
|
||||
exports.ones = ones
|
||||
|
||||
local rands_gen = function(param_x, _state_x)
|
||||
return 0, math.random(param_x[1], param_x[2])
|
||||
return 0, random_int(param_x[1], param_x[2])
|
||||
end
|
||||
|
||||
local rands_nil_gen = function(_param_x, _state_x)
|
||||
return 0, math.random()
|
||||
return 0, random()
|
||||
end
|
||||
|
||||
local rands = function(n, m)
|
||||
|
||||
@ -30,13 +30,17 @@ register_story_teller("_ACT_0", {
|
||||
if #possible == 0 then
|
||||
possible = find_events_by_tags({ "_ACT_0_FIGHT" })
|
||||
end
|
||||
set_event(possible[math.random(#possible)].id)
|
||||
|
||||
local choosen = possible[random_int(0, #possible)]
|
||||
if choosen ~= nil then
|
||||
set_event(choosen.id)
|
||||
end
|
||||
|
||||
-- if we cleared a stage, give the player a random artifact
|
||||
local last_stage_count = fetch("last_stage_count")
|
||||
local current_stage_count = get_stages_cleared()
|
||||
if last_stage_count ~= current_stage_count then
|
||||
local gets_random_artifact = math.random() < 0.25
|
||||
local gets_random_artifact = random() < 0.25
|
||||
|
||||
if gets_random_artifact then
|
||||
local player_artifacts = fun.iter(get_actor(PLAYER_ID).artifacts):map(function(id)
|
||||
|
||||
@ -78,6 +78,8 @@ func initSystems(hasAudio bool) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Setenv("EOE_IMG_TRUECOLOR", "1")
|
||||
|
||||
testArgs := testargs.New()
|
||||
flag.Parse()
|
||||
|
||||
|
||||
@ -65,10 +65,10 @@ Content that is dynamically generated at runtime is not included in this documen
|
||||
```mermaid
|
||||
pie
|
||||
title Action Points
|
||||
"3 AP" : 2
|
||||
"0 AP" : 12
|
||||
"2 AP" : 1
|
||||
"1 AP" : 6
|
||||
"3 AP" : 2
|
||||
```
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ title Card Types
|
||||
| ID | Name | Description | Initial HP | Max HP | Color | Used Callbacks | Test Present |
|
||||
|------------------------|-----------------------|-------------------------------------------------------------------|------------|--------|---------|------------------------------|-----------------|
|
||||
| ``CYBER_SPIDER`` | CYBER Spider | It waits for its prey to come closer | 8 | 8 | #ff4d6d | ``OnTurn`` | :no_entry_sign: |
|
||||
| ``CLEAN_BOT`` | Cleaning Bot | It never stopped cleaning... | 13 | 13 | #32a891 | ``OnTurn``, ``OnPlayerTurn`` | :no_entry_sign: |
|
||||
| ``CLEAN_BOT`` | Cleaning Bot | It never stopped cleaning... | 13 | 13 | #32a891 | ``OnPlayerTurn``, ``OnTurn`` | :no_entry_sign: |
|
||||
| ``CYBER_SLIME`` | Cyber Slime | A cybernetic slime that splits into smaller slimes when defeated. | 10 | 10 | #00ff00 | ``OnTurn``, ``OnActorDie`` | :no_entry_sign: |
|
||||
| ``CYBER_SLIME_MINION`` | Cyber Slime Offspring | A smaller version of the Cyber Slime. | 4 | 4 | #00ff00 | ``OnTurn`` | :no_entry_sign: |
|
||||
| ``DUMMY`` | Dummy | End me... | 100 | 100 | #deeb6a | ``OnTurn`` | :no_entry_sign: |
|
||||
@ -122,21 +122,21 @@ title Card Types
|
||||
| ID | Name | Description | Tags | Choices | Test Present |
|
||||
|------------------------------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-----------------|
|
||||
| ``GAIN_GOLD_ACT_0`` | | ... - | _ACT_0 | <ul><li>``Take it! [Gain 20 Gold]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``PLASMA_GOLEM`` | A glowing figure emerges... | As you delve deeper into the facility, you notice a bright glow emanating from a nearby chamber. A massive golem made of pure plasma energy steps into view. - **It looks ready to unleash its power!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``LASER_DRONE`` | A menacing drone appears... | As you explore the facility, you hear a high-pitched whirring sound. A drone equipped with a powerful laser cannon appears in front of you. - **It looks ready to attack!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``CYBER_SLIME`` | A strange cybernetic slime appears... | As you explore the facility, you come across a strange cybernetic slime. It seems to be pulsating with energy and looks hostile. - **Prepare for a fight!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``PLASMA_GOLEM`` | A glowing figure emerges... | !!plasma_golem.jpg - As you delve deeper into the facility, you notice a bright glow emanating from a nearby chamber. A massive golem made of pure plasma energy steps into view. - **It looks ready to unleash its power!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``LASER_DRONE`` | A menacing drone appears... | !!laser_drone.jpg - As you explore the facility, you hear a high-pitched whirring sound. A drone equipped with a powerful laser cannon appears in front of you. - **It looks ready to attack!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``CYBER_SLIME`` | A strange cybernetic slime appears... | !!cyber_slime.jpg - As you explore the facility, you come across a strange cybernetic slime. It seems to be pulsating with energy and looks hostile. - **Prepare for a fight!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``MERCHANT`` | A strange figure | !!merchant.jpg - - The merchant is a tall, lanky figure draped in a long, tattered coat made of plant fibers and animal hides. Their face is hidden behind a mask made of twisted roots and vines, giving them an unsettling, almost alien appearance. - Despite their strange appearance, the merchant is a shrewd negotiator and a skilled trader. They carry with them a collection of bizarre and exotic items, including plant-based weapons, animal pelts, and strange, glowing artifacts that seem to pulse with an otherworldly energy. - The merchant is always looking for a good deal, and they're not above haggling with potential customers... | _ACT_0, _ACT_1, _ACT_2, _ACT_3 | <ul><li>``Trade``</li> <li>``Pass``</li></ul> | :no_entry_sign: |
|
||||
| ``CLEAN_BOT`` | Corpse. Clean. Engage. | !!clean_bot.jpg - While exploring the facility you hear a strange noise. Suddenly a strange robot appears from one of the corridors. - It seems to be cleaning up the area, but it's not working properly anymore and you can see small sparks coming out of it. - It looks at you and says "Corpse. Clean. Engage.". - **You're not sure what it means, but it doesn't seem to be friendly!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``GAMBLE_1_ACT_0`` | Electro Barrier | You find a room with a strange device in the middle. It seems to be some kind of electro barrier protecting a storage container. You can either try to disable the barrier or leave. - | _ACT_0 | <ul><li>``50% [Gain Artifact & Consumeable] 50% [Take 5 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``GAMBLE_1_ACT_0`` | Electro Barrier | !!electro_barrier.jpg - You find a room with a strange device in the middle. It seems to be some kind of electro barrier protecting a storage container. You can either try to disable the barrier or leave. - | _ACT_0 | <ul><li>``50% [Gain Artifact & Consumeable] 50% [Take 2 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``CROWBAR`` | Found: Crowbar | !!red_room.jpg - **You found something!** A crowbar. It's a bit rusty, but it should still be useful! - **Important:** If you already carry a artifact in your hand, you will have to drop it and related cards to pick up the new one. | _ACT_0 | <ul><li>````</li> <li>``Leave...``</li></ul> | :no_entry_sign: |
|
||||
| ``HAR_II`` | Found: HAR-II | !!artifact_chest.jpg - **You found something!** A HAR-II. A heavy assault rifle with a high rate of fire. - **Important:** If you already carry a artifact in your hand, you will have to drop it and related cards to pick up the new one. | _ACT_1 | <ul><li>````</li> <li>``Leave...``</li></ul> | :no_entry_sign: |
|
||||
| ``LZR_PISTOL`` | Found: LZR Pistol | !!artifact_chest.jpg - **You found something!** A LZR pistol. Fires a concentrated beam of light. - **Important:** If you already carry a artifact in your hand, you will have to drop it and related cards to pick up the new one. | _ACT_1 | <ul><li>````</li> <li>``Leave...``</li></ul> | :no_entry_sign: |
|
||||
| ``VIBRO_KNIFE`` | Found: VIBRO Knife | !!artifact_chest.jpg - **You found something!** A VIBRO knife. Uses ultrasonic vibrations to cut through almost anything. - **Important:** If you already carry a artifact in your hand, you will have to drop it and related cards to pick up the new one. | _ACT_0 | <ul><li>````</li> <li>``Leave...``</li></ul> | :no_entry_sign: |
|
||||
| ``GOLD_TO_HP_ACT_0`` | Old Vending Machine | You find an old vending machine, it seems to be still working. You can either pay 20 Gold to get 5 HP or leave. - | _ACT_0 | <ul><li>``Pay [20 Gold] [Gain 5 HP]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``RANDOM_ARTIFACT_ACT_0`` | Random Artifact | !!artifact_chest.jpg - You found a chest with a strange symbol on it. The chest is protected by a strange barrier. You can either open it and take some damage or leave. - | _ACT_0 | <ul><li>``Random Artifact [Gain 1 Artifact] [Take 5 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``RANDOM_ARTIFACT_ACT_0`` | Random Artifact | !!artifact_chest.jpg - You found a chest with a strange symbol on it. The chest is protected by a strange barrier. You can either open it and take some damage or leave. - | _ACT_0 | <ul><li>``Random Artifact [Gain 1 Artifact] [Take 2 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``RANDOM_CONSUMEABLE_ACT_0`` | Random Consumeable | !!artifact_chest.jpg - You found a chest with a strange symbol on it. The chest is protected by a strange barrier. You can either open it and take some damage or leave. - | _ACT_0 | <ul><li>``Random Artifact [Gain 1 Consumeable] [Take 2 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``MAX_LIFE_ACT_0`` | Symbiotic Parasite | You find a strange creature, it seems to be a symbiotic parasite. It offers to increase your max HP by 5. You can either accept or leave. - | _ACT_0 | <ul><li>``Accept it! [Gain 5 Max HP]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``MAX_LIFE_ACT_0`` | Symbiotic Parasite | !!symbiotic_parasite.jpg - You find a strange creature, it seems to be a symbiotic parasite. It offers to increase your max HP by 5. You can either accept or leave. - | _ACT_0 | <ul><li>``Accept it! [Gain 5 Max HP]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``RUST_MITE`` | Tasty metals... | !!rust_mite.jpg - You are walking through the facility hoping to find a way out. After a few turns you hear a strange noise. You look around and come across a strange being. - It seems to be eating the metal from the walls. It looks at you and after a few seconds it rushes towards you. - **It seems to be hostile!** - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
| ``UPRAGDE_CARD_ACT_0`` | Upgrade Station | You find a old automatic workstation. You are able to get it working again. You can either upgrade a random card or leave. - | _ACT_0 | <ul><li>``Upgrade a card [Upgrade a card] [Take 5 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``UPRAGDE_CARD_ACT_0`` | Upgrade Station | !!upgrade_station.jpg - You find a old automatic workstation. You are able to get it working again. You can either upgrade a random card or leave. - | _ACT_0 | <ul><li>``Upgrade a card [Upgrade a card] [Take 2 damage]``</li> <li>``Leave!``</li></ul> | :no_entry_sign: |
|
||||
| ``START`` | Waking up... | !!cryo_start.jpg - You wake up in a dimly lit room, the faint glow of a red emergency light casting an eerie hue over the surroundings. The air is musty and stale, the metallic scent of the cryo-chamber still lingering in your nostrils. You feel groggy and disoriented, your mind struggling to process what's happening. - As you try to sit up, you notice that your body is stiff and unresponsive. It takes a few moments for your muscles to warm up and regain their strength. Looking around, you see that the walls are made of a dull gray metal, covered in scratches and scuff marks. There's a faint humming sound coming from somewhere, indicating that the facility is still operational. - You try to remember how you ended up here, but your memories are hazy and fragmented. The last thing you recall is a blinding flash of light and a deafening boom. You must have been caught in one of the nuclear explosions that devastated the world. - As you struggle to gather your bearings, you notice a blinking panel on the wall, with the words *"Cryo Sleep Malfunction"* displayed in bold letters. It seems that the system has finally detected the error that caused your prolonged slumber and triggered your awakening. - **Shortly after you realize that you are not alone...** | | <ul><li>``Try to find a weapon. [Find melee weapon] [Take 4 damage]``</li> <li>``Gather your strength and attack it!``</li></ul> | :no_entry_sign: |
|
||||
| ``CYBER_SPIDER`` | What is this thing at the ceiling? | !!cyber_spider.jpg - You come around a corner and see a strange creature hanging from the ceiling. It looks like a spider, but it's made out of metal. - It seems to be waiting for its prey to come closer and there is no way around it. - | _ACT_0_FIGHT | <ul><li>``Fight!``</li></ul> | :no_entry_sign: |
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# End Of Eden Lua Docs
|
||||
|
||||
## Index
|
||||
|
||||
- [Game Constants](#game-constants)
|
||||
@ -23,6 +24,7 @@
|
||||
General game constants.
|
||||
|
||||
### Globals
|
||||
|
||||
<details> <summary><b><code>DECAY_ALL</code></b> </summary> <br/>
|
||||
|
||||
Status effect decays by all stacks per turn.
|
||||
@ -67,7 +69,7 @@ Represents the random game state in which the active story teller will decide wh
|
||||
|
||||
<details> <summary><b><code>PLAYER_ID</code></b> </summary> <br/>
|
||||
|
||||
Player actor id for use in functions where the guid is needed, for example: ``deal_damage(PLAYER_ID, enemy_guid, 10)``.
|
||||
Player actor id for use in functions where the guid is needed, for example: `deal_damage(PLAYER_ID, enemy_guid, 10)`.
|
||||
|
||||
</details>
|
||||
|
||||
@ -84,6 +86,7 @@ General game constants.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>fetch</code></b> </summary> <br/>
|
||||
|
||||
Fetches a value from the persistent store
|
||||
@ -108,6 +111,30 @@ guid() -> guid
|
||||
|
||||
</details>
|
||||
|
||||
<details> <summary><b><code>random</code></b> </summary> <br/>
|
||||
|
||||
Returns a random number between 0 and 1
|
||||
|
||||
**Signature:**
|
||||
|
||||
```
|
||||
random() -> number
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details> <summary><b><code>random_int</code></b> </summary> <br/>
|
||||
|
||||
Returns a random number between min and max
|
||||
|
||||
**Signature:**
|
||||
|
||||
```
|
||||
random_int(min : number, max : number) -> number
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details> <summary><b><code>store</code></b> </summary> <br/>
|
||||
|
||||
Stores a persistent value for this run that will be restored after a save load. Can store any lua basic value or table.
|
||||
@ -129,6 +156,7 @@ Helper functions for text styling.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>text_bg</code></b> </summary> <br/>
|
||||
|
||||
Makes the text background colored. Takes hex values like #ff0000.
|
||||
@ -186,6 +214,7 @@ Various logging functions.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>log_d</code></b> </summary> <br/>
|
||||
|
||||
Log at **danger** level to player log.
|
||||
@ -255,9 +284,10 @@ Audio helper functions.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>play_audio</code></b> </summary> <br/>
|
||||
|
||||
Plays a sound effect. If you want to play ``button.mp3`` you call ``play_audio("button")``.
|
||||
Plays a sound effect. If you want to play `button.mp3` you call `play_audio("button")`.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -269,7 +299,7 @@ play_audio(sound : string) -> None
|
||||
|
||||
<details> <summary><b><code>play_music</code></b> </summary> <br/>
|
||||
|
||||
Start a song for the background loop. If you want to play ``song.mp3`` you call ``play_music("song")``.
|
||||
Start a song for the background loop. If you want to play `song.mp3` you call `play_music("song")`.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -288,6 +318,7 @@ Functions that modify the general game state.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>get_action_points_per_round</code></b> </summary> <br/>
|
||||
|
||||
get the number of action points per round.
|
||||
@ -441,6 +472,7 @@ Functions that modify or access the actors. Actors are either the player or enem
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>actor_add_hp</code></b> </summary> <br/>
|
||||
|
||||
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
|
||||
@ -491,7 +523,7 @@ actor_set_max_hp(guid : guid, amount : number) -> None
|
||||
|
||||
<details> <summary><b><code>add_actor_by_enemy</code></b> </summary> <br/>
|
||||
|
||||
Creates a new enemy fighting against the player. Example ``add_actor_by_enemy("RUST_MITE")``.
|
||||
Creates a new enemy fighting against the player. Example `add_actor_by_enemy("RUST_MITE")`.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -515,7 +547,7 @@ get_actor(guid : guid) -> actor
|
||||
|
||||
<details> <summary><b><code>get_opponent_by_index</code></b> </summary> <br/>
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -527,7 +559,7 @@ get_opponent_by_index(guid : guid, index : number) -> actor
|
||||
|
||||
<details> <summary><b><code>get_opponent_count</code></b> </summary> <br/>
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -539,7 +571,7 @@ get_opponent_count(guid : guid) -> number
|
||||
|
||||
<details> <summary><b><code>get_opponent_guids</code></b> </summary> <br/>
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -551,7 +583,7 @@ get_opponent_guids(guid : guid) -> guid[]
|
||||
|
||||
<details> <summary><b><code>get_player</code></b> </summary> <br/>
|
||||
|
||||
Get the player actor. Equivalent to ``get_actor(PLAYER_ID)``
|
||||
Get the player actor. Equivalent to `get_actor(PLAYER_ID)`
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -582,6 +614,7 @@ Functions that modify or access the artifacts.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>get_artifact</code></b> </summary> <br/>
|
||||
|
||||
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.
|
||||
@ -651,6 +684,7 @@ Functions that modify or access the status effects.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>add_status_effect_stacks</code></b> </summary> <br/>
|
||||
|
||||
Adds to the stack count of a status effect. Negative values are also allowed.
|
||||
@ -744,6 +778,7 @@ Functions that modify or access the cards.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>cast_card</code></b> </summary> <br/>
|
||||
|
||||
Tries to cast a card with a guid and optional target. If the cast isn't successful returns false.
|
||||
@ -849,6 +884,7 @@ Functions that deal damage or heal.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>deal_damage</code></b> </summary> <br/>
|
||||
|
||||
Deal damage from one source to a target. If flat is true the damage can't be modified by status effects or artifacts. Returns the damage that was dealt.
|
||||
@ -918,6 +954,7 @@ Functions that are related to the player.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>finish_player_turn</code></b> </summary> <br/>
|
||||
|
||||
Finishes the player turn.
|
||||
@ -999,6 +1036,7 @@ Functions that are related to the merchant.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>add_merchant_artifact</code></b> </summary> <br/>
|
||||
|
||||
Adds another random artifact to the merchant
|
||||
@ -1037,7 +1075,7 @@ get_merchant() -> merchant_state
|
||||
|
||||
<details> <summary><b><code>get_merchant_gold_max</code></b> </summary> <br/>
|
||||
|
||||
Returns the maximum value of artifacts and cards that the merchant will sell. Good to scale ``random_card`` and ``random_artifact``.
|
||||
Returns the maximum value of artifacts and cards that the merchant will sell. Good to scale `random_card` and `random_artifact`.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -1056,6 +1094,7 @@ Functions that help with random generation.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>gen_face</code></b> </summary> <br/>
|
||||
|
||||
Generates a random face.
|
||||
@ -1101,10 +1140,11 @@ Functions that help with localization.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>l</code></b> </summary> <br/>
|
||||
|
||||
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")``
|
||||
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")`
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -1123,6 +1163,7 @@ These functions are used to define new content in the base game and in mods.
|
||||
None
|
||||
|
||||
### Functions
|
||||
|
||||
<details> <summary><b><code>delete_base_game</code></b> </summary> <br/>
|
||||
|
||||
Deletes all base game content. Useful if you don't want to include base game content in your mod.
|
||||
@ -1435,7 +1476,7 @@ register_story_teller("STORY_TELLER_XYZ", {
|
||||
end
|
||||
|
||||
-- Fight against rust mites or clean bots
|
||||
local d = math.random(2)
|
||||
local d = random_int(0, 2)
|
||||
if d == 1 then
|
||||
add_actor_by_enemy("RUST_MITE")
|
||||
elseif d == 2 then
|
||||
@ -1454,4 +1495,3 @@ register_story_teller(id : type_id, definition : story_teller) -> None
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
14
game/lua.go
14
game/lua.go
@ -88,6 +88,20 @@ fun = require "fun"
|
||||
|
||||
d.Category("Utility", "General game constants.", 1)
|
||||
|
||||
d.Function("random", "Returns a random number between 0 and 1. Prefer this function over math.random(), as this is seeded for the session.", "number")
|
||||
l.SetGlobal("random", l.NewFunction(func(state *lua.LState) int {
|
||||
state.Push(lua.LNumber(session.rand.Float64()))
|
||||
return 1
|
||||
}))
|
||||
|
||||
d.Function("random_int", "Returns a random number between min and max. Prefer this function over math.random(), as this is seeded for the session.", "number", "min : number", "max : number")
|
||||
l.SetGlobal("random_int", l.NewFunction(func(state *lua.LState) int {
|
||||
min := state.ToInt(1)
|
||||
max := state.ToInt(2)
|
||||
state.Push(lua.LNumber(session.rand.IntN(max-min) + min))
|
||||
return 1
|
||||
}))
|
||||
|
||||
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")))
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package game
|
||||
|
||||
import "encoding/gob"
|
||||
import (
|
||||
"encoding/gob"
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(SavedState{})
|
||||
@ -10,6 +13,8 @@ func init() {
|
||||
// runtime or other pointer.
|
||||
type SavedState struct {
|
||||
State GameState
|
||||
Seed uint64
|
||||
Rand *rand.PCG
|
||||
Actors map[string]Actor
|
||||
Instances map[string]any
|
||||
StagesCleared int
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"math/rand/v2"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
@ -102,6 +102,9 @@ type Session struct {
|
||||
log *log.Logger
|
||||
luaState *lua.LState
|
||||
luaDocs *ludoc.Docs
|
||||
seed uint64
|
||||
randSrc *rand.PCG
|
||||
rand *rand.Rand
|
||||
resources *ResourcesManager
|
||||
|
||||
state GameState
|
||||
@ -128,8 +131,13 @@ type Session struct {
|
||||
|
||||
// NewSession creates a new game session.
|
||||
func NewSession(options ...func(s *Session)) *Session {
|
||||
seed := uint64(time.Now().UnixMilli())
|
||||
randSrc := rand.NewPCG(seed, 1337)
|
||||
session := &Session{
|
||||
log: log.New(io.Discard, "", 0),
|
||||
seed: seed,
|
||||
randSrc: randSrc,
|
||||
rand: rand.New(randSrc),
|
||||
state: GameStateEvent,
|
||||
actors: map[string]Actor{
|
||||
PlayerActorID: NewActor(PlayerActorID),
|
||||
@ -163,10 +171,13 @@ func NewSession(options ...func(s *Session)) *Session {
|
||||
|
||||
session.log.Println("Session started!")
|
||||
|
||||
session.log.Println("Seed:", session.seed)
|
||||
session.Log(LogTypeSuccess, fmt.Sprintf("Seed: %d", seed))
|
||||
|
||||
session.UpdatePlayer(func(actor *Actor) bool {
|
||||
actor.HP = 80
|
||||
actor.MaxHP = 80
|
||||
actor.Gold = 50 + rand.Intn(50)
|
||||
actor.HP = 100
|
||||
actor.MaxHP = 100
|
||||
actor.Gold = 0
|
||||
return true
|
||||
})
|
||||
|
||||
@ -201,6 +212,26 @@ func WithMods(mods []string) func(s *Session) {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSeed sets the seed for the random number generator.
|
||||
func WithSeed(seed uint64) func(s *Session) {
|
||||
return func(s *Session) {
|
||||
s.seed = seed
|
||||
s.randSrc.Seed(seed, 1337)
|
||||
}
|
||||
}
|
||||
|
||||
// WithSeedString sets the seed for the random number generator based on a string.
|
||||
func WithSeedString(seed string) func(s *Session) {
|
||||
return func(s *Session) {
|
||||
generatedSeed := uint64(0)
|
||||
for i, c := range seed {
|
||||
generatedSeed += uint64(c) + uint64(i)
|
||||
}
|
||||
s.seed = generatedSeed
|
||||
s.randSrc.Seed(generatedSeed, 1337)
|
||||
}
|
||||
}
|
||||
|
||||
// WithOnLuaError sets the function that will be called when a lua error happens.
|
||||
func WithOnLuaError(fn func(file string, line int, callback string, typeId string, err error)) func(s *Session) {
|
||||
return func(s *Session) {
|
||||
@ -242,6 +273,8 @@ func (s *Session) LuaErrors() chan LuaError {
|
||||
func (s *Session) ToSavedState() SavedState {
|
||||
return SavedState{
|
||||
State: s.state,
|
||||
Seed: s.seed,
|
||||
Rand: s.randSrc,
|
||||
Actors: s.actors,
|
||||
Instances: s.instances,
|
||||
StagesCleared: s.stagesCleared,
|
||||
@ -261,6 +294,8 @@ func (s *Session) ToSavedState() SavedState {
|
||||
// should be loaded or the state could be corrupted.
|
||||
func (s *Session) LoadSavedState(save SavedState) {
|
||||
s.state = save.State
|
||||
s.seed = save.Seed
|
||||
s.randSrc = save.Rand
|
||||
s.actors = lo.MapValues(save.Actors, func(item Actor, key string) Actor {
|
||||
return item.Sanitize()
|
||||
})
|
||||
|
||||
4
go.mod
4
go.mod
@ -1,8 +1,6 @@
|
||||
module github.com/BigJk/end_of_eden
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.6
|
||||
go 1.23.0
|
||||
|
||||
replace github.com/containerd/console => github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ func buildOption(options ...Option) (Options, []imeji.Option) {
|
||||
data.tag += os.Getenv("EOE_IMG_PATTERN")
|
||||
}
|
||||
|
||||
if runtime.GOOS == "js" {
|
||||
if runtime.GOOS == "js" || os.Getenv("EOE_IMG_TRUECOLOR") == "1" {
|
||||
imejiOptions = append(imejiOptions, imeji.WithTrueColor())
|
||||
data.tag += "truecolor"
|
||||
} else {
|
||||
|
||||
@ -18,6 +18,7 @@ const (
|
||||
ChoiceWaiting = Choice("WAITING")
|
||||
ChoiceContinue = Choice("CONTINUE")
|
||||
ChoiceNewGame = Choice("NEW_GAME")
|
||||
ChoiceNewGameSOD = Choice("NEW_GAME_SOD")
|
||||
ChoiceAbout = Choice("ABOUT")
|
||||
ChoiceSettings = Choice("SETTINGS")
|
||||
ChoiceMods = Choice("MODS")
|
||||
@ -45,6 +46,7 @@ func NewChoicesModel(zones *zone.Manager, hideSettings bool) ChoicesModel {
|
||||
choices := []list.Item{
|
||||
choiceItem{zones, "Continue", "Ready to continue dying?", ChoiceContinue},
|
||||
choiceItem{zones, "New Game", "Start a new try.", ChoiceNewGame},
|
||||
choiceItem{zones, "New Game: Seed of the Day", "Start a new try with the daily seed.", ChoiceNewGameSOD},
|
||||
choiceItem{zones, "About", "Want to know more?", ChoiceAbout},
|
||||
choiceItem{zones, "Settings", "Other settings won't let you survive...", ChoiceSettings},
|
||||
choiceItem{zones, "Mods", "Make the game even more fun!", ChoiceMods},
|
||||
|
||||
@ -2,6 +2,11 @@ package mainmenu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/BigJk/end_of_eden/game"
|
||||
"github.com/BigJk/end_of_eden/internal/fs"
|
||||
"github.com/BigJk/end_of_eden/system/audio"
|
||||
@ -20,10 +25,6 @@ import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
zone "github.com/lrstanley/bubblezone"
|
||||
"github.com/samber/lo"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
@ -119,6 +120,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
case ChoiceNewGameSOD:
|
||||
fallthrough
|
||||
case ChoiceNewGame:
|
||||
audio.Play("btn_menu")
|
||||
|
||||
@ -133,12 +136,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return fmt.Sprintf("./mods/%s/images/", item)
|
||||
})...)
|
||||
|
||||
isSOD := m.choices.selected == ChoiceNewGameSOD
|
||||
m.choices = m.choices.Clear()
|
||||
return m, tea.Sequence(
|
||||
cmd,
|
||||
root.Push(gameview.New(m, m.zones, game.NewSession(
|
||||
game.WithLogging(log.New(f, "SESSION ", log.Ldate|log.Ltime|log.Lshortfile)),
|
||||
game.WithMods(m.settings.GetStrings("mods")),
|
||||
lo.Ternary(isSOD, game.WithSeedString(time.Now().Format(time.DateOnly)), nil),
|
||||
lo.Ternary(os.Getenv("EOE_DEBUG") == "1", game.WithDebugEnabled(8272), nil),
|
||||
))),
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user