Advertisement
holmbergfan

Untitled

Nov 28th, 2022
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 75.37 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. //////////////////////////////////////////////////////////////////////
  4. //
  5. //////////////////////////////////////////////////////////////////////
  6. // This program is free software; you can redistribute it and/or
  7. // modify it under the terms of the GNU General Public License
  8. // as published by the Free Software Foundation; either version 2
  9. // of the License, or (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program; if not, write to the Free Software Foundation,
  18. // Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19. //////////////////////////////////////////////////////////////////////
  20.  
  21.  
  22. #include "definitions.h"
  23. #include "npc.h"
  24. #include "game.h"
  25. #include "tools.h"
  26. #include "configmanager.h"
  27. #include "position.h"
  28. #include "spells.h"
  29. #include "player.h"
  30.  
  31. #include <algorithm>
  32. #include <functional>
  33. #include <string>
  34. #include <sstream>
  35. #include <fstream>
  36.  
  37. #include <libxml/xmlmemory.h>
  38. #include <libxml/parser.h>
  39.  
  40. #include "luascript.h"
  41.  
  42. extern ConfigManager g_config;
  43. extern Game g_game;
  44. extern Spells* g_spells;
  45.  
  46. AutoList<Npc> Npc::listNpc;
  47.  
  48. NpcScriptInterface* Npc::m_scriptInterface = NULL;
  49.  
  50. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  51. uint32_t Npc::npcCount = 0;
  52. #endif
  53.  
  54. void Npcs::reload()
  55. {
  56.     delete Npc::m_scriptInterface;
  57.     Npc::m_scriptInterface = NULL;
  58.  
  59.     for(AutoList<Npc>::listiterator it = Npc::listNpc.list.begin(); it != Npc::listNpc.list.end(); ++it){
  60.         it->second->reload();
  61.     }
  62. }
  63.  
  64. Npc* Npc::createNpc(const std::string& name)
  65. {
  66.     Npc* npc = new Npc(name);
  67.     if(!npc){
  68.         return NULL;
  69.     }
  70.  
  71.     if(!npc->load()){
  72.         delete npc;
  73.         return NULL;
  74.     }
  75.  
  76.     return npc;
  77. }
  78.  
  79. Npc::Npc(const std::string& _name) :
  80.     Creature()
  81. {
  82.     m_datadir = g_config.getString(ConfigManager::DATA_DIRECTORY);
  83.     m_scriptdir = m_datadir + "npc/scripts/";
  84.     m_filename = m_datadir + "npc/" + _name + ".xml";
  85.     loaded = false;
  86.  
  87.     m_npcEventHandler = NULL;
  88.     reset();
  89.  
  90. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  91.     npcCount++;
  92. #endif
  93. }
  94.  
  95. Npc::~Npc()
  96. {
  97.     reset();
  98.  
  99. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  100.     npcCount--;
  101. #endif
  102. }
  103.  
  104. bool Npc::load()
  105. {
  106.     if(isLoaded()){
  107.         return true;
  108.     }
  109.  
  110.     reset();
  111.  
  112.     if(!m_scriptInterface){
  113.         m_scriptInterface = new NpcScriptInterface();
  114.         m_scriptInterface->loadNpcLib(std::string(m_datadir + "npc/scripts/lib/npc.lua"));
  115.     }
  116.  
  117.     loaded = loadFromXml(m_filename);
  118.     return isLoaded();
  119. }
  120.  
  121. void Npc::reset()
  122. {
  123.     loaded = false;
  124.     walkTicks = 1500;
  125.     floorChange = false;
  126.     attackable = false;
  127.     hasBusyReply = false;
  128.     hasScriptedFocus = false;
  129.     focusCreature = 0;
  130.     isIdle = true;
  131.     talkRadius = 2;
  132.     idleTime = 0;
  133.     idleInterval = 5 * 60;
  134.  
  135.     delete m_npcEventHandler;
  136.     m_npcEventHandler = NULL;
  137.  
  138.     for(ResponseList::iterator it = responseList.begin(); it != responseList.end(); ++it){
  139.         delete *it;
  140.     }
  141.  
  142.     for(StateList::iterator it = stateList.begin(); it != stateList.end(); ++it){
  143.         delete *it;
  144.     }
  145.  
  146.     responseList.clear();
  147.     stateList.clear();
  148.     queueList.clear();
  149.     m_parameters.clear();
  150.     itemListMap.clear();
  151.     responseScriptMap.clear();
  152. }
  153.  
  154. void Npc::reload()
  155. {
  156.     reset();
  157.     load();
  158.  
  159.     //Simulate that the creature is placed on the map again.
  160.     if(m_npcEventHandler){
  161.         m_npcEventHandler->onCreatureAppear(this);
  162.     }
  163.  
  164.     if(walkTicks > 0){
  165.         addEventWalk();
  166.     }
  167. }
  168.  
  169. bool Npc::loadFromXml(const std::string& filename)
  170. {
  171.     xmlDocPtr doc = xmlParseFile(filename.c_str());
  172.  
  173.     if(doc){
  174.         xmlNodePtr root, p;
  175.         root = xmlDocGetRootElement(doc);
  176.  
  177.         if(xmlStrcmp(root->name,(const xmlChar*)"npc") != 0){
  178.             std::cerr << "Malformed XML" << std::endl;
  179.             return false;
  180.         }
  181.  
  182.         int intValue;
  183.         std::string strValue;
  184.  
  185.         p = root->children;
  186.        
  187.         std::string scriptfile = "";
  188.         if(readXMLString(root, "script", strValue)){
  189.             scriptfile = strValue;
  190.         }
  191.  
  192.         if(readXMLString(root, "name", strValue)){
  193.             name = strValue;
  194.         }
  195.         else
  196.             name = "";
  197.  
  198.         if(readXMLInteger(root, "speed", intValue)){
  199.             baseSpeed = intValue;
  200.         }
  201.         else
  202.             baseSpeed = 110;
  203.  
  204.         if(readXMLInteger(root, "attackable", intValue)){
  205.             attackable = (intValue != 0);
  206.         }
  207.  
  208.         if(readXMLInteger(root, "walkinterval", intValue)){
  209.             walkTicks = intValue;
  210.         }
  211.         if(readXMLInteger(root, "autowalk", intValue)){
  212.             //Depricated attribute.
  213.             if(intValue == 0){
  214.                 walkTicks = 2000;
  215.             }
  216.         }
  217.  
  218.         if(readXMLInteger(root, "floorchange", intValue)){
  219.             floorChange = (intValue != 0);
  220.         }
  221.  
  222.         while(p){
  223.             if(xmlStrcmp(p->name, (const xmlChar*)"health") == 0){
  224.  
  225.                 if(readXMLInteger(p, "now", intValue)){
  226.                     health = intValue;
  227.                 }
  228.                 else
  229.                     health = 100;
  230.  
  231.                 if(readXMLInteger(p, "max", intValue)){
  232.                     healthMax = intValue;
  233.                 }
  234.                 else
  235.                     healthMax = 100;
  236.             }
  237.             else if(xmlStrcmp(p->name, (const xmlChar*)"look") == 0){
  238.  
  239.                 if(readXMLInteger(p, "type", intValue)){
  240.                     defaultOutfit.lookType = intValue;
  241.  
  242.                     if(readXMLInteger(p, "head", intValue)){
  243.                         defaultOutfit.lookHead = intValue;
  244.                     }
  245.  
  246.                     if(readXMLInteger(p, "body", intValue)){
  247.                         defaultOutfit.lookBody = intValue;
  248.                     }
  249.  
  250.                     if(readXMLInteger(p, "legs", intValue)){
  251.                         defaultOutfit.lookLegs = intValue;
  252.                     }
  253.  
  254.                     if(readXMLInteger(p, "feet", intValue)){
  255.                         defaultOutfit.lookFeet = intValue;
  256.                     }
  257.                 }
  258.                 else if(readXMLInteger(p, "typeex", intValue)){
  259.                     defaultOutfit.lookTypeEx = intValue;
  260.                 }
  261.  
  262.                 currentOutfit = defaultOutfit;
  263.             }
  264.             else if(xmlStrcmp(p->name, (const xmlChar*)"parameters") == 0){
  265.                
  266.                 for(xmlNodePtr q = p->children; q != NULL; q = q->next){
  267.                     if(xmlStrcmp(q->name, (const xmlChar*)"parameter") == 0){
  268.                         std::string paramKey;
  269.                         std::string paramValue;
  270.                         if(!readXMLString(q, "key", paramKey)){
  271.                             continue;
  272.                         }
  273.                         if(!readXMLString(q, "value", paramValue)){
  274.                             continue;
  275.                         }
  276.                         m_parameters[paramKey] = paramValue;
  277.                     }
  278.                 }
  279.  
  280.             }
  281.             else if(xmlStrcmp(p->name, (const xmlChar*)"interaction") == 0){
  282.                 if(readXMLInteger(p, "talkradius", intValue)){
  283.                     talkRadius = intValue;
  284.                 }
  285.  
  286.                 if(readXMLInteger(p, "idletime", intValue)){
  287.                     idleTime = intValue;
  288.                 }
  289.                
  290.                 if(readXMLInteger(p, "idleinterval", intValue)){
  291.                     idleInterval = intValue;
  292.                 }
  293.  
  294.                 responseList = loadInteraction(p->children);
  295.             }
  296.  
  297.             p = p->next;
  298.         }
  299.  
  300.         xmlFreeDoc(doc);
  301.  
  302.         if(!scriptfile.empty()){
  303.             m_npcEventHandler = new NpcScript(m_scriptdir + scriptfile, this);
  304.             if(!m_npcEventHandler->isLoaded()){
  305.                 return false;
  306.             }
  307.         }
  308.  
  309.         return true;
  310.     }
  311.  
  312.     return false;
  313. }
  314.  
  315. uint32_t Npc::loadParams(xmlNodePtr node)
  316. {
  317.     uint32_t params = RESPOND_DEFAULT;
  318.     std::string strValue;
  319.  
  320.     if(readXMLString(node, "param", strValue)){
  321.         std::vector<std::string> paramList = explodeString(strValue, ";");
  322.         for(std::vector<std::string>::iterator it = paramList.begin(); it != paramList.end(); ++it){
  323.             if(asLowerCaseString(*it) == "male"){
  324.                 params |= RESPOND_MALE;
  325.             }
  326.             else if(asLowerCaseString(*it) == "female"){
  327.                 params |= RESPOND_FEMALE;
  328.             }
  329.             else if(asLowerCaseString(*it) == "pzblock"){
  330.                 params |= RESPOND_PZBLOCK;
  331.             }
  332.             else if(asLowerCaseString(*it) == "lowmoney"){
  333.                 params |= RESPOND_LOWMONEY;
  334.             }
  335.             else if(asLowerCaseString(*it) == "noamount"){
  336.                 params |= RESPOND_NOAMOUNT;
  337.             }
  338.             else if(asLowerCaseString(*it) == "lowamount"){
  339.                 params |= RESPOND_LOWAMOUNT;
  340.             }
  341.             else if(asLowerCaseString(*it) == "premium"){
  342.                 params |= RESPOND_PREMIUM;
  343.             }
  344.             else if(asLowerCaseString(*it) == "druid"){
  345.                 params |= RESPOND_DRUID;
  346.             }
  347.             else if(asLowerCaseString(*it) == "knight"){
  348.                 params |= RESPOND_KNIGHT;
  349.             }
  350.             else if(asLowerCaseString(*it) == "paladin"){
  351.                 params |= RESPOND_PALADIN;
  352.             }
  353.             else if(asLowerCaseString(*it) == "sorcerer"){
  354.                 params |= RESPOND_SORCERER;
  355.             }
  356.             else if(asLowerCaseString(*it) == "lowlevel"){
  357.                 params |= RESPOND_LOWLEVEL;
  358.             }
  359.             else{
  360.                 std::cout << "Warning: [Npc::loadParams] Unknown param " << (*it) << std::endl;
  361.             }
  362.         }
  363.     }
  364.  
  365.     return params;
  366. }
  367.  
  368. ResponseList Npc::loadInteraction(xmlNodePtr node)
  369. {
  370.     ResponseList _responseList;
  371.     std::string strValue ;
  372.     int32_t intValue;
  373.  
  374.     while(node){
  375.         if(xmlStrcmp(node->name, (const xmlChar*)"include") == 0){
  376.             if(readXMLString(node, "file", strValue)){
  377.                 std::string includeFilename = m_datadir + "npc/lib/" + strValue;
  378.                 xmlDocPtr doc = xmlParseFile(includeFilename.c_str());
  379.                 if(doc){
  380.                     xmlNodePtr root;
  381.                     root = xmlDocGetRootElement(doc);
  382.  
  383.                     if(xmlStrcmp(root->name,(const xmlChar*)"interaction") == 0){
  384.                         ResponseList includeResponseList = loadInteraction(root->children);
  385.                         _responseList.insert(_responseList.end(), includeResponseList.begin(), includeResponseList.end());
  386.                     }
  387.                     else{
  388.                         std::cerr << "Malformed XML" << std::endl;
  389.                     }
  390.  
  391.                     xmlFreeDoc(doc);
  392.                 }
  393.             }          
  394.         }
  395.         else if(xmlStrcmp(node->name, (const xmlChar*)"itemlist") == 0){
  396.             if(readXMLString(node, "listid", strValue)){
  397.                
  398.                 ItemListMap::iterator it = itemListMap.find(strValue);
  399.                 if(it != itemListMap.end()){
  400.                     //duplicate listid found
  401.                     std::cout << "Warning: [Npc::loadInteraction] Duplicate listId found " << strValue << std::endl;
  402.                 }
  403.                 else{
  404.                     std::string listId = strValue;
  405.                     xmlNodePtr tmpNode = node->children;
  406.                     std::list<ListItem>& list = itemListMap[strValue];
  407.  
  408.                     while(tmpNode){
  409.                         if(xmlStrcmp(tmpNode->name, (const xmlChar*)"item") == 0){
  410.                             ListItem li;
  411.  
  412.                             if(readXMLInteger(tmpNode, "id", intValue)){
  413.                                 li.itemId = intValue;
  414.                             }
  415.                             else{
  416.                                 std::cout << "Warning: [Npc::loadInteraction] Missing list item itemId " << std::endl;
  417.                                 tmpNode = tmpNode->next;
  418.                                 continue;
  419.                             }
  420.  
  421.                             if(readXMLInteger(tmpNode, "sellprice", intValue)){
  422.                                 li.sellPrice = intValue;
  423.                             }
  424.  
  425.                             if(readXMLInteger(tmpNode, "buyprice", intValue)){
  426.                                 li.buyPrice = intValue;
  427.                             }
  428.  
  429.                             if(readXMLString(tmpNode, "keywords", strValue)){
  430.                                 li.keywords = strValue;
  431.                             }
  432.                             else{
  433.                                 std::cout << "Warning: [Npc::loadInteraction] Missing list item keywords " << std::endl;
  434.                                 tmpNode = tmpNode->next;
  435.                                 continue;
  436.                             }
  437.  
  438.                             //optional
  439.                             if(readXMLInteger(tmpNode, "subtype", intValue)){
  440.                                 li.subType = intValue;
  441.                             }
  442.  
  443.                             if(readXMLString(tmpNode, "name", strValue)){
  444.                                 li.name = strValue;
  445.                             }
  446.  
  447.                             if(readXMLString(tmpNode, "pname", strValue)){
  448.                                 li.pluralName = strValue;
  449.                             }
  450.  
  451.                             list.push_back(li);
  452.                         }
  453.  
  454.                         tmpNode = tmpNode->next;
  455.                     }
  456.                 }
  457.             }
  458.         }
  459.         else if(xmlStrcmp(node->name, (const xmlChar*)"interact") == 0){
  460.             NpcResponse::ResponseProperties prop;
  461.  
  462.             if(readXMLString(node, "keywords", strValue)){
  463.                 prop.inputList.push_back(asLowerCaseString(strValue));
  464.             }
  465.             else if(readXMLString(node, "event", strValue)){
  466.                 strValue = asLowerCaseString(strValue);
  467.                 if(strValue == "onbusy"){
  468.                     hasBusyReply = true;
  469.                 }
  470.  
  471.                 prop.interactType = INTERACT_EVENT;
  472.                 prop.inputList.push_back(strValue);
  473.             }
  474.  
  475.             if(readXMLInteger(node, "topic", intValue)){
  476.                 prop.topic = intValue;
  477.             }
  478.  
  479.             if(readXMLInteger(node, "focus", intValue)){
  480.                 prop.focusStatus = intValue;
  481.             }
  482.            
  483.             if(readXMLInteger(node, "storageId", intValue)){
  484.                 prop.storageId = intValue;
  485.             }
  486.  
  487.             if(readXMLInteger(node, "storageValue", intValue)){
  488.                 prop.storageValue = intValue;
  489.             }
  490.  
  491.             uint32_t interactParams = loadParams(node);
  492.  
  493.             if(readXMLString(node, "storageComp", strValue)){
  494.                 if(asLowerCaseString(strValue) == "equal"){
  495.                     prop.storageComp = STORAGE_EQUAL;
  496.                 }
  497.                 if(asLowerCaseString(strValue) == "greaterorequal"){
  498.                     prop.storageComp = STORAGE_GREATEROREQUAL;
  499.                 }
  500.                 if(asLowerCaseString(strValue) == "greater"){
  501.                     prop.storageComp = STORAGE_GREATER;
  502.                 }
  503.                 if(asLowerCaseString(strValue) == "less"){
  504.                     prop.storageComp = STORAGE_LESS;
  505.                 }
  506.                 if(asLowerCaseString(strValue) == "lessorequal"){
  507.                     prop.storageComp = STORAGE_LESSOREQUAL;
  508.                 }
  509.             }
  510.  
  511.             xmlNodePtr tmpNode = node->children;
  512.             while(tmpNode){
  513.                 if(xmlStrcmp(tmpNode->name, (const xmlChar*)"keywords") == 0){
  514.                     //alternative input keywords
  515.                     xmlNodePtr altKeyNode = tmpNode->children;
  516.                     while(altKeyNode){
  517.                         if(xmlStrcmp(altKeyNode->name, (const xmlChar*)"text") == 0){
  518.                             if(readXMLContentString(altKeyNode, strValue)){
  519.                                 prop.inputList.push_back(asLowerCaseString(strValue));
  520.                             }
  521.                         }
  522.  
  523.                         altKeyNode = altKeyNode->next;
  524.                     }
  525.                 }
  526.                 else if(xmlStrcmp(tmpNode->name, (const xmlChar*)"list") == 0){
  527.                     xmlNodePtr listNode = tmpNode->children;
  528.                     while(listNode){
  529.                         if(xmlStrcmp(listNode->name, (const xmlChar*)"text") == 0){
  530.                             if(readXMLContentString(listNode, strValue)){
  531.                                 ItemListMap::iterator it = itemListMap.find(strValue);
  532.                                 if(it != itemListMap.end()){
  533.                                     prop.itemList.insert(prop.itemList.end(), it->second.begin(), it->second.end());
  534.                                 }
  535.                                 else{
  536.                                     std::cout << "Warning: [Npc::loadInteraction] Could not find a list id called " << strValue << std::endl;
  537.                                 }
  538.                             }
  539.                         }
  540.  
  541.                         listNode = listNode->next;
  542.                     }
  543.                 }
  544.                 tmpNode = tmpNode->next;
  545.             }
  546.  
  547.  
  548.             tmpNode = node->children;
  549.             while(tmpNode){
  550.                 if(xmlStrcmp(tmpNode->name, (const xmlChar*)"response") == 0){
  551.  
  552.                     prop.output = "";
  553.                     prop.knowSpell = "";
  554.                     prop.params = interactParams | loadParams(tmpNode);
  555.                     ScriptVars scriptVars;
  556.  
  557.                     if(readXMLString(tmpNode, "knowspell", strValue)){
  558.                         prop.knowSpell = strValue;
  559.                     }
  560.  
  561.                     if(readXMLString(tmpNode, "text", strValue)){
  562.                         prop.responseType = RESPONSE_DEFAULT;
  563.                         prop.output = strValue;
  564.                     }
  565.                     else if(readXMLString(tmpNode, "function", strValue)){
  566.                         prop.responseType = RESPONSE_SCRIPT;
  567.                         prop.output = strValue;
  568.                     }
  569.  
  570.                     if(readXMLInteger(tmpNode, "b1", intValue)){
  571.                         scriptVars.b1 = (intValue == 1);
  572.                     }
  573.  
  574.                     if(readXMLInteger(tmpNode, "b2", intValue)){
  575.                         scriptVars.b2 = (intValue == 1);
  576.                     }
  577.  
  578.                     if(readXMLInteger(tmpNode, "b3", intValue)){
  579.                         scriptVars.b3 = (intValue == 1);
  580.                     }
  581.  
  582.                     ResponseList subResponseList;
  583.  
  584.                     xmlNodePtr subNode = tmpNode->children;
  585.                     while(subNode){
  586.                         if(xmlStrcmp(subNode->name, (const xmlChar*)"action") == 0){
  587.                             ResponseAction action;
  588.  
  589.                             if(readXMLString(subNode, "name", strValue)){
  590.                                 if(asLowerCaseString(strValue) == "topic"){
  591.                                     if(readXMLInteger(subNode, "value", intValue)){
  592.                                         action.actionType = ACTION_SETTOPIC;
  593.                                         action.intValue = intValue;
  594.                                     }
  595.                                 }
  596.                                 else if(asLowerCaseString(strValue) == "price"){
  597.                                     if(readXMLString(subNode, "value", strValue)){
  598.                                         action.actionType = ACTION_SETPRICE;
  599.                                         action.strValue = strValue;
  600.                                         action.intValue = atoi(strValue.c_str());
  601.                                     }
  602.                                 }
  603.                                 else if(asLowerCaseString(strValue) == "amount"){
  604.                                     if(readXMLString(subNode, "value", strValue)){
  605.                                         action.actionType = ACTION_SETAMOUNT;
  606.                                         action.strValue = strValue;
  607.                                         action.intValue = atoi(strValue.c_str());
  608.                                     }
  609.                                 }
  610.                                 else if(asLowerCaseString(strValue) == "item"){
  611.                                     if(readXMLInteger(subNode, "value", intValue)){
  612.                                         action.actionType = ACTION_SETITEM;
  613.                                         action.intValue = intValue;
  614.                                     }
  615.                                 }
  616.                                 else if(asLowerCaseString(strValue) == "subtype"){
  617.                                     if(readXMLInteger(subNode, "value", intValue)){
  618.                                         action.actionType = ACTION_SETSUBTYPE;
  619.                                         action.intValue = intValue;
  620.                                     }
  621.                                 }
  622.                                 else if(asLowerCaseString(strValue) == "spell"){
  623.                                     if(readXMLString(subNode, "value", strValue)){
  624.                                         action.actionType = ACTION_SETSPELL;
  625.                                         action.strValue = strValue;
  626.  
  627.                                         if(strValue != "|SPELL|"){
  628.                                             InstantSpell* spell = g_spells->getInstantSpellByName(strValue);
  629.                                             if(!spell){                
  630.                                                 std::cout << "Warning: [Npc::loadInteraction] Could not find an instant spell called " << strValue << std::endl;
  631.                                             }
  632.                                         }
  633.                                     }
  634.                                 }
  635.                                 else if(asLowerCaseString(strValue) == "listname"){
  636.                                     if(readXMLString(subNode, "value", strValue)){
  637.                                         action.actionType = ACTION_SETLISTNAME;
  638.                                         action.strValue = strValue;
  639.                                     }
  640.                                 }
  641.                                 else if(asLowerCaseString(strValue) == "listpname"){
  642.                                     if(readXMLString(subNode, "value", strValue)){
  643.                                         action.actionType = ACTION_SETLISTPNAME;
  644.                                         action.strValue = strValue;
  645.                                     }
  646.                                 }
  647.                                 else if(asLowerCaseString(strValue) == "teachspell"){
  648.                                     if(readXMLString(subNode, "value", strValue)){
  649.                                         action.actionType = ACTION_TEACHSPELL;
  650.                                         action.strValue = strValue;
  651.  
  652.                                         if(strValue != "|SPELL|"){
  653.                                             InstantSpell* spell = g_spells->getInstantSpellByName(strValue);
  654.                                             if(!spell){                
  655.                                                 std::cout << "Warning: [Npc::loadInteraction] Could not find an instant spell called " << strValue << std::endl;
  656.                                             }
  657.                                         }
  658.                                     }
  659.                                 }
  660.                                 else if(asLowerCaseString(strValue) == "sell"){
  661.                                     if(readXMLString(subNode, "value", strValue)){
  662.                                         action.actionType = ACTION_SELLITEM;
  663.                                         action.strValue = strValue;
  664.                                         action.intValue = atoi(strValue.c_str());
  665.                                     }
  666.                                 }
  667.                                 else if(asLowerCaseString(strValue) == "buy"){
  668.                                     if(readXMLString(subNode, "value", strValue)){
  669.                                         action.actionType = ACTION_BUYITEM;
  670.                                         action.strValue = strValue;
  671.                                         action.intValue = atoi(strValue.c_str());
  672.                                     }
  673.                                 }
  674.                                 else if(asLowerCaseString(strValue) == "takemoney"){
  675.                                     if(readXMLString(subNode, "value", strValue)){
  676.                                         action.actionType = ACTION_TAKEMONEY;
  677.                                         action.strValue = strValue;
  678.                                         action.intValue = atoi(strValue.c_str());
  679.                                     }
  680.                                 }
  681.                                 else if(asLowerCaseString(strValue) == "givemoney"){
  682.                                     if(readXMLString(subNode, "value", strValue)){
  683.                                         action.actionType = ACTION_GIVEMONEY;
  684.                                         action.strValue = strValue;
  685.                                         action.intValue = atoi(strValue.c_str());
  686.                                     }
  687.                                 }
  688.                                 else if(asLowerCaseString(strValue) == "level"){
  689.                                     if(readXMLString(subNode, "value", strValue)){
  690.                                         action.actionType = ACTION_SETLEVEL;
  691.                                         action.strValue = strValue;
  692.                                         action.intValue = atoi(strValue.c_str());
  693.                                     }
  694.                                 }
  695.                                 else if(asLowerCaseString(strValue) == "giveitem"){
  696.                                     if(readXMLString(subNode, "value", strValue)){
  697.                                         action.actionType = ACTION_GIVEITEM;
  698.                                         action.strValue = strValue;
  699.                                         action.intValue = atoi(strValue.c_str());
  700.                                     }
  701.                                 }
  702.                                 else if(asLowerCaseString(strValue) == "takeitem"){
  703.                                     if(readXMLString(subNode, "value", strValue)){
  704.                                         action.actionType = ACTION_TAKEITEM;
  705.                                         action.strValue = strValue;
  706.                                         action.intValue = atoi(strValue.c_str());
  707.                                     }
  708.                                 }
  709.                                 else if(asLowerCaseString(strValue) == "effect"){
  710.                                     if(readXMLString(subNode, "value", strValue)){
  711.                                         action.actionType = ACTION_SETEFFECT;
  712.                                         action.intValue = getMagicEffect(strValue);
  713.                                     }
  714.                                 }
  715.                                 else if(asLowerCaseString(strValue) == "idle"){
  716.                                     if(readXMLInteger(subNode, "value", intValue)){
  717.                                         action.actionType = ACTION_SETIDLE;
  718.                                         action.intValue = intValue;
  719.                                     }
  720.                                 }
  721.                                 else if(asLowerCaseString(strValue) == "script"){
  722.                                     if(readXMLString(subNode, "value", strValue)){
  723.                                         action.actionType = ACTION_SCRIPT;
  724.                                         action.strValue = strValue;
  725.                                     }
  726.                                     else{
  727.                                         xmlNodePtr scriptNode = subNode->children;
  728.                                         while(scriptNode){
  729.                                             if(xmlStrcmp(scriptNode->name, (const xmlChar*)"text") == 0){
  730.                                                 if(readXMLContentString(scriptNode, strValue)){
  731.                                                     action.actionType = ACTION_SCRIPT;
  732.                                                     action.strValue = strValue;
  733.                                                 }
  734.                                             }
  735.                                             scriptNode = scriptNode->next;
  736.                                         }
  737.                                     }
  738.                                 }
  739.                                 else if(asLowerCaseString(strValue) == "scriptparam"){
  740.                                     if(readXMLString(subNode, "value", strValue)){
  741.                                         action.actionType = ACTION_SCRIPTPARAM;
  742.                                         action.strValue = strValue;
  743.                                     }
  744.                                 }
  745.                                 else if(asLowerCaseString(strValue) == "storage"){
  746.                                     if(readXMLInteger(subNode, "value", intValue)){
  747.                                         action.actionType = ACTION_SETSTORAGE;
  748.                                         action.intValue = intValue;
  749.                                     }
  750.                                 }
  751.                                 else if(asLowerCaseString(strValue) == "addqueue"){
  752.                                     if(readXMLString(subNode, "value", strValue)){
  753.                                         action.actionType = ACTION_ADDQUEUE;
  754.                                         action.strValue = strValue;
  755.                                         action.intValue = atoi(strValue.c_str());
  756.                                     }
  757.                                 }
  758.                                 else if(asLowerCaseString(strValue) == "teleport"){
  759.                                     if(readXMLString(subNode, "value", strValue)){
  760.                                         std::vector<std::string> posList = explodeString(strValue, ";");
  761.                                         action.actionType = ACTION_SETTELEPORT;
  762.                                         action.strValue = strValue;
  763.                                         action.pos.x = 0;
  764.                                         action.pos.y = 0;
  765.                                         action.pos.z = 0;
  766.  
  767.                                         if(posList.size() == 3){
  768.                                             action.pos.x = atoi(posList[0].c_str());
  769.                                             action.pos.y = atoi(posList[1].c_str());
  770.                                             action.pos.z = atoi(posList[2].c_str());
  771.                                         }
  772.                                     }
  773.                                 }
  774.                                 else{
  775.                                     std::cout << "Warning: [Npc::loadInteraction] Unknown action " << strValue << std::endl;
  776.                                 }
  777.                             }
  778.                            
  779.                             if(readXMLInteger(subNode, "key", intValue)){
  780.                                 action.key = intValue;
  781.                             }
  782.  
  783.                             if(action.actionType != ACTION_NONE){
  784.                                 prop.actionList.push_back(action);
  785.                             }
  786.                         }
  787.                         else if(xmlStrcmp(subNode->name, (const xmlChar*)"interact") == 0){
  788.                             if(subResponseList.empty()){
  789.                                 ResponseList nodeResponseList = loadInteraction(subNode);
  790.                                 subResponseList.insert(subResponseList.end(),
  791.                                     nodeResponseList.begin(), nodeResponseList.end());
  792.                             }
  793.                             else{
  794.                                 //Already loaded this interaction.
  795.                             }
  796.                         }
  797.  
  798.                         subNode = subNode->next;
  799.                     }
  800.            
  801.                     //Check if this interaction has a |list| keyword
  802.                     bool hasListKeyword = false;
  803.                     for(std::list<std::string>::iterator it = prop.inputList.begin();
  804.                         it != prop.inputList.end(); ++it){
  805.  
  806.                         if((*it).find("|list|") != std::string::npos){
  807.                             hasListKeyword = true;
  808.                             break;
  809.                         }
  810.                     }
  811.  
  812.                     //Iterate through all input keywords and replace all |LIST| with the item list
  813.                     if(hasListKeyword && !prop.itemList.empty()){
  814.  
  815.                         for(std::list<ListItem>::iterator it = prop.itemList.begin(); it != prop.itemList.end(); ++it){
  816.                             NpcResponse::ResponseProperties listItemProp = prop;
  817.  
  818.                             for(std::list<std::string>::iterator iit = listItemProp.inputList.begin();
  819.                                 iit != listItemProp.inputList.end(); ++iit){
  820.                                 std::string& input = (*iit);
  821.  
  822.                                 if(input.find("|list|") == std::string::npos){
  823.                                     continue;
  824.                                 }
  825.                                
  826.                                 //Replace |LIST| with the keyword in the list
  827.                                 replaceString(input, "|list|", (*it).keywords);
  828.  
  829.                                 ResponseAction action;
  830.  
  831.                                 action.actionType = ACTION_SETITEM;
  832.                                 action.intValue = (*it).itemId;
  833.                                 listItemProp.actionList.push_front(action);
  834.  
  835.                                 action.actionType = ACTION_SETSELLPRICE;
  836.                                 action.intValue = (*it).sellPrice;
  837.                                 listItemProp.actionList.push_front(action);
  838.  
  839.                                 action.actionType = ACTION_SETBUYPRICE;
  840.                                 action.intValue = (*it).buyPrice;
  841.                                 listItemProp.actionList.push_front(action);
  842.  
  843.                                 action.actionType = ACTION_SETSUBTYPE;
  844.                                 action.intValue = (*it).subType;
  845.                                 listItemProp.actionList.push_front(action);
  846.  
  847.                                 action.actionType = ACTION_SETSUBTYPE;
  848.                                 action.intValue = (*it).subType;
  849.                                 listItemProp.actionList.push_front(action);
  850.  
  851.                                 action.actionType = ACTION_SETLISTNAME;
  852.                                 if(!(*it).name.empty()){
  853.                                     action.strValue = (*it).name;
  854.                                 }
  855.                                 else{
  856.                                     const ItemType& itemType = Item::items[(*it).itemId];
  857.                                     if(itemType.id != 0){
  858.                                         action.strValue = itemType.article + " " + itemType.name;
  859.                                     }
  860.                                 }
  861.                                 listItemProp.actionList.push_front(action);
  862.  
  863.                                 action.actionType = ACTION_SETLISTPNAME;
  864.                                 if(!(*it).pluralName.empty()){
  865.                                     action.strValue = (*it).pluralName;
  866.                                 }
  867.                                 else{
  868.                                     const ItemType& itemType = Item::items[(*it).itemId];
  869.                                     if(itemType.id != 0){
  870.                                         action.strValue = itemType.pluralName;
  871.                                     }
  872.                                 }
  873.                                 listItemProp.actionList.push_front(action);
  874.  
  875.                                 ResponseList list;
  876.                                 for(ResponseList::iterator respIter = subResponseList.begin();
  877.                                     respIter != subResponseList.end(); ++respIter){
  878.                                         list.push_back(new NpcResponse(*(*respIter)));
  879.                                 }
  880.                                 //Create a new response for this list item
  881.                                 NpcResponse* response = new NpcResponse(listItemProp, list, scriptVars);
  882.                                 _responseList.push_back(response);
  883.                             }
  884.                         }
  885.                     }
  886.                     else{
  887.                         NpcResponse* response = new NpcResponse(prop, subResponseList, scriptVars);
  888.                         _responseList.push_back(response);
  889.                     }
  890.                 }
  891.  
  892.                 tmpNode = tmpNode->next;
  893.             }
  894.         }
  895.  
  896.         node = node->next;
  897.     }
  898.  
  899.     return _responseList;
  900. }
  901.  
  902. NpcState* Npc::getState(const Player* player, bool makeNew /*= true*/)
  903. {
  904.     for(StateList::iterator it = stateList.begin(); it != stateList.end(); ++it){
  905.         if((*it)->respondToCreature == player->getID()){
  906.             return *it;
  907.         }
  908.     }
  909.  
  910.     if(!makeNew){
  911.         return NULL;
  912.     }
  913.  
  914.     NpcState* state = new NpcState;
  915.     state->prevInteraction = 0;
  916.     state->price = 0;
  917.     state->sellPrice = 0;
  918.     state->buyPrice = 0;
  919.     state->amount = 1;
  920.     state->itemId = 0;
  921.     state->subType = -1;
  922.     state->spellName = "";
  923.     state->listName = "";
  924.     state->listPluralName = "";
  925.     state->level = -1;
  926.     state->topic = -1;
  927.     state->isIdle = true;
  928.     state->isQueued = false;
  929.     state->respondToText = "";
  930.     state->respondToCreature = 0;
  931.     state->lastResponse = NULL;
  932.     state->prevRespondToText = "";
  933.     stateList.push_back(state);
  934.     return state;
  935. }
  936.  
  937. bool Npc::canSee(const Position& pos) const
  938. {
  939.     if(pos.z != getPosition().z){
  940.         return false;
  941.     }
  942.  
  943.     return Creature::canSee(getPosition(), pos, Map::maxClientViewportX, Map::maxClientViewportY);
  944. }
  945.  
  946. std::string Npc::getDescription(int32_t lookDistance) const
  947. {
  948.     std::stringstream s;
  949.     s << name << ".";
  950.     return s.str();
  951. }
  952.  
  953. void Npc::onAddTileItem(const Tile* tile, const Position& pos, const Item* item)
  954. {
  955.     Creature::onAddTileItem(tile, pos, item);
  956. }
  957.  
  958. void Npc::onUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos,
  959.     const Item* oldItem, const ItemType& oldType, const Item* newItem, const ItemType& newType)
  960. {
  961.     Creature::onUpdateTileItem(tile, pos, stackpos, oldItem, oldType, newItem, newType);
  962. }
  963.  
  964. void Npc::onRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos,
  965.     const ItemType& iType, const Item* item)
  966. {
  967.     Creature::onRemoveTileItem(tile, pos, stackpos, iType, item);
  968. }
  969.  
  970. void Npc::onUpdateTile(const Tile* tile, const Position& pos)
  971. {
  972.     Creature::onUpdateTile(tile, pos);
  973. }
  974.  
  975. void Npc::onCreatureAppear(const Creature* creature, bool isLogin)
  976. {
  977.     Creature::onCreatureAppear(creature, isLogin);
  978.  
  979.     if(creature == this && walkTicks > 0){
  980.         addEventWalk();
  981.     }
  982.  
  983.     if(creature == this){
  984.         if(m_npcEventHandler){
  985.             m_npcEventHandler->onCreatureAppear(creature);
  986.         }
  987.     }
  988.     //only players for script events
  989.     else if(Player* player = const_cast<Player*>(creature->getPlayer())){
  990.         if(m_npcEventHandler){
  991.             m_npcEventHandler->onCreatureAppear(creature);
  992.         }
  993.  
  994.         NpcState* npcState = getState(player);
  995.         if(npcState){
  996.             if(canSee(player->getPosition())){
  997.                 npcState->respondToCreature = player->getID();
  998.                 onPlayerEnter(player, npcState);
  999.             }
  1000.         }
  1001.     }
  1002. }
  1003.  
  1004. void Npc::onCreatureDisappear(const Creature* creature, uint32_t stackpos, bool isLogout)
  1005. {
  1006.     Creature::onCreatureDisappear(creature, stackpos, isLogout);
  1007.  
  1008.     if(creature == this){
  1009.  
  1010.         /*
  1011.         Can't use this yet because Jiddo's scriptsystem isn't able to handle it.
  1012.         if(m_npcEventHandler){
  1013.             m_npcEventHandler->onCreatureDisappear(creature);
  1014.         }
  1015.         */
  1016.     }
  1017.     //only players for script events
  1018.     else if(Player* player = const_cast<Player*>(creature->getPlayer())){
  1019.         if(m_npcEventHandler){
  1020.             m_npcEventHandler->onCreatureDisappear(creature);
  1021.         }
  1022.  
  1023.         NpcState* npcState = getState(player);
  1024.         if(npcState){
  1025.             npcState->respondToCreature = player->getID();
  1026.             onPlayerLeave(player, npcState);
  1027.         }
  1028.     }
  1029. }
  1030.  
  1031. void Npc::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
  1032.         const Tile* oldTile, const Position& oldPos, uint32_t oldStackPos, bool teleport)
  1033. {
  1034.     Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, oldStackPos, teleport);
  1035.  
  1036.     if(creature == this){
  1037.         if(m_npcEventHandler){
  1038.             m_npcEventHandler->onCreatureMove(creature, oldPos, newPos);
  1039.         }
  1040.     }
  1041.     else if(Player* player = const_cast<Player*>(creature->getPlayer())){
  1042.         if(m_npcEventHandler){
  1043.             m_npcEventHandler->onCreatureMove(creature, oldPos, newPos);
  1044.         }
  1045.  
  1046.         NpcState* npcState = getState(player);
  1047.         if(npcState){
  1048.             bool canSeeNewPos = canSee(newPos);
  1049.             bool canSeeOldPos = canSee(oldPos);
  1050.  
  1051.             if(canSeeNewPos && !canSeeOldPos){
  1052.                 npcState->respondToCreature = player->getID();
  1053.                 onPlayerEnter(player, npcState);
  1054.             }
  1055.             else if(!canSeeNewPos && canSeeOldPos){
  1056.                 npcState->respondToCreature = player->getID();
  1057.                 onPlayerLeave(player, npcState);
  1058.             }
  1059.             else if(canSeeNewPos && canSeeOldPos){
  1060.                 npcState->respondToCreature = player->getID();
  1061.                 const NpcResponse* response = getResponse(player, npcState, EVENT_PLAYER_MOVE);
  1062.                 executeResponse(player, npcState, response);
  1063.             }
  1064.         }
  1065.     }
  1066. }
  1067.  
  1068. void Npc::onCreatureTurn(const Creature* creature, uint32_t stackpos)
  1069. {
  1070.     Creature::onCreatureTurn(creature, stackpos);
  1071. }
  1072.  
  1073. void Npc::onCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text)
  1074. {
  1075.     if(creature->getID() == this->getID())
  1076.         return;
  1077.  
  1078.     //only players for script events
  1079.     if(const Player* player = creature->getPlayer()){
  1080.  
  1081.         if(m_npcEventHandler){
  1082.             m_npcEventHandler->onCreatureSay(player, type, text);
  1083.         }
  1084.        
  1085.         if(type == SPEAK_SAY){
  1086.             const Position& myPos = getPosition();
  1087.             const Position& pos = creature->getPosition();
  1088.             if(canSee(myPos)){
  1089.                 if ((pos.x >= myPos.x - talkRadius) && (pos.x <= myPos.x + talkRadius) &&
  1090.                     (pos.y >= myPos.y - talkRadius) && (pos.y <= myPos.y + talkRadius)){
  1091.  
  1092.                     NpcState* npcState = getState(player);
  1093.                     npcState->respondToText = text;
  1094.                     npcState->respondToCreature = player->getID();
  1095.                 }
  1096.             }
  1097.         }
  1098.     }
  1099. }
  1100.  
  1101. void Npc::onCreatureChangeOutfit(const Creature* creature, const Outfit_t& outfit)
  1102. {
  1103.     #ifdef __DEBUG_NPC__
  1104.         std::cout << "Npc::onCreatureChangeOutfit" << std::endl;
  1105.     #endif
  1106. }
  1107.  
  1108. void Npc::onPlayerEnter(Player* player, NpcState* state)
  1109. {
  1110.     const NpcResponse* response = getResponse(player, state, EVENT_PLAYER_ENTER);
  1111.     executeResponse(player, state, response);
  1112. }
  1113.  
  1114. void Npc::onPlayerLeave(Player* player, NpcState* state)
  1115. {
  1116.     if(player){
  1117.         const NpcResponse* response = getResponse(player, state, EVENT_PLAYER_LEAVE);
  1118.         executeResponse(player, state, response);
  1119.     }
  1120. }
  1121.  
  1122. void Npc::onThink(uint32_t interval)
  1123. {
  1124.     Creature::onThink(interval);
  1125.     if(m_npcEventHandler){
  1126.         m_npcEventHandler->onThink();
  1127.     }
  1128.  
  1129.     isIdle = true;
  1130.     bool idleResponse = false;
  1131.     #define MAX_RAND_RANGE 10000000
  1132.     if(((uint32_t)MAX_RAND_RANGE * (EVENT_CREATURE_THINK_INTERVAL / 1000)) / idleInterval >= (uint32_t)random_range(0, MAX_RAND_RANGE)){
  1133.         idleResponse = true;
  1134.     }
  1135.  
  1136.     for(StateList::iterator it = stateList.begin(); it != stateList.end();){
  1137.         NpcState* npcState = *it;
  1138.         const NpcResponse* response = NULL;
  1139.  
  1140.         Player* player = g_game.getPlayerByID(npcState->respondToCreature);
  1141.         bool closeConversation = false;
  1142.         bool idleTimeout = false;
  1143.         if(!npcState->isQueued){
  1144.             if(npcState->prevInteraction == 0){
  1145.                 npcState->prevInteraction = OTSYS_TIME();
  1146.             }
  1147.  
  1148.             if(idleTime > 0 && (OTSYS_TIME() - npcState->prevInteraction) > idleTime * 1000){
  1149.                 idleTimeout = true;
  1150.                 closeConversation = true;
  1151.             }
  1152.         }
  1153.  
  1154.         if(idleResponse && player){
  1155.             response = getResponse(player, EVENT_IDLE);
  1156.             executeResponse(player, npcState, response);
  1157.             idleResponse = false;
  1158.         }
  1159.  
  1160.         if(!player || closeConversation){
  1161.             if(queueList.empty()){
  1162.                 if(idleTimeout){
  1163.                     onPlayerLeave(player, npcState);
  1164.                 }
  1165.             }
  1166.             else{
  1167.                 Player* nextPlayer = NULL;
  1168.                 while(!queueList.empty()){
  1169.                     nextPlayer = g_game.getPlayerByID(*queueList.begin());
  1170.                     if(nextPlayer){
  1171.                         NpcState* nextPlayerState = getState(nextPlayer, false);
  1172.                         if(nextPlayerState){
  1173.                             nextPlayerState->respondToText = nextPlayerState->prevRespondToText;
  1174.                             nextPlayerState->isQueued = false;
  1175.                             break;
  1176.                         }
  1177.                     }
  1178.  
  1179.                     queueList.erase(queueList.begin());
  1180.                 }
  1181.             }
  1182.  
  1183.             delete *it;
  1184.             stateList.erase(it++);
  1185.             //std::cout << "Closing conversation." << std::endl;
  1186.  
  1187.             continue;
  1188.         }
  1189.  
  1190.         if(!npcState->respondToText.empty()){
  1191.             if(hasBusyReply && !isIdle){
  1192.                 //Check if we have a busy reply
  1193.                 response = getResponse(player, npcState, EVENT_BUSY);
  1194.                 if(response){
  1195.                     executeResponse(player, npcState, response);
  1196.                 }
  1197.             }
  1198.             else{
  1199.                 if(npcState->lastResponse){
  1200.                     //Check previous response chain first
  1201.                     const ResponseList& list = npcState->lastResponse->getResponseList();
  1202.                     response = getResponse(list, player, npcState, npcState->respondToText);
  1203.                 }
  1204.                
  1205.                 if(!response){
  1206.                     response = getResponse(player, npcState, npcState->respondToText);
  1207.                 }
  1208.                
  1209.                 if(response){
  1210.                     setCreatureFocus(player);
  1211.                     executeResponse(player, npcState, response);
  1212.                 }
  1213.             }
  1214.  
  1215.             npcState->prevRespondToText = npcState->respondToText;
  1216.             npcState->respondToText = "";
  1217.         }
  1218.  
  1219.         response = getResponse(player, npcState, EVENT_THINK);
  1220.         executeResponse(player, npcState, response);
  1221.  
  1222.         if(!npcState->isIdle){
  1223.             isIdle = false;
  1224.  
  1225.             if(hasBusyReply){
  1226.                 setCreatureFocus(player);
  1227.             }
  1228.         }
  1229.  
  1230.         ++it;
  1231.     }
  1232.  
  1233.     if(isIdle && !hasScriptedFocus){
  1234.         setCreatureFocus(NULL);
  1235.     }
  1236. }
  1237.  
  1238. void Npc::executeResponse(Player* player, NpcState* npcState, const NpcResponse* response)
  1239. {
  1240.     if(response){
  1241.         npcState->lastResponse = response;
  1242.         bool resetTopic = true;
  1243.  
  1244.         if(response->getFocusState() == 0){
  1245.             npcState->isIdle = true;
  1246.         }
  1247.         else if(response->getFocusState() == 1){
  1248.             npcState->isIdle = false;
  1249.         }
  1250.        
  1251.         if(response->getAmount() != -1){
  1252.             npcState->amount = response->getAmount();
  1253.         }
  1254.  
  1255.         for(ActionList::const_iterator it = response->getFirstAction(); it != response->getEndAction(); ++it){
  1256.             switch((*it).actionType){
  1257.                 case ACTION_SETTOPIC: npcState->topic = (*it).intValue; resetTopic = false; break;
  1258.                 case ACTION_SETSELLPRICE: npcState->sellPrice = (*it).intValue; break;
  1259.                 case ACTION_SETBUYPRICE: npcState->buyPrice = (*it).intValue; break;
  1260.                 case ACTION_SETITEM: npcState->itemId = (*it).intValue; break;
  1261.                 case ACTION_SETSUBTYPE: npcState->subType = (*it).intValue; break;
  1262.                 case ACTION_SETEFFECT: g_game.addMagicEffect(player->getPosition(), (*it).intValue); break;
  1263.                 case ACTION_SETPRICE:
  1264.                 {
  1265.                     if((*it).strValue == "|SELLPRICE|"){
  1266.                         npcState->price = npcState->sellPrice;
  1267.                     }
  1268.                     else if((*it).strValue == "|BUYPRICE|"){
  1269.                         npcState->price = npcState->buyPrice;
  1270.                     }
  1271.                     else{
  1272.                         npcState->price = (*it).intValue;
  1273.                     }
  1274.                     break;
  1275.                 }
  1276.                 case ACTION_SETTELEPORT:
  1277.                 {
  1278.                     Position teleportTo = (*it).pos;
  1279.                     if((*it).strValue == "|TEMPLE|"){
  1280.                         teleportTo = player->getTemplePosition();
  1281.                     }
  1282.                     g_game.internalTeleport(player, teleportTo);
  1283.                     break;
  1284.                 }
  1285.  
  1286.                 case ACTION_SETIDLE:
  1287.                 {
  1288.                     npcState->isIdle = ((*it).intValue == 1);
  1289.                     break;
  1290.                 }
  1291.  
  1292.                 case ACTION_SETLEVEL:
  1293.                 {
  1294.                     if((*it).strValue == "|SPELLLEVEL|"){
  1295.                         npcState->level = -1;
  1296.                         InstantSpell* spell = g_spells->getInstantSpellByName(npcState->spellName);
  1297.                         if(spell){                 
  1298.                             npcState->level = spell->getLevel();
  1299.                         }
  1300.                     }
  1301.                     else{
  1302.                         npcState->level = (*it).intValue;
  1303.                     }
  1304.                     break;
  1305.                 }
  1306.  
  1307.                 case ACTION_SETSPELL:
  1308.                 {
  1309.                     npcState->spellName = "";
  1310.                     InstantSpell* spell = g_spells->getInstantSpellByName((*it).strValue);
  1311.                     if(spell){                 
  1312.                         npcState->spellName = (*it).strValue;
  1313.                     }
  1314.                     break;
  1315.                 }
  1316.  
  1317.                 case ACTION_SETLISTNAME:
  1318.                 {
  1319.                     npcState->listName = (*it).strValue;
  1320.                     break;
  1321.                 }
  1322.  
  1323.                 case ACTION_SETLISTPNAME:
  1324.                 {
  1325.                     npcState->listPluralName = (*it).strValue;
  1326.                     break;
  1327.                 }
  1328.  
  1329.                 case ACTION_SETAMOUNT:
  1330.                 {
  1331.                     int32_t amount = 1;
  1332.                     if((*it).strValue == "|AMOUNT|"){
  1333.                         amount = npcState->amount;
  1334.                     }
  1335.                     else{
  1336.                         amount = (*it).intValue;
  1337.                     }
  1338.  
  1339.                     npcState->amount = amount;
  1340.                     break;
  1341.                 }
  1342.  
  1343.                 case ACTION_TEACHSPELL:
  1344.                 {
  1345.                     std::string spellName = "";
  1346.                     if((*it).strValue == "|SPELL|"){
  1347.                         spellName = npcState->spellName;
  1348.                     }
  1349.                     else{
  1350.                         spellName = (*it).strValue;
  1351.                     }
  1352.  
  1353.                     player->learnInstantSpell(spellName);
  1354.                     break;
  1355.                 }
  1356.  
  1357.                 case ACTION_SETSTORAGE:
  1358.                 {
  1359.                     if((*it).key > 0){
  1360.                         player->addStorageValue((*it).key, (*it).intValue);
  1361.                     }
  1362.                     break;
  1363.                 }
  1364.  
  1365.                 case ACTION_ADDQUEUE:
  1366.                 {
  1367.                     QueueList::iterator it = std::find(queueList.begin(), queueList.end(), player->getID());
  1368.                     if(it == queueList.end()){
  1369.                         queueList.push_back(player->getID());
  1370.                         npcState->isQueued = true;
  1371.                     }
  1372.                     break;
  1373.                 }
  1374.  
  1375.                 case ACTION_SELLITEM:
  1376.                 {
  1377.                     uint32_t moneyCount = 0;
  1378.                     if((*it).strValue == "|PRICE|"){
  1379.                         moneyCount = npcState->price * npcState->amount;
  1380.                     }
  1381.                     else{
  1382.                         moneyCount = (*it).intValue;
  1383.                     }
  1384.  
  1385.                     const ItemType& it = Item::items[npcState->itemId];
  1386.                     if(it.id != 0){
  1387.                         int32_t subType = -1;
  1388.                         if(it.hasSubType()){
  1389.                             subType = npcState->subType;
  1390.                         }
  1391.                        
  1392.                         uint32_t itemCount = player->__getItemTypeCount(it.id, subType);
  1393.                         if(itemCount >= npcState->amount){
  1394.                             g_game.removeItemOfType(player, it.id, npcState->amount, subType);
  1395.                             g_game.addMoney(player, moneyCount, FLAG_NOLIMIT);
  1396.                         }
  1397.                     }
  1398.                     break;
  1399.                 }
  1400.  
  1401.                 case ACTION_BUYITEM:
  1402.                 {
  1403.                     uint32_t moneyCount = 0;
  1404.                     if((*it).strValue == "|PRICE|"){
  1405.                         moneyCount = npcState->price * npcState->amount;
  1406.                     }
  1407.                     else{
  1408.                         moneyCount = (*it).intValue;
  1409.                     }
  1410.  
  1411.                     const ItemType& it = Item::items[npcState->itemId];
  1412.                     if(it.id != 0){
  1413.                         int32_t subType = -1;
  1414.                         if(it.hasSubType()){
  1415.                             subType = npcState->subType;
  1416.                         }
  1417.  
  1418.                         if(g_game.removeMoney(player, moneyCount)){
  1419.                             for(int32_t i = 0; i < npcState->amount; ++i){
  1420.                                 Item* item = Item::CreateItem(it.id, subType);
  1421.                                 if(g_game.internalPlayerAddItem(player, item) != RET_NOERROR){
  1422.                                     delete item;
  1423.                                 }
  1424.                             }
  1425.                         }
  1426.                         else{
  1427.                             std::cout << "Error [Npc::executeResponse] Not enough money: " << player->getName()  << "\tNpc: " << getName() << std::endl;
  1428.                         }
  1429.                     }
  1430.  
  1431.                     break;
  1432.                 }
  1433.  
  1434.                 case ACTION_TAKEITEM:
  1435.                 {
  1436.                     int32_t itemId = 0;
  1437.                     if((*it).strValue == "|ITEM|"){
  1438.                         itemId = npcState->itemId;
  1439.                     }
  1440.                     else{
  1441.                         itemId = (*it).intValue;
  1442.                     }
  1443.  
  1444.                     const ItemType& it = Item::items[npcState->itemId];
  1445.                     if(it.id != 0){
  1446.                         int32_t subType = -1;
  1447.                         if(it.hasSubType()){
  1448.                             subType = npcState->subType;
  1449.                         }
  1450.  
  1451.                         uint32_t itemCount = player->__getItemTypeCount(itemId, subType);
  1452.                         if(itemCount >= npcState->amount){
  1453.                             g_game.removeItemOfType(player, itemId, npcState->amount, subType);
  1454.                         }
  1455.                     }
  1456.                     break;
  1457.                 }
  1458.  
  1459.                 case ACTION_GIVEITEM:
  1460.                 {
  1461.                     int32_t itemId = 0;
  1462.                     if((*it).strValue == "|ITEM|"){
  1463.                         itemId = npcState->itemId;
  1464.                     }
  1465.                     else{
  1466.                         itemId = (*it).intValue;
  1467.                     }
  1468.  
  1469.                     const ItemType& it = Item::items[itemId];
  1470.                     if(it.id != 0){
  1471.                         int32_t subType = -1;
  1472.                         if(it.hasSubType()){
  1473.                             subType = npcState->subType;
  1474.                         }
  1475.  
  1476.                         for(int32_t i = 0; i < npcState->amount; ++i){
  1477.                             Item* item = Item::CreateItem(it.id, subType);
  1478.                             if(g_game.internalPlayerAddItem(player, item) != RET_NOERROR){
  1479.                                 delete item;
  1480.                             }
  1481.                         }
  1482.                     }
  1483.                     break;
  1484.                 }
  1485.  
  1486.                 case ACTION_TAKEMONEY:
  1487.                 {
  1488.                     uint32_t moneyCount = 0;
  1489.                     if((*it).strValue == "|PRICE|"){
  1490.                         moneyCount = npcState->price * npcState->amount;
  1491.                     }
  1492.                     else{
  1493.                         moneyCount = (*it).intValue;
  1494.                     }
  1495.  
  1496.                     g_game.removeMoney(player, moneyCount);
  1497.                     break;
  1498.                 }
  1499.  
  1500.                 case ACTION_GIVEMONEY:
  1501.                 {
  1502.                     uint32_t moneyCount = 0;
  1503.                     if((*it).strValue == "|PRICE|"){
  1504.                         moneyCount = npcState->price * npcState->amount;
  1505.                     }
  1506.                     else{
  1507.                         moneyCount = (*it).intValue;
  1508.                     }
  1509.  
  1510.                     g_game.addMoney(player, moneyCount);
  1511.                     break;
  1512.                 }
  1513.  
  1514.                 case ACTION_SCRIPT:
  1515.                 {
  1516.                     NpcScriptInterface scriptInterface;
  1517.                     if(scriptInterface.reserveScriptEnv()){
  1518.                         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  1519.  
  1520.                         std::stringstream scriptstream;
  1521.                         //attach various variables that could be interesting
  1522.                         scriptstream << "cid = " << env->addThing(player) << std::endl;
  1523.                         scriptstream << "text = \"" << npcState->respondToText << "\"" << std::endl;
  1524.                         scriptstream << "name = \"" << player->getName() << "\"" << std::endl;
  1525.                         scriptstream << "idletime = " << idleTime << std::endl;
  1526.                         scriptstream << "idleinterval = " << idleInterval << std::endl;
  1527.  
  1528.                         scriptstream << "itemlist = {" << std::endl;
  1529.                         uint32_t n = 0;
  1530.                         for(std::list<ListItem>::const_iterator iit = response->prop.itemList.begin(); iit != response->prop.itemList.end(); ++iit){
  1531.                             bool adddelim = (n + 1 != response->prop.itemList.size());
  1532.                             scriptstream <<  "{id = " << iit->itemId
  1533.                                 << ", subtype = " << iit->subType
  1534.                                 << ", buy=" << iit->buyPrice
  1535.                                 << ", sell=" << iit->sellPrice << "}";
  1536.  
  1537.                             if(adddelim){
  1538.                                 scriptstream << "," << std::endl;
  1539.                             }
  1540.                             ++n;
  1541.                         }
  1542.                         scriptstream << "}" << std::endl;
  1543.  
  1544.                         scriptstream << "_state = {" << std::endl;
  1545.                         scriptstream << "topic = " << npcState->topic << ',' << std::endl;
  1546.                         scriptstream << "itemid = " << npcState->itemId << ',' << std::endl;
  1547.                         scriptstream << "subtype = " << npcState->subType << ',' << std::endl;
  1548.                         scriptstream << "amount = " << npcState->amount << ',' << std::endl;
  1549.                         scriptstream << "price = " << npcState->price << ',' << std::endl;
  1550.                         scriptstream << "level = " << npcState->level << ',' << std::endl;
  1551.                         scriptstream << "spellname = \"" << npcState->spellName << "\"" << ',' << std::endl;
  1552.                         scriptstream << "listname = \"" << npcState->listName << "\"" << ',' << std::endl;
  1553.                         scriptstream << "listpname = \"" << npcState->listPluralName << "\"" << ',' << std::endl;
  1554.  
  1555.                         scriptstream << "n1 = " << npcState->scriptVars.n1 << ',' << std::endl;
  1556.                         scriptstream << "n2 = " << npcState->scriptVars.n2 << ',' << std::endl;
  1557.                         scriptstream << "n3 = " << npcState->scriptVars.n3 << ',' << std::endl;
  1558.  
  1559.                         scriptstream << "b1 = " << (npcState->scriptVars.b1 ? "true" : "false" ) << ',' << std::endl;
  1560.                         scriptstream << "b2 = " << (npcState->scriptVars.b2 ? "true" : "false" ) << ',' << std::endl;
  1561.                         scriptstream << "b3 = " << (npcState->scriptVars.b3 ? "true" : "false" ) << ',' << std::endl;
  1562.  
  1563.                         scriptstream << "s1 = \"" << npcState->scriptVars.s1 << "\"" << ',' << std::endl;
  1564.                         scriptstream << "s2 = \"" << npcState->scriptVars.s2 << "\"" << ',' << std::endl;
  1565.                         scriptstream << "s3 = \"" << npcState->scriptVars.s3 << "\"" << std::endl;
  1566.                         scriptstream << "}" << std::endl;                      
  1567.  
  1568.                         scriptstream << (*it).strValue;
  1569.  
  1570.                         //std::cout << scriptstream.str() << std::endl;
  1571.  
  1572.                         if(scriptInterface.loadBuffer(scriptstream.str(), this) != -1){
  1573.                             lua_State* L = scriptInterface.getLuaState();
  1574.                             lua_getglobal(L, "_state");
  1575.                             NpcScriptInterface::popState(L, npcState);
  1576.                         }
  1577.                         scriptInterface.releaseScriptEnv();
  1578.                     }
  1579.  
  1580.                     break;
  1581.                 }
  1582.  
  1583.                 default: break;
  1584.             }
  1585.         }
  1586.  
  1587.  
  1588.         /*
  1589.         if(npcState.amount == 0){
  1590.             npcState.amount = player->__getItemTypeCount(npcState.itemId);
  1591.         }
  1592.         */
  1593.  
  1594.         if(response->getResponseType() == RESPONSE_DEFAULT){
  1595.             std::string responseString = formatResponse(player, npcState, response);
  1596.             if(!responseString.empty()){
  1597.                 g_game.internalCreatureSay(this, SPEAK_SAY, responseString);
  1598.             }
  1599.         }
  1600.         else{
  1601.             int32_t functionId = -1;
  1602.             ResponseScriptMap::iterator it = responseScriptMap.find(response->getText());
  1603.             if(it != responseScriptMap.end()){
  1604.                 functionId = it->second;
  1605.             }
  1606.             else{
  1607.                 functionId = m_scriptInterface->getEvent(response->getText());
  1608.                 responseScriptMap[response->getText()] = functionId;
  1609.             }
  1610.  
  1611.             if(functionId != -1){
  1612.                 if(m_scriptInterface->reserveScriptEnv()){
  1613.                     ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  1614.  
  1615.                     #ifdef __DEBUG_LUASCRIPTS__
  1616.                     std::stringstream desc;
  1617.                     desc << "npc " << m_npc->getName();
  1618.                     env->setEventDesc(desc.str());
  1619.                     #endif
  1620.  
  1621.                     lua_State* L = m_scriptInterface->getLuaState();
  1622.  
  1623.                     env->setScriptId(functionId, m_scriptInterface);
  1624.                     Npc* prevNpc = env->getNpc();
  1625.                     env->setRealPos(getPosition());
  1626.                     env->setNpc(this);
  1627.  
  1628.                     m_scriptInterface->pushFunction(functionId);
  1629.                     int32_t paramCount = 0;
  1630.                     for(ActionList::const_iterator it = response->getFirstAction(); it != response->getEndAction(); ++it){
  1631.                         if((*it).actionType == ACTION_SCRIPTPARAM){
  1632.                             if((*it).strValue == "|PLAYER|"){
  1633.                                 uint32_t cid = env->addThing(player);
  1634.                                 lua_pushnumber(L, cid);
  1635.                             }
  1636.                             else if((*it).strValue == "|TEXT|"){
  1637.                                 lua_pushstring(L, npcState->respondToText.c_str());
  1638.                             }
  1639.                             else{
  1640.                                 std::cout << "Warning [Npc::executeResponse] Unknown script param: " << (*it).strValue << std::endl;
  1641.                                 break;
  1642.                             }
  1643.  
  1644.                             ++paramCount;
  1645.                         }
  1646.                     }
  1647.  
  1648.                     NpcScriptInterface::pushState(L, npcState);
  1649.                     lua_setglobal(L, "_state");
  1650.                     m_scriptInterface->callFunction(paramCount);
  1651.                     lua_getglobal(L, "_state");
  1652.                     NpcScriptInterface::popState(L, npcState);
  1653.                     if(prevNpc){
  1654.                         env->setRealPos(prevNpc->getPosition());
  1655.                         env->setNpc(prevNpc);
  1656.                     }
  1657.                     m_scriptInterface->releaseScriptEnv();
  1658.                 }
  1659.                 else{
  1660.                     std::cout << "[Error] Call stack overflow." << std::endl;
  1661.                 }
  1662.             }
  1663.         }
  1664.  
  1665.         if(resetTopic && response->getTopic() == npcState->topic){
  1666.             npcState->topic = -1;
  1667.         }
  1668.         npcState->prevInteraction = OTSYS_TIME();
  1669.     }
  1670. }
  1671.  
  1672. void Npc::doSay(std::string msg)
  1673. {
  1674.     g_game.internalCreatureSay(this, SPEAK_SAY, msg);
  1675. }
  1676.  
  1677. void Npc::doMove(Direction dir)
  1678. {
  1679.     g_game.internalMoveCreature(this, dir);
  1680. }
  1681.  
  1682. void Npc::doTurn(Direction dir)
  1683. {
  1684.     g_game.internalCreatureTurn(this, dir);
  1685. }
  1686.  
  1687. bool Npc::getNextStep(Direction& dir)
  1688. {
  1689.     if(Creature::getNextStep(dir)){
  1690.         return true;
  1691.     }
  1692.  
  1693.     if(walkTicks <= 0){
  1694.         return false;
  1695.     }
  1696.  
  1697.     if(!isIdle || focusCreature != 0){
  1698.         return false;
  1699.     }
  1700.  
  1701.     if(getTimeSinceLastMove() < walkTicks){
  1702.         return false;
  1703.     }
  1704.  
  1705.     return getRandomStep(dir);
  1706. }
  1707.  
  1708. bool Npc::canWalkTo(const Position& fromPos, Direction dir)
  1709. {
  1710.     Position toPos = fromPos;
  1711.  
  1712.     switch(dir){
  1713.         case NORTH:
  1714.             toPos.y -= 1;
  1715.         break;
  1716.  
  1717.         case SOUTH:
  1718.             toPos.y += 1;
  1719.         break;
  1720.  
  1721.         case WEST:
  1722.             toPos.x -= 1;
  1723.         break;
  1724.  
  1725.         case EAST:
  1726.             toPos.x += 1;
  1727.         break;
  1728.  
  1729.         default:
  1730.             break;
  1731.     }
  1732.  
  1733.     bool result = Spawns::getInstance()->isInZone(masterPos, masterRadius, toPos);
  1734.     if(!result){
  1735.         return false;
  1736.     }
  1737.  
  1738.     Tile* tile = g_game.getTile(toPos.x, toPos.y, toPos.z);
  1739.     if(!tile || tile->__queryAdd(0, this, 1, 0) != RET_NOERROR){
  1740.         return false;
  1741.     }
  1742.  
  1743.     if(!floorChange && (tile->floorChange() || tile->getTeleportItem())){
  1744.         return false;
  1745.     }
  1746.  
  1747.     return true;
  1748. }
  1749.  
  1750. bool Npc::getRandomStep(Direction& dir)
  1751. {
  1752.     std::vector<Direction> dirList;
  1753.     const Position& creaturePos = getPosition();
  1754.  
  1755.     if(canWalkTo(creaturePos, NORTH)){
  1756.         dirList.push_back(NORTH);
  1757.     }
  1758.  
  1759.     if(canWalkTo(creaturePos, SOUTH)){
  1760.         dirList.push_back(SOUTH);
  1761.     }
  1762.  
  1763.     if(canWalkTo(creaturePos, EAST)){
  1764.         dirList.push_back(EAST);
  1765.     }
  1766.  
  1767.     if(canWalkTo(creaturePos, WEST)){
  1768.         dirList.push_back(WEST);
  1769.     }
  1770.  
  1771.     if(!dirList.empty()){
  1772.         std::random_shuffle(dirList.begin(), dirList.end());
  1773.         dir = dirList[random_range(0, dirList.size() - 1)];
  1774.         return true;
  1775.     }
  1776.  
  1777.     return false;
  1778. }
  1779.  
  1780. void Npc::doMoveTo(Position target)
  1781. {
  1782.     std::list<Direction> listDir;
  1783.     if(!g_game.getPathToEx(this, target, listDir, 1, 1, true, true)){
  1784.         return;
  1785.     }
  1786.  
  1787.     startAutoWalk(listDir);
  1788. }
  1789.  
  1790. void Npc::setCreatureFocus(Creature* creature)
  1791. {
  1792.     if(creature){
  1793.         focusCreature = creature->getID();
  1794.         const Position& creaturePos = creature->getPosition();
  1795.         const Position& myPos = getPosition();
  1796.         int32_t dx = myPos.x - creaturePos.x;
  1797.         int32_t dy = myPos.y - creaturePos.y;
  1798.  
  1799.         Direction dir = SOUTH;
  1800.         float tan = 0;
  1801.  
  1802.         if(dx != 0){
  1803.             tan = dy/dx;
  1804.         }
  1805.         else{
  1806.             tan = 10;
  1807.         }
  1808.  
  1809.         if(std::abs(tan) < 1){
  1810.             if(dx > 0){
  1811.                 dir = WEST;
  1812.             }
  1813.             else{
  1814.                 dir = EAST;
  1815.             }
  1816.         }
  1817.         else{
  1818.             if(dy > 0){
  1819.                 dir = NORTH;
  1820.             }
  1821.             else{
  1822.                 dir = SOUTH;
  1823.             }
  1824.         }
  1825.  
  1826.         g_game.internalCreatureTurn(this, dir);
  1827.     }
  1828.     else{
  1829.         focusCreature = 0;
  1830.     }
  1831. }
  1832.  
  1833. const NpcResponse* Npc::getResponse(const ResponseList& list, const Player* player,
  1834.     NpcState* npcState, const std::string& text, bool exactMatch /*= false*/)
  1835. {
  1836.     std::string textString = asLowerCaseString(text);
  1837.     std::vector<std::string> wordList = explodeString(textString, " ");
  1838.     NpcResponse* response = NULL;
  1839.     int32_t bestMatchCount = 0;
  1840.     int32_t totalMatchCount = 0;
  1841.  
  1842.     for(ResponseList::const_iterator it = list.begin(); it != list.end(); ++it){
  1843.         int32_t matchCount = 0;
  1844.  
  1845.         if((*it)->getParams() != RESPOND_DEFAULT){
  1846.             uint32_t params = (*it)->getParams();
  1847.  
  1848.             if(hasBitSet(RESPOND_MALE, params)){
  1849.                 if(!player->getSex() == PLAYERSEX_MALE){
  1850.                     continue;
  1851.                 }
  1852.                 ++matchCount;
  1853.             }
  1854.  
  1855.             if(hasBitSet(RESPOND_FEMALE, params)){
  1856.                 if(!player->getSex() == PLAYERSEX_FEMALE){
  1857.                     continue;
  1858.                 }
  1859.                 ++matchCount;
  1860.             }
  1861.  
  1862.             if(hasBitSet(RESPOND_PZBLOCK, params)){
  1863.                 if(!player->isPzLocked()){
  1864.                     continue;
  1865.                 }
  1866.                 ++matchCount;
  1867.             }
  1868.  
  1869.             if(hasBitSet(RESPOND_PREMIUM, params)){
  1870.                 if(!player->isPremium()){
  1871.                     continue;
  1872.                 }
  1873.                 ++matchCount;
  1874.             }
  1875.  
  1876.             if(hasBitSet(RESPOND_DRUID, params)){
  1877.                 if(player->getVocationId() != VOCATION_DRUID){
  1878.                     continue;
  1879.                 }
  1880.                 ++matchCount;
  1881.             }
  1882.  
  1883.             if(hasBitSet(RESPOND_KNIGHT, params)){
  1884.                 if(player->getVocationId() != VOCATION_KNIGHT){
  1885.                     continue;
  1886.                 }
  1887.                 ++matchCount;
  1888.             }
  1889.  
  1890.             if(hasBitSet(RESPOND_PALADIN, params)){
  1891.                 if(player->getVocationId() != VOCATION_PALADIN){
  1892.                     continue;
  1893.                 }
  1894.                 ++matchCount;
  1895.             }
  1896.  
  1897.             if(hasBitSet(RESPOND_SORCERER, params)){
  1898.                 if(player->getVocationId() != VOCATION_SORCERER){
  1899.                     continue;
  1900.                 }
  1901.                 ++matchCount;
  1902.             }
  1903.  
  1904.             if(hasBitSet(RESPOND_LOWLEVEL, params)){
  1905.                 if(player->getLevel() > npcState->level){
  1906.                     continue;
  1907.                 }
  1908.                 ++matchCount;
  1909.             }
  1910.  
  1911.             if(hasBitSet(RESPOND_LOWMONEY, params)){
  1912.                 uint32_t moneyCount = g_game.getMoney(player);
  1913.                 if(moneyCount >= npcState->price){
  1914.                     continue;
  1915.                 }
  1916.                 ++matchCount;
  1917.             }
  1918.  
  1919.             if(hasBitSet(RESPOND_LOWAMOUNT, params) || hasBitSet(RESPOND_NOAMOUNT, params)){
  1920.                 uint32_t itemCount = player->__getItemTypeCount(npcState->itemId);
  1921.                
  1922.                 if(itemCount >= npcState->amount){
  1923.                     continue;
  1924.                 }
  1925.  
  1926.                 if(hasBitSet(RESPOND_LOWAMOUNT, params)){
  1927.                     if(npcState->amount == 1){
  1928.                         continue;
  1929.                     }
  1930.                     ++matchCount;
  1931.                 }
  1932.  
  1933.                 if(hasBitSet(RESPOND_NOAMOUNT, params)){
  1934.                     if(npcState->amount > 1){
  1935.                         continue;
  1936.                     }
  1937.                     ++matchCount;
  1938.                 }
  1939.             }
  1940.         }
  1941.  
  1942.         if((*it)->getKnowSpell() != ""){
  1943.             std::string spellName = (*it)->getKnowSpell();
  1944.             if(spellName == "|SPELL|"){
  1945.                 spellName = npcState->spellName;
  1946.             }
  1947.  
  1948.             if(!player->hasLearnedInstantSpell(spellName)){
  1949.                 continue;
  1950.             }
  1951.             ++matchCount;
  1952.         }
  1953.  
  1954.         if((*it)->scriptVars.b1){
  1955.             if(!npcState->scriptVars.b1){
  1956.                 continue;
  1957.             }
  1958.             ++matchCount;
  1959.         }
  1960.  
  1961.         if((*it)->scriptVars.b2){
  1962.             if(!npcState->scriptVars.b2){
  1963.                 continue;
  1964.             }
  1965.             ++matchCount;
  1966.         }
  1967.  
  1968.         if((*it)->scriptVars.b3){
  1969.             if(!npcState->scriptVars.b3){
  1970.                 continue;
  1971.             }
  1972.             ++matchCount;
  1973.         }
  1974.  
  1975.         if((*it)->getStorageId() != -1){
  1976.             int32_t playerStorageValue = -1;
  1977.             if(!player->getStorageValue((*it)->getStorageId(), playerStorageValue)){
  1978.                 playerStorageValue = -1;
  1979.             }
  1980.  
  1981.             int32_t storageValue = (*it)->getStorageValue();
  1982.             StorageComparision_t comp = (*it)->getStorageComp();
  1983.             switch(comp){
  1984.                 case STORAGE_LESS:
  1985.                 {
  1986.                     if(playerStorageValue >= storageValue){
  1987.                         continue;
  1988.                     }
  1989.                     break;
  1990.                 }
  1991.                 case STORAGE_LESSOREQUAL:
  1992.                 {
  1993.                     if(playerStorageValue > storageValue){
  1994.                         continue;
  1995.                     }
  1996.                     break;
  1997.                 }
  1998.                 case STORAGE_EQUAL:
  1999.                 {
  2000.                     if(playerStorageValue != storageValue){
  2001.                         continue;
  2002.                     }
  2003.                     break;
  2004.                 }
  2005.                 case STORAGE_GREATEROREQUAL:
  2006.                 {
  2007.                     if(playerStorageValue < storageValue){
  2008.                         continue;
  2009.                     }
  2010.                     break;
  2011.                 }
  2012.                 case STORAGE_GREATER:
  2013.                 {
  2014.                     if(playerStorageValue <= storageValue){
  2015.                         continue;
  2016.                     }
  2017.                     break;
  2018.                 }
  2019.  
  2020.                 default: break;
  2021.             }
  2022.            
  2023.             ++matchCount;
  2024.         }
  2025.  
  2026.         if((*it)->getInteractType() == INTERACT_TEXT || (*it)->getFocusState() != -1){
  2027.             if(npcState->isIdle && (*it)->getFocusState() != 1){
  2028.                 //We are idle, and this response does not activate the npc.
  2029.                 continue;
  2030.             }
  2031.  
  2032.             if(!npcState->isIdle && (*it)->getFocusState() == 1){
  2033.                 //We are not idle, and this response would activate us again.
  2034.                 continue;
  2035.             }
  2036.         }
  2037.  
  2038.         if(npcState->topic == -1 && (*it)->getTopic() != -1){
  2039.             //Not the right topic
  2040.             continue;
  2041.         }
  2042.  
  2043.         if(npcState->topic != -1 && npcState->topic == (*it)->getTopic()){
  2044.             //Topic is right
  2045.             matchCount += 1000;
  2046.         }
  2047.  
  2048.         if((*it)->getInteractType() == INTERACT_EVENT){
  2049.             if((*it)->getInputText() == asLowerCaseString(text)){
  2050.                 ++matchCount;
  2051.             }
  2052.             else{
  2053.                 matchCount = 0;
  2054.             }
  2055.         }
  2056.         else if((*it)->getInteractType() == INTERACT_TEXT){
  2057.             int32_t matchAllCount = 0;  //Contains the number of keywords that where matched
  2058.             int32_t totalKeywordCount = 0; //Contains the total number of keywords that where being compared
  2059.             int32_t matchWordCount = getMatchCount(*it, wordList, exactMatch, matchAllCount, totalKeywordCount);
  2060.  
  2061.             if(matchWordCount> 0){
  2062.                 //Remove points for |*| matches
  2063.                 matchWordCount -= matchAllCount;
  2064.  
  2065.                 //Remove points for not full match
  2066.                 matchWordCount -= (totalKeywordCount - matchAllCount - matchWordCount);
  2067.  
  2068.                 //Total "points" for this response, word matches are worth more
  2069.                 matchCount += matchWordCount * 100000;
  2070.             }
  2071.             else{
  2072.                 matchCount = 0;
  2073.             }
  2074.         }
  2075.  
  2076.         if(matchCount > bestMatchCount){
  2077.             totalMatchCount = 0;
  2078.             response = (*it);
  2079.             bestMatchCount = matchCount;
  2080.             //std::cout << "Found response string: " << response->getText() << ", keyword: " << response->getInputText() << std::endl;
  2081.         }
  2082.         else if(bestMatchCount > 0 && matchCount == bestMatchCount){
  2083.             ++totalMatchCount;
  2084.         }
  2085.     }
  2086.  
  2087.     if(totalMatchCount > 1){
  2088.         return NULL;
  2089.     }
  2090.  
  2091.     return response;
  2092. }
  2093.  
  2094. uint32_t Npc::getMatchCount(NpcResponse* response, std::vector<std::string> wordList,
  2095.     bool exactMatch, int32_t& matchAllCount, int32_t& totalKeywordCount)
  2096. {
  2097.     matchAllCount = 0;
  2098.     totalKeywordCount = 0;
  2099.     int32_t bestMatchCount = 0;
  2100.  
  2101.     const std::list<std::string>& inputList = response->getInputList();
  2102.     for(std::list<std::string>::const_iterator it = inputList.begin(); it != inputList.end(); ++it){
  2103.         int32_t matchCount = 0;
  2104.         std::vector<std::string>::iterator lastWordMatchIter = wordList.begin();
  2105.         std::string keywords = (*it);
  2106.         std::vector<std::string> keywordList = explodeString(keywords, ";");
  2107.  
  2108.         for(std::vector<std::string>::iterator keyIter = keywordList.begin(); keyIter != keywordList.end(); ++keyIter){
  2109.  
  2110.             if(!exactMatch && (*keyIter) == "|*|"){
  2111.                 //Match anything.
  2112.                 matchAllCount++;
  2113.             }
  2114.             else if((*keyIter) == "|amount|"){
  2115.                 //TODO: Should iterate through each word until a number or a new keyword is found.
  2116.                 int32_t amount = atoi((*lastWordMatchIter).c_str());
  2117.                 if(amount > 0){
  2118.                     response->setAmount(amount);
  2119.                 }
  2120.                 else{
  2121.                     response->setAmount(1);
  2122.                     continue;
  2123.                 }
  2124.             }
  2125.             else{
  2126.                 std::vector<std::string>::iterator wordIter = wordList.end();              
  2127.                 for(wordIter = lastWordMatchIter; wordIter != wordList.end(); ++wordIter){
  2128.                     size_t pos = (*wordIter).find_first_of("!\"#�%&/()=?`{[]}\\^*><,.-_'~");
  2129.                     if(pos == std::string::npos){
  2130.                         pos = 0;
  2131.                     }
  2132.  
  2133.                     if((*wordIter).find((*keyIter), pos) == pos){
  2134.                         break;
  2135.                     }
  2136.                 }
  2137.  
  2138.                 if(wordIter == wordList.end()){
  2139.                     continue;
  2140.                 }
  2141.                
  2142.                 lastWordMatchIter = wordIter + 1;
  2143.             }
  2144.  
  2145.             ++matchCount;
  2146.  
  2147.             if(matchCount > bestMatchCount){
  2148.                 bestMatchCount = matchCount;
  2149.                 totalKeywordCount = keywordList.size();
  2150.             }
  2151.  
  2152.             if(lastWordMatchIter == wordList.end()){
  2153.                 break;
  2154.             }
  2155.         }
  2156.     }
  2157.  
  2158.     return bestMatchCount;
  2159. }
  2160.  
  2161. const NpcResponse* Npc::getResponse(const Player* player, NpcState* npcState, const std::string& text)
  2162. {
  2163.     return getResponse(responseList, player, npcState, text);
  2164. }
  2165.  
  2166. const NpcResponse* Npc::getResponse(const Player* player, NpcEvent_t eventType)
  2167. {
  2168.     std::string eventName = getEventResponseName(eventType);
  2169.     if(eventName.empty()){
  2170.         return NULL;
  2171.     }
  2172.  
  2173.     std::vector<NpcResponse*> result;
  2174.     for(ResponseList::const_iterator it = responseList.begin(); it != responseList.end(); ++it){
  2175.         if((*it)->getInteractType() == INTERACT_EVENT){
  2176.             if((*it)->getInputText() == asLowerCaseString(eventName)){
  2177.                 result.push_back(*it);             
  2178.             }
  2179.         }
  2180.     }
  2181.  
  2182.     if(result.empty()){
  2183.         return NULL;
  2184.     }
  2185.  
  2186.     return result[random_range(0, result.size() - 1)];
  2187. }
  2188.  
  2189. const NpcResponse* Npc::getResponse(const Player* player, NpcState* npcState, NpcEvent_t eventType)
  2190. {
  2191.     std::string eventName = getEventResponseName(eventType);
  2192.     if(eventName.empty()){
  2193.         return NULL;
  2194.     }
  2195.  
  2196.     return getResponse(responseList, player, npcState, eventName, true);
  2197. }
  2198.  
  2199. std::string Npc::getEventResponseName(NpcEvent_t eventType)
  2200. {
  2201.     switch(eventType){
  2202.         case EVENT_BUSY: return "onBusy"; break;
  2203.         case EVENT_THINK: return "onThink"; break;
  2204.         case EVENT_IDLE: return "onIdle"; break;
  2205.         case EVENT_PLAYER_ENTER: return "onPlayerEnter"; break;
  2206.         case EVENT_PLAYER_MOVE: return "onPlayerMove"; break;
  2207.         case EVENT_PLAYER_LEAVE: return "onPlayerLeave"; break;
  2208.         default: return ""; break;
  2209.     }
  2210.  
  2211.     return "";
  2212. }
  2213.  
  2214. std::string Npc::formatResponse(Creature* creature, const NpcState* npcState, const NpcResponse* response) const
  2215. {
  2216.     std::string responseString = response->getText();
  2217.  
  2218.     std::stringstream ss;
  2219.     ss << npcState->price * npcState->amount;
  2220.     replaceString(responseString, "|PRICE|", ss.str());
  2221.  
  2222.     ss.str("");
  2223.     ss << npcState->amount;
  2224.     replaceString(responseString, "|AMOUNT|", ss.str());
  2225.  
  2226.     ss.str("");
  2227.     ss << npcState->level;
  2228.     replaceString(responseString, "|LEVEL|", ss.str());
  2229.  
  2230.     ss.str("");
  2231.     ss << npcState->scriptVars.n1;
  2232.     replaceString(responseString, "|N1|", ss.str());
  2233.  
  2234.     ss.str("");
  2235.     ss << npcState->scriptVars.n2;
  2236.     replaceString(responseString, "|N2|", ss.str());
  2237.  
  2238.     ss.str("");
  2239.     ss << npcState->scriptVars.n3;
  2240.     replaceString(responseString, "|N3|", ss.str());
  2241.  
  2242.     replaceString(responseString, "|S1|", npcState->scriptVars.s1);
  2243.     replaceString(responseString, "|S2|", npcState->scriptVars.s2);
  2244.     replaceString(responseString, "|S3|", npcState->scriptVars.s3);
  2245.  
  2246.     ss.str("");
  2247.     if(npcState->itemId != -1){
  2248.         const ItemType& it = Item::items[npcState->itemId];
  2249.         if(npcState->amount <= 1){
  2250.             ss << it.article + " " + it.name;
  2251.             replaceString(responseString, "|ITEMNAME|", ss.str());
  2252.         }
  2253.         else{
  2254.             ss << it.pluralName;
  2255.             replaceString(responseString, "|ITEMNAME|", ss.str());
  2256.         }
  2257.     }
  2258.  
  2259.     replaceString(responseString, "|NAME|", creature->getName());
  2260.     replaceString(responseString, "|NPCNAME|", getName());
  2261.     return responseString;
  2262. }
  2263.  
  2264. NpcScriptInterface* Npc::getScriptInterface()
  2265. {
  2266.     return m_scriptInterface;
  2267. }
  2268.  
  2269. NpcScriptInterface::NpcScriptInterface() :
  2270. LuaScriptInterface("Npc interface")
  2271. {
  2272.     m_libLoaded = false;
  2273.     initState();
  2274. }
  2275.  
  2276.  
  2277. NpcScriptInterface::~NpcScriptInterface()
  2278. {
  2279.     //
  2280. }
  2281.  
  2282. bool NpcScriptInterface::initState()
  2283. {
  2284.     return LuaScriptInterface::initState();
  2285. }
  2286.  
  2287. bool NpcScriptInterface::closeState()
  2288. {
  2289.     m_libLoaded = false;
  2290.     return LuaScriptInterface::closeState();
  2291. }
  2292.  
  2293. bool NpcScriptInterface::loadNpcLib(std::string file)
  2294. {
  2295.     if(m_libLoaded)
  2296.         return true;
  2297.  
  2298.     if(loadFile(file) == -1){
  2299.         std::cout << "Warning: [NpcScriptInterface::loadNpcLib] Can not load " << file  << std::endl;
  2300.         return false;
  2301.     }
  2302.  
  2303.     m_libLoaded = true;
  2304.     return true;
  2305. }
  2306.  
  2307. void NpcScriptInterface::registerFunctions()
  2308. {
  2309.     LuaScriptInterface::registerFunctions();
  2310.  
  2311.     //npc exclusive functions
  2312.     lua_register(m_luaState, "selfSay", NpcScriptInterface::luaActionSay);
  2313.     lua_register(m_luaState, "selfMove", NpcScriptInterface::luaActionMove);
  2314.     lua_register(m_luaState, "selfMoveTo", NpcScriptInterface::luaActionMoveTo);
  2315.     lua_register(m_luaState, "selfTurn", NpcScriptInterface::luaActionTurn);
  2316.     lua_register(m_luaState, "selfFollow", NpcScriptInterface::luaActionFollow);
  2317.     lua_register(m_luaState, "selfGetPosition", NpcScriptInterface::luaSelfGetPos);
  2318.     lua_register(m_luaState, "creatureGetName", NpcScriptInterface::luaCreatureGetName);
  2319.     lua_register(m_luaState, "creatureGetName2", NpcScriptInterface::luaCreatureGetName2);
  2320.     lua_register(m_luaState, "creatureGetPosition", NpcScriptInterface::luaCreatureGetPos);
  2321.     lua_register(m_luaState, "getDistanceTo", NpcScriptInterface::luagetDistanceTo);
  2322.     lua_register(m_luaState, "doNpcSetCreatureFocus", NpcScriptInterface::luaSetNpcFocus);
  2323.     lua_register(m_luaState, "getNpcCid", NpcScriptInterface::luaGetNpcCid);
  2324.     lua_register(m_luaState, "getNpcPos", NpcScriptInterface::luaGetNpcPos);
  2325.     lua_register(m_luaState, "getNpcState", NpcScriptInterface::luaGetNpcState);
  2326.     lua_register(m_luaState, "setNpcState", NpcScriptInterface::luaSetNpcState);
  2327.     lua_register(m_luaState, "getNpcName", NpcScriptInterface::luaGetNpcName);
  2328.     lua_register(m_luaState, "getNpcParameter", NpcScriptInterface::luaGetNpcParameter);
  2329. }
  2330.  
  2331.  
  2332. int NpcScriptInterface::luaCreatureGetName2(lua_State *L)
  2333. {
  2334.     //creatureGetName2(name) - returns creature id
  2335.     popString(L);
  2336.     reportErrorFunc("Deprecated function.");
  2337.     lua_pushnil(L);
  2338.     return 1;
  2339. }
  2340.  
  2341. int NpcScriptInterface::luaCreatureGetName(lua_State *L)
  2342. {
  2343.     //creatureGetName(cid)
  2344.     popNumber(L);
  2345.     reportErrorFunc("Deprecated function. Use getCreatureName");
  2346.     lua_pushstring(L, "");
  2347.     return 1;
  2348. }
  2349.  
  2350. int NpcScriptInterface::luaCreatureGetPos(lua_State *L)
  2351. {
  2352.     //creatureGetPosition(cid)
  2353.     popNumber(L);
  2354.     reportErrorFunc("Deprecated function. Use getCreaturePosition");
  2355.     lua_pushnil(L);
  2356.     lua_pushnil(L);
  2357.     lua_pushnil(L);
  2358.     return 3;
  2359. }
  2360.  
  2361. int NpcScriptInterface::luaSelfGetPos(lua_State *L)
  2362. {
  2363.     //selfGetPosition()
  2364.     ScriptEnviroment* env = getScriptEnv();
  2365.     Npc* npc = env->getNpc();
  2366.     if(npc){
  2367.         Position pos = npc->getPosition();
  2368.         lua_pushnumber(L, pos.x);
  2369.         lua_pushnumber(L, pos.y);
  2370.         lua_pushnumber(L, pos.z);
  2371.     }
  2372.     else{
  2373.         lua_pushnil(L);
  2374.         lua_pushnil(L);
  2375.         lua_pushnil(L);
  2376.     }
  2377.  
  2378.     return 3;
  2379. }
  2380.  
  2381. int NpcScriptInterface::luaActionSay(lua_State* L)
  2382. {
  2383.     //selfSay(words)
  2384.     std::string msg(popString(L));
  2385.    
  2386.     ScriptEnviroment* env = getScriptEnv();
  2387.  
  2388.     Npc* npc = env->getNpc();
  2389.     if(npc){
  2390.         npc->doSay(msg);
  2391.     }
  2392.  
  2393.     return 0;
  2394. }
  2395.  
  2396. int NpcScriptInterface::luaActionMove(lua_State* L)
  2397. {
  2398.     //selfMove(direction)
  2399.     Direction dir = (Direction)popNumber(L);
  2400.     ScriptEnviroment* env = getScriptEnv();
  2401.  
  2402.     Npc* npc = env->getNpc();
  2403.     if(npc){
  2404.         npc->doMove(dir);
  2405.     }
  2406.  
  2407.     return 0;
  2408. }
  2409.  
  2410. int NpcScriptInterface::luaActionMoveTo(lua_State* L)
  2411. {
  2412.     //selfMoveTo(x,y,z)
  2413.     Position target;
  2414.     target.z = (int)popNumber(L);
  2415.     target.y = (int)popNumber(L);
  2416.     target.x = (int)popNumber(L);
  2417.  
  2418.     ScriptEnviroment* env = getScriptEnv();
  2419.     Npc* npc = env->getNpc();
  2420.     if(npc){
  2421.         npc->doMoveTo(target);
  2422.     }
  2423.  
  2424.     return 0;
  2425. }
  2426.  
  2427. int NpcScriptInterface::luaActionTurn(lua_State* L)
  2428. {
  2429.     //selfTurn(direction)
  2430.     Direction dir = (Direction)popNumber(L);
  2431.  
  2432.     ScriptEnviroment* env = getScriptEnv();
  2433.  
  2434.     Npc* npc = env->getNpc();
  2435.     if(npc){
  2436.         npc->doTurn(dir);
  2437.     }
  2438.  
  2439.     return 0;
  2440. }
  2441.  
  2442. int NpcScriptInterface::luaActionFollow(lua_State* L)
  2443. {
  2444.     //selfFollow(cid)
  2445.     uint32_t cid = popNumber(L);
  2446.  
  2447.     ScriptEnviroment* env = getScriptEnv();
  2448.  
  2449.     Player* player = env->getPlayerByUID(cid);
  2450.     if(cid != 0 && !player){
  2451.         lua_pushboolean(L, false);
  2452.         return 1;
  2453.     }
  2454.  
  2455.     Npc* npc = env->getNpc();
  2456.     if(!npc){
  2457.         lua_pushboolean(L, false);
  2458.         return 1;
  2459.     }
  2460.  
  2461.     bool result = npc->setFollowCreature(player, true);
  2462.     lua_pushboolean(L, result);
  2463.     return 1;
  2464. }
  2465.  
  2466. int NpcScriptInterface::luagetDistanceTo(lua_State *L)
  2467. {
  2468.     //getDistanceTo(uid)
  2469.     uint32_t uid = popNumber(L);
  2470.  
  2471.     ScriptEnviroment* env = getScriptEnv();
  2472.  
  2473.     Npc* npc = env->getNpc();
  2474.     Thing* thing = env->getThingByUID(uid);
  2475.     if(thing && npc){
  2476.         Position thing_pos = thing->getPosition();
  2477.         Position npc_pos = npc->getPosition();
  2478.         if(npc_pos.z != thing_pos.z){
  2479.             lua_pushnumber(L, -1);
  2480.         }
  2481.         else{
  2482.             int32_t dist = std::max(std::abs(npc_pos.x - thing_pos.x), std::abs(npc_pos.y - thing_pos.y));
  2483.             lua_pushnumber(L, dist);
  2484.         }
  2485.     }
  2486.     else{
  2487.         reportErrorFunc(getErrorDesc(LUA_ERROR_THING_NOT_FOUND));
  2488.         lua_pushnil(L);
  2489.     }
  2490.  
  2491.     return 1;
  2492. }
  2493.  
  2494. int NpcScriptInterface::luaSetNpcFocus(lua_State *L)
  2495. {
  2496.     //doNpcSetCreatureFocus(cid)
  2497.     uint32_t cid = popNumber(L);
  2498.  
  2499.     ScriptEnviroment* env = getScriptEnv();
  2500.  
  2501.     Npc* npc = env->getNpc();
  2502.     if(npc){
  2503.         Creature* creature = env->getCreatureByUID(cid);
  2504.         if(creature){
  2505.             npc->hasScriptedFocus = true;
  2506.         }
  2507.         else{
  2508.             npc->hasScriptedFocus = false;
  2509.         }
  2510.  
  2511.         npc->setCreatureFocus(creature);
  2512.     }
  2513.     return 0;
  2514. }
  2515.  
  2516. int NpcScriptInterface::luaGetNpcPos(lua_State* L)
  2517. {
  2518.     //getNpcPos()
  2519.     ScriptEnviroment* env = getScriptEnv();
  2520.  
  2521.     Position pos(0, 0, 0);
  2522.     uint32_t stackpos = 0;
  2523.  
  2524.     Npc* npc = env->getNpc();
  2525.     if(npc){
  2526.         pos = npc->getPosition();
  2527.         stackpos = npc->getParent()->__getIndexOfThing(npc);
  2528.     }
  2529.  
  2530.     pushPosition(L, pos, stackpos);
  2531.     return 1;
  2532. }
  2533.  
  2534. int NpcScriptInterface::luaGetNpcState(lua_State* L)
  2535. {
  2536.     //getNpcState(cid)
  2537.     uint32_t cid = popNumber(L);
  2538.  
  2539.     ScriptEnviroment* env = getScriptEnv();
  2540.     const Player* player = env->getPlayerByUID(cid);
  2541.     if(!player){
  2542.         lua_pushnil(L);
  2543.         return 1;
  2544.     }
  2545.  
  2546.     Npc* npc = env->getNpc();
  2547.     if(!npc){
  2548.         lua_pushnil(L);
  2549.         return 1;
  2550.     }
  2551.  
  2552.     NpcState* state = npc->getState(player);
  2553.     NpcScriptInterface::pushState(L, state);
  2554.     return 1;
  2555. }
  2556.  
  2557. int NpcScriptInterface::luaSetNpcState(lua_State* L)
  2558. {
  2559.     //setNpcState(state, cid)
  2560.  
  2561.     uint32_t cid = popNumber(L);
  2562.  
  2563.     ScriptEnviroment* env = getScriptEnv();
  2564.     const Player* player = env->getPlayerByUID(cid);
  2565.     if(!player){
  2566.         lua_pushnil(L);
  2567.         return 1;
  2568.     }
  2569.  
  2570.     Npc* npc = env->getNpc();
  2571.     if(!npc){
  2572.         lua_pushboolean(L, false);
  2573.         return 1;
  2574.     }
  2575.  
  2576.     NpcState* state = npc->getState(player);
  2577.     NpcScriptInterface::popState(L, state);
  2578.     lua_pushboolean(L, true);
  2579.     return 1;
  2580. }
  2581.  
  2582. int NpcScriptInterface::luaGetNpcCid(lua_State* L)
  2583. {
  2584.     //getNpcCid()
  2585.     ScriptEnviroment* env = getScriptEnv();
  2586.  
  2587.     Npc* npc = env->getNpc();
  2588.     if(npc){
  2589.         uint32_t cid = env->addThing(npc);
  2590.         lua_pushnumber(L, cid);
  2591.     }
  2592.     else{
  2593.         lua_pushnil(L);
  2594.     }
  2595.  
  2596.     return 1;
  2597. }
  2598.  
  2599. int NpcScriptInterface::luaGetNpcName(lua_State* L)
  2600. {
  2601.     //getNpcName()
  2602.     ScriptEnviroment* env = getScriptEnv();
  2603.  
  2604.     Npc* npc = env->getNpc();
  2605.     if(npc){
  2606.         lua_pushstring(L, npc->getName().c_str());
  2607.     }
  2608.     else{
  2609.         lua_pushstring(L, "");
  2610.     }
  2611.  
  2612.     return 1;
  2613. }
  2614.  
  2615. int NpcScriptInterface::luaGetNpcParameter(lua_State *L)
  2616. {
  2617.     //getNpcParameter(paramKey)
  2618.     std::string paramKey = popString(L);
  2619.  
  2620.     ScriptEnviroment* env = getScriptEnv();
  2621.  
  2622.     Npc* npc = env->getNpc();
  2623.     if(npc){
  2624.         Npc::ParametersMap::iterator it = npc->m_parameters.find(paramKey);
  2625.         if(it != npc->m_parameters.end()){
  2626.             lua_pushstring(L, it->second.c_str());
  2627.         }
  2628.         else{
  2629.             lua_pushnil(L);
  2630.         }
  2631.     }
  2632.     else{
  2633.         lua_pushnil(L);
  2634.     }
  2635.  
  2636.     return 1;
  2637. }
  2638.  
  2639. void NpcScriptInterface::pushState(lua_State *L, NpcState* state)
  2640. {
  2641.     lua_newtable(L);
  2642.     setField(L, "price", state->price);
  2643.     setField(L, "amount", state->amount);
  2644.     setField(L, "itemid", state->itemId);
  2645.     setField(L, "subtype", state->subType);
  2646.     setField(L, "topic", state->topic);
  2647.     setField(L, "level", state->level);
  2648.     setField(L, "spellname", state->spellName);
  2649.     setField(L, "listname", state->listName);
  2650.     setField(L, "listpname", state->listPluralName);
  2651.     setFieldBool(L, "isidle", state->isIdle);
  2652.  
  2653.     setField(L, "n1", state->scriptVars.n1);
  2654.     setField(L, "n2", state->scriptVars.n2);
  2655.     setField(L, "n3", state->scriptVars.n3);
  2656.  
  2657.     setFieldBool(L, "b1", state->scriptVars.b1);
  2658.     setFieldBool(L, "b2", state->scriptVars.b2);
  2659.     setFieldBool(L, "b3", state->scriptVars.b3);
  2660.  
  2661.     setField(L, "s1", state->scriptVars.s1);
  2662.     setField(L, "s2", state->scriptVars.s2);
  2663.     setField(L, "s3", state->scriptVars.s3);
  2664. }
  2665.  
  2666. void NpcScriptInterface::popState(lua_State *L, NpcState* &state)
  2667. {
  2668.     state->price = getField(L, "price");
  2669.     state->amount = getField(L, "amount");
  2670.     state->itemId = getField(L, "itemid");
  2671.     state->subType = getField(L, "subtype");
  2672.     state->topic = getField(L, "topic");
  2673.     state->level = getField(L, "level");
  2674.     state->spellName = getFieldString(L, "spellname");
  2675.     state->listName = getFieldString(L, "listname");
  2676.     state->listPluralName = getFieldString(L, "listpname");
  2677.     state->isIdle = getFieldBool(L, "isidle");
  2678.  
  2679.     state->scriptVars.n1 = getField(L, "n1");
  2680.     state->scriptVars.n2 = getField(L, "n2");
  2681.     state->scriptVars.n3 = getField(L, "n3");
  2682.  
  2683.     state->scriptVars.b1 = getFieldBool(L, "b1");
  2684.     state->scriptVars.b2 = getFieldBool(L, "b2");
  2685.     state->scriptVars.n3 = getFieldBool(L, "b3");
  2686.  
  2687.     state->scriptVars.s1 = getFieldString(L, "s1");
  2688.     state->scriptVars.s2 = getFieldString(L, "s2");
  2689.     state->scriptVars.s3 = getFieldString(L, "s3");
  2690. }
  2691.  
  2692.  
  2693. NpcEventsHandler::NpcEventsHandler(Npc* npc)
  2694. {
  2695.     m_npc = npc;
  2696.     m_loaded = false;
  2697. }
  2698.  
  2699. NpcEventsHandler::~NpcEventsHandler()
  2700. {
  2701.     //
  2702. }
  2703.  
  2704. bool NpcEventsHandler::isLoaded()
  2705. {
  2706.     return m_loaded;
  2707. }
  2708.  
  2709.  
  2710. NpcScript::NpcScript(std::string file, Npc* npc) :
  2711. NpcEventsHandler(npc)
  2712. {
  2713.     m_scriptInterface = npc->getScriptInterface();
  2714.  
  2715.     if(m_scriptInterface->loadFile(file, npc) == -1){
  2716.         std::cout << "Warning: [NpcScript::NpcScript] Can not load script. " << file << std::endl;
  2717.         std::cout << m_scriptInterface->getLastLuaError() << std::endl;
  2718.         m_loaded = false;
  2719.         return;
  2720.     }
  2721.  
  2722.     m_onCreatureSay = m_scriptInterface->getEvent("onCreatureSay");
  2723.     m_onCreatureDisappear = m_scriptInterface->getEvent("onCreatureDisappear");
  2724.     m_onCreatureAppear = m_scriptInterface->getEvent("onCreatureAppear");
  2725.     m_onCreatureMove = m_scriptInterface->getEvent("onCreatureMove");
  2726.     m_onThink = m_scriptInterface->getEvent("onThink");
  2727.     m_loaded = true;
  2728. }
  2729.  
  2730. NpcScript::~NpcScript()
  2731. {
  2732.     //
  2733. }
  2734.  
  2735. void NpcScript::onCreatureAppear(const Creature* creature)
  2736. {
  2737.     if(m_onCreatureAppear == -1){
  2738.         return;
  2739.     }
  2740.     //onCreatureAppear(creature)
  2741.     if(m_scriptInterface->reserveScriptEnv()){
  2742.         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  2743.  
  2744.         #ifdef __DEBUG_LUASCRIPTS__
  2745.         std::stringstream desc;
  2746.         desc << "npc " << m_npc->getName();
  2747.         env->setEventDesc(desc.str());
  2748.         #endif
  2749.  
  2750.         lua_State* L = m_scriptInterface->getLuaState();
  2751.  
  2752.         env->setScriptId(m_onCreatureAppear, m_scriptInterface);
  2753.         env->setRealPos(m_npc->getPosition());
  2754.         env->setNpc(m_npc);
  2755.  
  2756.         uint32_t cid = env->addThing(const_cast<Creature*>(creature));
  2757.  
  2758.         m_scriptInterface->pushFunction(m_onCreatureAppear);
  2759.         lua_pushnumber(L, cid);
  2760.         m_scriptInterface->callFunction(1);
  2761.         m_scriptInterface->releaseScriptEnv();
  2762.     }
  2763.     else{
  2764.         std::cout << "[Error] Call stack overflow. NpcScript::onCreatureAppear" << std::endl;
  2765.     }
  2766. }
  2767.  
  2768. void NpcScript::onCreatureDisappear(const Creature* creature)
  2769. {
  2770.     if(m_onCreatureDisappear == -1){
  2771.         return;
  2772.     }
  2773.     //onCreatureDisappear(id)
  2774.     if(m_scriptInterface->reserveScriptEnv()){
  2775.         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  2776.  
  2777.         #ifdef __DEBUG_LUASCRIPTS__
  2778.         std::stringstream desc;
  2779.         desc << "npc " << m_npc->getName();
  2780.         env->setEventDesc(desc.str());
  2781.         #endif
  2782.  
  2783.         lua_State* L = m_scriptInterface->getLuaState();
  2784.  
  2785.         env->setScriptId(m_onCreatureDisappear, m_scriptInterface);
  2786.         env->setRealPos(m_npc->getPosition());
  2787.         env->setNpc(m_npc);
  2788.  
  2789.         uint32_t cid = env->addThing(const_cast<Creature*>(creature));
  2790.  
  2791.         m_scriptInterface->pushFunction(m_onCreatureDisappear);
  2792.         lua_pushnumber(L, cid);
  2793.         m_scriptInterface->callFunction(1);
  2794.         m_scriptInterface->releaseScriptEnv();
  2795.     }
  2796.     else{
  2797.         std::cout << "[Error] Call stack overflow. NpcScript::onCreatureDisappear" << std::endl;
  2798.     }
  2799. }
  2800.  
  2801. void NpcScript::onCreatureMove(const Creature* creature, const Position& oldPos, const Position& newPos)
  2802. {
  2803.     if(m_onCreatureMove == -1){
  2804.         return;
  2805.     }
  2806.     //onCreatureMove(creature, oldPos, newPos)
  2807.     if(m_scriptInterface->reserveScriptEnv()){
  2808.         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  2809.  
  2810.         #ifdef __DEBUG_LUASCRIPTS__
  2811.         std::stringstream desc;
  2812.         desc << "npc " << m_npc->getName();
  2813.         env->setEventDesc(desc.str());
  2814.         #endif
  2815.  
  2816.         lua_State* L = m_scriptInterface->getLuaState();
  2817.  
  2818.         env->setScriptId(m_onCreatureMove, m_scriptInterface);
  2819.         env->setRealPos(m_npc->getPosition());
  2820.         env->setNpc(m_npc);
  2821.  
  2822.         uint32_t cid = env->addThing(const_cast<Creature*>(creature));
  2823.  
  2824.         m_scriptInterface->pushFunction(m_onCreatureMove);
  2825.         lua_pushnumber(L, cid);
  2826.         LuaScriptInterface::pushPosition(L, oldPos, 0);
  2827.         LuaScriptInterface::pushPosition(L, newPos, 0);
  2828.         m_scriptInterface->callFunction(3);
  2829.         m_scriptInterface->releaseScriptEnv();
  2830.     }
  2831.     else{
  2832.         std::cout << "[Error] Call stack overflow. NpcScript::onCreatureMove" << std::endl;
  2833.     }
  2834. }
  2835.  
  2836. void NpcScript::onCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text)
  2837. {
  2838.     if(m_onCreatureSay == -1){
  2839.         return;
  2840.     }
  2841.     //onCreatureSay(cid, type, msg)
  2842.     if(m_scriptInterface->reserveScriptEnv()){
  2843.         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  2844.  
  2845.         #ifdef __DEBUG_LUASCRIPTS__
  2846.         std::stringstream desc;
  2847.         desc << "npc " << m_npc->getName();
  2848.         env->setEventDesc(desc.str());
  2849.         #endif
  2850.  
  2851.         env->setScriptId(m_onCreatureSay, m_scriptInterface);
  2852.         env->setRealPos(m_npc->getPosition());
  2853.         env->setNpc(m_npc);
  2854.  
  2855.         uint32_t cid = env->addThing(const_cast<Creature*>(creature));
  2856.  
  2857.         lua_State* L = m_scriptInterface->getLuaState();
  2858.         m_scriptInterface->pushFunction(m_onCreatureSay);
  2859.         lua_pushnumber(L, cid);
  2860.         lua_pushnumber(L, type);
  2861.         lua_pushstring(L, text.c_str());
  2862.         m_scriptInterface->callFunction(3);
  2863.         m_scriptInterface->releaseScriptEnv();
  2864.     }
  2865.     else{
  2866.         std::cout << "[Error] Call stack overflow. NpcScript::onCreatureSay" << std::endl;
  2867.     }
  2868. }
  2869.  
  2870. void NpcScript::onThink()
  2871. {
  2872.     if(m_onThink == -1){
  2873.         return;
  2874.     }
  2875.     //onThink()
  2876.     if(m_scriptInterface->reserveScriptEnv()){
  2877.         ScriptEnviroment* env = m_scriptInterface->getScriptEnv();
  2878.  
  2879.         #ifdef __DEBUG_LUASCRIPTS__
  2880.         std::stringstream desc;
  2881.         desc << "npc " << m_npc->getName();
  2882.         env->setEventDesc(desc.str());
  2883.         #endif
  2884.  
  2885.         env->setScriptId(m_onThink, m_scriptInterface);
  2886.         env->setRealPos(m_npc->getPosition());
  2887.         env->setNpc(m_npc);
  2888.  
  2889.         m_scriptInterface->pushFunction(m_onThink);
  2890.         m_scriptInterface->callFunction(0);
  2891.         m_scriptInterface->releaseScriptEnv();
  2892.     }
  2893.     else{
  2894.         std::cout << "[Error] Call stack overflow. NpcScript::onThink" << std::endl;
  2895.     }
  2896. }
  2897.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement