From 6ea98200a90304a7dd54cdddb6a11910ad57cc39 Mon Sep 17 00:00:00 2001 From: Per Inge Mathisen Date: Sat, 2 Sep 2017 17:27:02 +0200 Subject: [PATCH] qtscript: New function setObjectFlag() Added setObjectFlag(object, flag, value) which allows you to set a flag on or off for a game object. For now, only the new flag OBJECT_FLAG_UNSELECTABLE is supported, which will make game object unable to be selected by the player. New cheat code 'untouchable' allows you test test this functionality. --- src/basedef.h | 1 + src/cheat.cpp | 1 + src/display.cpp | 4 ++-- src/droid.cpp | 4 ++++ src/keybind.cpp | 29 +++++++++++++++++++++++++++++ src/keybind.h | 1 + src/qtscriptfuncs.cpp | 22 ++++++++++++++++++++++ src/selection.cpp | 9 ++++----- 8 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/basedef.h b/src/basedef.h index d72d3994fa6..ee141a04084 100644 --- a/src/basedef.h +++ b/src/basedef.h @@ -103,6 +103,7 @@ enum OBJECT_FLAG OBJECT_FLAG_JAMMED_TILES, OBJECT_FLAG_TARGETED, OBJECT_FLAG_DIRTY, + OBJECT_FLAG_UNSELECTABLE, OBJECT_FLAG_COUNT }; diff --git a/src/cheat.cpp b/src/cheat.cpp index cce05a0eb52..09670a3d4fc 100644 --- a/src/cheat.cpp +++ b/src/cheat.cpp @@ -47,6 +47,7 @@ static CHEAT_ENTRY cheatCodes[] = {"jsload", jsAutogame}, // load an AI script for selectedPlayer {"jsdebug", jsShowDebug}, // show scripting states {"teach us", kf_TeachSelected}, // give experience to selected units + {"untouchable", kf_Unselectable}, // make selected droids unselectable {"clone wars", []{ kf_CloneSelected(10); }}, // clone selected units {"clone wars!", []{ kf_CloneSelected(40); }}, // clone selected units {"clone wars!!", []{ kf_CloneSelected(135); }}, // clone selected units diff --git a/src/display.cpp b/src/display.cpp index ef145150e20..36e67121d9e 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -1733,7 +1733,7 @@ static void dealWithLMBStructure(STRUCTURE *psStructure, SELECTION_TYPE selectio } /* Got to be built. Also, you can't 'select' derricks */ - if (!specialOrderKeyDown() && (psStructure->status == SS_BUILT) && + if (!specialOrderKeyDown() && (psStructure->status == SS_BUILT) && !psStructure->flags.test(OBJECT_FLAG_UNSELECTABLE) && (psStructure->pStructureType->type != REF_RESOURCE_EXTRACTOR) && ownStruct) { if (bRightClickOrders) @@ -1770,7 +1770,7 @@ static void dealWithLMBStructure(STRUCTURE *psStructure, SELECTION_TYPE selectio } } - else if ((psStructure->status == SS_BUILT) && + else if ((psStructure->status == SS_BUILT) && !psStructure->flags.test(OBJECT_FLAG_UNSELECTABLE) && (psStructure->pStructureType->type == REF_RESOURCE_EXTRACTOR) && selection == SC_INVALID && ownStruct) { diff --git a/src/droid.cpp b/src/droid.cpp index 909cb74a258..dfde1e4dea2 100644 --- a/src/droid.cpp +++ b/src/droid.cpp @@ -3136,6 +3136,10 @@ bool checkValidWeaponForProp(DROID_TEMPLATE *psTemplate) // void SelectDroid(DROID *psDroid) { + if (psDroid->flags.test(OBJECT_FLAG_UNSELECTABLE)) + { + return; + } // we shouldn't ever control the transporter in SP games if (!isTransporter(psDroid) || bMultiPlayer) { diff --git a/src/keybind.cpp b/src/keybind.cpp index cbe6baee403..1268579c677 100644 --- a/src/keybind.cpp +++ b/src/keybind.cpp @@ -445,6 +445,35 @@ void kf_TeachSelected() } } +void kf_Unselectable() +{ +#ifndef DEBUG + // Bail out if we're running a _true_ multiplayer game (to prevent MP cheating) + if (runningMultiplayer()) + { + noMPCheatMsg(); + return; + } +#endif + + for (DROID *psDroid = apsDroidLists[selectedPlayer]; psDroid; psDroid = psDroid->psNext) + { + if (psDroid->selected) + { + psDroid->flags.set(OBJECT_FLAG_UNSELECTABLE, true); + psDroid->selected = false; + } + } + for (STRUCTURE *psStruct = apsStructLists[selectedPlayer]; psStruct; psStruct = psStruct->psNext) + { + if (psStruct->selected) + { + psStruct->flags.set(OBJECT_FLAG_UNSELECTABLE, true); + psStruct->selected = false; + } + } +} + // -------------------------------------------------------------------------- // ///* Prints out the date and time of the build of the game */ diff --git a/src/keybind.h b/src/keybind.h index cb9a2afea61..bb356fc9f47 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -235,6 +235,7 @@ void kf_SlowDown(); void kf_NormalSpeed(); void kf_TeachSelected(); +void kf_Unselectable(); void kf_CloneSelected(int); void kf_Reload(); diff --git a/src/qtscriptfuncs.cpp b/src/qtscriptfuncs.cpp index 21baa5f7574..f2637079a8c 100644 --- a/src/qtscriptfuncs.cpp +++ b/src/qtscriptfuncs.cpp @@ -4257,6 +4257,26 @@ static QScriptValue js_setHealth(QScriptContext *context, QScriptEngine *) return QScriptValue(); } +//-- \subsection{setObjectFlag(object, flag, value)} +//-- Set or unset an object flag on a given game object. Does not take care of network sync, so for multiplayer games, +//-- needs wrapping in a syncRequest. (3.2.4+ only.) +//-- Recognized object flags: OBJECT_FLAG_UNSELECTABLE - makes object unavailable for selection from player UI. +static QScriptValue js_setObjectFlag(QScriptContext *context, QScriptEngine *) +{ + QScriptValue obj = context->argument(0); + OBJECT_FLAG flag = (OBJECT_FLAG)context->argument(1).toInt32(); + SCRIPT_ASSERT(context, flag < OBJECT_FLAG_COUNT, "Bad flag value %d", context->argument(1).toInt32()); + int id = obj.property("id").toInt32(); + int player = obj.property("player").toInt32(); + OBJECT_TYPE type = (OBJECT_TYPE)obj.property("type").toInt32(); + SCRIPT_ASSERT(context, type == OBJ_DROID || type == OBJ_STRUCTURE || type == OBJ_FEATURE, "Bad object type"); + BASE_OBJECT *psObj = IdToObject(type, id, player); + SCRIPT_ASSERT(context, psObj, "Object not found!"); + bool value = context->argument(2).toBool(); + psObj->flags.set(flag, value); + return QScriptValue(); +} + //-- \subsection{addSpotter(x, y, player, range, type, expiry)} //-- Add an invisible viewer at a given position for given player that shows map in given range. \emph{type} //-- is zero for vision reveal, or one for radar reveal. The difference is that a radar reveal can be obstructed @@ -5508,6 +5528,7 @@ bool registerFunctions(QScriptEngine *engine, const QString& scriptName) engine->globalObject().setProperty("setNoGoArea", engine->newFunction(js_setNoGoArea)); engine->globalObject().setProperty("startTransporterEntry", engine->newFunction(js_startTransporterEntry)); engine->globalObject().setProperty("setTransporterExit", engine->newFunction(js_setTransporterExit)); + engine->globalObject().setProperty("setObjectFlag", engine->newFunction(js_setObjectFlag)); // Set some useful constants engine->globalObject().setProperty("TER_WATER", TER_WATER, QScriptValue::ReadOnly | QScriptValue::Undeletable); @@ -5600,6 +5621,7 @@ bool registerFunctions(QScriptEngine *engine, const QString& scriptName) engine->globalObject().setProperty("PLAYER_DATA", SCRIPT_PLAYER, QScriptValue::ReadOnly | QScriptValue::Undeletable); engine->globalObject().setProperty("RESEARCH_DATA", SCRIPT_RESEARCH, QScriptValue::ReadOnly | QScriptValue::Undeletable); engine->globalObject().setProperty("LZ_COMPROMISED_TIME", JS_LZ_COMPROMISED_TIME, QScriptValue::ReadOnly | QScriptValue::Undeletable); + engine->globalObject().setProperty("OBJECT_FLAG_UNSELECTABLE", OBJECT_FLAG_UNSELECTABLE, QScriptValue::ReadOnly | QScriptValue::Undeletable); // the constants below are subject to change without notice... engine->globalObject().setProperty("PROX_MSG", MSG_PROXIMITY, QScriptValue::ReadOnly | QScriptValue::Undeletable); engine->globalObject().setProperty("CAMP_MSG", MSG_CAMPAIGN, QScriptValue::ReadOnly | QScriptValue::Undeletable); diff --git a/src/selection.cpp b/src/selection.cpp index 65dffbfbe8d..c2b02d4158c 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -58,7 +58,7 @@ static unsigned selSelectUnitsIf(unsigned player, T condition, bool onlyOnScreen bool shouldSelect = (!onlyOnScreen || droidOnScreen(psDroid, 0)) && condition(psDroid); count += shouldSelect; - if (shouldSelect && !psDroid->selected) + if (shouldSelect && !psDroid->selected && !psDroid->flags.test(OBJECT_FLAG_UNSELECTABLE)) { SelectDroid(psDroid); } @@ -373,8 +373,7 @@ void selNextSpecifiedBuilding(STRUCTURE_TYPE structType) for (STRUCTURE *psCurr = apsStructLists[selectedPlayer]; psCurr && !psResult; psCurr = psCurr->psNext) { - if ((psCurr->pStructureType->type == structType) && - (psCurr->status == SS_BUILT)) + if (psCurr->pStructureType->type == structType && psCurr->status == SS_BUILT) { if (!psFirst) { @@ -447,12 +446,12 @@ void selCommander(int n) { if (droidIsCommanderNum(psCurr, n)) { - if (!psCurr->selected) + if (!psCurr->selected && !psCurr->flags.test(OBJECT_FLAG_UNSELECTABLE)) { clearSelection(); psCurr->selected = true; } - else + else if (!psCurr->flags.test(OBJECT_FLAG_UNSELECTABLE)) { clearSelection(); psCurr->selected = true;