1 /** @file world/actions.cpp 2 * 3 * @authors Copyright (c) 2015-2017 Jaakko Keränen <jaakko.keranen@iki.fi> 4 * 5 * @par License 6 * GPL: http://www.gnu.org/licenses/gpl.html 7 * 8 * <small>This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. This program is distributed in the hope that it 12 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 14 * Public License for more details. You should have received a copy of the GNU 15 * General Public License along with this program; if not, see: 16 * http://www.gnu.org/licenses</small> 17 */ 18 19 #include "doomsday/world/actions.h" 20 #include "doomsday/gameapi.h" 21 #include "doomsday/doomsdayapp.h" 22 #include "doomsday/players.h" 23 #include "doomsday/world/mobjthinkerdata.h" 24 #include "doomsday/defs/ded.h" 25 26 #include <de/DictionaryValue> 27 #include <de/NativePointerValue> 28 #include <de/Process> 29 #include <de/String> 30 #include <de/TextValue> 31 #include <QMap> 32 33 using namespace de; 34 35 static QMap<String, acfnptr_t> s_actions; ///< name => native function pointer. 36 static String s_currentAction; 37 A_DoomsdayScript(void * actor)38static void C_DECL A_DoomsdayScript(void *actor) 39 { 40 struct mobj_s *mobj = reinterpret_cast<struct mobj_s *>(actor); 41 int plrNum = -1; 42 43 auto &plrs = DoomsdayApp::players(); 44 45 // The actor can also be a player in the case of psprites. 46 // Look up the corresponding player. 47 { 48 for (int i = 0; i < DDMAXPLAYERS; ++i) 49 { 50 // Note: It is assumed that the player data structure begins with a pointer to 51 // the ddplayer_t. 52 53 if (&plrs.at(i).publicData() == 54 *reinterpret_cast<const ddplayer_t * const *>(actor)) 55 { 56 // Refer to the player mobj instead. 57 mobj = plrs.at(i).publicData().mo; 58 plrNum = i; 59 } 60 } 61 } 62 63 LOG_AS("A_DoomsdayScript"); 64 try 65 { 66 const ThinkerData &data = THINKER_DATA(mobj->thinker, ThinkerData); 67 Record ns; 68 if (plrNum >= 0) 69 { 70 ns.add(new Variable(QStringLiteral("player"), 71 new RecordValue(plrs.at(plrNum).objectNamespace()))); 72 } 73 ns.add(new Variable(QStringLiteral("self"), new RecordValue(data.objectNamespace()))); 74 Process proc(&ns); 75 const Script script(s_currentAction); 76 proc.run(script); 77 proc.execute(); 78 } 79 catch (const Error &er) 80 { 81 LOG_SCR_ERROR(er.asText()); 82 } 83 } 84 isScriptAction(const String & name)85static bool isScriptAction(const String &name) 86 { 87 return !name.beginsWith("A_"); 88 } 89 P_GetGameActions()90void P_GetGameActions() 91 { 92 s_actions.clear(); 93 94 // Action links are provided by the game (which owns the actual action functions). 95 if (auto getVar = DoomsdayApp::plugins().gameExports().GetPointer) 96 { 97 auto const *links = (actionlink_t const *) getVar(DD_ACTION_LINK); 98 for (actionlink_t const *link = links; link && link->name; link++) 99 { 100 s_actions.insert(String(link->name).toLower(), link->func); 101 } 102 } 103 } 104 P_SetCurrentAction(const String & name)105void P_SetCurrentAction(const String &name) 106 { 107 s_currentAction = name; 108 } 109 P_SetCurrentActionState(int state)110void P_SetCurrentActionState(int state) 111 { 112 P_SetCurrentAction(DED_Definitions()->states[state].gets(QStringLiteral("action"))); 113 } 114 P_GetAction(const String & name)115acfnptr_t P_GetAction(const String &name) 116 { 117 if (!name.isEmpty()) 118 { 119 if (isScriptAction(name)) 120 { 121 return de::function_cast<acfnptr_t>(A_DoomsdayScript); 122 } 123 auto found = s_actions.find(name.toLower()); 124 if (found != s_actions.end()) return found.value(); 125 } 126 return nullptr; // Not found. 127 } 128 P_GetAction(const char * name)129acfnptr_t P_GetAction(const char *name) 130 { 131 return P_GetAction(String(name)); 132 } 133