void Script::moveCharacterToPlayer(uint16 characterId, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *playerHotspot = res.getActiveHotspot(PLAYER_ID); Hotspot *charHotspot = res.getActiveHotspot(characterId); assert(charHotspot); // If character in same room as player, then no need to do anything if (!charHotspot->currentActions().isEmpty() && (charHotspot->currentActions().top().roomNumber() == playerHotspot->roomNumber())) return; uint16 destRoom = playerHotspot->roomNumber(); const RoomTranslationRecord *rec; for (rec = &roomTranslations[0]; rec->srcRoom != 0; ++rec) { if (rec->srcRoom == destRoom) { destRoom = rec->destRoom; break; } } if (charHotspot->currentActions().isEmpty()) charHotspot->currentActions().addFront(DISPATCH_ACTION, destRoom); else charHotspot->currentActions().top().setRoomNumber(destRoom); }
void Script::makeGoewinFollow(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *hotspot = res.getActiveHotspot(GOEWIN_ID); hotspot->setTickProc(FOLLOWER_TICK_PROC_2); hotspot->currentActions().clear(); CharacterScheduleEntry *entry = res.charSchedules().getEntry(GOEWIN_CAVE_SUPPORT_ID); hotspot->currentActions().addFront(DISPATCH_ACTION, entry, ROOMNUM_CAVE); hotspot->setActions(hotspot->resource()->actions | (1 << (TELL - 1))); hotspot->setActionCtr(0); hotspot->setDelayCtr(0); hotspot->setCharacterMode(CHARMODE_NONE); }
void Script::ratpouchPushBricks(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); // Mark the bricks exit as now open RoomExitJoinData *joinRec = res.getExitJoin(BRICKS_ID); joinRec->blocked = 0; // Set Ratpouch moving through the new exit to room #7 Hotspot *ratpouchHotspot = res.getActiveHotspot(RATPOUCH_ID); ratpouchHotspot->setActions(0); // Make sure he can't be interrupted ratpouchHotspot->currentActions().clear(); ratpouchHotspot->currentActions().addBack(DISPATCH_ACTION, 7); }
void Script::normalGoewin(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *hotspot = res.getActiveHotspot(GOEWIN_ID); assert(hotspot); if (!hotspot->currentActions().isEmpty()) hotspot->currentActions().top().setAction(DISPATCH_ACTION); hotspot->setCharacterMode(CHARMODE_NONE); hotspot->setDirection(UP); hotspot->setTickProc(STANDARD_CHARACTER_TICK_PROC); // Clear walk to position for Goewin so player must walk up to her when interacting hotspot->resource()->walkX = 0; hotspot->resource()->walkY = 0; }
void Script::fixGoewin(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *hotspot = res.getActiveHotspot(GOEWIN_ID); assert(hotspot); hotspot->setTickProc(STANDARD_CHARACTER_TICK_PROC); CharacterScheduleEntry *entry = res.charSchedules().getEntry(GOEWIN_STANDARD_SUPPORT_ID); assert(entry); hotspot->currentActions().clear(); hotspot->currentActions().addFront(DISPATCH_ACTION, entry, hotspot->roomNumber()); hotspot->setActions(hotspot->resource()->actions & ~(1 << (TELL - 1))); hotspot->setActionCtr(0); hotspot->setDelayCtr(0); hotspot->setCharacterMode(CHARMODE_NONE); }
void Script::setSupportData(uint16 hotspotId, uint16 index, uint16 v3) { Resources &res = Resources::getReference(); // WORKAROUND: In room #45, the script for the Skorl noticing you gets // the parameters back to front. If this the case, just ignore it if (index == CASTLE_SKORL_ID) return; uint16 dataId = res.getCharOffset(index); CharacterScheduleEntry *entry = res.charSchedules().getEntry(dataId); assert(entry != NULL); Hotspot *h = res.getActiveHotspot(hotspotId); assert(h); assert(!h->currentActions().isEmpty()); h->currentActions().pop(); h->currentActions().addFront(DISPATCH_ACTION, entry, h->roomNumber()); }
void Script::setNewSupportData(uint16 index, uint16 hotspotId, uint16 v3) { Resources &res = Resources::getReference(); uint16 dataId = res.getCharOffset(index); CharacterScheduleEntry *entry = res.charSchedules().getEntry(dataId); Hotspot *h = res.getActiveHotspot(hotspotId); h->setBlockedFlag(false); h->currentActions().addFront(DISPATCH_ACTION, entry, h->roomNumber()); h->setActionCtr(0); }
void Script::setBlockingHotspotScript(uint16 charId, uint16 scriptIndex, uint16 v3) { Resources &r = Resources::getReference(); uint16 offset = r.getHotspotScript(scriptIndex); if (charId == PLAYER_ID) Room::getReference().setCursorState(CS_SEQUENCE); Hotspot *hs = r.getActiveHotspot(charId); hs->setHotspotScript(offset); hs->currentActions().top().setAction(EXEC_HOTSPOT_SCRIPT); hs->setOccupied(true); }
void Script::makeGoewinWork(uint16 v1, uint16 v2, uint16 v3) { Resources &res = Resources::getReference(); Hotspot *goewin = res.getActiveHotspot(GOEWIN_ID); assert(goewin); goewin->updateMovement(); goewin->currentActions().addBack(EXEC_HOTSPOT_SCRIPT, 34); goewin->setHotspotScript(0x616); goewin->setDelayCtr(1500); goewin->setTickProc(GOEWIN_SHOP_TICK_PROC); // Set walk to position for Goewin whilst she's working goewin->resource()->walkX = 179; goewin->resource()->walkY = 138; }
Hotspot *Resources::activateHotspot(uint16 hotspotId) { Resources &resources = Resources::getReference(); HotspotData *res = getHotspot(hotspotId); if (!res) return NULL; res->roomNumber &= 0x7fff; // clear any suppression bit in room # // Make sure that the hotspot isn't already active Hotspot *h = getActiveHotspot(hotspotId); if (h != NULL) return h; // If it's NPC with a schedule, then activate the schedule if ((res->npcScheduleId != 0) && (res->npcSchedule.isEmpty())) { CharacterScheduleEntry *entry = resources.charSchedules().getEntry(res->npcScheduleId); res->npcSchedule.addFront(DISPATCH_ACTION, entry, res->roomNumber); } // Check the script load flag if (res->scriptLoadFlag) { // Execute a script rather than doing a standard load Script::execute(res->loadOffset); } else { // Standard load bool loadFlag = true; uint16 talkIndex; switch (res->loadOffset) { case 1: // Copy protection check - since the game is freeware now, ignore it loadFlag = false; break; case 2: // Empty handler used to prevent loading hotspots that // are yet to be active (such as the straw fire) loadFlag = false; break; case 3: case 4: // Standard animation load break; case 5: // Custom loader used by the notice hotspot 42ah in room #20 talkIndex = _fieldList.getField(TALK_INDEX); if ((talkIndex < 8) || (talkIndex >= 14)) // Don't load hotspot loadFlag = false; else // Make the notice be on-screen res->startY = 85; break; case 6: // Torch in room #1 loadFlag = _fieldList.getField(TORCH_HIDE) == 0; break; default: // All others simply activate the hotspot warning("Hotspot %d uses unknown load offset index %d", res->hotspotId, res->loadOffset); } if (loadFlag) { Hotspot *hotspot = addHotspot(hotspotId); assert(hotspot); // Special post-load handling if (res->loadOffset == 3) hotspot->setPersistant(true); if (res->loadOffset == 5) hotspot->handleTalkDialog(); if (hotspotId == CASTLE_SKORL_ID) { // The Castle skorl has a default room #99, so it needs to be adjusted dynamically res->npcSchedule.clear(); CharacterScheduleEntry *entry = resources.charSchedules().getEntry(res->npcScheduleId); res->npcSchedule.addFront(DISPATCH_ACTION, entry, res->roomNumber); } if ((hotspotId == GOEWIN_ID) && (hotspot->roomNumber() == 39)) { // WORKAROUND: When you re-join Goewin in the caves, clear her schedule. This may prevent a // situation where you could close the left door, and she'd be permanently stuck trying to go // the next room on the left, since her old schedule still had her following your old path hotspot->currentActions().clear(); // Since she's no longer a follower, clear her start room field hotspot->setStartRoomNumber(0); } // TODO: Figure out why there's a room set in the animation decode for a range of characters, // particularly since it doesn't seem to match what happens in-game /* if ((hotspot->hotspotId() >= RATPOUCH_ID) && (hotspot->hotspotId() < FIRST_NONCHARACTER_ID) && (hotspot->roomNumber() < 42)) { // Start wandering characters off in room 24 hotspot->setRoomNumber(24); hotspot->setPosition(64, 116); _fieldList.wanderingCharsLoaded() = true; } */ return hotspot; } } return NULL; }