bool Script::_ExecuteAction(action_node* act) { #if DEBUG_SCRIPTS printf("SCRIPT: %s (%d 0x%x)\n", IDTable::ActionAt(act->id).c_str(), act->id, act->id); act->Print(); #endif Core* core = Core::Get(); Actor* thisActor = dynamic_cast<Actor*>(fTarget.Target()); switch (act->id) { case 0x03: { /* Attack(O:Target*) */ Object* targetObject = FindObject(act); if (targetObject != NULL) { Actor* targetActor = dynamic_cast<Actor*>(targetObject); if (thisActor != NULL && targetActor != NULL) { Attack* attackAction = new Attack(thisActor, targetActor); thisActor->AddAction(attackAction); } } break; } case 0x07: { /* CreateCreature(S:NewObject*,P:Location*,I:Face*) */ // TODO: If point is (-1, -1) we should put the actor near // the active creature. Which one is the active creature? IE::point point = act->where; if (point.x == -1 && point.y == -1) { point = Game::Get()->Party()->ActorAt(0)->Position(); point.x += Core::RandomNumber(-20, 20); point.y += Core::RandomNumber(-20, 20); } Actor* actor = new Actor(act->string1, point, act->integer1); RoomContainer::Get()->ActorEnteredArea(actor); // TODO: Add actor to the current area break; } case 0x8: { /* DIALOGUE(O:OBJECT*) (8 0x8) */ Actor* actor = dynamic_cast<Actor*>(FindObject(act)); if (actor != NULL) { Dialogue* dialogueAction = new Dialogue(thisActor, actor); thisActor->AddAction(dialogueAction); } break; } case 0xA: { /* ENEMY() (10 0xa) */ uint32 id = IDTable::EnemyAllyValue("ENEM"); thisActor->SetEnemyAlly(id); break; } case 22: { // MoveToObject Object* object = FindObject(act); if (object != NULL) { WalkTo* walkTo = new WalkTo(thisActor, object->Position()); fTarget.Target()->AddAction(walkTo); } break; } case 23: { // MoveToPoint Actor* actor = dynamic_cast<Actor*>(fTarget.Target()); if (actor != NULL) { WalkTo* walkTo = new WalkTo(actor, act->where); actor->AddAction(walkTo); actor->StopCheckingConditions(); } break; } case 29: { /* RunAwayFrom(O:Creature*,I:Time*) */ Actor* targetActor = dynamic_cast<Actor*>(FindObject(act)); if (targetActor != NULL && thisActor != NULL) { RunAwayFrom* run = new RunAwayFrom(thisActor, targetActor); fTarget.Target()->AddAction(run); } break; } case 36: { /* * 36 Continue() * This action instructs the script parser to continue looking * for actions in the active creatures action list. * This is mainly included in scripts for efficiency. * Continue should also be appended to any script blocks added * to the top of existing scripts, to ensure correct functioning * of any blocks which include the OnCreation trigger. * Continue may prevent actions being completed until the script * parser has finished its execution cycle. Continue() must be * the last command in an action list to function correctly. * Use of continue in a script block will cause the parser * to treater subsequent empty response blocks as though they * contained a Continue() command - this parsing can be stopped * by including a NoAction() in the empty response block. */ // TODO: Implement break; } case 61: { /* 61 StartTimer(I:ID*,I:Time*) This action starts a timer local to the active creature. The timer is measured in seconds, and the timer value is not saved in save games. The timer is checked with the TimerExpired trigger.*/ // TODO: We should add the timer local to the active creature, // whatever that means if (fTarget.Target() == NULL) printf("NULL TARGET\n"); std::ostringstream stringStream; stringStream << fTarget.Target()->Name() << " " << act->integer1; GameTimer::Add(stringStream.str().c_str(), act->integer2); break; } case 85: { /* 85 RandomWalk */ if (thisActor != NULL && thisActor->IsInterruptable()) core->RandomWalk(thisActor); break; } case 86: { /* 86 SetInterrupt(I:State*Boolean) */ if (thisActor != NULL) thisActor->SetInterruptable(act->integer1 == 1); break; } case 0x1E: { std::string variableScope; variableScope.append(act->string1, 6); std::string variableName; variableName.append(&act->string1[6]); if (variableScope.compare("LOCALS") == 0) { if (fTarget != NULL) fTarget.Target()->SetVariable(variableName.c_str(), act->integer1); } else { // TODO: Check for AREA variables core->SetVariable(variableName.c_str(), act->integer1); } break; } case 0x53: { /* 83 SmallWait(I:Time*) */ // TODO: The time is probably wrong Wait* wait = new Wait(thisActor, act->integer1); fTarget.Target()->AddAction(wait); break; } case 106: { /* Shout */ // Check if target is silenced if (thisActor != NULL) thisActor->Shout(act->integer1); break; } case 0x64: { /* 100 RandomFly */ if (thisActor != NULL && thisActor->IsInterruptable()) core->RandomFly(thisActor); break; } case 0x65: { /* 101 FlyToPoint(Point, Time) */ if (thisActor != NULL && thisActor->IsInterruptable()) { FlyTo* flyTo = new FlyTo(thisActor, act->where, act->integer1); thisActor->AddAction(flyTo); } break; } case 111: { /* DESTROYSELF() (111 0x6f) */ // TODO: Delete it for real fTarget.Target()->SetStale(true); return false; } case 0x73: { /* SETGLOBALTIMER(S:NAME*,S:AREA*,I:TIME*GTIMES) (115 0x73)*/ std::string timerName; // TODO: We append the timer name to the area name, // check if it's okay timerName.append(act->string2).append(act->string1); GameTimer::Add(timerName.c_str(), act->integer1); break; } case 0x97: { /* 151 DisplayString(O:Object*,I:StrRef*) * This action displays the strref specified by the StrRef parameter * in the message window, attributing the text to * the specified object. */ core->DisplayMessage(act->integer1); break; } case 0xA7: { core->PlayMovie(act->string1); break; } case 134: { /* AttackReevaluate(O:Target*,I:ReevaluationPeriod*) * (134 0x86) */ Actor* targetActor = dynamic_cast<Actor*>(FindObject(act)); if (thisActor != NULL && targetActor != NULL) { IE::point point = targetActor->NearestPoint(thisActor->Position()); WalkTo* walkToAction = new WalkTo(thisActor, point); thisActor->AddAction(walkToAction); Attack* attackAction = new Attack(thisActor, targetActor); thisActor->AddAction(attackAction); } break; } case 198: // 0xc6 { /* STARTDIALOGNOSET(O:OBJECT*) (198 0xc6) */ // TODO: Implement more correctly. Actor* actor = dynamic_cast<Actor*>(FindObject(act)); if (actor != NULL) { Dialogue* dialogueAction = new Dialogue(thisActor, actor); thisActor->AddAction(dialogueAction); } break; } case 207: { /* 207 MoveToPointNoInterrupt(P:Point*) * This action causes the active creature to move to the specified coordinates. * The action will update the position of creatures as stored in ARE files * (first by setting the coordinates of the destination point, then by setting * the coordinates of the current point once the destination is reached). * Conditions are not checked until the destination point is reached.*/ Actor* actor = dynamic_cast<Actor*>(fTarget.Target()); if (actor != NULL) { WalkTo* walkTo = new WalkTo(actor, act->where); actor->AddAction(walkTo); actor->StopCheckingConditions(); } break; } case 228: // 0xe4 { /* CreateCreatureImpassable(S:NewObject*,P:Location*,I:Face*) (228 0xe4) */ /* This action creates the specified creature * on a normally impassable surface (e.g. on a wall, * on water, on a roof). */ Actor* actor = new Actor(act->string1, act->where, act->integer1); std::cout << "Created actor " << act->string1 << " on "; std::cout << act->where.x << ", " << act->where.y << std::endl; actor->SetDestination(act->where); RoomContainer::Get()->ActorEnteredArea(actor); break; } default: printf("SCRIPT: UNIMPLEMENTED ACTION!!!\n"); printf("SCRIPT: %s (%d 0x%x)\n", IDTable::ActionAt(act->id).c_str(), act->id, act->id); act->Print(); break; } return true; }