Feature: [GS] Goal destination can be updated (#10817)

This commit is contained in:
mrmbernardi 2023-06-08 19:00:31 +02:00 committed by GitHub
parent 9408ab4799
commit 35ef6c1723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 44 deletions

View File

@ -295,6 +295,7 @@ enum Commands : uint16 {
CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message
CMD_CREATE_GOAL, ///< create a new goal
CMD_REMOVE_GOAL, ///< remove a goal
CMD_SET_GOAL_DESTINATION, ///< update goal destination of a goal
CMD_SET_GOAL_TEXT, ///< update goal text of a goal
CMD_SET_GOAL_PROGRESS, ///< update goal progress text of a goal
CMD_SET_GOAL_COMPLETED, ///< update goal completed status of a goal

View File

@ -31,6 +31,41 @@
GoalPool _goal_pool("Goal");
INSTANTIATE_POOL_METHODS(Goal)
/* static */ bool Goal::IsValidGoalDestination(CompanyID company, GoalType type, GoalTypeID dest)
{
switch (type) {
case GT_NONE:
if (dest != 0) return false;
break;
case GT_TILE:
if (!IsValidTile(dest)) return false;
break;
case GT_INDUSTRY:
if (!Industry::IsValidID(dest)) return false;
break;
case GT_TOWN:
if (!Town::IsValidID(dest)) return false;
break;
case GT_COMPANY:
if (!Company::IsValidID(dest)) return false;
break;
case GT_STORY_PAGE: {
if (!StoryPage::IsValidID(dest)) return false;
CompanyID story_company = StoryPage::Get(dest)->company;
if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return false;
break;
}
default: return false;
}
return true;
}
/**
* Create a new goal.
* @param flags type of operation
@ -47,37 +82,7 @@ std::tuple<CommandCost, GoalID> CmdCreateGoal(DoCommandFlag flags, CompanyID com
if (_current_company != OWNER_DEITY) return { CMD_ERROR, INVALID_GOAL };
if (text.empty()) return { CMD_ERROR, INVALID_GOAL };
if (company != INVALID_COMPANY && !Company::IsValidID(company)) return { CMD_ERROR, INVALID_GOAL };
switch (type) {
case GT_NONE:
if (dest != 0) return { CMD_ERROR, INVALID_GOAL };
break;
case GT_TILE:
if (!IsValidTile(dest)) return { CMD_ERROR, INVALID_GOAL };
break;
case GT_INDUSTRY:
if (!Industry::IsValidID(dest)) return { CMD_ERROR, INVALID_GOAL };
break;
case GT_TOWN:
if (!Town::IsValidID(dest)) return { CMD_ERROR, INVALID_GOAL };
break;
case GT_COMPANY:
if (!Company::IsValidID(dest)) return { CMD_ERROR, INVALID_GOAL };
break;
case GT_STORY_PAGE: {
if (!StoryPage::IsValidID(dest)) return { CMD_ERROR, INVALID_GOAL };
CompanyID story_company = StoryPage::Get(dest)->company;
if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return { CMD_ERROR, INVALID_GOAL };
break;
}
default: return { CMD_ERROR, INVALID_GOAL };
}
if (!Goal::IsValidGoalDestination(company, type, dest)) return { CMD_ERROR, INVALID_GOAL };
if (flags & DC_EXEC) {
Goal *g = new Goal();
@ -127,6 +132,29 @@ CommandCost CmdRemoveGoal(DoCommandFlag flags, GoalID goal)
return CommandCost();
}
/**
* Update goal destination of a goal.
* @param flags type of operation
* @param goal GoalID to update.
* @param type GoalType of destination.
* @param dest GoalTypeID of destination.
* @return the cost of this operation or an error
*/
CommandCost CmdSetGoalDestination(DoCommandFlag flags, GoalID goal, GoalType type, GoalTypeID dest)
{
if (_current_company != OWNER_DEITY) return CMD_ERROR;
if (!Goal::IsValidID(goal)) return CMD_ERROR;
Goal *g = Goal::Get(goal);
if (!Goal::IsValidGoalDestination(g->company, type, dest)) return CMD_ERROR;
if (flags & DC_EXEC) {
g->type = type;
g->dst = dest;
}
return CommandCost();
}
/**
* Update goal text of a goal.
* @param flags type of operation

View File

@ -35,6 +35,8 @@ struct Goal : GoalPool::PoolItem<&_goal_pool> {
* (Empty) destructor has to be defined else operator delete might be called with nullptr parameter
*/
inline ~Goal() { }
static bool IsValidGoalDestination(CompanyID company, GoalType type, GoalTypeID dest);
};
#endif /* GOAL_BASE_H */

View File

@ -15,6 +15,7 @@
std::tuple<CommandCost, GoalID> CmdCreateGoal(DoCommandFlag flags, CompanyID company, GoalType type, GoalTypeID dest, const std::string &text);
CommandCost CmdRemoveGoal(DoCommandFlag flags, GoalID goal);
CommandCost CmdSetGoalDestination(DoCommandFlag flags, GoalID goal, GoalType type, GoalTypeID dest);
CommandCost CmdSetGoalText(DoCommandFlag flags, GoalID goal, const std::string &text);
CommandCost CmdSetGoalProgress(DoCommandFlag flags, GoalID goal, const std::string &text);
CommandCost CmdSetGoalCompleted(DoCommandFlag flags, GoalID goal, bool completed);
@ -23,6 +24,7 @@ CommandCost CmdGoalQuestionAnswer(DoCommandFlag flags, uint16 uniqueid, uint8 bu
DEF_CMD_TRAIT(CMD_CREATE_GOAL, CmdCreateGoal, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_REMOVE_GOAL, CmdRemoveGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_GOAL_DESTINATION, CmdSetGoalDestination, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_GOAL_TEXT, CmdSetGoalText, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_GOAL_PROGRESS, CmdSetGoalProgress, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_GOAL_COMPLETED, CmdSetGoalCompleted, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)

View File

@ -75,6 +75,8 @@
* \li GSGroupList
* \li GSVehicleList_Group
* \li GSVehicleList_DefaultGroup
* \li GSGoal::IsValidGoalDestination
* \li GSGoal::SetDestination
*
* API removals:
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.

View File

@ -28,6 +28,20 @@
return ::Goal::IsValidID(goal_id);
}
/* static */ bool ScriptGoal::IsValidGoalDestination(ScriptCompany::CompanyID company, GoalType type, SQInteger destination)
{
CompanyID c = (::CompanyID)company;
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
StoryPage *story_page = nullptr;
if (type == GT_STORY_PAGE && ScriptStoryPage::IsValidStoryPage((ScriptStoryPage::StoryPageID)destination)) story_page = ::StoryPage::Get((ScriptStoryPage::StoryPageID)destination);
return (type == GT_NONE && destination == 0) ||
(type == GT_TILE && ScriptMap::IsValidTile(destination)) ||
(type == GT_INDUSTRY && ScriptIndustry::IsValidIndustry(destination)) ||
(type == GT_TOWN && ScriptTown::IsValidTown(destination)) ||
(type == GT_COMPANY && ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)destination) != ScriptCompany::COMPANY_INVALID) ||
(type == GT_STORY_PAGE && story_page != nullptr && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c));
}
/* static */ ScriptGoal::GoalID ScriptGoal::New(ScriptCompany::CompanyID company, Text *goal, GoalType type, SQInteger destination)
{
CCountedPtr<Text> counter(goal);
@ -37,20 +51,9 @@
const std::string &text = goal->GetEncodedText();
EnforcePreconditionEncodedText(GOAL_INVALID, text);
EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
EnforcePrecondition(GOAL_INVALID, IsValidGoalDestination(company, type, destination));
CompanyID c = (::CompanyID)company;
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
StoryPage *story_page = nullptr;
if (type == GT_STORY_PAGE && ScriptStoryPage::IsValidStoryPage((ScriptStoryPage::StoryPageID)destination)) story_page = ::StoryPage::Get((ScriptStoryPage::StoryPageID)destination);
EnforcePrecondition(GOAL_INVALID, (type == GT_NONE && destination == 0) ||
(type == GT_TILE && ScriptMap::IsValidTile(destination)) ||
(type == GT_INDUSTRY && ScriptIndustry::IsValidIndustry(destination)) ||
(type == GT_TOWN && ScriptTown::IsValidTown(destination)) ||
(type == GT_COMPANY && ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)destination) != ScriptCompany::COMPANY_INVALID) ||
(type == GT_STORY_PAGE && story_page != nullptr && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c)));
if (!ScriptObject::Command<CMD_CREATE_GOAL>::Do(&ScriptInstance::DoCommandReturnGoalID, c, (::GoalType)type, destination, text)) return GOAL_INVALID;
if (!ScriptObject::Command<CMD_CREATE_GOAL>::Do(&ScriptInstance::DoCommandReturnGoalID, (::CompanyID)company, (::GoalType)type, destination, text)) return GOAL_INVALID;
/* In case of test-mode, we return GoalID 0 */
return (ScriptGoal::GoalID)0;
@ -64,6 +67,16 @@
return ScriptObject::Command<CMD_REMOVE_GOAL>::Do(goal_id);
}
/* static */ bool ScriptGoal::SetDestination(GoalID goal_id, GoalType type, SQInteger destination)
{
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidGoal(goal_id));
Goal *g = Goal::Get(goal_id);
EnforcePrecondition(false, IsValidGoalDestination((ScriptCompany::CompanyID)g->company, type, destination));
return ScriptObject::Command<CMD_SET_GOAL_DESTINATION>::Do(goal_id, (::GoalType)type, destination);
}
/* static */ bool ScriptGoal::SetText(GoalID goal_id, Text *goal)
{
CCountedPtr<Text> counter(goal);

View File

@ -89,6 +89,15 @@ public:
*/
static bool IsValidGoal(GoalID goal_id);
/**
* Check whether this is a valid goal destination.
* @param company The relevant company if a story page is the destination.
* @param type The type of the goal.
* @param destination The destination of the \a type type.
* @return True if and only if this goal destination is valid.
*/
static bool IsValidGoalDestination(ScriptCompany::CompanyID company, GoalType type, SQInteger destination);
/**
* Create a new goal.
* @param company The company to create the goal for, or ScriptCompany::COMPANY_INVALID for all.
@ -114,6 +123,18 @@ public:
*/
static bool Remove(GoalID goal_id);
/**
* Update goal destination of a goal.
* @param goal_id The goal to update.
* @param type The type of the goal.
* @param destination The destination of the \a type type.
* @return True if the action succeeded.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
* @pre IsValidGoalDestination(g->company, type, destination).
*/
static bool SetDestination(GoalID goal_id, GoalType type, SQInteger destination);
/**
* Update goal text of a goal.
* @param goal_id The goal to update.