#include "stdafx.h" #include "CCallback.h" #include "CPathfinder.h" #include "hch\CHeroHandler.h" #include "hch\CTownHandler.h" #include "CGameInfo.h" #include "hch\CAmbarCendamo.h" #include "mapHandler.h" #include "CGameState.h" #include "CPlayerInterface.h" #include "CLua.h" #include "hch/CGeneralTextHandler.h" #include "CAdvmapInterface.h" #include "CPlayerInterface.h" LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); int CCallback::lowestSpeed(CGHeroInstance * chi) { int min = 150; for ( std::map >::iterator i = chi->army.slots.begin(); i!=chi->army.slots.end(); i++ ) { if (min>(*i).second.first->speed) min = (*i).second.first->speed; } return min; } int CCallback::valMovePoints(CGHeroInstance * chi) { int ret = 1270+70*lowestSpeed(chi); if (ret>2000) ret=2000; //TODO: additional bonuses (but they aren't currently stored in chi) return ret; } void CCallback::newTurn() { //std::map::iterator i = gs->players.begin() ; gs->day++; for (std::set::iterator i=gs->cppscripts.begin();i!=gs->cppscripts.end();i++) { (*i)->newTurn(); } for ( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) { for (int j=0;j<(*i).second.heroes.size();j++) { (*i).second.heroes[j]->movement = valMovePoints((*i).second.heroes[j]); } } } bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType) { CGHeroInstance * hero = NULL; if (idtype==0) { if (player==-1) hero=gs->players[player+1].heroes[ID]; else hero=gs->players[player].heroes[ID]; } else if (idtype==1 && player>=0) //looking for it in local area { for (int i=0; iplayers[player].heroes.size();i++) { if (gs->players[player].heroes[i]->type->ID == ID) hero = gs->players[player].heroes[i]; } } else //idtype==1; player<0 { for(std::map::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j) { for (int i=0; i<(*j).second.heroes.size();i++) { if ((*j).second.heroes[i]->type->ID == ID) { hero = (*j).second.heroes[i]; } } } } if (!hero) return false; //can't find hero if(!verifyPath(path,!hero->canWalkOnSea()))//TODO: not check sea, if hero has flying or walking on water return false; //invalid path //check path format if (pathType==0) CPathfinder::convertPath(path,pathType); if (pathType>1) throw std::exception("Unknown path format"); CPath * ourPath = path; if(!ourPath) return false; for(int i=ourPath->nodes.size()-1; i>0; i--) { int3 stpos, endpos; stpos = int3(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z); endpos = int3(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z); HeroMoveDetails curd; curd.src = stpos; curd.dst = endpos; curd.ho = hero; curd.owner = hero->getOwner(); /*if(player!=-1) { hero->pos = endpos; }*/ if((hero->movement>=CGI->mh->getCost(stpos, endpos, hero)) || player==-1) { //performing move hero->movement-=CGI->mh->getCost(stpos, endpos, hero); std::vector< CGObjectInstance * > vis = CGI->mh->getVisitableObjs(CHeroInstance::convertPosition(curd.dst,false)); bool blockvis = false; for (int pit = 0; pitblockVisit) blockvis = true; if (!blockvis) { curd.successful = true; hero->pos = curd.dst; int heroSight = hero->getSightDistance(); int xbeg = stpos.x - heroSight - 2; if(xbeg < 0) xbeg = 0; int xend = stpos.x + heroSight + 2; if(xend >= CGI->ac->map.width) xend = CGI->ac->map.width; int ybeg = stpos.y - heroSight - 2; if(ybeg < 0) ybeg = 0; int yend = stpos.y + heroSight + 2; if(yend >= CGI->ac->map.height) yend = CGI->ac->map.height; for(int xd=xbeg; xdgetPosition(false).x-xd)*(hero->getPosition(false).x-xd); int deltaY = (hero->getPosition(false).y-yd)*(hero->getPosition(false).y-yd); if(deltaX+deltaYgetSightDistance()*hero->getSightDistance()) { if(gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] == 0) { CGI->playerint[gs->players[player].serial]->tileRevealed(int3(xd, yd, hero->getPosition(false).z)); } gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] = 1; } } } int nn=0; //number of interfece of currently browsed player for(std::map::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing { if (j->first > PLAYER_LIMIT) break; if(j->second.fogOfWarMap[stpos.x-1][stpos.y][stpos.z] || j->second.fogOfWarMap[endpos.x-1][endpos.y][endpos.z]) { //player should be notified CGI->playerint[j->second.serial]->heroMoved(curd); } ++nn; } for (int iii=0; iiicheckFunc(vis[iii]->ID,"heroVisit")) //script function gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID); if(vis[iii]->state) //hard-coded function vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID); } } else //interaction with blocking object (like resources) { curd.successful = false; CGI->playerint[gs->players[hero->getOwner()].serial]->heroMoved(curd); for (int iii=0; iiiblockVisit) { if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID); if(vis[iii]->state) //hard-coded function vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID); } } return false; } } else return true; //move ended - no more movement points } return true; } void CCallback::selectionMade(int selection, int asker) { //todo - jak bedzie multiplayer po sieci, to moze wymagac przerobek zaleznych od obranego modelu IChosen * ask = (IChosen *)asker; ask->chosen(selection); } int CCallback::howManyTowns() { return gs->players[gs->currentPlayer].towns.size(); } const CGTownInstance * CCallback::getTownInfo(int val, bool mode) //mode = 0 -> val = serial; mode = 1 -> val = ID { if (!mode) return gs->players[gs->currentPlayer].towns[val]; else { //TODO: add some smart ID to the CTownInstance //for (int i=0; iplayers[gs->currentPlayer].towns.size();i++) //{ // if (gs->players[gs->currentPlayer].towns[i]->someID==val) // return gs->players[gs->currentPlayer].towns[i]; //} return NULL; } return NULL; } int CCallback::howManyHeroes() { return gs->players[player].heroes.size(); } const CGHeroInstance * CCallback::getHeroInfo(int player, int val, bool mode) //mode = 0 -> val = serial; mode = 1 -> val = ID { if (gs->currentPlayer!=player) //TODO: checking if we are allowed to give that info return NULL; if (!mode) if(valplayers[player].heroes.size()) return gs->players[player].heroes[val]; else return NULL; else { for (int i=0; iplayers[player].heroes.size();i++) { if (gs->players[player].heroes[i]->type->ID==val) return gs->players[player].heroes[i]; } } return NULL; } int CCallback::getResourceAmount(int type) { return gs->players[player].resources[type]; } int CCallback::getDate(int mode) { int temp; switch (mode) { case 0: return gs->day; break; case 1: temp = (gs->day)%7; if (temp) return temp; else return 7; break; case 2: temp = ((gs->day-1)/7)+1; if (!(temp%4)) return 4; else return (temp%4); break; case 3: return ((gs->day-1)/28)+1; break; } return 0; } bool CCallback::verifyPath(CPath * path, bool blockSea) { for (int i=0;inodes.size();i++) { if ( CGI->mh->ttiles[path->nodes[i].coord.x][path->nodes[i].coord.y][path->nodes[i].coord.z].blocked && (! (CGI->mh->ttiles[path->nodes[i].coord.x][path->nodes[i].coord.y][path->nodes[i].coord.z].visitable))) return false; //path is wrong - one of the tiles is blocked if (blockSea) { if (i==0) continue; if ( ((CGI->mh->ttiles[path->nodes[i].coord.x][path->nodes[i].coord.y][path->nodes[i].coord.z].terType==EterrainType::water) && (CGI->mh->ttiles[path->nodes[i-1].coord.x][path->nodes[i-1].coord.y][path->nodes[i-1].coord.z].terType!=EterrainType::water)) || ((CGI->mh->ttiles[path->nodes[i].coord.x][path->nodes[i].coord.y][path->nodes[i].coord.z].terType!=EterrainType::water) && (CGI->mh->ttiles[path->nodes[i-1].coord.x][path->nodes[i-1].coord.y][path->nodes[i-1].coord.z].terType==EterrainType::water)) || (CGI->mh->ttiles[path->nodes[i-1].coord.x][path->nodes[i-1].coord.y][path->nodes[i-1].coord.z].terType==EterrainType::rock) ) return false; } } return true; } std::vector < std::string > CCallback::getObjDescriptions(int3 pos) { if(gs->players[player].fogOfWarMap[pos.x][pos.y][pos.z]) return CGI->mh->getObjDescriptions(pos); else return std::vector< std::string > (); } PseudoV< PseudoV< PseudoV > > & CCallback::getVisibilityMap() { return gs->players[player].fogOfWarMap; } bool CCallback::isVisible(int3 pos, int Player) { return gs->players[Player].fogOfWarMap[pos.x][pos.y][pos.z]; } std::vector < const CGHeroInstance *> CCallback::getHeroesInfo(bool onlyOur) { std::vector < const CGHeroInstance *> ret = std::vector < const CGHeroInstance *>(); for ( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) { for (int j=0;j<(*i).second.heroes.size();j++) { if ( ( isVisible((*i).second.heroes[j]->getPosition(false),player) ) || (*i).first==player) { ret.push_back((*i).second.heroes[j]); } } } // for ( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) return ret; } bool CCallback::isVisible(int3 pos) { return isVisible(pos,player); } int CCallback::getMyColor() { return player; } int CCallback::getHeroSerial(const CGHeroInstance * hero) { for (int i=0; iplayers[player].heroes.size();i++) { if (gs->players[player].heroes[i]==hero) return i; } return -1; } int CCallback::swapCreatures(const CCreatureSet *s1, const CCreatureSet *s2, int p1, int p2) { CCreatureSet *S1=const_cast(s1), *S2 = const_cast(s2);//todo - ugly if (false) { //TODO: check if we are allowed to swap these creatures return -1; } //if(S1->slots[p1].first) { //if(s2->slots[p2].first) { CCreature * pom = S2->slots[p2].first; S2->slots[p2].first = S1->slots[p1].first; S1->slots[p1].first = pom; int pom2 = S2->slots[p2].second; S2->slots[p2].second = S1->slots[p1].second; S1->slots[p1].second = pom2; } } return -1; } int CCallback::getMySerial() { return gs->players[player].serial; } int3 CScriptCallback::getPos(CGObjectInstance * ob) { return ob->pos; } void CScriptCallback::changePrimSkill(int ID, int which, int val) { CGHeroInstance * hero = CGI->state->getHero(ID,0); if (whichprimSkills[which]+=val; for (int i=0; iplayerint.size(); i++) { if (CGI->playerint[i]->playerID == hero->getOwner()) { CGI->playerint[i]->heroPrimarySkillChanged(hero, which, val); break; } } } else if (which==4) { hero->exp+=val; std::cout << "Bohater o ID " << ID <<" (" <heroh->heroes[ID]->name <<") dostaje "<state->getHero(heroID,0); return hero->getOwner(); } void CScriptCallback::showInfoDialog(int player, std::string text, std::vector * components) { //TODO: upewniac sie ze mozemy to zrzutowac (przy customowych interfejsach cos moze sie kopnac) if (player>=0) { CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial]; if (temp->human) ((CPlayerInterface*)(temp))->showInfoDialog(text,*components); return; } else { for (int i=0; iplayerint.size();i++) { if (CGI->playerint[i]->human) ((CPlayerInterface*)(CGI->playerint[i]))->showInfoDialog(text,*components); } } } void CScriptCallback::showSelDialog(int player, std::string text, std::vector*components, IChosen * asker) { CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial]; if (temp->human) ((CPlayerInterface*)(temp))->showSelDialog(text,*components,(int)asker); return; } int CScriptCallback::getSelectedHero() { int ret; if (LOCPLINT->adventureInt->selection.type == HEROI_TYPE) ret = ((CGHeroInstance*)(LOCPLINT->adventureInt->selection.selected))->subID; else ret = -1;; return ret; } int CScriptCallback::getDate(int mode) { int temp; switch (mode) { case 0: return gs->day; break; case 1: temp = (gs->day)%7; if (temp) return temp; else return 7; break; case 2: temp = ((gs->day-1)/7)+1; if (!(temp%4)) return 4; else return (temp%4); break; case 3: return ((gs->day-1)/28)+1; break; } return 0; } void CScriptCallback::giveResource(int player, int which, int val) { gs->players[player].resources[which]+=val; CGI->playerint[gs->players[player].serial]->receivedResource(which,val); } void CScriptCallback::showCompInfo(int player, SComponent * comp) { CPlayerInterface * i = dynamic_cast(CGI->playerint[gs->players[player].serial]); if(i) i->showComp(*comp); } void CLuaCallback::registerFuncs(lua_State * L) { lua_newtable(L); #define REGISTER_C_FUNC(x) \ lua_pushstring(L, #x); \ lua_pushcfunction(L, x); \ lua_rawset(L, -3) REGISTER_C_FUNC(getPos); REGISTER_C_FUNC(changePrimSkill); REGISTER_C_FUNC(getGnrlText); REGISTER_C_FUNC(getSelectedHero); /* REGISTER_C_FUNC(changePrimSkill); REGISTER_C_FUNC(getGnrlText); REGISTER_C_FUNC(changePrimSkill); REGISTER_C_FUNC(getGnrlText); REGISTER_C_FUNC(changePrimSkill); REGISTER_C_FUNC(getGnrlText);*/ lua_setglobal(L, "vcmi"); #undef REGISTER_C_FUNC(x) } int CLuaCallback::getPos(lua_State * L)//(CGObjectInstance * object); { const int args = lua_gettop(L); // number of arguments if ((args < 1) || !lua_isnumber(L, 1) ) luaL_error(L, "Incorrect arguments to getPos([Object address])"); CGObjectInstance * object = (CGObjectInstance *)(lua_tointeger(L, 1)); lua_pushinteger(L,object->pos.x); lua_pushinteger(L,object->pos.y); lua_pushinteger(L,object->pos.z); return 3; } int CLuaCallback::changePrimSkill(lua_State * L)//(int ID, int which, int val); { const int args = lua_gettop(L); // number of arguments if ((args < 1) || !lua_isnumber(L, 1) || ((args >= 2) && !lua_isnumber(L, 2)) || ((args >= 3) && !lua_isnumber(L, 3)) ) { luaL_error(L, "Incorrect arguments to changePrimSkill([Hero ID], [Which Primary skill], [Change by])"); } int ID = lua_tointeger(L, 1), which = lua_tointeger(L, 2), val = lua_tointeger(L, 3); CScriptCallback::changePrimSkill(ID,which,val); return 0; } int CLuaCallback::getGnrlText(lua_State * L) //(int which),returns string { const int args = lua_gettop(L); // number of arguments if ((args < 1) || !lua_isnumber(L, 1) ) luaL_error(L, "Incorrect arguments to getGnrlText([Text ID])"); int which = lua_tointeger(L,1); lua_pushstring(L,CGI->generaltexth->allTexts[which].c_str()); return 1; } int CLuaCallback::getSelectedHero(lua_State * L) //(),returns int (ID of hero, -1 if no hero is seleceted) { int ret; if (LOCPLINT->adventureInt->selection.type == HEROI_TYPE) ret = ((CGHeroInstance*)(LOCPLINT->adventureInt->selection.selected))->subID; else ret = -1; lua_pushinteger(L,ret); return 1; }