From 913119487fa58bb4346af8d0024f95b6517f4d46 Mon Sep 17 00:00:00 2001 From: Pavel Stupnikov Date: Sat, 28 Apr 2018 18:37:59 +0300 Subject: Feature: Add GS method to question a single client (#6748) --- src/goal.cpp | 32 ++++++++++++++++++++++++++++---- src/script/api/game/game_goal.hpp.sq | 19 ++++++++++--------- src/script/api/game_changelog.hpp | 1 + src/script/api/script_goal.cpp | 25 ++++++++++++++++++++++--- src/script/api/script_goal.hpp | 27 ++++++++++++++++++++++++++- 5 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/goal.cpp b/src/goal.cpp index 2f6ca242a..f7aae350e 100644 --- a/src/goal.cpp +++ b/src/goal.cpp @@ -23,6 +23,8 @@ #include "string_func.h" #include "gui.h" #include "network/network.h" +#include "network/network_base.h" +#include "network/network_func.h" #include "safeguards.h" @@ -234,7 +236,9 @@ CommandCost CmdSetGoalCompleted(TileIndex tile, DoCommandFlag flags, uint32 p1, * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - Unique ID to use for this question. - * - p1 = (bit 16 - 23) - Company for which this question is. + * - p1 = (bit 16 - 23) - Company or client for which this question is. + * - p1 = (bit 24 - 25) - Question type. + * - p1 = (bit 31) - Question target: 0 - company, 1 - client. * @param p2 Buttons of the question. * @param text Text of the question. * @return the cost of this operation or an error @@ -243,17 +247,37 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint { uint16 uniqueid = (GoalType)GB(p1, 0, 16); CompanyID company = (CompanyID)GB(p1, 16, 8); - byte type = GB(p1, 24, 8); +#ifdef ENABLE_NETWORK + ClientIndex client = (ClientIndex)GB(p1, 16, 8); +#endif + byte type = GB(p1, 24, 2); + bool is_client = HasBit(p1, 31); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; - if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; + if (is_client) { +#ifdef ENABLE_NETWORK + if (!NetworkClientInfo::IsValidID(client)) return CMD_ERROR; +#else + return CMD_ERROR; +#endif + } else { + if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; + } if (CountBits(p2) < 1 || CountBits(p2) > 3) return CMD_ERROR; if (p2 >= (1 << GOAL_QUESTION_BUTTON_COUNT)) return CMD_ERROR; if (type >= GOAL_QUESTION_TYPE_COUNT) return CMD_ERROR; if (flags & DC_EXEC) { - if ((company != INVALID_COMPANY && company == _local_company) || (company == INVALID_COMPANY && Company::IsValidID(_local_company))) ShowGoalQuestion(uniqueid, type, p2, text); + if (is_client) { +#ifdef ENABLE_NETWORK + if (NetworkClientInfo::Get(client)->client_id != _network_own_client_id) return CommandCost(); +#endif + } else { + if (company == INVALID_COMPANY && !Company::IsValidID(_local_company)) return CommandCost(); + if (company != INVALID_COMPANY && company != _local_company) return CommandCost(); + } + ShowGoalQuestion(uniqueid, type, p2, text); } return CommandCost(); diff --git a/src/script/api/game/game_goal.hpp.sq b/src/script/api/game/game_goal.hpp.sq index 7d8a3bf5e..4cf15b3fc 100644 --- a/src/script/api/game/game_goal.hpp.sq +++ b/src/script/api/game/game_goal.hpp.sq @@ -51,15 +51,16 @@ void SQGSGoal_Register(Squirrel *engine) SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_SURRENDER, "BUTTON_SURRENDER"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_CLOSE, "BUTTON_CLOSE"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsValidGoal, "IsValidGoal", 2, ".i"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::New, "New", 5, ".i.ii"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Remove, "Remove", 2, ".i"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetText, "SetText", 3, ".i."); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetProgress, "SetProgress", 3, ".i."); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetCompleted, "SetCompleted", 3, ".ib"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsCompleted, "IsCompleted", 2, ".i"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Question, "Question", 6, ".ii.ii"); - SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::CloseQuestion, "CloseQuestion", 2, ".i"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsValidGoal, "IsValidGoal", 2, ".i"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::New, "New", 5, ".i.ii"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Remove, "Remove", 2, ".i"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetText, "SetText", 3, ".i."); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetProgress, "SetProgress", 3, ".i."); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetCompleted, "SetCompleted", 3, ".ib"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsCompleted, "IsCompleted", 2, ".i"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Question, "Question", 6, ".ii.ii"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::QuestionClient, "QuestionClient", 6, ".ii.ii"); + SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::CloseQuestion, "CloseQuestion", 2, ".i"); SQGSGoal.PostRegister(engine); } diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 5f278e4f0..390c1f31f 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -25,6 +25,7 @@ * \li GSViewport::ScrollEveryoneTo * \li GSViewport::ScrollCompanyClientsTo * \li GSViewport::ScrollClientTo + * \li GSGoal::QuestionClient * * \b 1.8.0 * diff --git a/src/script/api/script_goal.cpp b/src/script/api/script_goal.cpp index 5153e0ef0..c183b7583 100644 --- a/src/script/api/script_goal.cpp +++ b/src/script/api/script_goal.cpp @@ -10,6 +10,7 @@ /** @file script_goal.cpp Implementation of ScriptGoal. */ #include "../../stdafx.h" +#include "script_game.hpp" #include "script_goal.hpp" #include "script_error.hpp" #include "script_industry.hpp" @@ -19,6 +20,7 @@ #include "../script_instance.hpp" #include "../../goal_base.h" #include "../../string_func.h" +#include "../../network/network_base.h" #include "../../safeguards.h" @@ -107,7 +109,7 @@ return g != NULL && g->completed; } -/* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons) +/* static */ bool ScriptGoal::DoQuestion(uint16 uniqueid, uint8 target, bool is_client, Text *question, QuestionType type, int buttons) { CCountedPtr counter(question); @@ -115,15 +117,32 @@ EnforcePrecondition(false, question != NULL); const char *text = question->GetEncodedText(); EnforcePreconditionEncodedText(false, text); - EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); EnforcePrecondition(false, CountBits(buttons) >= 1 && CountBits(buttons) <= 3); EnforcePrecondition(false, buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT)); EnforcePrecondition(false, (int)type < ::GOAL_QUESTION_TYPE_COUNT); + return ScriptObject::DoCommand(0, uniqueid | (target << 16) | (type << 24) | (is_client ? (1 << 31) : 0), buttons, CMD_GOAL_QUESTION, text); +} + +/* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons) +{ + EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; - return ScriptObject::DoCommand(0, uniqueid | (c << 16) | (type << 24), buttons, CMD_GOAL_QUESTION, text); + return DoQuestion(uniqueid, c, false, question, type, buttons); +} + +/* static */ bool ScriptGoal::QuestionClient(uint16 uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, int buttons) +{ + EnforcePrecondition(false, ScriptGame::IsMultiplayer()); + EnforcePrecondition(false, ScriptClient::ResolveClientID(client) != ScriptClient::CLIENT_INVALID); +#ifdef ENABLE_NETWORK + ClientIndex c = NetworkClientInfo::GetByClientID((::ClientID)client)->index; + return DoQuestion(uniqueid, c, true, question, type, buttons); +#else + return false; +#endif } /* static */ bool ScriptGoal::CloseQuestion(uint16 uniqueid) diff --git a/src/script/api/script_goal.hpp b/src/script/api/script_goal.hpp index a9c7b239d..f5dfba095 100644 --- a/src/script/api/script_goal.hpp +++ b/src/script/api/script_goal.hpp @@ -12,6 +12,7 @@ #ifndef SCRIPT_GOAL_HPP #define SCRIPT_GOAL_HPP +#include "script_client.hpp" #include "script_company.hpp" #include "../../goal_type.h" @@ -160,7 +161,7 @@ public: static bool IsCompleted(GoalID goal_id); /** - * Ask a question. + * Ask a question of all players in a company. * @param uniqueid Your unique id to distinguish results of multiple questions in the returning event. * @param company The company to ask the question, or ScriptCompany::COMPANY_INVALID for all. * @param question The question to ask (can be either a raw string, or a ScriptText object). @@ -176,6 +177,24 @@ public: */ static bool Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons); + /** + * Ask client a question. + * @param uniqueid Your unique id to distinguish results of multiple questions in the returning event. + * @param client The client to ask the question. + * @param question The question to ask (can be either a raw string, or a ScriptText object). + * @param type The type of question that is being asked. + * @param buttons Any combinations (at least 1, up to 3) of buttons defined in QuestionButton. Like BUTTON_YES + BUTTON_NO. + * @return True if the action succeeded. + * @pre No ScriptCompanyMode may be in scope. + * @pre ScriptGame::IsMultiplayer() + * @pre question != NULL && len(question) != 0. + * @pre ResolveClientID(client) != CLIENT_INVALID. + * @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3. + * @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer. + * @note There is no guarantee you ever get a reply on your question. + */ + static bool QuestionClient(uint16 uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, int buttons); + /** * Close the question on all clients. * @param uniqueid The uniqueid of the question you want to close. @@ -187,6 +206,12 @@ public: * companies, but you are only interested in the reply of the first. */ static bool CloseQuestion(uint16 uniqueid); + +protected: + /** + * Does common checks and asks the question. + */ + static bool DoQuestion(uint16 uniqueid, uint8 target, bool is_client, Text *question, QuestionType type, int buttons); }; #endif /* SCRIPT_GOAL_HPP */ -- cgit v1.2.3-54-g00ecf