// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // Nel Misc #include "nel/misc/command.h" #include "nel/misc/variable.h" #include "nel/misc/file.h" #include "nel/misc/i_xml.h" #include "nel/misc/path.h" #include "nel/misc/algo.h" // Local includes #include "ags_test.h" #include "actor.h" #include "actor_manager.h" #include "macro_manager.h" #include "position_generator.h" #include "sheets.h" #include "mirrors.h" #include "ai_mgr.h" #include "nel/ligo/primitive.h" using namespace NLMISC; using namespace NLNET; using namespace std; namespace AGS_TEST { //------------------------------------------------------------------------- // Some global variables uint32 GlobalActorCount=0; uint32 GlobalActorUpdates=0; uint32 GlobalActorMoves=0; NLMISC_VARIABLE(uint32, GlobalActorCount, "actors"); NLMISC_VARIABLE(uint32, GlobalActorUpdates, "updates"); NLMISC_VARIABLE(uint32, GlobalActorMoves, "moves"); //------------------------------------------------------------------------- // some globals local to this file static CActor::EActivity DefaultActivity = CActor::SQUARE; static NLLIGO::CPrimZone * DefaultPatatEvolution = 0; static float DefaultOrientation = 0.0f; static float DefaultMagnetRange = 50.0f; static float DefaultMagnetDecay = 10.0f; static float DefaultAttackDistance = 0.0f; static std::string DefaultBehaviour; static int DefaultDialogue = 0; static float DefaultMinSpawnTime = 25.0f; static float DefaultMaxSpawnTime = 25.0f; static map PrimOrigin; // map of prim points and zones to prim filename static std::string SpawnName; // name or coordinates of the spawn point static CAiMgrFile * AIFile=0; // the file to which ai managers are to be added static CAiMgrInstance * AIManager=0; // the ai manager to which entities are to be added static CAiMgrPopulation * AIPopulation=0; // the ai manager to which entities are to be added //------------------------------------------------------------------------- // some stuff for manageing the output of AI_MANAGER files CAiMgrFile *CurrentAiMgrFile; CAiMgrInstance *CurrentAiMgrInstance; //------------------------------------------------------------------------- // CLEANING AND INITIALISING THE SYSTEM // Command for resetting the system NLMISC_COMMAND(actorReset,"Remove all actors and reset the actor system","") { COMMAND_MACRO_RECORD_TEST CActorManager::release(); CActorManager::init(); GlobalActorCount = 0; return true; } /* // Command for removing actors NLMISC_COMMAND(actorRemove,"Kill one or more actors"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST // iterate through the actor names for (unsigned i=0;i") { if(args.size() !=1) return false; CIFile f(CPath::lookup(args[0])); NLLIGO::CPrimRegion region; CIXml xml; xml.init(f); region.serial(xml); uint i; // adding zones to move manager for (i=0; i prim file for (i=0; i [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST if (args[0]==std::string("grid") && args.size()==1) {} else if (args[0]==std::string("line") && args.size()==1) {} else if (args[0]==std::string("line") && args.size()==2) CPositionGenerator::setSpacing(atoi(args[0].c_str())); else return false; CPositionGenerator::setPattern(args[0]); return true; } // Command for configuring how actors are placed on landscape NLMISC_COMMAND(actorCreateSpacing,"Setup spacing for new actors","") { if(args.size() !=1) return false; COMMAND_MACRO_RECORD_TEST CPositionGenerator::setSpacing(atoi(args[0].c_str())); return true; } // Command for configuring how actors are placed on landscape NLMISC_COMMAND(actorCreatePosition,"Setup start position for new actors"," []") { COMMAND_MACRO_RECORD_TEST switch(args.size()) { case 0: return false; case 1: CPositionGenerator::setPosition(args[0].c_str()); SpawnName=args[0]; break; case 3: CPositionGenerator::setSpacing(atoi(args[2].c_str())); // no break - drop through! case 2: CPositionGenerator::setPosition(atoi(args[0].c_str()), atoi(args[1].c_str())); SpawnName=args[0]+" "+args[1]; break; default: return false; } return true; } //------------------------------------------------------------------------- // CREATING ACTORS static CActor *createActor(std::string type,std::string name) { CActor *theNewActor=CActorManager::newActor(type,name); if (theNewActor) { theNewActor->setActivity (DefaultActivity); theNewActor->setPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); } return theNewActor; } void addPopulation(std::string type,std::string name,uint count) { // if no file has been opened yet then create one if (AIFile==0) { AIFile=new CAiMgrFile; AIFile->setName(std::string("ags_test.ai_manager")); CAiMgr::addFile(AIFile); } // create a new ai_manager instance AIManager= new CAiMgrInstance; AIFile->addChild(AIManager); AIManager->setName(name); AIManager->setCreatureLimit(count); if (DefaultPatatEvolution!=0) AIManager->setBoundary(DefaultPatatEvolution->getName()); // add a population record AIPopulation=new CAiMgrPopulation; AIManager->addPopulation(AIPopulation); AIPopulation->setName(name); AIPopulation->setOrientation(DefaultOrientation); AIPopulation->setQuantity(count); AIPopulation->setSpawnRate(int(DefaultMinSpawnTime*1000.0),int(DefaultMaxSpawnTime*1000.0)); AIPopulation->setType(NLMISC::CSheetId(type)); // add a spawn location CAiMgrSpawn *spawn=new CAiMgrSpawn; AIManager->addSpawn(spawn); spawn->setPlace(SpawnName); // check whether the spawn or evolution patats are in an unrefferenced prim file if (PrimOrigin.find(CPositionGenerator::getSpawnName())!=PrimOrigin.end()) { if (AIFile->getPrim().empty()) AIFile->setPrim(PrimOrigin[CPositionGenerator::getSpawnName()]); else if (AIFile->getPrim()!=PrimOrigin[CPositionGenerator::getSpawnName()]) nlwarning("WARNING: Can only apply one prim file per AI manager - spawn '%s' in '%s' NOT '%s'", CPositionGenerator::getSpawnName().c_str(), PrimOrigin[CPositionGenerator::getSpawnName()].c_str(), AIFile->getPrim().c_str() ); } if (DefaultPatatEvolution!=0) if (PrimOrigin.find(DefaultPatatEvolution->getName())!=PrimOrigin.end()) { if (AIFile->getPrim().empty()) AIFile->setPrim(PrimOrigin[DefaultPatatEvolution->getName()]); else if (AIFile->getPrim()!=PrimOrigin[DefaultPatatEvolution->getName()]) nlwarning("WARNING: Can only apply one prim file per AI manager - spawn '%s' in '%s' NOT '%s'", DefaultPatatEvolution->getName().c_str(), PrimOrigin[DefaultPatatEvolution->getName()].c_str(), AIFile->getPrim().c_str() ); } } // Command for creating actors NLMISC_COMMAND(actorCreate,"Add one or more moving actors"," [...]") { if(args.size() <2) return false; COMMAND_MACRO_RECORD_TEST // store the population information in an AI_MGR file record addPopulation(args[0],args[1],args.size()-1); // iterate through the actor names for (unsigned i=1;isetActivity (DefaultActivity); theNewActor->setPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); */ CActor *theNewActor=createActor(args[0],args[i]); } return true; } // Command for creating actors NLMISC_COMMAND(actorCreateCustom,"Add one or more moving actors"," [ [-act ] [-pos ] [-ctop ] [-cbot ] [-chair ] [-rhand ] [-lhand ] ] [...]") { if(args.size() <2) return false; COMMAND_MACRO_RECORD_TEST /* uint i; for (i=1; i ") { if(args.size()!=3 || atoi(args[2].c_str())<=0 || atoi(args[2].c_str())>1024) return false; COMMAND_MACRO_RECORD_TEST CActorGroup *theNewGroup=CActorManager::newActorGroup(args[1]); // store the population information in an AI_MGR file record addPopulation(args[0],args[1],atoi(args[2].c_str())); // iterate through the actor names for (int i=0;iactorCount())); theNewActor->setActivity (DefaultActivity); theNewActor->setPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); */ CActor *theNewActor=createActor(args[0],args[1]+toString(theNewGroup->actorCount())); if (theNewActor) theNewGroup->addActor(theNewActor); } return true; } // Command for creating actors NLMISC_COMMAND(actorCreateMoving,"Add one or more static actors"," [...]") { if(args.size() ==1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::SQUARE; } else { // store the population information in an AI_MGR file record addPopulation(args[0],args[1],args.size()-1); // iterate through the actor names for (unsigned i=1;isetPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); */ CActor *theNewActor=createActor(args[0],args[i]); if (theNewActor) { theNewActor->doSquare(); theNewActor->setActivity(CActor::SQUARE); } } } return true; } // Command for creating actors NLMISC_COMMAND(actorCreateStationary,"Add one or more static actors"," [...]") { if(args.size() ==1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::NOTHING; } else { // store the population information in an AI_MGR file record addPopulation(args[0],args[1],args.size()-1); // iterate through the actor names for (unsigned i=1;isetPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); */ CActor *theNewActor=createActor(args[0],args[i]); if (theNewActor) { theNewActor->doNothing(); theNewActor->setActivity(CActor::NOTHING); } } } return true; } // Command for creating actors NLMISC_COMMAND(actorCreateWandering,"Add one or more static actors"," [...]") { if(args.size() ==1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::WANDER; } else { // store the population information in an AI_MGR file record addPopulation(args[0],args[1],args.size()-1); // iterate through the actor names for (unsigned i=1;isetPrimZone (DefaultPatatEvolution); theNewActor->setAngle (DefaultOrientation); theNewActor->setMagnetRange (DefaultMagnetRange,DefaultMagnetDecay); theNewActor->setBehaviour (DefaultBehaviour); theNewActor->setAttackDistance (DefaultAttackDistance); theNewActor->setChatSet (DefaultDialogue); */ CActor *theNewActor=createActor(args[0],args[i]); if (theNewActor) { theNewActor->doWander(); theNewActor->setActivity(CActor::WANDER); } } } return true; } // Command for moving actor from a group to another NLMISC_COMMAND(moveActorsToGroup,"Move actors from a group to another (source group is emptied). If no source specified, all actors from defaultGroup assumed.","[] ") { COMMAND_MACRO_RECORD_TEST if (args.size() < 1) return false; if (args.size() > 2) return false; if (args.size() == 1) CActorManager::setActorsToGroup("defaultGroup", args[0]); else CActorManager::setActorsToGroup(args[0], args[1]); return true; } //------------------------------------------------------------------------- // MANAGING EXISTING ACTORS // Command for setting an actor PrimZone NLMISC_COMMAND(actorSetPatatEvolution,"Set actor patat evolution"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST NLLIGO::CPrimZone *primZone = CMoveManager::getPrimZone(args[0]); if (primZone == NULL) { nlwarning("Can't find prim zone '%s'", args[0].c_str()); return false; } if (args.size()==1) { // no actor names specified so setup the default value to apply to new actors DefaultPatatEvolution = primZone; } else { // apply this evolution patat to the last manager stored in ai manager if (AIManager) AIManager->setBoundary(args[0]); // iterate through the actor names uint i; for (i=1;isetPrimZone(primZone); } } return true; } // Command for setting actor orientations NLMISC_COMMAND(actorSetOrientation,"Add one or more static actors"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST const char *angleNames[]= {"E", "ENE", "NE", "NNE", "N","NNW","NW","WNW","W","WSW","SW","SSW","S","SSE","SE","ESE"}; unsigned i; float theta; #ifndef NL_OS_WINDOWS #define stricmp strcasecmp #endif for (i=0; isetOrientation(theta); // iterate through the actor names for (i=1;isetAngle(theta); } } return true; } // Command for setting actor magnet range NLMISC_COMMAND(actorSetMagnetRange,"Set the magnet properties for wandering behaviour"," [] [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST float range=(float)atof(args[0].c_str()); if (range<=0.0f) return false; unsigned start; float decay=(float)atof(args[0].c_str()); if (decay<0.0f) return false; if (decay==0.0f) { decay=10.0f; start=1; } else start=2; if((sint)args.size() <(start+1)) return false; if (args.size()1) DefaultMagnetDecay = decay; } else { // iterate through the actor names for (unsigned i=start;isetMagnetRange(range,decay); } } return true; } // Command for setting actor attack distance NLMISC_COMMAND(actorSetAttackDistance,"set actor attack distance"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST float distance=(float)atof(args[0].c_str()); // if (distance<=0.0f) return false; if (args.size()<2) { // no actor names specified so setup the default value to apply to new actors DefaultAttackDistance = distance; } else { // iterate through the actor names for (unsigned i=1;isetAttackDistance(distance); } } return true; } // Command for setting actor mode /*NLMISC_COMMAND(actorSetMode,"Set actor mode"," [...]") { if(args.size() <2) return false; COMMAND_MACRO_RECORD_TEST // iterate through the named actors setting their mode for (unsigned i=1;isetMode(args[0]); } return true; }*/ // Command for setting actor behaviour NLMISC_COMMAND(actorSetBehaviour,"Set actor behaviour"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()<2) { // no actor names specified so setup the default value to apply to new actors DefaultBehaviour = args[0]; } else if (args.size() == 2 && args[1] == "all") { uint num = CActorManager::numActors(); uint i; for (i=0; isetBehaviour(args[0]); } } else { // iterate through the named actors setting their behaviour for (unsigned i=1;isetBehaviour(args[0]); } } return true; } // Command for setting actor dialogue for bot chat NLMISC_COMMAND(actorSetDialogue,"Set actor bot-chat dialogue"," [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST int dialogue=atoi(args[0].c_str()); if (args.size()<2) { // no actor names specified so setup the default value to apply to new actors DefaultDialogue = dialogue; } else { // iterate through the named actors setting their behaviour for (unsigned i=1;isetChatSet(dialogue); } } return true; } // Command for setting actor respawn time (when dead) NLMISC_COMMAND(actorSetRespawnDelay,"set actor respawn delay"," [] [...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST float min=(float)atof(args[0].c_str()); if (min<=0.0f) return false; unsigned start; float max=(float)atof(args[0].c_str()); if (max==0.0f) { max=min; start=1; } else { if (max1) DefaultMaxSpawnTime = max; } else { // apply this orientation to the last manager stored in ai manager if (AIPopulation) AIPopulation->setSpawnRate(int(1000.0*min),int(1000.0*max)); // iterate through the actor names for (unsigned i=start;isetSpawnTime(min,max); } } return true; } // Command for making actors walk in a square pattern NLMISC_COMMAND(actorSetActivitySquare,"Make actors walk in a square shape","[...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::SQUARE; } else if (args.size() == 1 && args[0] == "all") { uint num = CActorManager::numActors(); uint i; for (i=0; isetActivity(CActor::SQUARE); } } else { // iterate through the actor names for (unsigned i=0;isetActivity(CActor::SQUARE); } } return true; } // Command for making actor(s) wander about randomly NLMISC_COMMAND(actorSetActivityWander,"Make actors walk in a square shape","[...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::WANDER; } else if (args.size() == 1 && args[0] == "all") { uint num = CActorManager::numActors(); uint i; for (i=0; isetActivity(CActor::WANDER); } } else { // iterate through the actor names for (unsigned i=0;isetActivity(CActor::WANDER); } } return true; } // Command for making actor(s) stand still NLMISC_COMMAND(actorSetActivityStationary,"Make actors stop walking/ fighting","[...]") { if(args.size() <1) return false; COMMAND_MACRO_RECORD_TEST if (args.size()==0) { // no actor names specified so setup the default value to apply to new actors DefaultActivity = CActor::NOTHING; } else if (args.size() == 1 && args[0] == "all") { uint num = CActorManager::numActors(); uint i; for (i=0; isetActivity(CActor::NOTHING); } } else { // iterate through the actor names for (unsigned i=0;isetActivity(CActor::NOTHING); } } return true; } // Command for making actors attack entities NLMISC_COMMAND(actorFight,"Make actors fight eachother"," ") { if(args.size()!=2) return false; COMMAND_MACRO_RECORD_TEST CActor *actor0=CActorManager::getActor(args[0]); CActor *actor1=CActorManager::getActor(args[1]); CActorGroup *group0=CActorManager::getActorGroup(args[0]); CActorGroup *group1=CActorManager::getActorGroup(args[1]); if (actor0) { if (actor1) { actor0->doFight(actor1); nlinfo("ACTOR %s Attacking ACTOR: %s",args[0].c_str(),args[1].c_str()); // actor1->doFight(actor0); } else if (group1) { actor0->doFight(group1); nlinfo("ACTOR %s Attacking GROUP: %s",args[0].c_str(),args[1].c_str()); // group1->doFight(actor0); } else { CEntityId id; id.fromString( args[1].c_str() ); actor0->doFight(id); nlinfo("ACTOR %s Attacking entity with SID: %s",args[0].c_str(),args[1].c_str()); } } else if (group0) { if (actor1) { group0->doFight(actor1); nlinfo("GROUP %s Attacking ACTOR: %s",args[0].c_str(),args[1].c_str()); // actor1->doFight(group0); } else if (group1) { group0->doFight(group1); nlinfo("GROUP %s Attacking GROUP: %s",args[0].c_str(),args[1].c_str()); // group1->doFight(group0); } else { CEntityId id; id.fromString( args[1].c_str() ); //group0->doFight(id); nlinfo("GROUP %s Cannot attack: %s (no actor or group of this name found in this service)",args[0].c_str(),args[1].c_str()); } } else nlinfo("Actor or group doesn't exist: %s",args[0].c_str()); return true; } // Command for displaying all of or named actors NLMISC_COMMAND(actorDisplay,"List the actors","[...]") { COMMAND_MACRO_RECORD_TEST if(args.size() <1) { // list all the actors' stats for (unsigned i=0;idisplay(); } else { // iterate through the named actors listing their stats for (unsigned i=0;idisplay(&log); } } return true; } //------------------------------------------------------------------------- // MANAGING AI FILES // command to display ai manager hierachy NLMISC_COMMAND(aiDisplay,"Display the ai manager hierachy","") { if(args.size()!=0) return false; COMMAND_MACRO_RECORD_TEST CAiMgr::display(0, &log); return true; } // command to set the output file for ai populations NLMISC_COMMAND(aiFile,"Set the file name for the following ai populations","") { if(args.size()!=1) return false; COMMAND_MACRO_RECORD_TEST AIFile=new CAiMgrFile; AIFile->setName(args[0]+std::string(".ai_manager")); CAiMgr::addFile(AIFile); return true; } // command to write ai manager hierachy to files NLMISC_COMMAND(aiWrite,"Write the ai manager hierachy to disk","") { if(args.size()!=0) return false; COMMAND_MACRO_RECORD_TEST CAiMgr::write(); return true; } // command to read ai manager hierachy from files NLMISC_COMMAND(aiRead,"Read the ai manager hierachy from disk","") { if(args.size()!=1) return false; COMMAND_MACRO_RECORD_TEST CAiMgr::read(args[0],true); return true; } //------------------------------------------------------------------------- // MANAGING MACROS // Command for creating a new macro NLMISC_COMMAND(macroRecord,"Start recording a new macro","") { if(args.size() !=1) return false; CMacroManager::recordMacro(args[0]); return true; } // Command for adding a line to a macro NLMISC_COMMAND(macroStopRecord,"stop macro recording","") { if(args.size() !=0) return false; CMacroManager::stopRecord(); return true; } // Command for executing a macro NLMISC_COMMAND(macroExecute,"Execute one or more macros"," [...]") { if(args.size() <1) return false; for (unsigned i=0;i [ ...]") { if (args.size() < 6) return false; const string &scriptName = args[0]; double spawnX = atof(args[1].c_str()); double spawnY = atof(args[2].c_str()); double spacing = atof(args[3].c_str()); uint width = atoi(args[4].c_str()); const string &extension = args[5]; vector filters; uint i; for (i=6; i files; CPath::getFileList(extension, files); if (!filters.empty()) { vector::iterator itr; for (itr=files.begin(); itr!=files.end(); ) { bool match = false; if (files[i][0] != '_') { for (i=0; !match && i= width) { cx = spawnX; cy += spacing; inLine = 0; } } script.close(); return true; } // NLMISC_COMMAND(generateAndRun, "Generate and run a sript that spawn a given type of creature", " [ ...]") { string scriptfile = IService::getInstance()->WriteFilesDirectory.toString()+"ags_generated.script"; string commandLine = "generateScript "+scriptfile; uint i; for (i=0; i [ ...]") { if (args.size() < 6) return false; string scriptName = args[0]; string filename = scriptName+".script"; string scriptfile = CPath::lookup(filename, false, false); if (scriptfile.empty()) { if (!CFile::isExists("data_shard/")) CFile::createDirectory("data_shard/"); if (!CFile::isExists("data_shard/ags_script/")) CFile::createDirectory("data_shard/ags_script/"); scriptfile = string("data_shard/ags_script/")+filename; string commandLine = "generateScript "+scriptfile; uint i; for (i=1; i [ ...]") { if (args.size() < 2) return false; CEntityId caster; list targets; caster.fromString(args[0].c_str()); CMirrorPropValueList targetList(TheDataset, caster, "TargetList"); targetList.clear(); uint i; for (i=args.size()-1; i>=2; --i) { CEntityId target; target.fromString(args[i].c_str()); TDataSetRow targetIndex = CMirrors::DataSet->getDataSetRow(target); targetList.push_front(targetIndex); } TGameCycle castTime = CTickEventHandler::getGameCycle() + atoi(args[1].c_str()); targetList.push_front(*((TDataSetRow*)(&castTime))); return true; } //------------------------------------------------------------------------- } // end of namespace AGS_TEST