diff --git a/doc/quest_db.txt b/doc/quest_db.txt index 723ec0aa45..153d7af71a 100644 --- a/doc/quest_db.txt +++ b/doc/quest_db.txt @@ -20,11 +20,30 @@ Title: Quest title. TimeLimit: Amount of time before the quest expires. -Use a number followed by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s). Specifying with "+" will mark how long until the quest expires. -Specifying without "+" will mark the exact time the quest expires. Format: "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional). +Use a number followed by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s). +Format: "d" (optional), [0-23]"h" (optional), [0-59]"mn" (optional), [0-59]"s" (optional). -Please note the number before "d" only shifts the exact timer to the given day(s). +Example: + - Id: 2069 + Title: Tierra Gorge Battle + # The quest expires 5 minutes after being taken. + TimeLimit: +5mn + +Specifying without "+" will mark the exact time the quest expires. +Use a number followed by "d" for day(s) to shift the exact timer to the given day(s) or use the days of the week to set the expiration day, +and "h" for hour(s), "mn" for minute(s), and "s" for second(s). +Format: [days of the week] or "d" (optionals), [0-23]"h" (optional), [0-59]"mn" (optional), [0-59]"s" (optional). + +Examples: + - Id: 9419 + Title: Attack Sky Fortress Invading Prontera + # The quest expires 3 days after being taken at 4am. + TimeLimit: 3d 4h + - Id: 5965 + Title: "[Standby] Devil's Special" + # The quest expires Monday at 4am. + TimeLimit: Monday 4h --------------------------------------- diff --git a/src/map/quest.cpp b/src/map/quest.cpp index 0624710818..4730c5a7cc 100644 --- a/src/map/quest.cpp +++ b/src/map/quest.cpp @@ -28,7 +28,7 @@ using namespace rathena; -static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minute, int *second); +static int split_exact_quest_time(char* modif_p, int* week, int* day, int* hour, int* minute, int *second); const std::string QuestDatabase::getDefaultLocation() { return std::string(db_path) + "/quest_db.yml"; @@ -81,20 +81,25 @@ uint64 QuestDatabase::parseBodyNode(const ryml::NodeRef& node) { quest->time = static_cast(timediff); } else {// '+' not found, set to specific time - int32 day, hour, minute, second; + int32 day, hour, minute, second, week; - if (split_exact_quest_time(const_cast(time.c_str()), &day, &hour, &minute, &second) == 0) { + if (split_exact_quest_time(const_cast(time.c_str()), &week, &day, &hour, &minute, &second) == 0) { this->invalidWarning(node["TimeLimit"], "Incorrect TimeLimit format %s given, skipping.\n", time.c_str()); return 0; } - quest->time = day * 86400 + hour * 3600 + minute * 60 + second; + if (week > 0) + quest->time = hour * 3600 + minute * 60 + second; + else + quest->time = day * 86400 + hour * 3600 + minute * 60 + second; quest->time_at = true; + quest->time_week = week; } } else { if (!exists) { quest->time = 0; quest->time_at = false; + quest->time_week = -1; } } @@ -441,8 +446,8 @@ uint64 QuestDatabase::parseBodyNode(const ryml::NodeRef& node) { } -static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minute, int *second) { - int d = -1, h = -1, mn = -1, s = -1; +static int split_exact_quest_time(char* modif_p, int* week, int* day, int* hour, int* minute, int *second) { + int w = -1, d = -1, h = -1, mn = -1, s = -1; nullpo_retr(0, modif_p); @@ -453,7 +458,28 @@ static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minut modif_p++; while (modif_p[0] >= '0' && modif_p[0] <= '9') modif_p++; - if (modif_p[0] == 's') { + if (strncasecmp(modif_p, "SUNDAY", 6) == 0) { + w = 0; + modif_p = modif_p + 6; + } else if (strncasecmp(modif_p, "MONDAY", 6) == 0) { + w = 1; + modif_p = modif_p + 6; + } else if (strncasecmp(modif_p, "TUESDAY", 7) == 0) { + w = 2; + modif_p = modif_p + 7; + } else if (strncasecmp(modif_p, "WEDNESDAY", 9) == 0) { + w = 3; + modif_p = modif_p + 9; + } else if (strncasecmp(modif_p, "THURSDAY", 8) == 0) { + w = 4; + modif_p = modif_p + 8; + } else if (strncasecmp(modif_p, "FRIDAY", 6) == 0) { + w = 5; + modif_p = modif_p + 6; + } else if (strncasecmp(modif_p, "SATURDAY", 8) == 0) { + w = 6; + modif_p = modif_p + 8; + } else if (modif_p[0] == 's') { s = value; modif_p++; } else if (modif_p[0] == 'm' && modif_p[1] == 'n') { @@ -473,6 +499,7 @@ static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minut if (h < 0 || h > 23 || mn > 59 || s > 59) // hour is required return 0; + *week = w; *day = max(0,d); *hour = h; *minute = max(0,mn); @@ -536,10 +563,18 @@ static time_t quest_time(std::shared_ptr qi) struct tm *lt = localtime(&t); uint32 time_today = lt->tm_hour * 3600 + lt->tm_min * 60 + lt->tm_sec; - if (time_today < (qi->time % 86400)) - return static_cast(t + qi->time - time_today); - else // Carry over to the next day - return static_cast(t + 86400 + qi->time - time_today); + int32 day_shift = 0; + + if (time_today >= (qi->time % 86400)) // Carry over to the next day + day_shift = 1; + + if (qi->time_week > -1) { + if (qi->time_week < (lt->tm_wday + day_shift)) + day_shift = qi->time_week + 7 - lt->tm_wday; + else + day_shift = qi->time_week - lt->tm_wday; + } + return static_cast(t + (day_shift * 86400) + qi->time - time_today); } return 0; diff --git a/src/map/quest.hpp b/src/map/quest.hpp index 1645eef822..03f25dba82 100644 --- a/src/map/quest.hpp +++ b/src/map/quest.hpp @@ -42,6 +42,7 @@ struct s_quest_db { int32 id; time_t time; bool time_at; + int32 time_week; std::vector> objectives; std::vector> dropitem; std::string name;