├── hexroll3
├── src
│ └── main.rs
└── Cargo.toml
├── .gitignore
├── hexroll3-testbed
├── assets
│ ├── icon.png
│ └── screenshot.png
├── src
│ ├── app
│ │ ├── helpers
│ │ │ ├── mod.rs
│ │ │ ├── router.rs
│ │ │ ├── logger.rs
│ │ │ └── config.rs
│ │ └── views
│ │ │ ├── mod.rs
│ │ │ ├── raw_html.rs
│ │ │ ├── rendered_json.rs
│ │ │ ├── center_panel_selectors.rs
│ │ │ ├── open_or_roll.rs
│ │ │ ├── raw_json.rs
│ │ │ ├── preview.rs
│ │ │ └── top_app_bar.rs
│ └── main.rs
└── Cargo.toml
├── hexroll3-scroll
├── tests
│ ├── utils.rs
│ └── renderer.rs
├── src
│ └── lib.rs
└── Cargo.toml
├── Cargo.toml
├── hexroll3-scroll-data
├── utils
│ ├── index.scroll
│ └── sigils.scroll
├── names
│ ├── base.scroll
│ ├── jibrish.scroll
│ ├── regions.scroll
│ ├── dungeons.scroll
│ └── taverns.scroll
├── dungeons
│ ├── fountain.scroll
│ ├── encounters
│ │ ├── dragons.scroll
│ │ ├── caves.scroll
│ │ ├── humanoids.scroll
│ │ ├── undead.scroll
│ │ ├── vermins.scroll
│ │ ├── ooze.scroll
│ │ ├── temples.scroll
│ │ ├── aberrations.scroll
│ │ └── magical.scroll
│ ├── appearance.scroll
│ ├── portal.scroll
│ ├── tomb.scroll
│ ├── fungi.scroll
│ ├── pools.scroll
│ ├── cave.scroll
│ ├── temple.scroll
│ ├── remains.scroll
│ ├── mouth.scroll
│ └── debris.scroll
├── wilderness
│ ├── base.scroll
│ ├── desert.scroll
│ ├── swamps.scroll
│ ├── plains.scroll
│ ├── forest.scroll
│ ├── tundra.scroll
│ ├── jungle.scroll
│ └── mountains.scroll
├── settlements
│ ├── folk.scroll
│ ├── castle.scroll
│ ├── dwelling.scroll
│ ├── village.scroll
│ ├── base.scroll
│ └── town.scroll
├── hooks
│ ├── quests
│ │ ├── escort.scroll
│ │ └── delivery.scroll
│ ├── rumor.scroll
│ ├── artifacts.scroll
│ ├── relation.scroll
│ └── quest.scroll
├── realms
│ ├── name.scroll
│ └── base.scroll
├── monsters
│ ├── base.scroll
│ └── activities.scroll
├── npc
│ ├── state.scroll
│ └── gender.scroll
├── factions
│ ├── militia.scroll
│ ├── syndicate.scroll
│ └── cult.scroll
└── osr
│ └── npc_allocs.scroll
└── README.md
/hexroll3/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {}
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Cargo.lock
2 | debug
3 | target
4 | **/*.rs.bk
5 | *.pdb
6 |
--------------------------------------------------------------------------------
/hexroll3-testbed/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hexroll/hexroll3/HEAD/hexroll3-testbed/assets/icon.png
--------------------------------------------------------------------------------
/hexroll3-testbed/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hexroll/hexroll3/HEAD/hexroll3-testbed/assets/screenshot.png
--------------------------------------------------------------------------------
/hexroll3-scroll/tests/utils.rs:
--------------------------------------------------------------------------------
1 | pub fn create_tempfile() -> tempfile::NamedTempFile {
2 | if cfg!(target_os = "wasi") {
3 | tempfile::NamedTempFile::new_in("/").unwrap()
4 | } else {
5 | tempfile::NamedTempFile::new().unwrap()
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hexroll3-scroll/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate pest_derive;
3 |
4 | pub mod commands;
5 | pub mod frame;
6 | pub mod generators;
7 | pub mod instance;
8 | pub mod parser;
9 | pub mod renderer;
10 | pub mod renderer_env;
11 | pub mod repository;
12 | pub mod semantics;
13 |
--------------------------------------------------------------------------------
/hexroll3/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "hexroll3"
3 | version = "0.1.1"
4 | authors = ["Pen, Dice & Paper"]
5 | description = "HEXROLL3 - the OSR sandbox generator"
6 | license-file = "../LICENSE"
7 | repository = "https://github.com/hexroll/hexroll3"
8 | homepage = "https://hexroll.app"
9 | readme = "../README.md"
10 | edition = "2021"
11 |
12 | [dependencies]
13 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 | [workspace]
26 | members = [ "hexroll3",
27 | "hexroll3",
28 | "hexroll3-scroll",
29 | "hexroll3-testbed"
30 | ]
31 | resolver = "2"
32 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/helpers/mod.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | pub mod actions;
26 | pub mod config;
27 | pub mod html;
28 | pub mod logger;
29 | pub mod router;
30 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/utils/index.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | IndexedEntity {
27 | Anchor = ""
28 | }
29 |
30 | TocEntry {
31 | Title! = none
32 | Type! = none
33 | UUID! = none
34 | Class! = none
35 | }
36 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/names/base.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Name {
27 | NameGender :: STRING # one of "NameFemale", "NameMale" or "NameFluid"
28 | First! :: STRING
29 | Last! :: STRING
30 | Full! :: STRING
31 | }
32 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/mod.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | pub mod center_panel_selectors;
26 | pub mod open_or_roll;
27 | pub mod preview;
28 | pub mod raw_html;
29 | pub mod raw_json;
30 | pub mod rendered_json;
31 | pub mod top_app_bar;
32 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/fountain.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonFountain {
27 | Title = fountain
28 | Liquid @ [
29 | * clear water are
30 | * dark liquid is
31 | ]
32 | Outlet @ [
33 | * a hole in the wall
34 | * a stone statue of a fish
35 | ]
36 | Description! = <%
37 | {{capitalize(Liquid)}} coming out of {{Outlet}} here
38 | %>
39 | }
40 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/base.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Feature { ^ [
27 | *(x9) Bridge
28 | *(x9) Watchtower
29 | *(x9) DeadAdventurers
30 | *(x9) Wagons
31 | *(x9) AbandonedVillage
32 | *(x9) Altar
33 | *(x9) SacrificialSite
34 | *(x9) SignalingTower
35 | *(x9) DeadMonster
36 | *(x6) Graveyard
37 | *(x3) Arena
38 | *(x5) CaravanCamp
39 | *(x1) Artifact
40 | *(x1) Portal
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/main.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | mod app;
26 |
27 | #[cfg(not(target_arch = "wasm32"))]
28 | fn main() {
29 | use app::HexrollTestbedApp;
30 |
31 | let _ = eframe::run_native(
32 | "HEXROLL3-Testbed",
33 | eframe::NativeOptions::default(),
34 | Box::new(|cc| {
35 | egui_extras::install_image_loaders(&cc.egui_ctx);
36 | Ok(Box::::default())
37 | }),
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/raw_html.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::Ui;
26 |
27 | use crate::app::HexrollTestbedApp;
28 |
29 | impl HexrollTestbedApp {
30 | pub fn raw_html_panel(&mut self, ui: &mut Ui) {
31 | egui::ScrollArea::vertical().show(ui, |ui| {
32 | ui.set_width(ui.available_width());
33 | ui.horizontal_top(|ui| {
34 | ui.label(&self.current_entity.html_source);
35 | })
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/dragons.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterDragonsTier3(DungeonEncounterMagical) {
27 | Monster! @ MonstersDragonsTier3
28 | | DungeonEncounterMagical
29 | Rumor @ DungeonMonsterRumor {
30 | DungeonMonster = &Monster
31 | }
32 | }
33 |
34 | DungeonEncounterDragonsTier4(DungeonEncounterMagical) {
35 | Monster! @ MonstersDragonsTier4
36 | | DungeonEncounterMagical
37 | Rumor @ DungeonMonsterRumor {
38 | DungeonMonster = &Monster
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/folk.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Folk(Character) {
27 | | Character
28 | PersonalQuest! @ Quest
29 | OwnerTitle! = ""
30 | ShopTitle! = ""
31 | ServiceTitle = ""
32 | Profession! = none
33 | $IndexRef @ IndexedEntity {
34 | Render = "Name"
35 | Details = "The {{OwnerTitle | lower}} from {{capitalize(SettlementName)}}"
36 | Anchor = &uuid
37 | Link = &HostingEntity
38 | Type = "location"
39 | Full = ""
40 | Search = "{{Full}}"
41 | Icon = "user"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/rendered_json.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::Ui;
26 | use egui_json_tree::{DefaultExpand, JsonTree};
27 |
28 | use crate::app::HexrollTestbedApp;
29 |
30 | impl HexrollTestbedApp {
31 | pub fn rendered_json_panel(&mut self, ui: &mut Ui) {
32 | ui.set_width(ui.available_width());
33 | egui::ScrollArea::vertical().show(ui, |ui| {
34 | ui.set_width(ui.available_width());
35 | JsonTree::new("rendered_json_panel", &self.current_entity.json_rendered)
36 | .default_expand(DefaultExpand::All)
37 | .show(ui);
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/quests/escort.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | EscortQuest {
27 | Destination % Hex
28 |
29 | Frequency @ [
30 | * Once a season
31 | * Twice a season
32 | * Twice a year
33 | ]
34 |
35 | ShopOwner = :Shop.Owner
36 | QuestMission = :Shop.HexQuestMission
37 |
38 | Description! ~ <%
39 | {{Frequency}}, {{ShopOwner.Name.First}} will want to {{QuestMission}} in
40 | {{Destination.Region}} (hex {{hex_coords(Destination.uuid)}})
41 | and will look for someone to protect {{ShopOwner.Gender.PronounObject}} throughout the
42 | journey.
43 | %>
44 |
45 | Reward @ [
46 | * 500
47 | * 600
48 | * 700
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/caves.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterCaveSpecific (DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! @ [
29 | * It is impossible to hear anything inside
30 | * You hear echoing droplets of water
31 | ]
32 |
33 | Hint! @ [
34 | * You feel as if you're being watched
35 | * A strange sensation is creeping up your spine
36 | * Something here makes the hair at the back of the neck stand
37 | ]
38 | }
39 |
40 | DungeonEncounterCaveSpecificTier1 (DungeonEncounterCaveSpecific) {
41 | Monster! @ MonsterCavernsTier1
42 | | DungeonEncounterCaveSpecific
43 | }
44 |
45 | DungeonEncounterCaveSpecificTier2 (DungeonEncounterCaveSpecific) {
46 | Monster! @ MonsterCavernsTier2
47 | | DungeonEncounterCaveSpecific
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/humanoids.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterHumanoids(DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! ~ <%
29 | When listening from outside,
30 | {%if Monster.NumberAppearingRoaming > 1%}speaking {{Monster.Title}}s
31 | {%else%}footsteps{%endif%}
32 | can be faintly heard from inside this area
33 | %>
34 | Hint! @ [
35 | * There’s movement inside
36 | * You see glowing eyes staring at you from inside
37 | * A violent shout in an unknown language is coming from inside
38 | * You see the shimmer of a blade inside
39 | ]
40 | }
41 |
42 | DungeonEncounterHumanoidsTier1(DungeonEncounterHumanoids) {
43 | Monster! @ MonstersHumanoidTier1
44 | | DungeonEncounterHumanoids
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/castle.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Castle {
27 | Used = false
28 | RealmType = false
29 | RulerTitle ~ <%
30 | {% if RealmType %}{{RealmType.Ruler.Title}} {{RealmType.Ruler.NPC.Name.Full}}{% endif %}
31 | %>
32 | SettlementName = *Settlement.NamePart
33 | SettlementUUID = :Settlement.uuid
34 | SettlementClass! = :Settlement.class
35 | Type @ [
36 | * citadel
37 | * castle
38 | * palace
39 | ]
40 | Title! ~ <%
41 | {{Type}} in {{capitalize(SettlementName)}}
42 | %>
43 |
44 | Desc! ~ <%
45 | {% if Used %}
46 | The {{Type}}
47 | The {{Type}} is the formal residence of {{RulerTitle}}.
48 | {% endif %}
49 | %>
50 | }
51 |
52 |
53 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/realms/name.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | RealmName {
27 |
28 | Prefix @ [
29 | * Ca
30 | * Al
31 | * El
32 | * Va
33 | * Vo
34 | * Ne
35 | * Jo
36 | ]
37 |
38 | Infix @ [
39 | *
40 | * saf
41 | * dar
42 | * der
43 | * nar
44 | * sil
45 | * v
46 | * r
47 | ]
48 |
49 | Suffix @ [
50 | * a
51 | * ia
52 | * ana
53 | * iana
54 | * 'il
55 | ]
56 |
57 | Prefix2 @ [
58 | * A
59 | * E
60 | * O
61 | * I
62 | * U
63 | ]
64 |
65 | Infix2 @ [
66 | * ra
67 | * ze
68 | * re
69 | * sha
70 | ]
71 |
72 | Suffix2 @ [
73 | * zar
74 | * zor
75 | * bar
76 | * bor
77 | * nar
78 | * nor
79 | * dar
80 | * dor
81 | ]
82 |
83 | Name @ [
84 | * {{Prefix}}{{Infix}}{{Suffix}}
85 | * {{Prefix2}}{{Infix2}}{{Suffix2}}
86 | ]
87 |
88 | Title! ` "{{Name}}"
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/monsters/base.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | TreasureType {
27 | Empty! :: BOOL
28 | Details! :: STRING
29 | }
30 |
31 | Monster {
32 | RandomEncountersNumberAppearingFactor = 3
33 | Title! :: STRING
34 | NumberAppearingRoaming! :: DICE
35 | NumberAppearingLair! :: DICE
36 | Sound! :: STRING
37 | Activity! :: TYPE(MonsterActivity)
38 | Intelligent! :: BOOL
39 | Stats! :: STRING
40 | Alignment! :: STRING
41 | HitDice! :: INTEGER
42 | HitDiceRoll! :: STRING
43 | TreasureType! :: TYPE(TreasureType)
44 | TitlePluralizedByRoaming! ~ <%{{plural(NumberAppearingRoaming | int,Title)}}%>
45 | TitlePluralizedByLair! ~ <%
46 | {{plural(round(NumberAppearingLair / RandomEncountersNumberAppearingFactor,0.0),Title)}}
47 | {%if round(NumberAppearingLair / RandomEncountersNumberAppearingFactor,0.0) > 1%}
48 | ({{round(NumberAppearingLair / RandomEncountersNumberAppearingFactor,0.0) | int }}){%else%}{%endif%}
49 | %>
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/center_panel_selectors.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::Ui;
26 |
27 | use crate::app::CenterViewMode;
28 | use crate::app::HexrollTestbedApp;
29 |
30 | impl HexrollTestbedApp {
31 | pub fn center_panel_selectors(&mut self, ui: &mut Ui) {
32 | ui.selectable_value(
33 | &mut self.center_view_mode,
34 | CenterViewMode::Preview,
35 | "Preview",
36 | )
37 | .on_hover_cursor(egui::CursorIcon::Default);
38 | ui.selectable_value(
39 | &mut self.center_view_mode,
40 | CenterViewMode::RawHtml,
41 | "Raw HTML",
42 | )
43 | .on_hover_cursor(egui::CursorIcon::Default);
44 | ui.selectable_value(
45 | &mut self.center_view_mode,
46 | CenterViewMode::RenderedJson,
47 | "Rendered JSON",
48 | )
49 | .on_hover_cursor(egui::CursorIcon::Default);
50 | ui.label(&self.current_url);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/names/jibrish.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | JibrishWord {
27 | Part1 @ [
28 | * ga
29 | * ba
30 | * ka
31 | * za
32 | ]
33 | Part2 @ [
34 | * ru
35 | * du
36 | * vu
37 | * mu
38 | ]
39 | Part3 @ [
40 | * xa
41 | * sa
42 | * ja
43 | ]
44 | Part4 @ [
45 | * un
46 | * il
47 | * wa
48 | * ju
49 | ]
50 | Part5 @ [
51 | * ri
52 | * xi
53 | * bi
54 | * ni
55 | ]
56 | Part6 @ [
57 | * ge
58 | * me
59 | * te
60 | * ye
61 | ]
62 | Part7 @ [
63 | * ko
64 | * po
65 | * ao
66 | ]
67 | Text @ [
68 | * !jinja "{{Part1}}{{Part2}}{{Part3}}"
69 | * !jinja "{{Part2}}{{Part1}}{{Part3}}"
70 | * !jinja "{{Part3}}{{Part2}}{{Part1}}"
71 | * !jinja "{{Part1}}{{Part2}}{{Part3}} {{Part4}} {{Part5}}{{Part6}}{{Part7}}"
72 | * !jinja "{{Part2}}{{Part1}}{{Part3}} {{Part4}} {{Part6}}{{Part7}}{{Part5}}"
73 | * !jinja "{{Part3}}{{Part2}}{{Part1}} {{Part4}} {{Part7}}{{Part5}}{{Part6}}"
74 | ]
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/undead.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterUndead(DungeonEncounter) {
27 | Monster! @@ [
28 | * MonsterUndeadTier1
29 | * MonsterUndeadTier2
30 | ]
31 | | DungeonEncounter
32 | Foreshadow! ~ < It is impossible to hear anything inside >
33 |
34 | Hint! @ [
35 | * You feel the chill of death curling up your spine
36 | * Other than that, there's a silence of death in here
37 | * Looking down, you realize you just stepped into a pool of blood
38 | * A strange sensation is creeping up your spine
39 | * Something here makes the hair at the back of the neck stand
40 | ]
41 | }
42 |
43 | DungeonEncounterUndeadTier3(DungeonEncounterUndead) {
44 | Monster! @ MonsterUndeadTier3
45 | | DungeonEncounterUndead
46 | Rumor @ DungeonMonsterRumor {
47 | DungeonMonster = &Monster
48 | }
49 | }
50 |
51 | DungeonEncounterUndeadTier4(DungeonEncounterUndead) {
52 | Monster! @ MonsterUndeadTier4
53 | | DungeonEncounterUndead
54 | Rumor @ DungeonMonsterRumor {
55 | DungeonMonster = &Monster
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/hexroll3-testbed/Cargo.toml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 | [package]
26 | name = "hexroll3-testbed"
27 | version = "0.1.1"
28 | authors = ["Pen, Dice & Paper"]
29 | description = "HEXROLL3 Testbed - an egui testbed app for HEXROLL3"
30 | license-file = "../LICENSE"
31 | repository = "https://github.com/hexroll/hexroll3"
32 | homepage = "https://hexroll.app"
33 | readme = "../README.md"
34 | edition = "2021"
35 | default-run = "hexroll3-testbed"
36 |
37 | [dependencies]
38 | anyhow = "1.0.82"
39 | chrono = "0.4.39"
40 | console_error_panic_hook = "0.1.7"
41 | dirs = "5.0.1"
42 | eframe = "0.29.1"
43 | egui = {version = "0.29.1", default-features = false}
44 | egui-file-dialog = "0.7.0"
45 | egui_extras = { version = "0.29.1", features = ["all_loaders"] }
46 | egui_json_tree = "0.8.0"
47 | hexroll3-scroll = { path = "../hexroll3-scroll" }
48 | html5ever = "0.29.0"
49 | image = { version = "0.25", features = ["jpeg", "png"] }
50 | log = "0.4.22"
51 | path-tree = "0.8.1"
52 | serde = "1.0.216"
53 | serde_json = "1.0.133"
54 | wasm-bindgen = "0.2.99"
55 | web-sys = { version = "0.3.76", features = ["Window", "Document", "HtmlElement", "Text"] }
56 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HEXROLL 3
2 |
3 | This is the new work-in-progress version of HEXROLL (https://hexroll.app) - the OSR sandbox generator.
4 |
5 | ## Currently Included
6 |
7 | - hexroll3-scroll: the core content generator
8 | - hexroll3-scroll-data: the new data model, based on the hexroll2e model
9 | - hexroll3-testbed: an egui application for testing and messing around
10 | - hexroll3: placeholder for the full app
11 |
12 | You can look at each part to see how it all works.
13 |
14 | ## Running the testbed
15 |
16 | Make sure you have `git` and an up-to-date Rust development environment, and then:
17 |
18 | ```
19 | git clone https://github.com/hexroll/hexroll3 && cd hexroll3
20 | cargo run --release
21 | ```
22 |
23 | This should open up the testbed where you can generate your first sandbox:
24 |
25 | 
26 |
27 | ## License
28 |
29 | ```text
30 | Copyright (C) 2020-2025 Pen, Dice & Paper
31 |
32 | This program is dual-licensed under the following terms:
33 |
34 | Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
35 | This program is free software: you can redistribute it and/or modify
36 | it under the terms of the GNU Affero General Public License as
37 | published by the Free Software Foundation, either version 3 of the
38 | License, or (at your option) any later version.
39 |
40 | This program is distributed in the hope that it will be useful,
41 | but WITHOUT ANY WARRANTY; without even the implied warranty of
42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 | GNU Affero General Public License for more details.
44 |
45 | You should have received a copy of the GNU Affero General Public License
46 | along with this program. If not, see .
47 |
48 | Option 2: Commercial License
49 | For commercial use, you are required to obtain a separate commercial
50 | license. Please contact ithai at pendicepaper.com
51 | for more information about commercial licensing terms.
52 |
53 | HEXROLL3 contains Open Game Content, subject to the Open Game License,
54 | released under the Open Game License, Version 1.0a (enclosed in the LICENSE
55 | file), as described in Section 1(d) of the License.
56 | ```
57 |
--------------------------------------------------------------------------------
/hexroll3-scroll/Cargo.toml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 | [package]
26 | name = "hexroll3-scroll"
27 | version = "0.1.1"
28 | authors = ["Pen, Dice & Paper"]
29 | description = "HEXROLL3 Scroll - the sandbox content generator"
30 | license-file = "../LICENSE"
31 | repository = "https://github.com/hexroll/hexroll3"
32 | homepage = "https://hexroll.app"
33 | readme = "../README.md"
34 | edition = "2021"
35 |
36 | [features]
37 | zstd = ["dep:zstd"]
38 |
39 | [dependencies]
40 | anyhow = "1.0.82"
41 | caith = "4.2.3"
42 | ciborium = "0.2.2"
43 | getrandom = { version = "0.2", features = ["js"] }
44 | indexmap = {version="2.2.6",features=["serde"]}
45 | log = "0.4.22"
46 | minijinja = {version="2.3.0" , features=["builtins"]}
47 | moka = {version="0.12.8",features=["sync"]}
48 | pest = "2.7"
49 | pest_derive = "2.7"
50 | rand = {version="0.8.5", features=["std_rng"]}
51 | rand_chacha = "0.3.1"
52 | redb = "2.3.0"
53 | serde = {version="1.0.197",features = ["derive"]}
54 | serde_json = { version="1.0.133",features = ["preserve_order"]}
55 | zstd = {version = "0.13.2", optional= true}
56 |
57 | [lib]
58 | path = "src/lib.rs"
59 |
60 | [dev-dependencies]
61 | tempfile = "3.10.1"
62 |
63 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/vermins.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterVermins(DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! ~ <%
29 | A successful listening roll could detect the sounds that the
30 | {{Monster.TitlePluralizedByRoaming}} {%if
31 | Monster.NumberAppearingRoaming>1%}are{%else%}is{%endif%} making inside this
32 | area %>
33 | Hint! @ [
34 | * There’s movement inside
35 | * There’s also a foul smell of decay and rot
36 | * Looking down, you see countless fragments of small animal skeletons
37 | * Flies swarm off bones covered with rotting flesh on the ground
38 | ]
39 | }
40 |
41 | DungeonEncounterVerminsTier1(DungeonEncounterVermins) {
42 | Monster! @ MonstersVerminTier1
43 | | DungeonEncounterVermins
44 | }
45 |
46 | DungeonEncounterVerminsTier2(DungeonEncounterVermins) {
47 | Monster! @ MonstersVerminTier2
48 | | DungeonEncounterVermins
49 | }
50 |
51 | DungeonEncounterVerminsTier3(DungeonEncounterVermins) {
52 | Monster! @ MonstersVerminTier3
53 | | DungeonEncounterVermins
54 | Rumor @ DungeonMonsterRumor {
55 | DungeonMonster = &Monster
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/ooze.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterOozes(DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! ~ <%
29 | There's a good chance players could sense the vile stench that the
30 | {{Monster.TitlePluralizedByRoaming}} {%if
31 | Monster.NumberAppearingRoaming>1%}are{%else%}is{%endif%} emitting from
32 | inside this area
33 | %>
34 | Hint! @ [
35 | * There’s a strong burning sensation when breathing the air here
36 | * There’s also a very strong acidic stench here, making breathing almost
37 | unbearable
38 | * There are bones on the ground, clean bones.. almost bleach-white
39 | * A strange sensation is creeping up your spine
40 | ]
41 | }
42 |
43 | DungeonEncounterOozesTier1(DungeonEncounterOozes) {
44 | Monster! @ MonstersOozeTier1
45 | | DungeonEncounterOozes
46 | }
47 |
48 | DungeonEncounterOozesTier2(DungeonEncounterOozes) {
49 | Monster! @ MonstersOozeTier2
50 | | DungeonEncounterOozes
51 | }
52 |
53 | DungeonEncounterOozesTier3(DungeonEncounterOozes) {
54 | Monster! @ MonstersOozeTier3
55 | | DungeonEncounterOozes
56 | Rumor @ DungeonMonsterRumor {
57 | DungeonMonster = &Monster
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/appearance.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | AreaAppearance {
27 | Cover @ [
28 | * splatters of dark matter
29 | * claw marks
30 | * burn marks
31 | * scorch marks
32 | * cracks
33 | * fractures
34 | * spots of green rot
35 | * spots of yellow ooze
36 | ]
37 |
38 | State @ [
39 | * deeply fractured
40 | * scorched with burn marks
41 | * carved with claw marks
42 | ]
43 |
44 | Recency @ [
45 | * old
46 | * fresh
47 | ]
48 |
49 | Quantity @ [
50 | * a few
51 | * some
52 | * several
53 | ]
54 | Description! @ [
55 | * there are {{Quantity}} {{Cover}} on the {{Part}}
56 | * the {{Part}} {{if_plural_else(Part,"have","has")}} {{Quantity}} {{Cover}} on
57 | * the {{Part}} {{if_plural_else(Part,"are","is")}} covered with {{Cover}}
58 | * the {{Part}} {{if_plural_else(Part,"are","is")}} {{State}}
59 | ]
60 | }
61 |
62 | DungeonAreaAppearance (AreaAppearance) {
63 | Part @ [
64 | * walls
65 | * ground
66 | * ceiling
67 | ]
68 | | AreaAppearance
69 | }
70 |
71 |
72 | CaveAreaAppearance (AreaAppearance) {
73 | Part @ [
74 | * stalagmites
75 | * stalactites
76 | * ground
77 | * canopy
78 | ]
79 | | AreaAppearance
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/rumor.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Rumor {
27 | Details! = ""
28 | }
29 |
30 | LocalRumor(Rumor) {
31 | }
32 |
33 | RealmRumor(Rumor) {
34 | }
35 |
36 | HexRumor(Rumor) {
37 |
38 | }
39 |
40 | RumorsTable {
41 |
42 | [2..5 rumors] ? LocalRumor
43 | [6..6 rumors2] ? RealmRumor
44 | [6..6 rumors3] ? HexRumor
45 |
46 | table! ~ <%
47 |
48 | | d6 | Rumor |
49 | {%set counter=namespace(value=0)%}
50 | {%for r in rumors%}
51 | {% if trim(r.Details) != "" %}
52 | {%set counter.value=counter.value+1%}
53 | | {{counter.value}} | {{begin_spoiler()}}{{r.Details}}{{end_spoiler()}} |
54 | {% endif %}
55 | {%endfor%}
56 | {%for r in range(6-counter.value)%}
57 | {% if rumors2[r] %}
58 | {%set counter.value=counter.value+1%}
59 | | {{counter.value}} | {{begin_spoiler()}}{{rumors2[r].Details}}{{end_spoiler()}} |
60 | {% endif %}
61 | {%endfor%}
62 | {%for r in range(6-counter.value)%}
63 | {%set counter.value=counter.value+1%}
64 | | {{counter.value}} | {{begin_spoiler()}}{{rumors3[r].Details}}{{end_spoiler()}} |
65 | {%endfor%}
66 |
67 | %>
68 | }
69 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/temples.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterCultistsClasses {
27 | ^ [
28 | * MonsterCultistsTier1
29 | ]
30 | }
31 |
32 | DungeonEncounterCultists(DungeonEncounter) {
33 | Foreshadow! ~ <%
34 | If listening to one of the doors here is successful, the faint voices
35 | of chanting by cultists could be heard
36 | %>
37 |
38 | Hint! @ [
39 | * There are cultists inside
40 | * There are cloaked and hooded humans inside
41 | * There are humans wearing red robes inside
42 | * There are humans wearing dark robes inside
43 | ]
44 | Monster! @ DungeonEncounterCultistsClasses
45 | | DungeonEncounter
46 | }
47 |
48 | DungeonEncounterTempleAnimalsClasses {
49 | ^ [
50 | * MonsterTempleAnimalsTier1
51 | ]
52 | }
53 |
54 | DungeonEncounterTempleAnimals(DungeonEncounter) {
55 | Monster! @ DungeonEncounterTempleAnimalsClasses
56 | Foreshadow! ~ <%
57 | A successful listening roll could detect the sounds that the
58 | {{Monster.TitlePluralizedByRoaming}} {%if
59 | Monster.NumberAppearingRoaming>1%}are{%else%}is{%endif%} making inside this
60 | area
61 | %>
62 | Hint! @ [
63 | * There’s some sort of a beast inside
64 | ]
65 |
66 | | DungeonEncounter
67 | }
68 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/helpers/router.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use path_tree::PathTree;
26 |
27 | use crate::app::{HexrollTestbedApp, RouteHandler};
28 |
29 | impl HexrollTestbedApp {
30 | pub fn routes(tree: &mut PathTree) {
31 | let _ = tree.insert(
32 | "/inspect/:sandbox/:location/:id",
33 | Box::new(|s, args| {
34 | s.navigate(args["id"].as_str(), true);
35 | }),
36 | );
37 | let _ = tree.insert(
38 | "/inspect/:sandbox/location/:id/npc/:npc_id",
39 | Box::new(|s, args| {
40 | s.navigate(args["id"].as_str(), true);
41 | }),
42 | );
43 | let _ = tree.insert(
44 | "/reroll/:id",
45 | Box::new(|s, args| {
46 | s.reroll(args["id"].as_str());
47 | }),
48 | );
49 | let _ = tree.insert(
50 | "/unroll/:id",
51 | Box::new(|s, args| {
52 | s.unroll(args["id"].as_str());
53 | }),
54 | );
55 | let _ = tree.insert(
56 | "/append/:parent_id/:attr/:cls",
57 | Box::new(|s, args| {
58 | s.append(args["parent_id"].as_str(), args["attr"].as_str());
59 | }),
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/portal.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonPortalDestination {
27 | AreaUUID! = none
28 | Portal = none
29 | Origin = none
30 | OriginUUID = none
31 | RoomNumber = :AreaDescription.RoomNumber
32 | Location! = <{{RoomNumber}}>
33 | Active! = false
34 | }
35 |
36 | DungeonPortal {
37 | Title =
38 | Portal @ [
39 | * painting of a door on the wall
40 | * stained old full-size mirror on the wall
41 | * stone-carved demon face on the wall with a large gaping mouth
42 | ]
43 | Destination ? DungeonPortalDestination {
44 | Portal = &Portal
45 | Origin = &Origin
46 | OriginUUID = &OriginUUID
47 | Active = <%
48 | {{capitalize(articlize(Portal))}} is a magical portal.
49 | Anyone stepping into the portal will be magically teleported into
50 | area {{Origin}}
51 | %>
52 | }
53 | Description! = <%
54 | {{capitalize(articlize(Portal))}} is a magical portal.
55 | Anyone stepping into the portal will be magically teleported
56 | into area {{Destination.Location}}
57 | %>
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/tomb.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | TombFeatureTier1 {
27 | ^ [
28 | *(x3) DungeonEncounterVerminsTier1
29 | *(x2) DungeonEncounterHumanoidsTier1
30 | * DungeonTreasureTier1
31 | * DungeonRemains
32 | * DungeonFungi
33 | * DungeonPool
34 | ]
35 | }
36 |
37 | TombFeatureTier2 {
38 | ^ [
39 | *(x2) DungeonEncounterUndead
40 | * DungeonTreasureTier2
41 | * DungeonRemains
42 | * DungeonFungi
43 | * DungeonPool
44 | ]
45 | }
46 |
47 | TombFeatureTier3 {
48 | ^ [
49 | *(x2) DungeonEncounterUndeadTier3
50 | * DungeonTreasureTier3
51 | * DungeonRemains
52 | * DungeonFungi
53 | * DungeonPool
54 | ]
55 | }
56 |
57 | TombFeatureTier4 {
58 | ^ [
59 | *(x10) DungeonEncounterUndeadTier4
60 | * DungeonTreasureTier4
61 | ]
62 | }
63 |
64 | Tomb(Dungeon) {
65 | Name! @ TombName
66 | HexLink! = :Hex.uuid
67 | Coords! = <%
68 |
69 | %>
70 | FactionLair = none
71 |
72 | | Dungeon
73 |
74 | DungeonFeatureTier1 = TombFeatureTier1
75 | DungeonFeatureTier2 = TombFeatureTier2
76 | DungeonFeatureTier3 = TombFeatureTier3
77 | DungeonFeatureTier4 = TombFeatureTier4
78 |
79 | # TODO: add a dungeon map
80 | # map @ DungeonMap
81 |
82 | WanderingMonsters @ DungeonWanderingMonsters
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/aberrations.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterAberrations(DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! = <%
29 | A successful listening roll could detect the sounds
30 | that the {{Monster.TitlePluralizedByRoaming}}
31 | {%if Monster.NumberAppearingRoaming>1%}are{%else%}is{%endif%}
32 | making inside this area
33 | %>
34 | Hint! @ [
35 | * Red eyes are glowing inside like fire, and you hear a
36 | {%if Monster.Sound%} {{Monster.Sound}}{%else%}growl{%endif%}
37 | * Looking down, you realize you just stepped into a pool of blood
38 | * You feel the warm stench of a monster’s breath
39 | * There’s something moving inside
40 | * There’s movement inside
41 | * You feel chills curling up your spine
42 | ]
43 | }
44 |
45 | DungeonEncounterAberrationsTier1(DungeonEncounterAberrations) {
46 | Monster! @ MonstersAberrationTier1
47 | | DungeonEncounterAberrations
48 | }
49 |
50 | DungeonEncounterAberrationsTier2(DungeonEncounterAberrations) {
51 | Monster! @ MonstersAberrationTier2
52 | | DungeonEncounterAberrations
53 | }
54 |
55 |
56 | DungeonEncounterAberrationsTier3(DungeonEncounterAberrations) {
57 | Monster! @ MonstersAberrationTier3
58 | | DungeonEncounterAberrations
59 | Rumor @ DungeonMonsterRumor {
60 | DungeonMonster = &Monster
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/artifacts.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Shard {
27 | HexCoords! = none
28 | HexUUID! = none
29 | Region! = none
30 | Name! @ [
31 | * Blue Meteor Shards
32 | * Blood Crystal Shards
33 | * Lightning Stone
34 | ]
35 | HexDescription! =<%
36 | There's a 2 in 6 chance of finding a {{Name}}
37 | reservoir when searching minerals here. %>
38 | Findable! = false
39 | }
40 |
41 | Plant {
42 | HexCoords! = none
43 | HexUUID! = none
44 | Region! = none
45 | PrefixPartA1 @ [
46 | * Orcish
47 | * Dragon's
48 | * Ogre's
49 | * Elven
50 | * Highlands
51 | ]
52 |
53 | PrefixPartA2 @ [
54 | * Black
55 | * Spell
56 | * Pale
57 | * Dark
58 | * Deep
59 | ]
60 |
61 | PrefixPartB @ [
62 | * night
63 | * blood
64 | * fire
65 | * bolt
66 | * blade
67 | * wind
68 | * death
69 | ]
70 |
71 | Suffix @ [
72 | * Berry
73 | * Root
74 | * Cane
75 | * Flower
76 | * Weed
77 | * Moss
78 | * Vine
79 | ]
80 |
81 | Name! @ [
82 | * "{{PrefixPartA1}}-{{PrefixPartB}} {{Suffix}}"
83 | * "{{PrefixPartA2}}{{PrefixPartB}} {{Suffix}}"
84 | ]
85 |
86 | HexDescription! = <%
87 | The {{Name}} grows here and there's a 2 in 6
88 | chance of finding it when searching. %>
89 |
90 | Findable! = false
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/encounters/magical.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEncounterMagical(DungeonEncounter) {
27 | | DungeonEncounter
28 | Foreshadow! ~ <%
29 | A successful listening roll could detect the sounds that the
30 | {{Monster.TitlePluralizedByRoaming}} {%if
31 | Monster.NumberAppearingRoaming>1%}are{%else%}is{%endif%} making inside this
32 | area
33 | %>
34 | Hint! @ [
35 | * You’re not alone here
36 | * This is not looking good
37 | * There’s something moving inside
38 | * There’s movement inside
39 | * A weird sensation is creeping up your spine
40 | ]
41 | }
42 |
43 | DungeonEncounterMagicalTier2(DungeonEncounterMagical) {
44 | Monster! @ MonstersMagicalTier2
45 | | DungeonEncounterMagical
46 | }
47 |
48 | DungeonEncounterMagicalTier3(DungeonEncounterMagical) {
49 | Monster! @ MonstersMagicalTier3
50 | | DungeonEncounterMagical
51 | Rumor @ DungeonMonsterRumor {
52 | DungeonMonster = &Monster
53 | }
54 | }
55 |
56 | DungeonEncounterMimic(DungeonEncounter) {
57 | Monster! @ Mimic
58 | | DungeonEncounter
59 | Foreshadow! ~ <%
60 | A successful search roll could detect the sticky substance that the
61 | Mimic discharged %>
62 | Hint! @ [
63 | * The ground under your feet feels a bit sticky
64 | * Your boots and feet feel sticky as you step forward
65 | * There is an unfamiliar stench in the air
66 | * There is a very unpleasant smell around here
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/fungi.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonFungi {
27 | Foreshadow! = none
28 | Hint! @ [
29 | * Faint colourful light is emitting from everywhere
30 | * There’s also a colourful glow emitting from the ground
31 | ]
32 |
33 | Quantity @ [
34 | * a few
35 | * a few dozen of
36 | * countless
37 | ]
38 |
39 | Effect @ [
40 | * might be severely poisoned (1d4 of damage until a successful saving throw per turn)
41 | *(x3) will be paralyzed with mind twisting hallucinations for 1d6 turns
42 | *(x4) will suffer a severe stomach ache and a -2 penalty to attack rolls for 1d6 turns
43 | ]
44 |
45 | PotionEffect @ RandomPotion
46 |
47 | Description! @ [
48 | * {{capitalize(Quantity)}} green and purple bioluminescent mushrooms are
49 | growing from cracks in the ground. Anyone consuming them {{Effect}}
50 | * There are {{Quantity}} colourful bioluminescent mushrooms growing from
51 | cracks in the ground. Anyone consuming these {{Effect}}
52 | * {{capitalize(Quantity)}} blue, red and yellow bioluminescent mushrooms
53 | are growing from cracks in the ground. Anyone consuming them {{Effect}}
54 | * There are {{Quantity}} colourful bioluminescent mushrooms growing from
55 | cracks in the ground. Anyone consuming these will gain the same
56 | effect as if they consumed {{articlize(PotionEffect.Description)}}
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/relation.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Relation(Quest) {
27 | Related % Character
28 |
29 | OwnerUUID = :Character.uuid
30 | OwnerName = :Character.Name
31 | OwnerGender = :Character.Gender
32 |
33 | WhatLimited @ [
34 | * some business with
35 | * a severe dispute with
36 | * a grudge against
37 | * bad blood with
38 | * a vendetta against
39 | * a special interest in
40 | ]
41 |
42 | WhatFull @ [
43 | * some business with
44 | * a severe dispute with
45 | * a grudge against
46 | * bad blood with
47 | * a vendetta against
48 | * a special interest in
49 | * feelings for
50 | * fallen in love with
51 | * an affair with
52 | ]
53 |
54 | SameSex @ 1d10
55 |
56 | Description! ~ <%
57 | {%if Related and Related.uuid%}
58 | {%if Related.uuid!=OwnerUUID%}
59 | {{OwnerName.First}} {{OwnerGender.Possession}}
60 | {%if OwnerGender.class == Related.Gender.class and SameSex > 8 %}
61 | {{WhatFull}}
62 | {%elif OwnerGender.class != Related.Gender.class%}
63 | {{WhatFull}}
64 | {%else%}
65 | {{WhatLimited}}
66 | {%endif%}
67 |
68 | {{Related.Name.Full}}.
69 | {%endif%}
70 | {%endif%}
71 | %>
72 | }
73 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/open_or_roll.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::Ui;
26 |
27 | use crate::app::HexrollTestbedApp;
28 |
29 | impl HexrollTestbedApp {
30 | pub fn open_or_roll_panel(&mut self, ctx: &egui::Context) {
31 | if !self.scroll_in_filepath_is_valid {
32 | return;
33 | }
34 | egui::CentralPanel::default().show(ctx, |ui| {
35 | ui.set_width(ui.available_width());
36 | ui.vertical_centered(|ui| {
37 | ui.set_max_width(300.0);
38 | ui.horizontal_centered(|ui| {
39 | ui.set_max_height(50.0);
40 | self.open_or_roll_fragment(ui);
41 | });
42 |
43 | let mrus = &self.config.recently_opened.clone();
44 | mrus.iter().rev().for_each(|v| {
45 | if ui.link(v).clicked() {
46 | self.open_existing_sandbox(v)
47 | .map_err(|_| {
48 | log::warn!("Unable to open file {}", v);
49 | })
50 | .ok();
51 | }
52 | });
53 | });
54 | });
55 | }
56 |
57 | pub fn open_or_roll_fragment(&mut self, ui: &mut Ui) {
58 | if ui.button("Roll a new sandbox").clicked() {
59 | self.roll_new_sandbox_dialog(ui);
60 | }
61 | ui.separator();
62 | if ui.button("Open an existing sandbox").clicked() {
63 | self.open_existing_sandbox_dialog();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/names/regions.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | kRegionNames = [
27 | * Hell Pit
28 | * Stargazer
29 | * Dark Storm
30 | * Ironhammer
31 | * Nightshard
32 | * Pantheon
33 | * Goblinchaser
34 | * Vazul's Spear
35 | * Watermaze
36 | * Dragon's Flame
37 | * Goldseeker's
38 | * Bonecrusher
39 | * Blood Blade
40 | * Battleworn
41 | * Demon's Fork
42 | * Devil's Eye
43 | * Holloweye
44 | * Gem of Elderia
45 | * Dragon Fury
46 | * Revenger
47 | * Karla's Hammer
48 | * Heart of Avaya
49 | * Black Shield
50 | * Dark Armor
51 | * Nightmare
52 | * Spiderweb
53 | * Vicious
54 | * Javelin
55 | * Heartseeker
56 | * Thousand Shrines
57 | * Blackapple
58 | * Redfeather
59 | * Ragthorn
60 | * Crimsonblade
61 | * Nightshadow
62 | * Halfmoon
63 | * Howling Wolves
64 | * Hell's Gate
65 | * Aurora
66 | * Sunbreak
67 | * Goldmass
68 | * Dragonclaw
69 | * Moonwatcher
70 | * Fallen Star
71 | * Crater
72 | * Savage
73 | * Demonskull
74 | * Wyvern's Sting
75 | * Axe of Sal'zazoo
76 | * Vortex
77 | * Spiral
78 | * Bloodborn
79 | * Bloodforged
80 | * Fireforged
81 | * Iceforged
82 | * Fireborn
83 | * Iceborn
84 | * Wintercry
85 | * Summerwave
86 | * Firefly
87 | * Alvania
88 | * Fearless
89 | * Thunderwave
90 | * Lifeless
91 | * Arrowpoint
92 | * Retribution
93 | * Light of Valor
94 | * Goldenswan
95 | * Emerald
96 | * Darkfall
97 | * Grey Mist
98 | ]
99 |
100 | RegionName {
101 | Value! @ $kRegionNames
102 | }
103 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/npc/state.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | kNPCState = [
27 | * Aggressive
28 | * Aghast
29 | * Agitated
30 | * Alone
31 | * Angry
32 | * Annoyed
33 | * Anxious
34 | * Apprehensive
35 | * Arrogant
36 | * Ashamed
37 | * Bothered
38 | * Calm
39 | * Cheerful
40 | * Confident
41 | * Contented
42 | * Crushed
43 | * Delighted
44 | * Depressed
45 | * Desperate
46 | * Determined
47 | * Disorganized
48 | * Disoriented
49 | * Distressed
50 | * Drained
51 | * Ecstatic
52 | * Elated
53 | * Embarrassed
54 | * Energetic
55 | * Enraged
56 | * Excited
57 | * Exhausted
58 | * Fearful
59 | * Forceful
60 | * Frustrated
61 | * Guilty
62 | * Happy
63 | * Heartbroken
64 | * Helpless
65 | * Hopeless
66 | * Horny
67 | * Horrified
68 | * Hurt
69 | * Joyful
70 | * Livid
71 | * Lazy
72 | * Lifeless
73 | * Lost
74 | * Irritated
75 | * Mellow
76 | * Moody
77 | * Nervous
78 | * Offended
79 | * Outraged
80 | * Overwhelmed
81 | * Pained
82 | * Panicky
83 | * Paranoid
84 | * Persuasive
85 | * Petrified
86 | * Pleased
87 | * Proud
88 | * Puzzled
89 | * Queasy
90 | * Rejected
91 | * Relieved
92 | * Remorseful
93 | * Repentant
94 | * Sad
95 | * Satisfied
96 | * Scared
97 | * Shocked
98 | * Sickened
99 | * Sorrowful
100 | * Surprised
101 | * Terrified
102 | * Timid
103 | * Tired
104 | * Troubled
105 | * Uncomfortable
106 | * Unimpressed
107 | * Unsatisfied
108 | * Unsure
109 | * Upset
110 | * Worried
111 | * Worthless
112 | ]
113 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/names/dungeons.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonNameNoun = [
27 | * skeletons
28 | * ogre
29 | * lich
30 | * goblin
31 | * blades
32 | * spider
33 | * souls
34 | * horrors
35 | * blood
36 | * fire
37 | * witch
38 | * desire
39 | * hopes
40 | * pain
41 | * pits
42 | * order
43 | * slaves
44 | ]
45 |
46 | DungeonNameAdjective = [
47 | * betraying
48 | * corrupted
49 | * grey
50 | * corrupted
51 | * lost
52 | * cursed
53 | * hidden
54 | * unspoken
55 | * lonely
56 | * foresaken
57 | * dark
58 | * feared
59 | * tormented
60 | * raging
61 | * cruel
62 | * mourning
63 | * nameless
64 | * dishonored
65 | * deadly
66 | * cold
67 | * hopeless
68 | * unholy
69 | * savage
70 | * crying
71 | * burning
72 | * doomed
73 | * violent
74 | * mad
75 | * infernal
76 | * twisted
77 | * ruthless
78 | * furious
79 | ]
80 |
81 | DungeonName {
82 | Noun @ $DungeonNameNoun
83 | Adjective @ $DungeonNameAdjective
84 | Title! = "{{capitalize(NamePrefix)}} of the {{ capitalize(Adjective)}} {{capitalize(Noun)}}"
85 | }
86 |
87 | CavernName (DungeonName) {
88 | NamePrefix @ [
89 | * caverns
90 | * lair
91 | * hideout
92 | ]
93 | | DungeonName
94 | }
95 |
96 |
97 | TombName (DungeonName){
98 | NamePrefix @ [
99 | * tomb
100 | * crypt
101 | ]
102 | | DungeonName
103 | }
104 |
105 | TempleName (DungeonName){
106 | NamePrefix @ [
107 | * temple
108 | * shrine
109 | ]
110 | | DungeonName
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/names/taverns.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | BaseTavernName {
27 | Creature @ [
28 | * Ghoul
29 | * Mummy
30 | * Skeleton
31 | * Spectre
32 | * Wight
33 | * Wraith
34 | * Zombie
35 | * Werewolf
36 | * Hawk
37 | * Harpy
38 | * Dragon
39 | * Vampire
40 | * Pixie
41 | * Unicorn
42 | * Orc
43 | * Goblin
44 | * Gnoll
45 | * Ogre
46 | * Troll
47 | ]
48 |
49 | Title @ [
50 | * Devil
51 | * Queen
52 | * King
53 | * Knight
54 | * Hunter
55 | * Baker
56 | * Brewer
57 | * Wizard
58 | * Bard
59 | * Rogue
60 | * Mage
61 | * Witch
62 | * Paladin
63 | * Peasant
64 | ]
65 |
66 | Object @ [
67 | * Sword
68 | * Mace
69 | * Stone
70 | * Torch
71 | * Arrow
72 | * Spear
73 | * Staff
74 | ]
75 |
76 | LivingAdjective @ [
77 | * Bleeding
78 | * Fearless
79 | * Gloomy
80 | * Sad
81 | * Crying
82 | * Laughing
83 | * Cursed
84 | ]
85 |
86 | StaticAdjective @ [
87 | * Flaming
88 | * Glowing
89 | * Magic
90 | * Black
91 | * Cursed
92 | * Lost
93 | ]
94 | Full! @ [
95 | * "The {{Creature}} & The {{LivingAdjective}} {{Title}} {{Type}}"
96 | * "The {{LivingAdjective}} {{Creature}} {{Type}}"
97 | * "{{StaticAdjective}} {{Object}} {{Type}}"
98 | * "The {{StaticAdjective}} {{Object}} {{Type}}"
99 | * "The {{Title}}'s {{Object}} {{Type}}"
100 | ]
101 | }
102 |
103 | TavernName(BaseTavernName) {
104 | Type! = Tavern
105 | | BaseTavernName
106 | }
107 |
108 | InnName(BaseTavernName) {
109 | Type! @ [
110 | * Inn
111 | * Lodge
112 | ]
113 | | BaseTavernName
114 | }
115 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/raw_json.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::CursorIcon;
26 | use egui::Ui;
27 | use egui_json_tree::{render::DefaultRender, DefaultExpand, JsonTree};
28 |
29 | use crate::app::HexrollTestbedApp;
30 |
31 | impl HexrollTestbedApp {
32 | pub fn raw_json_panel(&mut self, ui: &mut Ui, value: serde_json::Value) {
33 | let tree = JsonTree::new("", &value);
34 | ui.style_mut().interaction.selectable_labels = false;
35 | tree.on_render(
36 | |ui, context| match serde_json::to_string_pretty(context.value()) {
37 | Ok(pretty_str) if pretty_str.trim_matches('"').len() == 8 => {
38 | let rendered_tree_item = context.render_default(ui);
39 | if rendered_tree_item.hovered() {
40 | let rendered_tree_item = rendered_tree_item
41 | .highlight()
42 | .on_hover_cursor(CursorIcon::Default);
43 | if rendered_tree_item.is_pointer_button_down_on() {
44 | rendered_tree_item.ctx.set_cursor_icon(CursorIcon::Wait);
45 | }
46 | if rendered_tree_item.clicked() {
47 | rendered_tree_item.ctx.set_cursor_icon(CursorIcon::Wait);
48 | self.navigate(pretty_str.to_string().trim_matches('"'), true);
49 | rendered_tree_item.ctx.set_cursor_icon(CursorIcon::Default);
50 | }
51 | }
52 | }
53 | _ => {
54 | context.render_default(ui);
55 | }
56 | },
57 | )
58 | .default_expand(DefaultExpand::All)
59 | .show(ui);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/pools.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonPool {
27 | Foreshadow! = none
28 |
29 | Hint! @ [
30 | * There’s a large round pool in the middle of the floor
31 | * There’s a large elevated oval pool on the floor
32 | * There’s a large circular pool embedded in the center of the floor
33 | ]
34 |
35 | Effect @ [
36 | * The liquid is a strong acid. When it comes in touch with human skin,
37 | it will inflict 1d4 of damage each round until it
38 | is completely washed off.
39 | * Anyone submerging into the pool will regain 1d6 per level of hitpoints.
40 | * If the pool is disturbed, it will start overflowing, rapidly
41 | flooding the area. If the doors are closed, it could drown
42 | anyone here.
43 | * When anything is submerged into the pool, the liquid inside will
44 | solidify around it into stone. It will take either magic or incredible
45 | external effort to break out.
46 | * If anything dead is thrown into the pool, a demon (or any other referee
47 | elected creature) will emerge from within.
48 | * Gazing into the pool will reflect a demonic entity that will secretly
49 | possess anyone looking at it. Save vs Spells
50 | or secretly serve the demon's evil intentions until a Bless
51 | or a similar spell is used.
52 | ]
53 |
54 | Liquid @ [
55 | * dark, tar-colored liquid
56 | * crystal clear liquid
57 | * milky-white liquid
58 | * blood-like liquid
59 | * glowing-green liquid
60 | * stinky yellowish liquid
61 | ]
62 |
63 | Description! @ [
64 | * The pool contains {{Liquid}}. {{Effect}}
65 | * The pool is filled with {{Liquid}}. {{Effect}}
66 | * The pool has {{Liquid}} inside it. {{Effect}}
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/factions/militia.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | MilitiaName(FactionName) {
27 | Name_Prefix @ [
28 | * fists
29 | * swords
30 | * spears
31 | * arrows
32 | * hammers
33 | * army
34 | * defenders
35 |
36 | ]
37 |
38 | Name_Suffix @ [
39 | * of hope
40 | * of justice
41 | * of power
42 | * of honor
43 | * of victory
44 | * of valor
45 | * of fire
46 | * of revival
47 | ]
48 | | FactionName
49 | }
50 |
51 | Militia (Faction) {
52 |
53 | FactionName! @ MilitiaName
54 |
55 | AcceptedAlignment @ [
56 | * Chaotic
57 | * Neutral
58 | ]
59 |
60 | Race @ [
61 | * humans
62 | * elves
63 | * gnolls
64 | * kobolds
65 | ]
66 |
67 | Verb @ [
68 | * conspiring to
69 | * plotting to
70 | ]
71 |
72 | Purpose @ [
73 | * overthrow the ruler of the realm
74 | * abolish all magic-users
75 | * eliminate all cultists
76 | ]
77 |
78 | Tavern ? Tavern {
79 | FactionName = *FactionName
80 | FactionUUID = &uuid
81 | Faction = <%
82 | {{FactionName.Full}}
83 | are using this place as a meeting place from time to time.
84 | %>
85 | }
86 |
87 | Leader @ MilitiaLeader {
88 | HostingEntity := &uuid
89 | Alignment = Neutral
90 | }
91 |
92 | Brief! ~ <%
93 |
94 | {{FactionName.Full}}
95 | {{class | lower}} are {{Verb}} {{Purpose}}.
96 |
97 | {% if Tavern %}
98 |
99 | The {{class | lower}}’s usual gathering venue is
100 | {{Tavern.Title}}
101 | {%if Tavern.SettlementName%}in {{title(Tavern.SettlementName)}}{%else%}
102 | {%endif%}
103 |
104 | {%endif%}
105 | %>
106 |
107 | Coords! ~ <{%if Tavern%}{{Tavern.Coords}}{%endif%}>
108 | | Faction
109 | }
110 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/cave.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | CaveEncounterTier1 {
27 | ^ [
28 | *(x2) DungeonEncounterHumanoidsTier1
29 | * DungeonEncounterVerminsTier1
30 | * DungeonEncounterOozesTier1
31 | * DungeonEncounterAberrationsTier1
32 | * DungeonEncounterCaveSpecificTier1
33 | ]
34 | }
35 |
36 | CaveEncounterTier2 {
37 | ^ [
38 | * DungeonEncounterHumanoidsTier1
39 | * DungeonEncounterVerminsTier2
40 | * DungeonEncounterOozesTier2
41 | * DungeonEncounterAberrationsTier2
42 | * DungeonEncounterCaveSpecificTier2
43 | ]
44 | }
45 |
46 | CaveEncounterTier3 {
47 | ^ [
48 | * DungeonEncounterVerminsTier3
49 | * DungeonEncounterOozesTier3
50 | * DungeonEncounterAberrationsTier3
51 | * DungeonEncounterDragonsTier3
52 | ]
53 | }
54 |
55 | CaveFeatureTier1 {
56 | ^ [
57 | *(x2) CaveEncounterTier1
58 | * DungeonTreasureTier1
59 | * DungeonRemains
60 | * DungeonFungi
61 | ]
62 | }
63 |
64 | CaveFeatureTier2 {
65 | ^ [
66 | *(x2) CaveEncounterTier2
67 | * DungeonTreasureTier2
68 | * DungeonRemains
69 | * DungeonFungi
70 | ]
71 | }
72 |
73 | CaveFeatureTier3 {
74 | ^ [
75 | *(x2) CaveEncounterTier3
76 | * DungeonTreasureTier3
77 | * DungeonRemains
78 | * DungeonFungi
79 | ]
80 | }
81 |
82 | Cavern(Dungeon) {
83 | Name! @ CavernName
84 | HexLink! = :Hex.uuid
85 | Coords! = <%
86 |
87 | %>
88 | FactionLair @ FactionLair {
89 | DungeonUUID = &uuid
90 | Name = *Name
91 | HexLink = &HexLink
92 | Coords = &Coords
93 | }
94 |
95 | | Dungeon
96 |
97 | DungeonFeatureTier1 = CaveFeatureTier1
98 | DungeonFeatureTier2 = CaveFeatureTier2
99 | DungeonFeatureTier3 = CaveFeatureTier3
100 | DungeonFeatureTier4 = CaveFeatureTier4
101 |
102 | # map @ CaveMap
103 |
104 | WanderingMonsters @ DungeonWanderingMonsters
105 | }
106 |
107 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/dwelling.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Hut {
27 | Name! = Hut
28 | Motivation! @ [
29 | * hiding here as a fugitive
30 | * living in solitude here
31 | ]
32 | }
33 |
34 | Cottage {
35 | Name! = Cottage
36 | Motivation! @ [
37 | * finding refuge from the world
38 | * seeking solitude from others
39 | * spending retirement here
40 | * looking for some peace and quiet
41 | ]
42 | }
43 |
44 | Farmhouse {
45 | Name! = Farmhouse
46 | Motivation! @ [
47 | * trying to sustain independently here
48 | * growing a unique specie of smoking-pipe leaves
49 | ]
50 | }
51 |
52 | House (Residency){
53 | Prefix @ [
54 | * aging
55 | * well-maintained
56 | * decorated
57 | * barricaded
58 | ]
59 | Encounter = "Yes"
60 | Type! @@ [
61 | * Hut
62 | * Cottage
63 | * Farmhouse
64 | ]
65 |
66 | Population = 1
67 |
68 | HexLink = :Hex.uuid
69 | HexRegion = :Hex.Region
70 | Resident! @@ [
71 | * Character
72 | ]~{
73 | HostingEntity := &HexLink
74 | URLExt = "/location/{{HostingEntity}}"
75 | SettlementName = &HexRegion
76 | }
77 |
78 | Quest @ [
79 | * Feeling someone or something is lurking around the {{Type.Name}}
80 | * Hearing strange noises at night and fearing someone or something will raid the {{Type.Name}}
81 | ]
82 |
83 | Details! =<%
84 | -
85 | {{Resident.Name.First}} {{Resident.Gender.BeVerb}} {{Type.Motivation}}.
86 |
87 | {{capitalize(Resident.Gender.PronounSubject)}} {{Resident.Gender.Possession}} {{Resident.Appearance}}
88 | ({{Resident.State}}). {{Resident.InThePocket.Details}}
89 |
90 |
91 | {%if Resident.Association%}{{Resident.Association}}{%endif%}
92 | {%if Resident.Story2%}{{Resident.Story2.Description}}{%endif%}
93 | -
94 | {{Quest}}.
95 |
96 |
97 |
98 |
99 | %>
100 | | Residency
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/factions/syndicate.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | SyndicateName(FactionName) {
27 |
28 | Name_Prefix @ [
29 | * dark
30 | * red
31 | * black
32 | * white
33 | * avenging
34 | * rough
35 | * silent
36 | ]
37 |
38 | Name_Suffix @ [
39 | * blades
40 | * shadows
41 | * cloaks
42 | * daggers
43 | * snakes
44 | * spiders
45 | * ghosts
46 | * wyverns
47 | * wolves
48 | * masks
49 | * hyaenas
50 | ]
51 | | FactionName
52 | }
53 |
54 | Syndicate (Faction) {
55 |
56 | FactionName! @ SyndicateName
57 |
58 | AcceptedAlignment @ [
59 | * Chaotic
60 | ]
61 |
62 | Race @ [
63 | * humans
64 | * elves
65 | * gnolls
66 | * kobolds
67 | ]
68 |
69 | Verb @ [
70 | * conspiring to
71 | * plotting to
72 | ]
73 |
74 | Purpose @ [
75 | * assassinate the ruler of the realm
76 | * abduct and smuggle people to slave traders
77 | * collect protection money for an unknown purpose
78 | ]
79 |
80 | Tavern ? Tavern {
81 | FactionName = *FactionName
82 | FactionUUID = &uuid
83 | Faction = <%
84 | {{FactionName.Full}}
85 | are using this place as their secret meeting place from time to time.
86 | %>
87 | }
88 |
89 | Leader @ SyndicateLeader {
90 | HostingEntity := &uuid
91 | Alignment = Neutral
92 | }
93 |
94 | Brief! ~ <%
95 |
96 | {{FactionName.Full}}
97 | {{class | lower}} are {{Verb}} {{Purpose}}.
98 |
99 | {% if Tavern %}
100 |
101 | The {{class | lower}}’s usual gathering venue is
102 | {{Tavern.Title}}
103 | {%if Tavern.SettlementName%}in {{title(Tavern.SettlementName)}}{%else%}
104 | {%endif%}
105 |
106 | {%endif%}
107 | %>
108 |
109 | Coords! ~ <{%if Tavern%}{{Tavern.Coords}}{%endif%}>
110 | | Faction
111 | }
112 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/temple.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | TempleEncounterTier1 {
27 | ^ [
28 | *(x2) DungeonEncounterCultists
29 | * DungeonEncounterTempleAnimals
30 | ]
31 | }
32 |
33 | TempleEncounterTier2 {
34 | ^ [
35 | * DungeonEncounterMagicalTier2
36 | * DungeonEncounterAberrationsTier2
37 | ]
38 | }
39 |
40 | TempleEncounterTier3 {
41 | ^ [
42 | *(x4) DungeonEncounterMagicalTier3
43 | *(x4) DungeonEncounterAberrationsTier3
44 | * DungeonEncounterMimic
45 | ]
46 | }
47 |
48 | TempleEncounterTier4 {
49 | ^ [
50 | *(x3) DungeonEncounterDragonsTier3
51 | * DungeonEncounterDragonsTier4
52 | ]
53 | }
54 |
55 | TempleFeatureTier1 {
56 | ^ [
57 | *(x3) TempleEncounterTier1
58 | * DungeonTreasureTier1
59 | * DungeonRemains
60 | * DungeonPool
61 | ]
62 | }
63 |
64 | TempleFeatureTier2 {
65 | ^ [
66 | *(x2) TempleEncounterTier2
67 | * DungeonTreasureTier2
68 | * DungeonRemains
69 | * DungeonPool
70 | ]
71 | }
72 |
73 | TempleFeatureTier3 {
74 | ^ [
75 | *(x2) TempleEncounterTier3
76 | * DungeonTreasureTier3
77 | * DungeonRemains
78 | * DungeonPool
79 | ]
80 | }
81 |
82 | TempleFeatureTier4 {
83 | ^ [
84 | *(x10) TempleEncounterTier4
85 | * DungeonTreasureTier4
86 | ]
87 | }
88 |
89 | Temple(Dungeon) {
90 | Name! @ TempleName
91 | HexLink! = :Hex.uuid
92 | Coords! = <%
93 |
94 | %>
95 | FactionLair @ FactionLair {
96 | DungeonUUID = &uuid
97 | Name = *Name
98 | HexLink = &HexLink
99 | Coords = &Coords
100 | }
101 |
102 | | Dungeon
103 |
104 | DungeonFeatureTier1 = TempleFeatureTier1
105 | DungeonFeatureTier2 = TempleFeatureTier2
106 | DungeonFeatureTier3 = TempleFeatureTier3
107 | DungeonFeatureTier4 = TempleFeatureTier4
108 | # TODO: add a dungeon map
109 | # map @ DungeonMap
110 |
111 | WanderingMonsters @ DungeonWanderingMonsters
112 | }
113 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/village.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | VillageDistrict(District) {
27 | Title = Village District
28 | CostFactor = 0.9
29 | << Advert
30 | << LocalRumor
31 | [5..19 shops!] @ TownShops
32 | | District
33 | }
34 |
35 | Village(Settlement) {
36 | | Settlement
37 |
38 | Title! = "village of {{title(NamePart)}}"
39 |
40 | Prefix! @ [
41 | * thriving
42 | * bustling
43 | * sleepy
44 | * flourishing
45 | * lively
46 | * struggling
47 | * growing
48 | * withering
49 | * prospering
50 | * expanding
51 | ]
52 |
53 | Connector! @ [
54 | * blends seamlessly
55 | * sits quietly
56 | * rests peacefully
57 | ]
58 |
59 | District? @ VillageDistrict
60 | Population? = "{{int(District.Population)}}"
61 |
62 | GAlignment @ [
63 | *(x5) Lawful
64 | *(x1) Neutral
65 | ]
66 | [2..3 Guards?] @ Guard {
67 | Alignment = &GAlignment
68 | HostingEntity := &uuid
69 | Profession = "guard"
70 | URLExt = "/location/{{HostingEntity}}/npc/{{uuid}}"
71 | }
72 |
73 | Overview? ~ <%
74 |
75 | Population: {{Population}} villagers
76 |
77 | Village Shops & Services
78 | {{District.Index}}
79 | {% if Guards %}
80 | Guards
81 | {% for g in Guards %}
82 |
83 |
84 | {{reroller(g, "", False)}} {{g.Description}}
85 | {{g.Stats}}
86 | {% if g.Association %}
87 |
88 | {{g.Association}}
89 |
90 | {% endif %}
91 |
92 |
93 | {% endfor %}
94 | {% endif %}
95 | %>
96 |
97 | Supplemental! = ""
98 |
99 | Brief? = <%
100 | {{Overview}}
101 | %>
102 |
103 |
105 | %metadata>
106 |
107 | {{capitalize(Title)}} from {{Realm}}
109 |
110 | {{NamePart}}
111 | {{Breadcrumbs}}
112 |
113 | %header>
114 |
115 |
118 | }
119 |
120 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/realms/base.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | minimum_number_of_regions = 6
27 | maximum_number_of_regions = 12
28 |
29 | mountains_probability= 3
30 | forest_probability= 5
31 | desert_probability= 1
32 | plains_probability= 4
33 | jungle_probability= 0
34 | swamps_probability= 2
35 | tundra_probability= 0
36 |
37 | minimum_number_of_settlements= 6
38 | maximum_number_of_settlements= 9
39 | cities_probability= 2
40 | towns_probability= 3
41 | villages_probability= 3
42 | minimum_number_of_dwellings= 7
43 | maximum_number_of_dwellings= 11
44 | house_probability= 2
45 | stronghold_probability= 3
46 | minimum_number_of_inns= 3
47 | maximum_number_of_inns= 6
48 | minimum_number_of_dungeons= 6
49 | maximum_number_of_dungeons= 9
50 | tombs_probability= 1
51 | temples_probability= 1
52 | caves_probability= 1
53 | minimum_number_of_factions= 3
54 | maximum_number_of_factions= 5
55 | cults_probability= 1
56 | militias_probability= 1
57 | syndicates_probability= 1
58 | wandering_monsters_max_hd= 4
59 | treasure_factor= 1
60 |
61 | RealmExtension {
62 | Prescript! ~ ""
63 | Postscript! ~ ""
64 | }
65 |
66 | Realm {
67 | ^ [
68 | * RuledRealm
69 | * UnruledRealm
70 | ]
71 |
72 | Title! ` "The {{RealmType.Title}} of {{Name.Title}}"
73 |
74 | << Plant
75 | << Shard
76 |
77 | << HexRumor
78 | << RealmRumor
79 | << Character
80 | << Residency
81 | << Settlement
82 | << Tavern
83 | << FactionLair
84 | << DungeonTreasureTier3
85 | << MissingPersonQuestCell
86 | << QuestTreasureHiding
87 | << Hex
88 | << LostItemMagical
89 | << Castle
90 | toc! << TocEntry
91 |
92 | [$minimum_number_of_regions..$maximum_number_of_regions regions] @ Region
93 |
94 | HexLink = "Realm"
95 |
96 |
97 | Breadcrumbs! ~ <%
98 |
99 | {{sandbox_breadcrumb()}}
100 | {{toc_breadcrumb()}}
101 |
102 | %>
103 |
104 |
105 |
107 | %metadata>
108 |
109 |
111 | {{Title}}
112 |
113 |
114 | {{Title}}
115 | {{Breadcrumbs}}
116 |
117 | %header>
118 |
119 |
124 | }
125 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/desert.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Desert {
27 | Name! = Desert
28 | Supplemental! @ [
29 | * The sand here is as dark as the night. Not a fire nor a volcano could have
30 | been the cause.
31 |
32 | * You can clearly see bones revealing under the dunes when the wind shifts
33 | the sand. This was no land of peace.
34 |
35 | * Surrounded by the soft dunes, a huge rock shaped like a dome is planted in
36 | the sand. It is almost too slippery to climb on.
37 |
38 | * Either wind or some other force creates dozens of giant sand vortexes
39 | here, as tall as the eye can see.
40 |
41 | * There are numerous sinkholes in the sands here. Some of them are big
42 | enough to swallow an inn.
43 |
44 | * The wind here is gentle and the sand is soft and warm. Large canopied
45 | desert trees provide enough shadow to rest or camp under.
46 |
47 | * Vast dunes stretch in all directions, shimmering in the desert heat. The
48 | sun makes the sand scorching hot.
49 |
50 | * Tall pillars of rock emerge from the sands here, like giant columns to
51 | support the cloudless sky.
52 |
53 | * The sand here is riddled with small craters, as if a cluster of rocks rained
54 | violently from above.
55 |
56 | * A giant perfect wall of stones stands lonely and unconnected in the middle
57 | of the wasteland, with only empty stretches of sand to surround it.
58 |
59 | * Gusts of warm desert wind sweep and swirl the sands, creating ghost-like
60 | clouds of desert dust.
61 | ]
62 | Location! @ [
63 | * on the dunes sands
64 | * near an oasis
65 | * between two giant dunes
66 | * beside the ruins of a pyramid
67 | * near an ancient monument
68 | ]
69 | Hideout! @ [
70 | * under the ruins of an ancient temple
71 | * underground
72 | * near an abandoned ritual site
73 | ]
74 | }
75 |
76 | DesertRandomEncounterTable {
77 | [4..4 OtherEncounters!] @ DesertRandomEncounter
78 | }
79 |
80 | DesertHex (Hex) {
81 | Terrain! @ Desert
82 | Monster! @ DesertFeatureEncounter
83 | RandomEncounters @ DesertRandomEncounterTable
84 | ExtensionTypeClass = "DesertHexExtension"
85 | | Hex
86 | }
87 |
88 | DesertRegion (Region) {
89 | Suffix @ [
90 | * Dunes
91 | * Desert
92 | * Wastelands
93 | * Barrens
94 | * Wastes
95 | ]
96 | | Region
97 | Weather? @ DesertWeatherContainer
98 | [$minimum_tiles_per_desert_region..$maximum_tiles_per_desert_region Hexmap?] @ DesertHex
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/factions/cult.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | CultName(FactionName) {
27 | Name_Prefix @ [
28 | * dark
29 | * defiled
30 | * white
31 | * black
32 | * burning
33 | * flaming
34 | * desecrated
35 | * foul
36 | * corrupt
37 | * sacred
38 | ]
39 |
40 | Name_Suffix @ [
41 | * horrors
42 | * sun
43 | * followers
44 | * truthseekers
45 | * saviors
46 | * scrolls
47 | * saints
48 | * bones
49 | * lambs
50 | * wolves
51 | * servants
52 | * seekers
53 | * prophets
54 | ]
55 | | FactionName
56 | }
57 |
58 | Cult (Faction) {
59 | FactionName! @ CultName
60 |
61 | AcceptedAlignment = Chaotic
62 |
63 | Race @ [
64 | * humans
65 | * elves
66 | * gnolls
67 | * kobolds
68 | ]
69 |
70 | Verb = secretly
71 |
72 | Purpose @ [
73 | * conducting horrid experiments in humanoids
74 | * sacrificing humans
75 | * attempting demon summoning rituals
76 | ]
77 |
78 | Leader @ CultLeader {
79 | HostingEntity := &uuid
80 | Alignment = Chaotic
81 | }
82 |
83 | Lair ? FactionLair {
84 | FactionName = *FactionName
85 | FactionLeader = *Leader
86 | FactionUUID = &uuid
87 | Faction = <%
88 | {{FactionName.Full}}
89 | are using this dungeon, and there's a 2 in 6 chance to find
90 | {{FactionLeader.Name.Full}}
91 | together with {{FactionLeader.Gender.PronounPossessive}} acolytes or mediums here.
92 | %>
93 | }
94 |
95 | LairRumor @ RealmRumor {
96 | FactionName := *FactionName
97 | FactionUUID := &uuid
98 | FactionLair := *Lair
99 | Details = <%
100 | {% if FactionLair %}
101 | {{FactionName.Full}}
102 | are using the
103 | {{FactionLair.Name.Title}}
104 | as their hideout.
105 | {% else %}
106 | {{FactionName.Full}}
107 | are looking for a hideout.
108 | {% endif %}
109 | %>
110 | }
111 |
112 | Brief! ~ <%
113 |
114 | {{FactionName.Full}}
115 | {{class | lower}} are {{Purpose}}.
116 |
117 |
118 | {% if Lair %}
119 | The {{class | lower}} hideout is the {{Lair.Name.Title}}.
120 | {% endif %}
121 |
122 | %>
123 |
124 | Coords! ~ <%{% if Lair %} {{Lair.Coords}} {%endif%}%>
125 | | Faction
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/preview.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use std::collections::HashMap;
26 |
27 | use egui::{Context, CursorIcon, FontId, Ui};
28 | use path_tree::PathTree;
29 |
30 | use crate::{
31 | app::helpers::html::render_demidom,
32 | app::{HexrollTestbedApp, RouteHandler},
33 | };
34 |
35 | impl HexrollTestbedApp {
36 | pub fn preview_panel(&mut self, ctx: &Context, ui: &mut Ui) {
37 | ui.scope(|ui| {
38 | // Some styling before we render
39 | ui.style_mut().visuals.button_frame = true;
40 | ui.style_mut().visuals.widgets.inactive.rounding = egui::Rounding::same(5.0);
41 | ui.style_mut().visuals.widgets.active.rounding = egui::Rounding::same(5.0);
42 | ui.style_mut().visuals.widgets.hovered.rounding = egui::Rounding::same(5.0);
43 |
44 | // This controls the overall scale of the rendered HTML
45 | let font_size = (ui.available_width() / 50.0) * self.config.zoom_level;
46 |
47 | ui.style_mut().override_font_id = Some(FontId::proportional(font_size));
48 | ui.style_mut().text_styles.insert(
49 | egui::TextStyle::Button,
50 | egui::FontId::new(font_size * 0.8, eframe::epaint::FontFamily::Proportional),
51 | );
52 |
53 | // Render and process any DemidomResponse we get, which is mostly click
54 | // events on links or buttons.
55 | let ret = render_demidom(self.current_entity.html_demidom.clone(), ui, font_size, 1);
56 | if let Some(ret) = ret {
57 | if ret.url != self.current_url {
58 | self.current_url = ret.url.clone();
59 | ctx.output_mut(|o| {
60 | o.cursor_icon = CursorIcon::Wait;
61 | });
62 | // Response URLs are passed to the router for in exchange
63 | // for a callback for things like navigating to another entity,
64 | // rerolling or appending.
65 | let mut tree = PathTree::::new();
66 | HexrollTestbedApp::routes(&mut tree);
67 | [&ret].map(|v| {
68 | if let Some(route) = tree.find(&v.url).clone() {
69 | let param_map: HashMap = route
70 | .1
71 | .params()
72 | .iter()
73 | .map(|&(k, v)| (k.to_string(), v.to_string()))
74 | .collect();
75 | route.0(self, ¶m_map);
76 | }
77 | });
78 | }
79 | }
80 | });
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/utils/sigils.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Sigil {
27 | Symbol! @ [
28 | * 🜀
29 | * 🜁
30 | * 🜂
31 | * 🜃
32 | * 🜄
33 | * 🜅
34 | * 🜆
35 | * 🜇
36 | * 🜈
37 | * 🜉
38 | * 🜊
39 | * 🜋
40 | * 🜌
41 | * 🜍
42 | * 🜎
43 | * 🜏
44 | * 🜐
45 | * 🜑
46 | * 🜒
47 | * 🜓
48 | * 🜔
49 | * 🜕
50 | * 🜖
51 | * 🜗
52 | * 🜘
53 | * 🜙
54 | * 🜚
55 | * 🜛
56 | * 🜜
57 | * 🜝
58 | * 🜞
59 | * 🜟
60 | * 🜠
61 | * 🜡
62 | * 🜢
63 | * 🜣
64 | * 🜤
65 | * 🜥
66 | * 🜦
67 | * 🜧
68 | * 🜨
69 | * 🜩
70 | * 🜪
71 | * 🜫
72 | * 🜬
73 | * 🜭
74 | * 🜮
75 | * 🜯
76 | * 🜰
77 | * 🜱
78 | * 🜲
79 | * 🜳
80 | * 🜴
81 | * 🜵
82 | * 🜶
83 | * 🜷
84 | * 🜸
85 | * 🜹
86 | * 🜺
87 | * 🜻
88 | * 🜼
89 | * 🜽
90 | * 🜾
91 | * 🜿
92 | * 🝀
93 | * 🝁
94 | * 🝂
95 | * 🝃
96 | * 🝄
97 | * 🝅
98 | * 🝆
99 | * 🝇
100 | * 🝈
101 | * 🝉
102 | * 🝊
103 | * 🝋
104 | * 🝌
105 | * 🝍
106 | * 🝎
107 | * 🝏
108 | * 🝐
109 | * 🝑
110 | * 🝒
111 | * 🝓
112 | * 🝔
113 | * 🝕
114 | * 🝖
115 | * 🝗
116 | * 🝘
117 | * 🝙
118 | * 🝚
119 | * 🝛
120 | * 🝜
121 | * 🝝
122 | * 🝞
123 | * 🝟
124 | * 🝠
125 | * 🝡
126 | * 🝢
127 | * 🝣
128 | * 🝤
129 | * 🝥
130 | * 🝦
131 | * 🝧
132 | * 🝨
133 | * 🝩
134 | * 🝪
135 | * 🝫
136 | * 🝬
137 | * 🝭
138 | * 🝮
139 | * 🝯
140 | * 🝰
141 | * 🝱
142 | * 🝲
143 | * 🝳
144 | ]
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/remains.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | RandomEquipmentOnBody {
27 | ^ [
28 | * Club
29 | * Dagger
30 | * Mace
31 | * ShortBow
32 | * SilverDagger
33 | * Sling
34 | * Sword
35 | * IronRations
36 | * Mirror
37 | * IronSpikes
38 | * HolySymbol
39 | * Garlic
40 | * SmallSack
41 | * Rope
42 | * Pole
43 | * Oil
44 | * SmallHammer
45 | * ThieveTools
46 | * ClothingAdventurerBoots
47 | * ClothingHighBoots
48 | * ClothingWarmCloak
49 | * ClothingLeatherHat
50 | ]
51 | }
52 |
53 | RandomEquipmentOnBodyState = [
54 | * Usable
55 | * Unusable
56 | ]
57 |
58 | DungeonRemains {
59 | # TODO: add foreshadow?
60 | Foreshadow! = none
61 | Hint! @ [
62 | *(x2) There’s something lying on the floor
63 | *(x2) You spot something quite big lying on the floor
64 | * There’s a dead body here
65 | ]
66 |
67 | AreaTrap! @ AreaTrap
68 |
69 | Treasure @ TreasureTypeBody
70 |
71 | EquipmentItems @ 1d4-1
72 | EquipmentItem1 @ RandomEquipmentOnBody
73 | EquipmentItem1State @ $RandomEquipmentOnBodyState
74 | EquipmentItem2 @ RandomEquipmentOnBody
75 | EquipmentItem2State @ $RandomEquipmentOnBodyState
76 | EquipmentItem3 @ RandomEquipmentOnBody
77 | EquipmentItem3State @ $RandomEquipmentOnBodyState
78 |
79 | RoomNumber = :AreaDescription.RoomNumber
80 | AreaUUID = :AreaDescription.uuid
81 | Key @ DungeonDoorKey {
82 | AreaNumber = &RoomNumber
83 | AreaUUID = &AreaUUID
84 | }
85 |
86 | Remains @ [
87 | *(x2) a dust covered human skeleton
88 | * the dust covered skeleton of an orc
89 | * the dust covered skeleton of a goblin
90 | *(x2) a rotting human corpse
91 | * a rotting orc corpse
92 | * a rotting goblin corpse
93 | ]
94 | Description! ~ <%
95 | Lying on the floor is {{Remains}}.
96 | {%if (trim(Treasure.Details))=="" and EquipmentItems < 1 and not Key.Active%}
97 | Searching it will uncover nothing.
98 | {%else%}
99 | Searching it will uncover:
100 |
101 | {{Treasure.Details}}
102 | {%-if EquipmentItems > 0%}
103 | -
104 | {{nobrackets(EquipmentItem1.Title)}} ({{EquipmentItem1State}}){%endif%}
105 |
106 | {%-if EquipmentItems > 1%}
107 | -
108 | {{nobrackets(EquipmentItem2.Title)}} ({{EquipmentItem2State}}){%endif%}
109 |
110 | {%-if EquipmentItems > 2%}
111 | -
112 | {{nobrackets(EquipmentItem3.Title)}} ({{EquipmentItem3State}}){%endif%}
113 |
114 | {%endif%}
115 | {%-if Key.Active%}
116 | -
117 | The {{Key.Active}}
118 |
119 | {%endif%}
120 |
121 | %>
122 |
123 | }
124 |
125 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/helpers/logger.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use std::sync::{Arc, Mutex};
26 |
27 | use chrono::Local;
28 | use log::LevelFilter;
29 |
30 | struct LogEntry {
31 | timestamp: String,
32 | level: String,
33 | message: String,
34 | }
35 |
36 | pub struct LogStorage {
37 | messages: Arc>>,
38 | }
39 |
40 | impl LogStorage {
41 | pub fn new() -> Self {
42 | Self {
43 | messages: Arc::new(Mutex::new(Vec::new())),
44 | }
45 | }
46 | pub fn init_logger(&self) {
47 | let messages = self.messages.clone();
48 | log::set_boxed_logger(Box::new(SimpleLogger { messages })).unwrap();
49 | log::set_max_level(LevelFilter::Trace);
50 | }
51 |
52 | pub fn show(&self, ctx: &egui::Context, ui: &mut egui::Ui) {
53 | egui::ScrollArea::vertical().show(ui, |ui| {
54 | ui.set_width(ui.available_width());
55 | egui::Grid::new("log_messages")
56 | .num_columns(3)
57 | .striped(true)
58 | .show(ui, |ui| {
59 | ui.set_width(ui.available_width());
60 | for msg in self.messages.lock().unwrap().iter().rev() {
61 | ui.style_mut().visuals.override_text_color = match msg.level.as_str() {
62 | "TRACE" => Some(ctx.theme().default_visuals().weak_text_color()),
63 | "ERROR" => Some(ctx.theme().default_visuals().error_fg_color),
64 | "WARN" => Some(ctx.theme().default_visuals().warn_fg_color),
65 | _ => None,
66 | };
67 | ui.label(&msg.timestamp);
68 | ui.label(&msg.level);
69 | ui.label(&msg.message);
70 | ui.end_row();
71 | }
72 | });
73 | });
74 | }
75 | }
76 |
77 | struct SimpleLogger {
78 | messages: Arc>>,
79 | }
80 |
81 | impl log::Log for SimpleLogger {
82 | fn enabled(&self, _: &log::Metadata) -> bool {
83 | true
84 | }
85 | fn log(&self, record: &log::Record) {
86 | if !record.module_path().unwrap().contains("hexroll") {
87 | return;
88 | }
89 | let mut msgs = self.messages.lock().unwrap();
90 | if msgs.len() > 10000 {
91 | msgs.remove(0);
92 | }
93 |
94 | let timestamp = Local::now().format("%H:%M:%S%.6f").to_string();
95 | msgs.push(LogEntry {
96 | timestamp,
97 | level: format!("{}", record.level()),
98 | message: format!("{}", record.args()),
99 | });
100 | }
101 | fn flush(&self) {}
102 | }
103 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/quest.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Quest {
27 | ^ [
28 | *(x10) NoQuest
29 | *(x5) TrivialHook
30 | *(x1) MissingPersonQuest
31 | *(x1) TreasureQuest
32 | *(x2) Relation
33 | ]
34 | }
35 |
36 | RerollerQuest {
37 | ^ [
38 | *(x1) MissingPersonQuest
39 | *(x1) TreasureQuest
40 | *(x1) Relation
41 | ]
42 | }
43 |
44 | NoQuest {
45 | Description! = ""
46 | }
47 |
48 | Secret {
49 | Details! = "[..]"
50 | }
51 |
52 | QuestSecret(Secret) {
53 | }
54 |
55 | Advert {
56 | Details! = ""
57 | }
58 |
59 | TrivialHook {
60 | ^ [
61 | * TrivialHookIsDoingSomething
62 | * TrivialHookWasRecently
63 | * TrivialHookJustReceived
64 | * TrivialHookMadeA
65 | ]
66 | }
67 |
68 | kSomeone = [
69 | * a guard
70 | * a tavern keeper
71 | * a mysterious stranger
72 | * a drunkard
73 | * a suspicious noble
74 | * a shady adventurer
75 | ]
76 |
77 | TrivialHookMadeA {
78 | Made @ [
79 | * a regretful bet
80 | * an unholy pact
81 | * a secret agreement
82 | * a shady contract
83 | * a secret pact
84 | ]
85 | With @ $kSomeone
86 | Description! ~ <% Recently made {{Made}} with {{With}}.%>
87 | }
88 |
89 | TrivialHookJustReceived {
90 | What @ [
91 | * a mysterious box
92 | * a sealed letter
93 | * a sealed bottle
94 | * a locket
95 | * a covered jar
96 | * a pouch
97 | ]
98 |
99 | And @ [
100 | * is afraid to open it
101 | * is trying to find its origin
102 | * is terrified of what's inside it
103 |
104 | ]
105 | Description! ~ <% Just received {{What}} and {{And}}.%>
106 | }
107 |
108 | TrivialHookWasRecently {
109 | experience @ [
110 | * intimidated by
111 | * helping
112 | * arguing with
113 | * gambling with
114 |
115 | ]
116 |
117 | who @ $kSomeone
118 | Description! ~ <% Was recently {{experience}} {{who}}.%>
119 | }
120 |
121 |
122 | TrivialHookIsDoingSomething {
123 | doing @ [
124 | * Preparing for
125 | * Avoiding
126 | * Thinking about
127 | * Bothered by
128 | ]
129 | adj @ [
130 | * an important
131 | * an unplanned
132 | * an unwanted
133 | ]
134 | something @ [
135 | * {{adj}} event
136 | * {{adj}} guest
137 | * {{adj}} travel
138 | * {{adj}} visit
139 | ]
140 | Description! ~ <% {{doing}} {{something}}.%>
141 | }
142 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/mouth.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonEntrance {
27 | AreaNumber = 0
28 | AreaUUID! = none
29 | HexClass = none
30 | DungeonContext = none
31 | EntranceLocationPrefix = ""
32 | EntranceDescLeadingTo = ""
33 |
34 | MountainLocation @ [
35 | * in a cave on the face of cliff, at the end of a rope bridge above a chasm
36 | * inside a cave, hidden behind a raging waterfall
37 | * inside an adandoned mine
38 | * inside a cave on the face of a steep cliff
39 | * under the ruines of an old fortress
40 | * in the basement of an abandoned inn
41 | * inside an abandoned wooden cabin, under loose floor boards
42 | ]
43 | ForestLocation @ [
44 | * deep inside the trunk of a giant oak, at the bottom of an excavated spiral staircase
45 | * under the ruins of an ancient temple, masked by dense undergrowth
46 | * deep inside the mouth of a giant stone skull, entirely covered with moss and ivy
47 | * in the basement of an abandoned inn
48 | * inside an abandoned wooden cabin, under loose floor boards
49 | ]
50 | PlainsLocation @ [
51 | * hidden deep inside a burial mound
52 | * deep inside the mouth of a giant stone skull
53 | * under a wooden trapdoor buried 5 feet in the ground
54 | * under the ruines of an old fortress
55 | * at the bottom of a false outhouse
56 | * in the basement of an abandoned inn
57 | * inside an adandoned mine
58 | * inside an abandoned wooden hut, under loose floor boards
59 | ]
60 | DesertLocation @ [
61 | * under a wooden trapdoor buried 5 feet into the sand, with only an arrow-shaped sign pointing down hinting on the location
62 | * deep inside the mouth of a giant stone craved skull, partly buried under a dune
63 | * in the basement of an abandoned inn
64 | * inside a cave on a formation of rock surrounded by dunes
65 | * inside an abandoned wooden hut, under loose floor boards
66 | ]
67 |
68 | DefaultLocation @ [
69 | * located behind a giant skull's gaping mouth
70 | * under a wooden trapdoor buried 5 feet in the ground
71 | ]
72 | DungeonHex = :Dungeon.Hex
73 | Location! ~ <%
74 | {%if DungeonHex == "MountainsHex"%}{{MountainLocation}}
75 | {%elif DungeonHex == "ForestHex"%}{{ForestLocation}}
76 | {%elif DungeonHex == "PlainsHex"%}{{PlainsLocation}}
77 | {%elif DungeonHex == "DesertHex"%}{{DesertLocation}}
78 | {%else%}{{DefaultLocation}}{%endif%}
79 | %>
80 | Description! ~ <%
81 | {{EntranceDescLeadingTo}} {{AreaNumber}} {{EntranceLocationPrefix}}
82 | {%if DungeonHex == "MountainsHex"%}
83 | {{MountainLocation}}.
84 | {%elif DungeonHex == "ForestHex"%}
85 | {{ForestLocation}}.
86 | {%elif DungeonHex == "PlainsHex"%}
87 | {{PlainsLocation}}.
88 | {%elif DungeonHex == "DesertHex"%}
89 | {{DesertLocation}}.
90 | {%else%}
91 | {{DefaultLocation}}.
92 | {%endif%}
93 | %>
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/swamps.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Swamps {
27 | Name! = Swamps
28 | Supplemental! @ [
29 | * The trees here are dark and dripping, leaning over the murky water.
30 | There are hissing noises all around, and the air is thick and humid.
31 |
32 | * These marshes are dark and thick. Rotting tree trunks are scattered
33 | around, some are floating, some are splintered in the black mud.
34 |
35 | * To walk here one must submerge deep in the swamp and suffer not only the wet
36 | and mud, but the occasional leech and water centipede.
37 |
38 | * The mud here is deep enough to sink a tall boot, and has boils that
39 | emit a vile scent of rot into the air.
40 |
41 | * Dense fog covers the wet ground here. It is difficult to tell what
42 | lies ahead or what lurks under your feet.
43 |
44 | * Tall and naked trees are all submerged in the muddy water. They
45 | are so dense and close to each other, making navigation and travel a
46 | challenge.
47 |
48 | * The land here is drier, easier to walk on and can provide a good camping site.
49 |
50 | * The area here is hilly and covered with soggy bushes growing between
51 | many small streams of watery mud.
52 |
53 | * The land here is mostly dry. A small lake with clear water provides a good
54 | opportunity for fishing and camping next to it.
55 |
56 | * Murky dark water covers most of the land here. Rotting tree trunks,
57 | partially submerged, provide the occasional improvised beam bridge
58 | for travel.
59 |
60 | * Large, entangled roots provide some solid ground to walk on in
61 | the desert of mud here.
62 |
63 | * In between murky puddles, mudcracked patches of land provide a thin
64 | dry crust to walk on. Few water bushes are sparsely scattered around.
65 |
66 | ]
67 |
68 | Location! @ [
69 | * on the muddy lands
70 | * on a dry patch of land
71 | * beside a stream of water
72 | ]
73 |
74 | Hideout! @ [
75 | * under a group of mounds in the area
76 | * under a large patch of rotting tree trunks
77 | * within the muddy hills
78 | * under the ruins of an old keep
79 | * under the ruins of an ancient settlement
80 | ]
81 | }
82 |
83 | SwampsRandomEncounterTable {
84 | [4..4 OtherEncounters!] @ SwampsRandomEncounter
85 | }
86 |
87 | SwampsHex (Hex) {
88 | Terrain! @ Swamps
89 | Monster! @ SwampsFeatureEncounter
90 | RandomEncounters @ SwampsRandomEncounterTable
91 | ExtensionTypeClass = "SwampsHexExtension"
92 | | Hex
93 | }
94 |
95 | SwampsRegion (Region) {
96 | Suffix @ [
97 | * Moors
98 | * Swamps
99 | * Pools
100 | * Wetlands
101 | ]
102 | | Region
103 | Weather? @@ [
104 | * TropicalWeatherContainer
105 | * NormalWeatherContainer
106 | ]
107 | [$minimum_tiles_per_swamps_region..$maximum_tiles_per_swamps_region Hexmap?] @ SwampsHex
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/base.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Populated {
27 | }
28 |
29 | SettlementLocation {
30 | SettlementName? = *Settlement.NamePart
31 | SettlementClass? = :Settlement.class
32 | SettlementUUID? = :Settlement.uuid
33 |
34 | RealmUUID? = :Realm.uuid
35 | RealmType? = :Realm.RealmType
36 | RealmName? = :Realm.Name
37 | Realm? = *Realm.Title
38 |
39 | DistrictUUID? = :District.uuid
40 | DistrictTitleNoun? = :District.TitleNoun
41 | DistrictTitleSuffix? = :District.TitleSuffix
42 | DistrictClass? = :District.class
43 |
44 | Breadcrumbs? ~ <%
45 |
46 | {{sandbox_breadcrumb()}}
47 | {{toc_breadcrumb()}}
48 | {{Realm}} >
49 | {{SettlementClass}} of {{SettlementName}} >
50 | {% if DistrictClass != "TownDistrict" and DistrictClass != "VillageDistrict" %}
51 | {{DistrictTitleNoun}} {{DistrictTitleSuffix}}
52 | {% endif %}
53 |
54 | %>
55 | }
56 |
57 | residency_classes = [
58 | * House
59 | * Stronghold
60 | ]
61 |
62 | Residency(Populated) { ^ $residency_classes
63 | NamePart = null
64 | Connector! @ [
65 | * is situated
66 | * is located
67 | * can be found
68 | ]
69 |
70 | Header! ~ "{%if Resident %}{{Resident.Name.First}}'s{% endif %} {%if Type %}{{Type.Name}}{% endif %}"
71 | Description! ~ <%
72 |
73 | The {{Prefix}} {{Type.Name}} of {{Resident.Name.Full}}
74 | %>
75 | Encounter! = "No"
76 | }
77 |
78 | settlement_classes = [
79 | *(x3) Village
80 | *(x2) Town
81 | *(x2) City
82 | ]
83 |
84 | IndexedSettlementEntity(IndexedEntity) {
85 | Name! = *Settlement.NamePart
86 | Class! = ""
87 | }
88 |
89 | Settlement(Populated) {
90 | ^ $settlement_classes
91 |
92 | # TODO: NamePart! @ $EnforcedSettlementList
93 | NamePart! @ $TownName
94 | Name! = "{{capitalize(class)}} of {{title(NamePart)}}"
95 |
96 | Header! = <%
97 | {{capitalize(class)}} of {{title(NamePart)}}
98 | %>
99 |
100 | Realm! = *Realm.Title
101 |
102 | $IndexRef @ IndexedSettlementEntity {
103 | Link = &HexLink
104 | Realm = "xx"
105 | Details = "{{Realm}}"
106 | Type = "hex"
107 | Class = &class
108 | Self = true
109 | Value = "{{Class}} of {{Name}}"
110 | Icon = "house"
111 | }
112 |
113 | Region! = *Region.Name
114 |
115 | RealmUUID = :Realm.uuid
116 |
117 | Breadcrumbs? ~ <%
118 |
119 | {{sandbox_breadcrumb()}}
120 | {{toc_breadcrumb()}}
121 | {{Realm}}
122 |
123 | %>
124 |
125 | $TocEntry @ TocEntry {
126 | Type = Settlement
127 | Title = &NamePart
128 | Class = &class
129 | UUID = &uuid
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/osr/npc_allocs.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | EntourageChiefCommander {
27 | ^ [
28 | * FighterLevel10
29 | * FighterLevel11
30 | * DwarfLevel10
31 | * ElfLevel9
32 | ]
33 | }
34 |
35 | EntourageCleric {
36 | ^ [
37 | * ClericLevel10
38 | * ClericLevel11
39 | ]
40 | }
41 |
42 | EntourageSage {
43 | ^ [
44 | * MagicuserLevel10
45 | * MagicuserLevel11
46 | * ElfLevel9
47 | ]
48 | }
49 |
50 | EntourageConfidant {
51 | ^ [
52 | * HalflingLevel7
53 | * DwarfLevel10
54 | * ElfLevel9
55 | * ThiefLevel10
56 | * ThiefLevel11
57 | ]
58 | }
59 |
60 | NobleRuler {
61 | ^ [
62 | * FighterLevel12
63 | * FighterLevel13
64 | * ElfLevel10
65 | * DwarfLevel11
66 | * HalflingLevel8
67 | ]
68 | }
69 |
70 | BishopRuler {
71 | ^ [
72 | * ClericLevel12
73 | * ClericLevel13
74 | ]
75 | }
76 |
77 | MonarchRuler {
78 | ^ [
79 | * FighterLevel12
80 | * FighterLevel13
81 | * ElfLevel10
82 | * DwarfLevel11
83 | * HalflingLevel8
84 | ]
85 | }
86 |
87 | WarexpertRuler {
88 | ^ [
89 | * FighterLevel12
90 | * FighterLevel13
91 | * ElfLevel10
92 | * DwarfLevel11
93 | * HalflingLevel8
94 | ]
95 | }
96 |
97 | NecromancerRuler {
98 | ^ [
99 | * MagicuserLevel12
100 | * MagicuserLevel13
101 | ]
102 | }
103 |
104 | CultLeader {
105 | ^ [
106 | * MagicuserLevel6
107 | * MagicuserLevel7
108 | * MagicuserLevel8
109 | * MagicuserLevel9
110 | * ClericLevel6
111 | * ClericLevel7
112 | * ClericLevel8
113 | * ClericLevel9
114 | ]
115 | }
116 |
117 | MilitiaLeader {
118 | ^ [
119 | * FighterLevel6
120 | * FighterLevel7
121 | * FighterLevel8
122 | * FighterLevel9
123 | * FighterLevel10
124 | ]
125 | }
126 |
127 | SyndicateLeader {
128 | ^ [
129 | * ThiefLevel6
130 | * ThiefLevel7
131 | * ThiefLevel8
132 | * ThiefLevel9
133 | * ThiefLevel10
134 | ]
135 | }
136 |
137 | ArenaJudge {
138 | ^ [
139 | * FighterLevel6
140 | * FighterLevel7
141 | * HalflingLevel6
142 | * HalflingLevel7
143 | ]
144 | }
145 |
146 | ArenaContestant {
147 | ^ [
148 | * FighterLevel3
149 | * FighterLevel4
150 | * FighterLevel5
151 | ]
152 | }
153 |
154 | CastleResident {
155 | ^ [
156 | * FighterLevel4
157 | * FighterLevel5
158 | * FighterLevel6
159 | * FighterLevel7
160 | * FighterLevel8
161 | * FighterLevel9
162 | * FighterLevel10
163 | * FighterLevel11
164 | ]
165 | }
166 |
167 | MagicAcademyMedium {
168 | ^ [
169 | * MagicuserLevel1
170 | * MagicuserLevel2
171 | ]
172 | }
173 |
174 | MagicLaboratoryAssistant {
175 | ^ [
176 | * MagicuserLevel1
177 | * MagicuserLevel2
178 | ]
179 | }
180 |
181 | WizardTowerResident {
182 | ^ [
183 | * MagicuserLevel11
184 | * MagicuserLevel12
185 | ]
186 | }
187 |
188 | PirateShipCaptain {
189 | ^ [
190 | * FighterLevel5
191 | * FighterLevel6
192 | * HalflingLevel5
193 | * HalflingLevel6
194 | * ElfLevel5
195 | * ElfLevel6
196 | ]
197 | }
198 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/helpers/config.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use std::{fs, path::PathBuf};
26 |
27 | use serde::{Deserialize, Serialize};
28 |
29 | use crate::app::HexrollTestbedApp;
30 |
31 | impl HexrollTestbedApp {
32 | pub fn save_settings(&self) -> std::io::Result<()> {
33 | let path = get_settings_path();
34 | if let Some(parent) = path.parent() {
35 | fs::create_dir_all(parent)?;
36 | }
37 | fs::write(path, serde_json::to_string_pretty(&self.config)?)?;
38 | Ok(())
39 | }
40 |
41 | pub fn update_mru_list(&mut self, filepath: &str) {
42 | if self.config.recently_opened.len() > 5 {
43 | self.config
44 | .recently_opened
45 | .drain(0..self.config.recently_opened.len() - 5);
46 | }
47 | self.config.recently_opened.retain(|p| p != filepath);
48 | self.config.recently_opened.push(filepath.to_owned());
49 | self.save_settings()
50 | .map_err(|e| log::warn!("Unable to save configuration. Error is {:#}", e))
51 | .ok();
52 | }
53 | }
54 | fn get_settings_path() -> PathBuf {
55 | match dirs::config_dir() {
56 | Some(mut path) => {
57 | path.push("hexroll3");
58 | path.push("settings.json");
59 | path
60 | }
61 | None => panic!("Could not determine the configuration directory."),
62 | }
63 | }
64 |
65 | pub fn load_settings() -> std::io::Result {
66 | let path = get_settings_path();
67 | log::info!("Configuration file path is {}", path.to_str().unwrap());
68 | let data = fs::read_to_string(path)?;
69 | let settings: TestbedConfig = serde_json::from_str(&data)?;
70 | Ok(settings)
71 | }
72 |
73 | #[derive(Serialize, Deserialize, Default)]
74 | pub struct ConfigSandboxState {
75 | pub last_uid: String,
76 | }
77 | use std::{
78 | collections::HashMap,
79 | ops::{Index, IndexMut},
80 | };
81 |
82 | #[derive(Serialize, Deserialize)]
83 | pub struct TestbedConfig {
84 | pub main_scroll_filepath: String,
85 | pub recently_opened: Vec,
86 | pub sandbox_state: HashMap,
87 | pub zoom_level: f32,
88 | }
89 |
90 | impl Default for TestbedConfig {
91 | fn default() -> Self {
92 | TestbedConfig {
93 | main_scroll_filepath: String::new(),
94 | recently_opened: Vec::new(),
95 | sandbox_state: HashMap::new(),
96 | zoom_level: 1.1,
97 | }
98 | }
99 | }
100 |
101 | impl Index<&str> for TestbedConfig {
102 | type Output = ConfigSandboxState;
103 |
104 | fn index(&self, index: &str) -> &Self::Output {
105 | &self.sandbox_state[index]
106 | }
107 | }
108 |
109 | impl IndexMut<&str> for TestbedConfig {
110 | fn index_mut(&mut self, index: &str) -> &mut Self::Output {
111 | if !self.sandbox_state.contains_key(index) {
112 | self.sandbox_state
113 | .insert(index.to_owned(), ConfigSandboxState::default());
114 | }
115 | self.sandbox_state.get_mut(index).expect("Key not found")
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/monsters/activities.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | MinionActivity {
27 | Dungeon! @ [
28 | * standing and chanting
29 | * preparing an altar for sacrifice
30 | * drinking from a ceremonial bowl
31 | * dancing in ecstasy
32 | * carving graffiti on the walls
33 | ]
34 |
35 | Wilderness! @ [
36 | * digging a grave
37 | * preparing an altar for sacrifice
38 | * skinning a dead animal
39 | * sharpening wooden stakes
40 | ]
41 | }
42 |
43 | HumanoidActivity {
44 | NumberAppearingRoaming = 1
45 | NumberAppearingLair = 1
46 | Dungeon! @ [
47 | * frantically searching for something
48 | * eating a piece of rotting meat
49 | * cleaning their weapons
50 | * alert and ready for combat
51 | * roasting a rat using {%if NumberAppearingRoaming>1%}their
52 | torches{%else%}its torch{%endif%}
53 | * trying to light some torches
54 | * looking through some rubble
55 | * hammering on the wall, trying to find something
56 | * fighting over a flask
57 | * carving graffiti on the walls
58 | ]
59 |
60 | Wilderness! @ [
61 | * preparing a rudimentary trap
62 | * trying to light a fire
63 | * digging a grave
64 | * skinning a dead animal
65 | * drumming and dancing in circles
66 | * teasing and toying with a trapped bunny
67 | * fighting over a flask
68 | * sharpening wooden stakes
69 | ]
70 | }
71 |
72 | OversizedHumanoidActivity {
73 | NumberAppearingRoaming = 1
74 | NumberAppearingLair = 1
75 | Dungeon! @ [
76 | * frantically searching for something
77 | * eating a piece of rotting meat
78 | * !jinja >
79 | cleaning {%if NumberAppearingRoaming>1%}their{%else%}its{%endif%} weapons
80 | * alert and ready for combat
81 | ]
82 |
83 | Wilderness! @ [
84 | * preparing a rudimentary trap
85 | * trying to start a fire
86 | * practicing javelin throwing
87 | * dragging a realistic statue of a humanoid with a rope
88 | * eating an over-sized fish
89 | * teasing and toying with a trapped fox
90 | * stomping a miserable villager
91 | * tracking someone or something
92 | ]
93 | }
94 |
95 | MimicActivity {
96 | Dungeon! @ [
97 | * appearing in the form of a treasure chest
98 | * appearing as a fake wooden door
99 | * appearing as a wooden table
100 | * appearing as a stone table
101 | * appearing as a stone pillar
102 | ]
103 | }
104 |
105 | VerminActivity {
106 | Dungeon! @ [
107 | * feasting over some rotting remains of a goblin
108 | * digging into what is left of a dead adventurer
109 | * dragging around torn pieces of flesh
110 | * feeding on some dead or dying adventurer
111 | * ripping an old torn sack of rotting potatoes
112 | * creeping back into a corner
113 | * trying to climb on a shadowed wall
114 | ]
115 |
116 | Wilderness! @ [
117 | * feasting over rotting remains of rats
118 | * digging into what is left of a dead adventurer
119 | * creeping into an opening in the ground
120 | * dragging around torn pieces of flesh
121 | * feeding on some dead or dying adventurer
122 | * ripping an old torn sack of rotting potatoes
123 | ]
124 | }
125 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/plains.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Plains {
27 | Name! = Plains
28 | Supplemental! @ [
29 | * There are several large craters in the green fields here. Something
30 | violent must have hit the ground from the sky in the past.
31 |
32 | * Crushed skulls and rusty swords are scattered around the hills here.
33 | You can almost hear the noises and screams of the ancient battlefield.
34 |
35 | * A tall stone tower fell and now lay crushed on the ground. A few small
36 | bunnies run and hide under its stone bricks.
37 |
38 | * A violent earthquake left the ground here broken with deep and narrow
39 | chasms. If listening carefully, one can hear eerie sounds coming from
40 | deep inside.
41 |
42 | * Several large geysers discharge boiling streams of water and vapour every few
43 | minutes.
44 |
45 | * A vast field of colourful flowers covers the shallow hills here. Butterflies
46 | and bees hop from flower to flower.
47 |
48 | * There’s a perfect circle of large stones, each standing tall above
49 | the ground. In the center, a shallow pit seems to have hosted a bonfire not
50 | too long ago.
51 |
52 | * A pile of stones form a pyramid of steps, tall enough to provide a better
53 | vantage point over the region. At the top, a rusty old sword is planted
54 | blade first inside the ground.
55 |
56 | * The grasslands here are lush and green, but every now and then there's a
57 | perfectly dug cubic pit in the mud, much like a fresh and ready grave.
58 |
59 | * Giant iron shrapnel, as big as tree trunks, erect from the ground every
60 | hundred feet or so. It is as if they fell down from the sky.
61 |
62 | * Carcasses of farm animals are scattered around, some in worse shape than
63 | others. Swarms of flies are hovering over them like dark veils in the wind.
64 |
65 | * A small lake sits between the lush green hills here. At night, countless
66 | mysterious forms glow an eerie blue light in its deep water.
67 |
68 | * A small lake sits between the black rocky hills here, its water darker
69 | than night. Some dead fish are floating near its banks.
70 | ]
71 |
72 | Location! @ [
73 | * in a valley
74 | * at the top of a hill
75 | * between two hills
76 | * on a hill’s slope
77 | * on the terraced hills
78 | * in the grasslands
79 | * atop a rocky hill
80 | ]
81 |
82 | Hideout! @ [
83 | * behind a waterfall
84 | * under the ruins of an old fortress
85 | * inside an oak
86 | ]
87 | }
88 |
89 | PlainsRandomEncounterTable {
90 | [4..4 OtherEncounters!] @ PlainsRandomEncounter
91 | }
92 |
93 | PlainsHex (Hex) {
94 | Terrain! @ Plains
95 | Monster! @ PlainsFeatureEncounter
96 | RandomEncounters @ PlainsRandomEncounterTable
97 | ExtensionTypeClass = "PlainsHexExtension"
98 | | Hex
99 | }
100 |
101 | PlainsRegion (Region) {
102 | Suffix @ [
103 | * Plains
104 | * Prairie
105 | * Steppe
106 | * Meadows
107 | * Fields
108 | ]
109 | | Region
110 | Weather? @ NormalWeatherContainer
111 | [$minimum_tiles_per_plains_region..$maximum_tiles_per_plains_region Hexmap?] @ PlainsHex
112 | }
113 |
114 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/settlements/town.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | TownDistrict(District) {
27 | Title = Town District
28 | CostFactor = 1.0
29 | << Advert
30 | << LocalRumor
31 | [12..34 shops!] @ TownShops
32 | | District
33 | }
34 |
35 | Town(Settlement) {
36 | | Settlement
37 |
38 | Title! = "town of {{title(NamePart)}}"
39 |
40 | Prefix! = ""
41 |
42 | PopulationMultiplier! @ 2d4+1
43 | Connector! @ [
44 | * stands secure on high grounds
45 | * sits behind a wall
46 | ]
47 |
48 | Castle @ Castle
49 | District? @ TownDistrict
50 | Population? = "{{int(District.Population) * PopulationMultiplier}}"
51 | GAlignment @ [
52 | *(x5) Lawful
53 | *(x1) Neutral
54 | ]
55 | [2..3 Guards?] @ Guard {
56 | Alignment = &GAlignment
57 | HostingEntity := &uuid
58 | Profession = "guard"
59 | URLExt = "/location/{{HostingEntity}}/npc/{{uuid}}"
60 | }
61 |
62 | Overview? ~ <%
63 |
64 | Population: {{Population}} townsfolk
65 |
66 | {{Castle.Desc}}
67 | Town Shops & Services
68 | {{District.Index}}
69 | {% if Guards %}
70 | Guards
71 | {% for g in Guards %}
72 |
73 |
74 | {{reroller(g, "", False)}} {{g.Description}}
75 | {{g.Stats}}
76 | {% if g.Association %}
77 |
78 | {{g.Association}}
79 |
80 | {% endif %}
81 |
82 |
83 | {% endfor %}
84 | {% endif %}
85 | %>
86 |
87 | Supplemental! = ""
88 |
89 | Brief? = <%
90 | {{Overview}}
91 | %>
92 |
93 |
95 | %metadata>
96 |
97 | {{capitalize(Title)}} from {{Realm}}
99 |
100 | {{NamePart}}
101 | {{Breadcrumbs}}
102 |
103 | %header>
104 |
105 |
108 | }
109 |
110 | TownShops {
111 | ^ [
112 | * Bakery
113 | * GeneralGoods
114 | * Bookstore
115 | * Grocer
116 | * PetShop
117 | * Herbalist
118 | * Jeweler
119 | * Bunkhouse
120 | * Carpenter
121 | * Stables
122 | *(x3) ArmorWeapons
123 | * Hatter
124 | * Butchery
125 | * Clothing
126 | * Blacksmith
127 | * Barber
128 | * Liquor
129 | * Craft
130 | * Music
131 | * Salon
132 | * Spice
133 | * Bathhouse
134 | * AnimalSupplies
135 | * Brewery
136 | * Distillery
137 | * Flower
138 | * Cobbler
139 | * Tinkerer
140 | * Weaver
141 | * Veterinarian
142 | * Brothel
143 | *(x0) Bank
144 | * GlassBlower
145 | * Leatherworker
146 | * Physician
147 | * Barracks
148 | * School
149 | * Daycare
150 | * Library
151 | * Lawyer
152 | * TinWorker
153 | * FishMarket
154 | * Tailor
155 | * Prison
156 | * PostOffice
157 | * Mill
158 | * Smokehouse
159 | * GameShop
160 | * Witch
161 | * PrintingPress
162 | * AnimalPound
163 | * Mortician
164 | * Tanner
165 | * Registry
166 | * TradePost
167 | * VehicleMaker
168 | * FortuneTeller
169 | * Matchmaker
170 | ]
171 | }
172 |
173 |
--------------------------------------------------------------------------------
/hexroll3-scroll/tests/renderer.rs:
--------------------------------------------------------------------------------
1 | mod utils;
2 |
3 | #[cfg(test)]
4 | mod renderer {
5 | use hexroll3_scroll::renderer::render_entity;
6 | use minijinja::Environment;
7 |
8 | use hexroll3_scroll::instance::*;
9 | use hexroll3_scroll::renderer_env::*;
10 |
11 | use crate::utils::create_tempfile;
12 |
13 | fn render(template: &str) -> String {
14 | let mut env = Environment::new();
15 | let instance = SandboxInstance::new();
16 | prepare_renderer(&mut env, &instance);
17 | env.add_template("test", template).unwrap();
18 | let tmpl = env.get_template("test").unwrap();
19 | tmpl.render(serde_json::json!({})).unwrap()
20 | }
21 |
22 | #[test]
23 | fn test_func_empty() {
24 | let result = render("{{note_button('test')}}");
25 | assert_eq!(result, "");
26 | }
27 |
28 | #[test]
29 | fn test_func_stable_dice() {
30 | let result_a = render("{{stable_dice('1d100','uuid',1)}}");
31 | let result_b = render("{{stable_dice('1d100','uuid',1)}}");
32 | assert_eq!(result_a, result_b);
33 | }
34 |
35 | #[test]
36 | fn test_func_max() {
37 | assert_eq!(render("{{max(5,1)}}"), "5");
38 | assert_eq!(render("{{max(-10,1)}}"), "1");
39 | }
40 |
41 | #[test]
42 | fn test_func_plural() {
43 | assert_eq!(render("{{plural(3,'wraith')}}"), "wraithes");
44 | assert_eq!(render("{{plural(4,'orc')}}"), "orcs");
45 | assert_eq!(render("{{plural(5,'wolf')}}"), "wolves");
46 | assert_eq!(render("{{plural(6,'fly')}}"), "flies");
47 | assert_eq!(render("{{plural(1,'orc')}}"), "orc");
48 | }
49 |
50 | #[test]
51 | fn test_func_length() {
52 | assert_eq!(render("{{length('zero')}}"), "0");
53 | assert_eq!(render("{{length([1,2,3])}}"), "3");
54 | }
55 |
56 | #[test]
57 | fn test_func_trim() {
58 | assert_eq!(render("{{trim(' core ')}}"), "core");
59 | assert_eq!(render("{{trim('core ')}}"), "core");
60 | assert_eq!(render("{{trim(' core')}}"), "core");
61 | assert_eq!(render("{{trim(' ')}}"), "");
62 | }
63 |
64 | #[test]
65 | fn test_func_articlize() {
66 | assert_eq!(render("{{articlize('sword')}}"), "a sword");
67 | assert_eq!(render("{{articlize('axe')}}"), "an axe");
68 | assert_eq!(render("{{articlize('swords')}}"), "swords");
69 | assert_eq!(render("{{articlize('axes')}}"), "axes");
70 | }
71 |
72 | #[test]
73 | fn test_func_unique() {
74 | assert_eq!(
75 | render("{{unique([{'a':'a'},{'a':'a'}],'a')}}"),
76 | "[{\"a\": \"a\"}]"
77 | );
78 | }
79 |
80 | #[test]
81 | fn test_func_capitalize() {
82 | assert_eq!(render("{{capitalize('fighter')}}"), "Fighter");
83 | }
84 |
85 | #[test]
86 | fn test_func_currency() {
87 | assert_eq!(render("{{currency(1000)}}"), "1,000 gp");
88 | assert_eq!(render("{{currency(3.5)}}"), "3 gp");
89 | assert_eq!(render("{{currency(0.5)}}"), "5 sp");
90 | assert_eq!(render("{{currency(0.05)}}"), "5 cp");
91 | }
92 |
93 | #[test]
94 | fn test_func_first() {
95 | assert_eq!(render("{{first([1,2,3])}}"), "1");
96 | }
97 |
98 | #[test]
99 | fn test_recursive_render() {
100 | let mut instance = SandboxInstance::new();
101 | instance.parse_buffer(
102 | "
103 | Hex {
104 | Description! = <%foo%>
105 | realm = *Realm.Name
106 | }
107 |
108 | Region {
109 | [3..3 hexes] @ Hex
110 | foo = bar
111 | xyz = `foo`
112 | }
113 |
114 | Realm {
115 | [3..3 regions] @ Region
116 | name! = \"bar\"
117 | }
118 |
119 | main {
120 | realm @ Realm
121 | hexes << Hex
122 | output! ~ <%{{realm.name}}%>
123 | }
124 | ",
125 | );
126 | let tmp = create_tempfile();
127 | instance.create(tmp.path().to_str().unwrap()).unwrap();
128 | instance
129 | .repo
130 | .inspect(|tx| {
131 | let main = tx.fetch("root").unwrap();
132 | Ok(main.clone())
133 | })
134 | .and_then(|realm_uid| instance.repo.load(&realm_uid.as_str().unwrap()))
135 | .and_then(|main| {
136 | let rendered_result = instance
137 | .repo
138 | .inspect(|tx| render_entity(&instance, tx, &main, false))
139 | .unwrap();
140 | assert_eq!(rendered_result["output"], "bar");
141 | Ok(())
142 | });
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/forest.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Forest {
27 | Name! = Forest
28 | Statue @ [
29 | * warrior
30 | * king
31 | * queen
32 | ]
33 | Skeleton @ [
34 | * dragon, as if sleeping peacefully
35 | * giant humanoid, lying face down
36 | ]
37 | Supplemental! @ [
38 | * Giant red, purple and blue mushrooms grow beside the trees here, their
39 | colors are vibrant and bright, much like gemstones.
40 |
41 | * The trees here are naked and twisted. Their branches reach down like bony
42 | claws. Was this place cursed in days long gone?
43 |
44 | * So big and tall are the trees here. Their tops are almost hidden by the
45 | dense mist. Their trunks are as wide as a hut. Some of them have planks
46 | of wood attached, forming a ladder.
47 |
48 | * A huge, lush tree is standing in a clearing here, covered with colourful
49 | flowers and holding a sweet berry inside. Birds fly cheerfully around it.
50 |
51 | * Moss covered ruins of an ancient stone structure emerge from within the
52 | vegetation. Carvings of spirals and swirls decorate some of the larger
53 | stones.
54 |
55 | * The forest is dense and dark here, but countless clusters of
56 | phosphorescent fungi are growing near the base of the trunks, creating a
57 | luminous colourful glow above the ground.
58 |
59 | * Dense ivy and vegetation cover an old skeleton of a {{Skeleton}}
60 | in a clearing surrounded by the trees.
61 |
62 | * Ropes tangle down from the branches here. On some of them, human-sized
63 | straw-made figures are hanging by their canvas covered heads.
64 |
65 | * Dozens of giant dead tree trunks are laying on the ground here, covered
66 | with moss and undergrowth. Some of them seem to have a face, with a
67 | frozen expression of agony.
68 |
69 | * An oversized statue of {{articlize(Statue)}} holding a sword
70 | against the ground stands proudly in a clearing here.
71 | Fresh flowers were recently placed near its base.
72 |
73 | * There's a stream of clear water here, flowing gently between the woods,
74 | over the smooth rock ground.
75 |
76 | * Colourful flowers, berry shrubs and mushrooms grow under the woods
77 | here, dense enough to almost entirely cover a large number of human-like bones.
78 |
79 | * A small pond sits between the woods here. At night, countless
80 | mysterious forms glow an eerie purple light deep in the water.
81 |
82 | ]
83 | Location! @ [
84 | * near a water stream
85 | * next to a clearing
86 | * deep in the woods
87 | * where the woods meet a large hill
88 | ]
89 | Hideout! @ [
90 | * under the ruins of an ancient city
91 | * in one of the tree covered hills
92 | * near an abandoned stronghold, deep in the woods
93 | ]
94 | }
95 |
96 | ForestRandomEncounterTable {
97 | [4..4 OtherEncounters!] @ ForestRandomEncounter
98 | }
99 |
100 | ForestHex (Hex) {
101 | Terrain! @ Forest
102 | Monster! @ ForestFeatureEncounter
103 | RandomEncounters @ ForestRandomEncounterTable
104 | ExtensionTypeClass = "ForestHexExtension"
105 | | Hex
106 | }
107 |
108 | ForestRegion (Region) {
109 | Suffix @ [
110 | * Forest
111 | * Woods
112 | * Woodlands
113 | * Timberlands
114 | * Grove
115 | ]
116 | | Region
117 | Weather? @ NormalWeatherContainer
118 | [$minimum_tiles_per_forest_region..$maximum_tiles_per_forest_region Hexmap?] @ ForestHex
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/hooks/quests/delivery.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DeliveryQuestAdvert(Advert) {
27 | QuestFolk = none
28 | QuestLink = none
29 | QuestDestination = none
30 | | Advert
31 | }
32 |
33 | DeliveryQuestRumor(LocalRumor) {
34 | QuestFolk = none
35 | QuestLink = none
36 | QuestObject = none
37 | QuestDestination = none
38 | | LocalRumor
39 | }
40 |
41 | DeliveryQuest(Quest) {
42 |
43 | Destination % Character
44 |
45 | Reward @ [
46 | * 500
47 | * 600
48 | * 700
49 | ]
50 |
51 | PackagePrefix @ [
52 | * sealed
53 | * mysterious
54 | ]
55 |
56 | PackageObject @ [
57 | * bottle
58 | * box
59 | * chest
60 | * crate
61 | * casket
62 | ]
63 |
64 | Package = <%
65 | a {{PackagePrefix}} {{PackageObject}}
66 | %>
67 |
68 | Description! ~ <%
69 | {% if Destination %}
70 | Looking for someone to deliver {{Package}} to
71 | {{Destination.Name.Full}}
72 | {%if Destination.SettlementName and Destination.SettlementName%}in
73 | {{capitalize(Destination.SettlementName)}}.{%endif%}
74 | -
75 | Reward is {{currency(Reward)}}
76 |
77 | {% endif %}
78 | %>
79 |
80 | Questgiver = :SettlementLocation.Owner
81 |
82 | QuestgiverLocationUUID = :SettlementLocation.uuid
83 |
84 | Advert @ DeliveryQuestAdvert {
85 | QuestFolk = *Questgiver
86 | QuestLink = &QuestgiverLocationUUID
87 | QuestDestination = *Destination
88 | Details @ [
89 | * “Job offer! I have a package to deliver
90 | {%if QuestDestination.SettlementName %}in
91 | {{capitalize(QuestDestination.SettlementName)}}{%endif%}.
92 | Payment guaranteed at destination upon delivery.
93 | Yours,
94 |
95 | {{QuestFolk.Name.Full}}”
96 | * “Travelling{%if QuestDestination.SettlementName%} to
97 | {{capitalize(QuestDestination.SettlementName)}}{%endif%}?
98 | I will pay anyone carrying a package for me.
99 | Yours,
100 |
101 | {{QuestFolk.Name.Full}}”
102 | * {%if QuestDestination.SettlementName and QuestDestination.SettlementName%}
103 | Heading to
104 | {{capitalize(QuestDestination.SettlementName)}}?
105 | {%else%}Heading away?{%endif%}
106 | Payment guaranteed to a trusty courier. Ask for
107 |
108 | {{QuestFolk.Name.Full}}”
109 | ]
110 | }
111 |
112 | Rumor @ DeliveryQuestRumor {
113 | QuestFolk = *Questgiver
114 | QuestLink = &QuestgiverLocationUUID
115 | QuestObject = &PackageObject
116 | QuestDestination = *Destination
117 | Details @ [
118 | *
119 | {{QuestFolk.Name.Full}}
120 | is willing to pay well for a delivery job.
121 | *
122 | {{QuestFolk.Name.Full}}
123 | {{QuestFolk.Gender.Possession}} a {{QuestObject}}
124 | {{QuestFolk.Gender.PronounSubject}} would like delivered
125 | {%if QuestDestination.SettlementName and QuestDestination.SettlementName%}to
126 | {{capitalize(QuestDestination.SettlementName)}}{%endif%}
127 | ]
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/dungeons/debris.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | DungeonDebris {
27 | Debris2Location @ [
28 | * next to it
29 | * spread all over the place
30 | ]
31 |
32 | Debris1 @ [
33 | * an old, ripped backpack
34 | * a used flask of oil
35 | * a torn quiver
36 | * a rusty short sword
37 | * a burnt torch
38 | * an old broken mirror
39 | * a wicker basket
40 | * a torn hide armor
41 | * a small empty bottle
42 | * a broken wooden box
43 | * an empty drinking flask
44 | * a rusted pile of chains
45 | * a dirty stuffed doll
46 | * a pile of cockroaches
47 | * a figure made of sticks and twine
48 | * several large decorative pillows
49 | * a nest of straw and blankets
50 | * many candles, burnt out in a pile of wax
51 | * a ring of fist-sized stones
52 | * a broken talisman
53 | * a torn cloak
54 | * a spotted mushroom
55 | * a collection of offerings, long ago forgotten
56 | * several iron bars, each about a foot in length
57 | * a bouquet of flowers
58 | * a muddy puddle
59 | * knitting needles and yarn
60 | * a pile of papers
61 | * the rotting hide of a large animal
62 | * a pile of gravel and small stones
63 | * three large bird skulls
64 | * the skull of a strange animal
65 | * a carved idol
66 | * a pile of bones
67 | * a bundle of sticks
68 | * a broken table
69 | * a tangle of vines
70 | * many shoes and boots, piled together
71 | * a tall pointy hat
72 | * a boot, skeletal foot still inside
73 | * a bucket of guts
74 | * a pouch of dice
75 | * feathers
76 | * a blanket, laid out and covering something small
77 | * a broken music box
78 | * vomit
79 | * a small bell
80 | * an eyeball in a sealed jar
81 | * a clear puddle
82 | * a stagnant puddle
83 | * a shattered sword
84 | * an empty cage with the bars bent out
85 | * a smashed lyre
86 | ]
87 | Debris2 @ [
88 | * broken pieces of wood
89 | * torn pieces of clothing
90 | * rotting remains of food
91 | * dry remains of food
92 | * ripped pieces of old rope
93 | * traces of fur
94 | * garlic leftovers
95 | * hundred tiny bones
96 | * feathers
97 | * cube shaped stones
98 | * shreded pieces of clothing
99 | * shreded pages of a book
100 | * shreded pieces of a map
101 | * small mounds of ashes
102 | * dried flowers
103 | * brightly colored leaves
104 | * tiny mushrooms
105 | * thick spiderwebs
106 | * shattered pieces of glass
107 | * marbles
108 | * dead mice
109 | * seeds
110 | * carved figurines
111 | * damp leaves
112 | * small stones with runes etchings
113 | * broken arrows
114 | * small iron cages
115 | ]
116 | Description! @ [
117 | * There’s also {{Debris1}} {{Debris1Location}} and some {{Debris2}}
118 | {{Debris2Location}}.
119 | * {{capitalize(Debris2)}} litter the area.
120 | * {{capitalize(Debris1)}} can be found {{Debris1Location}}.
121 | ]
122 | }
123 |
124 | RoomDebris (DungeonDebris) {
125 | Debris1Location @ [
126 | * in the far corner
127 | * in the near corner
128 | * near the wall on the left
129 | * near the wall on the right
130 | * near the wall on the far end
131 | * in an alcove
132 | * on an altar
133 | * below an arch
134 | * in a large basin
135 | ]
136 | | DungeonDebris
137 | }
138 |
139 | CaveDebris (DungeonDebris) {
140 | Debris1Location @ [
141 | * in the far corner
142 | * in the near corner
143 | * near the wall on the left
144 | * near the wall on the right
145 | * near the wall on the far end
146 | * in a large basin
147 | ]
148 | | DungeonDebris
149 | }
150 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/tundra.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Tundra {
27 | Name! = Tundra
28 | Direction @ [
29 | * north
30 | * south
31 | * north-east
32 | * south-east
33 | * north-west
34 | * south-west
35 | ]
36 | Supplemental! @ [
37 | * The ice here is blindingly bright in daylight. It is almost too much
38 | to bear for those who are accustomed to the darkness of the depths.
39 |
40 | * The ice plateaus here are mostly opaque, but every now and then it
41 | reveals ominous shadows of creatures swimming or perhaps lurking underneath.
42 |
43 | * In the middle of the icy wasteland, a large round snowy rock emerges from
44 | the snow. Easy enough to climb on and perhaps find some shelter from
45 | the cold.
46 |
47 | * The ice here is thick but broken and cracked. It is a challenge to find
48 | a safe path to follow, and quite often, a leap is required to move about.
49 |
50 | * The snow here is soft to walk on. Too soft. In some places, taking the
51 | next step means falling down deep into a sinkhole.
52 |
53 | * Gusts of wind swirl the soft snow in the air, making it difficult to
54 | walk safely and comfortably as it obscures the vision and hits any
55 | exposed skin with a freezing sting.
56 |
57 | * Vast plateaus of ice stretch in all directions, feature-less and
58 | monotonous. Navigating is difficult without any distant landmarks.
59 |
60 | * Tall pillars of ice emerge from the snow here, as if water has risen
61 | from the ground, only to be captured by the frost.
62 |
63 | * The snow here is riddled with giant craters. Something with
64 | much force and velocity must have fallen from the sky.
65 |
66 | * The ruins of a giant wall of ice can be seen in the distance.
67 | The formation is unnatural, unmaintained, and impressive.
68 |
69 | * There are caverns of translucent ice here. Frozen creatures
70 | and ancient artifacts could be spotted if walking inside them.
71 |
72 | * There are several deep frozen chasms here, with unnatural thin
73 | bridges providing the only way to cross.
74 |
75 | * There's a glacier here, almost impossible to climb through, with
76 | fragile excavated tunnels dug in it to provide an unsafe passage.
77 |
78 | * There's a large ice wall here, forming a natural dam, blocking
79 | a large body of icy water from flooding the area.
80 |
81 | * A frozen waterfall is the only way to march {{Direction}} from here
82 | and will require climbing or rappelling to cross it.
83 |
84 | * Several dome shaped shelters are scattered on the snowy planes
85 | here, providing a convenient hideout from the cold.
86 |
87 | ]
88 | Location! @ [
89 | * on the icy plateau
90 | * near a hot spring
91 | * between two snowy giant boulders
92 | ]
93 |
94 | Hideout! @ [
95 | * under the ruins of an ancient temple
96 | * underground
97 | * near an abandoned ritual site
98 | * under the ruins of an ancient settlement
99 | * inside an ancient iceberg
100 | ]
101 | }
102 |
103 | TundraRandomEncounterTable {
104 | [4..4 OtherEncounters!] @ TundraRandomEncounter
105 | }
106 |
107 | TundraHex (Hex) {
108 | Terrain! @ Tundra
109 | Monster! @ TundraFeatureEncounter
110 | RandomEncounters @ TundraRandomEncounterTable
111 | ExtensionTypeClass = "TundraHexExtension"
112 | | Hex
113 | }
114 |
115 | TundraRegion (Region) {
116 | Suffix @ [
117 | * Tundra
118 | * Wastelands
119 | * Barrens
120 | * Wastes
121 | * Icefields
122 | * Snowlands
123 | ]
124 | | Region
125 | Weather? @ ArcticWeatherContainer
126 | [$minimum_tiles_per_tundra_region..$maximum_tiles_per_tundra_region Hexmap?] @ TundraHex
127 | }
128 |
129 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/npc/gender.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Gender { ^ [ *(x50) Female
27 | *(x50) Male
28 | *(x01) Fluid ]
29 | }
30 |
31 | GenderFeature {
32 | HairColor! @ [ * red
33 | * blonde
34 | * black
35 | * brown
36 | * almond
37 | * white ]
38 |
39 | HairLength! @ [ * long
40 | * short ]
41 |
42 | }
43 |
44 | MasculineFeature (GenderFeature) {
45 | | GenderFeature
46 | Feature! @ [ *(x3) a {{HairLength}} {{HairColor}} beard
47 | *(x3) a heavy {{HairColor}} beard
48 | *(x5) short {{HairColor}} hair
49 | *(x5) thin {{HairColor}} hair
50 | *(x1) no hair
51 | *(x1) thick bushy eyebrows
52 | *(x1) a strong, prominent chin
53 | *(x1) a square jaw
54 | *(x1) a two day stubble
55 | *(x1) a scruff
56 | *(x1) a thick moustache
57 | *(x1) a goatee beard
58 | *(x1) a frowny expression
59 | *(x1) a long smoking pipe in his mouth
60 | *(x1) a big round belly
61 | *(x1) a deep, commanding voice
62 | *(x1) a hoarse voice
63 | *(x1) a hairy chest
64 | *(x1) a chiseled chin
65 | *(x1) thick sideburns
66 | *(x1) patchy beard
67 | *(x1) thin greying hair ]
68 | }
69 |
70 | FeminineFeature (GenderFeature) {
71 | | GenderFeature
72 | HairTrait @ [ * silky
73 | * flowing
74 | * curly
75 | * wavy
76 | * braided
77 | * wild
78 | * well-brushed ]
79 | Feature! @ [ *(x3) {{HairLength}} and {{HairTrait}} {{HairColor}} hair
80 | *(x3) {{HairLength}} {{HairColor}} hair
81 | *(x3) {{HairTrait}} {{HairColor}} hair
82 | *(x3) {{HairLength}} {{HairColor}} pony-tail
83 | *(x3) soft gentle features
84 | *(x3) delicate features
85 | *(x3) soft voice
86 | *(x3) warm voice
87 | *(x3) painted skin decorations
88 | *(x3) delicate makeup
89 | *(x3) heavy makeup
90 | *(x2) full lips
91 | *(x1) a beauty mark above the lips
92 | *(x1) ample breasts
93 | *(x1) ample hips ]
94 | }
95 |
96 | Male (Gender) {
97 | | Gender
98 | NameClass! = "NameMale"
99 | PronounSubject! = < he >
100 | PronounObject! = < him >
101 | PronounPossessive! = < his >
102 | Possession! = < has >
103 | BeVerb! = < is >
104 | GenderFeature! @@ [
105 | *(x100) MasculineFeature
106 | *(x1) FeminineFeature ]
107 | Feature! = < {{GenderFeature.Feature}} >
108 | }
109 |
110 | Female (Gender) {
111 | | Gender
112 | NameClass! = "NameFemale"
113 | PronounSubject! = < she >
114 | PronounObject! = < her >
115 | PronounPossessive! = < her >
116 | Possession! = < has >
117 | BeVerb! = < is >
118 | GenderFeature! @@ [
119 | *(x1) MasculineFeature
120 | *(x100) FeminineFeature ]
121 | Feature! = < {{GenderFeature.Feature}} >
122 | }
123 |
124 | Fluid (Gender) {
125 | | Gender
126 | NameClass! = "NameFluid"
127 | PronounSubject! = < they >
128 | PronounObject! = < them >
129 | PronounPossessive! = < their >
130 | Possession! = < have >
131 | BeVerb! = < are >
132 | GenderFeature! @@ [
133 | *(x1) MasculineFeature
134 | *(x1) FeminineFeature ]
135 | Feature! = < {{GenderFeature.Feature}} >
136 | }
137 |
--------------------------------------------------------------------------------
/hexroll3-testbed/src/app/views/top_app_bar.rs:
--------------------------------------------------------------------------------
1 | /*
2 | // Copyright (C) 2020-2025 Pen, Dice & Paper
3 | //
4 | // This program is dual-licensed under the following terms:
5 | //
6 | // Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | // This program is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU Affero General Public License as
9 | // published by the Free Software Foundation, either version 3 of the
10 | // License, or (at your option) any later version.
11 | //
12 | // This program is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU Affero General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU Affero General Public License
18 | // along with this program. If not, see .
19 | //
20 | // Option 2: Commercial License
21 | // For commercial use, you are required to obtain a separate commercial
22 | // license. Please contact ithai at pendicepaper.com
23 | // for more information about commercial licensing terms.
24 | */
25 | use egui::{Color32, Context, CursorIcon, Ui};
26 |
27 | use crate::app::HexrollTestbedApp;
28 |
29 | impl HexrollTestbedApp {
30 | pub fn top_app_bar(&mut self, ctx: &Context, ui: &mut Ui) {
31 | ui.horizontal_centered(|ui| {
32 | ui.add(
33 | egui::Image::new(egui::include_image!("../../../assets/icon.png")).rounding(5.0),
34 | );
35 | ui.heading("HEXROLL3 / Testbed");
36 | ui.label(egui::RichText::new("Theme").monospace());
37 | egui::global_theme_preference_buttons(ui);
38 | ui.add_space(10.0);
39 | ui.separator();
40 | ui.add_space(10.0);
41 | ui.label("Scroll file path:");
42 | ui.scope(|ui| {
43 | if self.scroll_in_filepath_is_valid {
44 | ui.style_mut().visuals.override_text_color = Some(Color32::LIGHT_BLUE);
45 | } else {
46 | ui.style_mut().visuals.override_text_color = Some(Color32::LIGHT_RED);
47 | }
48 | if ui
49 | .text_edit_singleline(&mut self.config.main_scroll_filepath)
50 | .changed()
51 | {
52 | self.scroll_in_filepath_is_valid = false;
53 | self.save_settings()
54 | .map_err(|e| log::warn!("Unable to save configuration. Error is {:#}", e))
55 | .ok();
56 | }
57 | });
58 | if !self.scroll_in_filepath_is_valid {
59 | ui.scope(|ui| {
60 | ui.style_mut().visuals.override_text_color = Some(Color32::LIGHT_RED);
61 | ui.label("Click");
62 | if ui.button("Test").clicked() {
63 | self.scroll_in_filepath_is_valid = HexrollTestbedApp::test_scroll_filepath(
64 | &self.config.main_scroll_filepath,
65 | );
66 | }
67 | ui.label("to verify the scroll. Check the trace logs for errors.");
68 | });
69 | }
70 | if self.instance.is_some() && self.scroll_in_filepath_is_valid {
71 | ui.menu_button("⬣", |ui| {
72 | self.open_or_roll_fragment(ui);
73 | ui.separator();
74 | if ui.button("Reload Scroll").clicked() {
75 | self.instance
76 | .as_mut()
77 | .unwrap()
78 | .with_scroll((&self.config.main_scroll_filepath).into())
79 | .expect("That's odd!");
80 | }
81 | });
82 | }
83 | if let Some(mut path) = self.file.take_selected() {
84 | match self.file.mode() {
85 | egui_file_dialog::DialogMode::SaveFile => {
86 | ctx.set_cursor_icon(CursorIcon::Wait);
87 | if path.set_extension("h3")
88 | && self.roll_new_sandbox(path.to_str().unwrap()).is_err()
89 | {
90 | self.instance = None;
91 | }
92 | ctx.set_cursor_icon(CursorIcon::Default);
93 | }
94 | egui_file_dialog::DialogMode::SelectFile => {
95 | self.open_existing_sandbox(path.to_str().unwrap())
96 | .map_err(|_| self.instance = None)
97 | .ok();
98 | }
99 | _ => {}
100 | }
101 | }
102 | });
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/jungle.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Jungle {
27 | Name! = Jungle
28 | Statue @ [
29 | * angry demon
30 | * giant sleeping monkey
31 | * three robed priestesses
32 | ]
33 | Skeleton @ [
34 | * dragon, as if sleeping peacefully
35 | * giant humanoid, lying face down
36 | ]
37 | Supplemental! @ [
38 | * Droplets of water fall down from the oversized leaves of the tall trees here.
39 | Ancient stone made totem-like pillars emerge from the undergrowth, each
40 | with a different carving of an animal.
41 |
42 | * This part of the jungle has a very dense undergrowth of bushes and vines.
43 | A sword or a machete is likely needed to carve the way forward.
44 |
45 | * The trees here are naked and twisted. Their branches reach down like bony
46 | claws. Was this place cursed in days long gone?
47 |
48 | * The trees here are big and tall. Their tops are almost hidden by the
49 | dense mist. Their trunks are as wide as a hut. Some of them have planks
50 | of wood attached, forming a ladder.
51 |
52 | * A huge, lush tree is standing in a clearing here, covered with colourful
53 | flowers and holding a sweet berry inside. Birds fly cheerfully around it.
54 |
55 | * Moss covered ruins of an ancient stone structure emerge from within the
56 | vegetation. Carvings of spirals and swirls decorate some of the larger
57 | stones.
58 |
59 | * The forest is dense and dark here, but countless clusters of
60 | phosphorescent fungi are growing near the base of the trunks, creating a
61 | luminous colourful glow above the ground.
62 |
63 | * Dense ivy and vegetation cover an old skeleton of a {{Skeleton}}
64 | in a clearing surrounded by the jungle trees.
65 |
66 | * Ropes tangle down the branches here. On some, straw-made figures
67 | of humanoids are hanging down by their canvas covered heads.
68 |
69 | * Dozens of giant dead tree trunks are laying on the ground here, covered
70 | with moss and undergrowth. Some of them seem to have a face, with a
71 | frozen expression of agony.
72 |
73 | * An oversized statue of {{articlize(Statue)}} holding a sword
74 | against the ground stands proudly in a clearing here.
75 | Fresh flowers were recently placed near its base.
76 |
77 | * There's a stream of clear water here, flowing gently between the jungle trees,
78 | over the smooth rock ground.
79 |
80 | * Colourful plants and mushrooms grow within the undergrowth
81 | here - almost densely enough to hide the bones of an alien creature.
82 |
83 | * A small pond sits between the jungle trees here. At night, countless
84 | mysterious forms glow an eerie purple light deep in the water.
85 |
86 | ]
87 | Location! @ [
88 | * near a water stream
89 | * next to a clearing
90 | * deep in the jungle
91 | * where the jungle meets a tall mountain
92 | ]
93 | Hideout! @ [
94 | * under the ruins of an ancient temple
95 | * withing the dense undergrowth
96 | * near an abandoned ritual site, deep in the jungle
97 | * under the remains of an ancient settlement
98 | * under the ruins of an ancient ziggurat
99 | ]
100 | }
101 |
102 | JungleRandomEncounterTable {
103 | [4..4 OtherEncounters!] @ ForestRandomEncounter
104 | }
105 |
106 | JungleHex (Hex) {
107 | Terrain! @ Jungle
108 | Monster! @ ForestFeatureEncounter
109 | RandomEncounters @ ForestRandomEncounterTable
110 | ExtensionTypeClass = "JungleHexExtension"
111 | | Hex
112 | }
113 |
114 | JungleRegion (Region) {
115 | Suffix @ [
116 | * Jungle
117 | * Wilds
118 | * Bushes
119 | * Rainforest
120 | * Wilderness
121 | ]
122 | | Region
123 | Weather? @ TropicalWeatherContainer
124 | [$minimum_tiles_per_jungle_region..$maximum_tiles_per_jungle_region Hexmap?] @ JungleHex
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/hexroll3-scroll-data/wilderness/mountains.scroll:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020-2025 Pen, Dice & Paper
3 | #
4 | # This program is dual-licensed under the following terms:
5 | #
6 | # Option 1: (Non-Commercial) GNU Affero General Public License (AGPL)
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | # Option 2: Commercial License
21 | # For commercial use, you are required to obtain a separate commercial
22 | # license. Please contact ithai at pendicepaper.com
23 | # for more information about commercial licensing terms.
24 | #
25 |
26 | Mountains {
27 | Name! = Mountains
28 | Supplemental! @ [
29 | * A thundering waterfall drops hundreds of feet down from an overhang in the
30 | steep slopes, forming a cloud of raging water at the base.
31 |
32 | * A giant peak stands taller than any of the mountains around it. An eerie
33 | red glow surrounding its top is visible from afar.
34 |
35 | * Waterfalls of lava flow from caves in a cliff, melting pieces of rock as
36 | they fall and form a river of inferno in the deep canyon.
37 |
38 | * The skeleton of a huge dragon is fossilised in one of the cliff faces
39 | here. Its wings are spread as if it was about to fly to the clouds one
40 | last time.
41 |
42 | * Multiple plateaus separated by seemingly bottomless chasms are connected
43 | with fragile rope bridges. The strong wind swings the brides from side to
44 | side, making crossing them a terrifying experience.
45 |
46 | * Giant boulders are hanging in mid air by some kind of invisible magic.
47 | Some have rope ladders attached, reaching all the way down for anyone to
48 | climb.
49 |
50 | * A small patch of dark clouds circle an even darker peak. Jolts of
51 | lightning flash from within, followed by rumbling thunders.
52 |
53 | * The narrow and winding trails here are on the faces of the cliffs.
54 | Carelessness or combat are especially risky here.
55 |
56 | * The path here leads to a cliffside, more than a hundrad feet tall. Planks
57 | of wood attached against the rocky wall form the only way ahead.
58 |
59 | * The passages here are surrounded with steep vertical cliffs and are
60 | branching to all directions like a fractured maze.
61 |
62 | * Two giant stone figures of guards, gazing into the sky and holding a sword
63 | against the ground are carved on both cliff sides of the valley
64 | here.
65 |
66 | * The rock formations here are sharp, pointy and dark. Walking here
67 | feels like entering the a skull of a colossal monster.
68 |
69 | * Small unexplained earthquakes tremble the rocks here a few times a day.
70 | Loose rocks and boulders may block the pathways, or even worse, fall
71 | from above unexpectedly.
72 |
73 | * Dense fog makes travelling on the trails here difficult and slow.
74 | The reduced visibility renders it almost impossible to scout for danger.
75 |
76 | * Weird colourful crystal formations are decorating the rocky walls here.
77 | Mesmerising rays of light are bouncing from their countless facets.
78 |
79 | * Giant thin pillars of rocks are barely supporting even bigger plates
80 | of stone. Some of these huge mushroom-like formations have already
81 | collapsed. The others are likely to fall as well soon.
82 | ]
83 | Location! @ [
84 | * on the edge of the cliffs, at the end of a winding steep trail
85 | * high in the mountains
86 | * across a seemingly bottomless chasm, where a rope bridge meets an overhang
87 | * near the base of a steep cliff
88 | * near the base of the tallest mountain
89 | ]
90 | Hideout! @ [
91 | * behind a waterfall
92 | * inside a cave on the cliff
93 | * inside an old volcano
94 | ]
95 | }
96 |
97 | MountainsRandomEncounterTable {
98 | [4..4 OtherEncounters!] @ MountainsRandomEncounter
99 | }
100 |
101 | MountainsHex (Hex) {
102 | Terrain! @ Mountains
103 | Monster! @ MountainsFeatureEncounter
104 | RandomEncounters @ MountainsRandomEncounterTable
105 | ExtensionTypeClass = "MountainsHexExtension"
106 | | Hex
107 | }
108 |
109 | MountainsRegion (Region) {
110 | Suffix @ [
111 | * Mountains
112 | * Ridge
113 | * Range
114 | * Peaks
115 | * Teeth
116 | * Crags
117 | * Cliffs
118 | ]
119 |
120 | | Region
121 | Weather? @ MountainWeatherContainer
122 | [$minimum_tiles_per_mountains_region..$maximum_tiles_per_mountains_region Hexmap?] @ MountainsHex
123 | }
124 |
125 |
--------------------------------------------------------------------------------