Skip to content

Commit 7d07ba9

Browse files
factory methods for creating paragraph asynchronously
1 parent 0dfd5f1 commit 7d07ba9

File tree

5 files changed

+216
-8
lines changed

5 files changed

+216
-8
lines changed

include/ssod/paragraph.h

Lines changed: 200 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#include <dpp/unicode_emoji.h>
2626
#include <sstream>
2727

28+
/**
29+
* Emojis used for travel buttons
30+
*/
2831
inline const char* directions[] = {
2932
dpp::unicode_emoji::zero,
3033
dpp::unicode_emoji::one,
@@ -64,6 +67,9 @@ inline const char* directions[] = {
6467
dpp::unicode_emoji::regional_indicator_z,
6568
};
6669

70+
/**
71+
* Nav link button types
72+
*/
6773
enum nav_link_type {
6874
nav_type_disabled_link,
6975
nav_type_link,
@@ -77,6 +83,9 @@ enum nav_link_type {
7783
nav_type_pick_one,
7884
};
7985

86+
/**
87+
* A navigation link
88+
*/
8089
struct nav_link {
8190
long paragraph;
8291
nav_link_type type;
@@ -89,47 +98,235 @@ struct nav_link {
8998
};
9099

91100
struct paragraph {
101+
/**
102+
* Paragraph ID for accessing row in database
103+
*/
92104
uint32_t id{};
105+
106+
/**
107+
* Temporary text value for last token read
108+
*/
93109
std::string text;
110+
111+
/**
112+
* Secure ID, used for display of location to user
113+
*/
94114
std::string secure_id;
115+
116+
/**
117+
* List of possible links out of this paragraph,
118+
* to other related paragraphs or actions
119+
*/
95120
std::vector<nav_link> navigation_links;
121+
122+
/**
123+
* Stacks of items dropped to the ground here that
124+
* the player can pick up.
125+
*/
96126
std::vector<stacked_item> dropped_items;
127+
128+
/**
129+
* Output stream, contains content from database
130+
*/
97131
std::stringstream* output{nullptr};
132+
133+
/**
134+
* True if players cannot PVP here
135+
*/
98136
bool combat_disabled{};
137+
138+
/**
139+
* True if players cannot cast passive spells here
140+
*/
99141
bool magic_disabled{};
142+
143+
/**
144+
* True if players cannot steal from each other here
145+
*/
100146
bool theft_disabled{};
147+
148+
/**
149+
* True if players cannot chat here
150+
*/
101151
bool chat_disabled{};
152+
153+
/**
154+
* True if this location is safe, determined by if the location
155+
* does not adjust stats, and has no PVE combat.
156+
*/
102157
bool safe{true};
158+
159+
/**
160+
* True if this location has a shop or trader here, which means
161+
* we should allow the player to sell items.
162+
*/
103163
bool trader{false};
164+
165+
/**
166+
* True if the player has a disease
167+
*/
104168
bool sick{false};
105169

106-
size_t links{0}, words{0};
170+
/**
171+
* Number of outbound links found in the content - this may be different to
172+
* navigation_links.size() as not all navigation links are outbound
173+
* links that lead elsewhere.
174+
*/
175+
size_t links{0};
176+
177+
/**
178+
* Number of printable non-code words in the paragraph
179+
*/
180+
size_t words{0};
181+
182+
/**
183+
* Current tag name whilst parsing
184+
*/
107185
std::string tag;
186+
187+
/**
188+
* True if the last element found in the paragraph text was a link
189+
*/
108190
bool last_was_link{false};
191+
192+
/**
193+
* A stack of display states, while the top display state on the stack
194+
* is true, we output text and action tags, else we discard them.
195+
*/
109196
std::vector<bool> display;
110-
long current_fragment{0};
111-
bool auto_test{false}, didntmove{false};
112197

198+
/**
199+
* Current fragment. Where a paragraph has combat encounters, each section
200+
* before that encounter's combat tag to the next is known as a fragment.
201+
* We only display the current fragment, e.g. up to and including the current
202+
* combat encounter the player is engaged in. When the beat that enemy, the
203+
* fragment count is incremented, until they are on the last fragment, where
204+
* potentially there are active ountbound links to leave the location.
205+
*/
206+
long current_fragment{0};
207+
208+
/**
209+
* The result of the last <TEST LUCK> etc tag in the location
210+
*/
211+
bool auto_test{false};
212+
213+
/**
214+
* True if the users last interaction with the game didn't result in them moving
215+
* to a new location
216+
*/
217+
bool didntmove{false};
218+
219+
/**
220+
* Pointer to current player, used by js interpreters
221+
*/
113222
player* cur_player{nullptr};
114223

224+
/**
225+
* Default constructor
226+
*/
115227
paragraph() = default;
228+
229+
/**
230+
* Default destructor
231+
*/
116232
~paragraph() = default;
233+
234+
/**
235+
* Construct a paragraph with existing data.
236+
* @note Does not parse the content, this is done asynchronously via the parse method.
237+
* @param data Paragraph content
238+
* @param current Current player
239+
*/
117240
paragraph(const std::string& data, player& current);
241+
242+
/**
243+
* Construct a paragraph from paragraph id
244+
* @note Does not parse the content, this is done asynchronously via the parse method.
245+
* @param paragraph_id Paragraph id in database
246+
* @param current Current player
247+
* @param user_id Discord user id
248+
*/
118249
paragraph(uint32_t paragraph_id, player& current, dpp::snowflake user_id);
119250

251+
/**
252+
* Given a current paragraph id, return true if the next id is a valid move,
253+
* or false if it isn't. Used as a double check against cheating.
254+
* @param current current id
255+
* @param next next id
256+
* @return true if valid move
257+
*/
120258
static dpp::task<bool> valid_next(long current, long next);
121259

260+
/**
261+
* @brief Factory function to create a new paragraph instance with a paragraph id, player and user id
262+
* @param paragraph_id Paragraph ID to construct and parse
263+
* @param current Current player
264+
* @param user_id Discord user id
265+
* @return awaitable which will return paragraph when fulfilled
266+
*/
267+
static dpp::task<paragraph> create(uint32_t paragraph_id, player& current, dpp::snowflake user_id);
268+
269+
/**
270+
* @brief Factory function to create a new paragraph instance with existing content and a player
271+
* @param data String containing existing content to parse
272+
* @param current Current player
273+
* @return awaitable which will return paragraph when fulfilled
274+
*/
275+
static dpp::task<paragraph> create(const std::string& data, player& current);
276+
277+
/**
278+
* Parse paragraph content, this may take some time to complete as it has to interpret the content
279+
* and retrieve it from the database.
280+
* @param current_player Current active player
281+
* @param user_id Discord user id
282+
* @return awaitable
283+
*/
122284
dpp::task<void> parse(player& current_player, dpp::snowflake user_id);
123285
};
124286

287+
/**
288+
* Extract the next string value from a key/value list, e.g.
289+
* if the string contains 'NAME="Big Monster"' this will return
290+
* Big Monster.
291+
* @param p_text text to extract from
292+
* @return extracted string
293+
*/
125294
std::string extract_value(const std::string& p_text);
126295

296+
/**
297+
* Extract the next numeric value from a key/value list, e.g.
298+
* if the string contains 'A="1"' this will return 1.
299+
* @param p_text text to extract from
300+
* @return extracted number
301+
*/
127302
long extract_value_number(const std::string& p_text);
128303

304+
/**
305+
* Returns true if a global flag is set
306+
* @param flag flag name
307+
* @return awaitable true if set
308+
*/
129309
dpp::task<bool> global_set(const std::string& flag);
130310

311+
/**
312+
* Returns true if a timed flag is set
313+
* @param event user's event
314+
* @param flag flag name
315+
* @return awaitable true if set
316+
*/
131317
dpp::task<bool> timed_set(dpp::interaction_create_t& event, const std::string& flag);
132318

319+
/**
320+
* Given some text, extract all text up to but not including the end character
321+
* @param p_text text to extract into
322+
* @param content stream to extract from
323+
* @param end end character to stop at
324+
*/
133325
void extract_to_quote(std::string& p_text, std::stringstream& content, char end = '>');
134326

327+
/**
328+
* Removes the last character from a string
329+
* @param s string to remove from
330+
* @return modified string
331+
*/
135332
std::string remove_last_char(const std::string& s);

src/game.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,8 +1353,7 @@ dpp::task<void> continue_game(const dpp::interaction_create_t& event, player p)
13531353
co_await bank(event, p);
13541354
co_return;
13551355
}
1356-
paragraph location(p.paragraph, p, event.command.usr.id);
1357-
co_await location.parse(p, event.command.usr.id);
1356+
paragraph location = co_await paragraph::create(p.paragraph, p, event.command.usr.id);
13581357
/* If the current paragraph is an empty page with nothing but a link, skip over it.
13591358
* These link pages are old data and not relavent to gameplay. Basically just a paragraph
13601359
* that says "Turn to X" which were an anti-cheat holdover from book-form content.

src/game_player.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ bool player::save(dpp::snowflake user_id, bool put_backup)
760760
}
761761
last_use = time(nullptr);
762762

763-
json crumbs = json::array();;
763+
json crumbs = json::array();
764764
if (!put_backup) {
765765
for (long p : breadcrumb_trail) {
766766
crumbs.push_back(p);

src/js/js.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ static duk_ret_t js_tag(duk_context *cx) {
104104
bot->log(dpp::ll_warning, "JS tag(): Cannot recursively execute a script tag inside tag()!");
105105
return 0;
106106
}
107-
paragraph inner(output, *p.cur_player);
108-
inner.parse(*p.cur_player, p.cur_player->event.command.usr.id).sync_wait();
107+
paragraph inner = paragraph::create(output, *p.cur_player).sync_wait();
108+
109109
*p.output << inner.text;
110110
p.links += inner.links;
111111
for (const auto& nav : inner.navigation_links) {

src/paragraph.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ paragraph::paragraph(uint32_t paragraph_id, player& current, dpp::snowflake user
3333
display.push_back(true);
3434
}
3535

36+
dpp::task<paragraph> paragraph::create(uint32_t paragraph_id, player& current, dpp::snowflake user_id) {
37+
paragraph new_paragraph(paragraph_id, current, user_id);
38+
co_await new_paragraph.parse(current, user_id);
39+
co_return new_paragraph;
40+
}
41+
42+
dpp::task<paragraph> paragraph::create(const std::string& data, player& current) {
43+
paragraph new_paragraph(data, current);
44+
co_await new_paragraph.parse(current, current.event.command.usr.id);
45+
co_return new_paragraph;
46+
}
47+
3648
paragraph::paragraph(const std::string& data, player& current) {
3749
id = 0;
3850
text = data;

0 commit comments

Comments
 (0)