TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) { init(Point32(zoomX, zoomY), angle, Point32(hotspotX, hotspotY), true, BLEND_NORMAL, kDefaultRgbaMod, false, false, Point32(kDefaultOffsetX, kDefaultOffsetY)); }
TransformStruct::TransformStruct() { init(Point32(kDefaultZoomX, kDefaultZoomY), kDefaultAngle, Point32(kDefaultHotspotX, kDefaultHotspotY), true, BLEND_NORMAL, kDefaultRgbaMod, false, false, Point32(kDefaultOffsetX, kDefaultOffsetY)); }
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { init(Point32(zoomX, zoomY), angle, Point32(hotspotX, hotspotY), false, blendMode, rgbaMod, mirrorX, mirrorY, Point32(offsetX, offsetY)); }
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) { init(Point32(zoomX, zoomY), kDefaultAngle, Point32(kDefaultHotspotX, kDefaultHotspotY), false, blendMode, rgbaMod, mirrorX, mirrorY, Point32(kDefaultOffsetX, kDefaultOffsetY)); }
TransformStruct::TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { init(Point32((int32)(zoomX / 100.0 * kDefaultZoomX), (int32)(zoomY / 100.0 * kDefaultZoomY)), angle, Point32(hotspotX, hotspotY), false, blendMode, rgbaMod, mirrorX, mirrorY, Point32(offsetX, offsetY)); }
TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) { init(Point32(kDefaultZoomX, kDefaultZoomY), kDefaultAngle, Point32(kDefaultHotspotX, kDefaultHotspotY), false, BLEND_NORMAL, kDefaultRgbaMod, false, false, Point32(kDefaultOffsetX, kDefaultOffsetY)); _numTimesX = numTimesX; _numTimesY = numTimesY; }
void Unit::Order_NukeGround() { unk_move_waypoint = order_target_pos; int sight_range = GetSightRange(false) * 32; int dist = Distance(exact_position, Point32(order_target_pos) * 256 + Point32(128, 128)) / 256; if (ai && dist <= sight_range * 3) Ai_Cloak(); if (dist > sight_range) { if (move_target_update_timer == 0) ChangeMovementTarget(order_target_pos); // What, it is not moving? } else { bw::StopMoving(this); if (position != unk_move_waypoint) { auto pos = sprite->position; int diff = facing_direction - bw::GetFacingDirection(pos.x, pos.y, unk_move_waypoint.x, unk_move_waypoint.y); if (diff < -1 || diff > 1) return; } Unit *silo = nullptr; for (Unit *unit : bw::first_player_unit[player]) { if (unit->Type() == UnitId::NuclearSilo && unit->silo.has_nuke) { silo = unit; break; } } if (!silo) { OrderDone(); return; } Unit *nuke = silo->silo.nuke; silo->silo.nuke = nullptr; silo->silo.has_nuke = 0; bw::PlaySound(Sound::NukeLaser, this, 1, 0); nuke->IssueOrderTargetingGround(OrderId::NukeLaunch, order_target_pos); related = nuke; nuke->related = this; nuke->sprite->SetDirection32(0); bw::ShowUnit(nuke); IssueOrderTargetingGround(OrderId::NukeTrack, sprite->position); if (!IsDisabled() || Type().IsBuilding()) // Huh? buttons = 0xed; RefreshUi(); } }
/** * Moves relevant windows if they've been moved offscreen by a window resize. * Also forces the bottom toolbar to be moved, as that will always be in the wrong position. * @param new_width New width of the display. * @param new_height New height of the display. */ void WindowManager::RepositionAllWindows(uint new_width, uint new_height) { Rectangle32 rect(0, 0, new_width, new_height); for (Window *w = this->top; w != nullptr; w = w->lower) { if (w->wtype == WC_MAINDISPLAY) { w->SetSize(new_width, new_height); /* Add an arbitrary amount for closebox/titlebar, so the window is still actually accessible. */ } else if (!rect.IsPointInside(Point32(w->rect.base.x + 20, w->rect.base.y + 20)) || w->wtype == WC_BOTTOM_TOOLBAR) { w->SetPosition(w->OnInitialPosition()); } } }
/** * Moves relevant windows if they've been moved offscreen by a window resize. * Also forces the bottom toolbar to be moved, as that will always be in the wrong position. */ void WindowManager::RepositionAllWindows() { Viewport *vp = GetViewport(); if (vp == nullptr) return; Rectangle32 vp_rect = vp->rect; for (Window *w = this->top; w != nullptr; w = w->lower) { if (w->wtype == WC_MAINDISPLAY) continue; /* Add an arbitrary amount for closebox/titlebar, * so the window is still actually accessible. */ if (!vp_rect.IsPointInside(Point32(w->rect.base.x + 20, w->rect.base.y + 20)) || w->wtype == WC_BOTTOM_TOOLBAR) { w->SetPosition(w->OnInitialPosition()); } } }
People::People(SherlockEngine *vm) : _vm(vm) { _holmesOn = true; _allowWalkAbort = true; _portraitLoaded = false; _portraitsOn = true; _clearingThePortrait = false; _talkPics = nullptr; _portraitSide = 0; _speakerFlip = false; _holmesFlip = false; _holmesQuotient = 0; _savedPos = Point32(-1, -1); _savedPos._facing = -1; _forceWalkReload = false; _useWalkLib = false; _walkControl = 0; _portrait._sequences = new byte[32]; }
OpcodeReturn TattooTalk::cmdWalkHolmesToCoords(const byte *&str) { People &people = *_vm->_people; ++str; int xp = (str[0] - 1) * 256 + str[1] - 1; if (xp > 16384) // Negative X xp = -1 * (xp - 16384); int yp = (str[2] - 1) * 256 + str[3] - 1; people[HOLMES].walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER), DIRECTION_CONVERSION[str[4] - 1]); if (_talkToAbort) return RET_EXIT; str += 4; return RET_SUCCESS; }
OpcodeReturn TattooTalk::cmdSetNPCPosition(const byte *&str) { int npcNum = *++str - 1; ++str; TattooPeople &people = *(TattooPeople *)_vm->_people; TattooPerson &person = people[npcNum]; int32 posX = (str[0] - 1) * 256 + str[1] - 1; if (posX > 16384) posX = -1 * (posX - 16384); int32 posY = (str[2] - 1) * 256 + str[3] - 1; people[npcNum]._position = Point32(posX * FIXED_INT_MULTIPLIER, posY * FIXED_INT_MULTIPLIER); if (person._seqTo && person._walkLoaded) { person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo; person._seqTo = 0; } assert(str[4] - 1 < 16); person._sequenceNumber = DIRECTION_CONVERSION[str[4] - 1]; person._frameNumber = 0; if (person._walkLoaded) person.checkWalkGraphics(); if (person._walkLoaded && person._type == CHARACTER && person._sequenceNumber >= STOP_UP && person._sequenceNumber <= STOP_UPLEFT) { bool done = false; do { person.checkSprite(); for (int x = 0; x < person._frameNumber; x++) { if (person._walkSequences[person._sequenceNumber]._sequences[x] == 0) { done = true; break; } } } while(!done); } str += 4; return RET_SUCCESS; }
OpcodeReturn TattooTalk::cmdWalkNPCToCoords(const byte *&str) { int npcNum = *++str; str++; TattooPeople &people = *(TattooPeople *)_vm->_people; TattooPerson &person = people[npcNum]; if (person._pathStack.empty()) person.pushNPCPath(); person._npcMoved = true; int xp = (str[0] - 1) * 256 + str[1] - 1; if (xp > 16384) xp = -1 * (xp - 16384); int yp = (str[2] - 1) * 256 + str[3] - 1; person.walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER), DIRECTION_CONVERSION[str[4] - 1]); if (_talkToAbort) return RET_EXIT; str += 4; return RET_SUCCESS; }
void People::reset() { SaveManager &saves = *_vm->_saves; Talk &talk = *_vm->_talk; _data[HOLMES]->_description = "Sherlock Holmes!"; // Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS; for (int idx = 0; idx < count; ++idx) { Person &p = *_data[idx]; if (IS_SERRATED_SCALPEL) { p._type = CHARACTER; p._position = Point32(100 * FIXED_INT_MULTIPLIER, 110 * FIXED_INT_MULTIPLIER); } else if (!talk._scriptMoreFlag && !saves._justLoaded) { p._type = (idx == 0) ? CHARACTER : INVALID; p._position = Point32(36 * FIXED_INT_MULTIPLIER, 29 * FIXED_INT_MULTIPLIER); p._use[0]._verb = ""; p._use[1]._verb = ""; } p._sequenceNumber = IS_SERRATED_SCALPEL ? (int)Tattoo::STOP_DOWNRIGHT : (int)Tattoo::STOP_DOWNRIGHT; p._imageFrame = nullptr; p._frameNumber = 1; p._startSeq = 0; p._delta = Point32(0, 0); p._oldPosition = Common::Point(0, 0); p._oldSize = Common::Point(0, 0); p._misc = 0; p._pickUp = ""; p._allow = 0; p._noShapeSize = Common::Point(0, 0); p._goto = Common::Point(0, 0); p._status = 0; p._seqTo = 0; p._seqCounter = p._seqCounter2 = 0; p._seqStack = 0; p._gotoSeq = p._talkSeq = 0; p._restoreSlot = 0; p._startSeq = 0; p._altImages = nullptr; p._altSeq = 0; p._centerWalk = true; p._adjust = Common::Point(0, 0); // Load the default walk sequences p._walkCount = 0; p._walkTo.clear(); p._oldWalkSequence = -1; p._walkSequences.clear(); if (IS_SERRATED_SCALPEL) { p._walkSequences.resize(MAX_HOLMES_SEQUENCE); for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) { p._walkSequences[seqIdx]._sequences.clear(); const byte *pSrc = &CHARACTER_SEQUENCES[seqIdx][0]; do { p._walkSequences[seqIdx]._sequences.push_back(*pSrc); } while (*pSrc++); } } } }
void ScalpelPerson::setWalking() { Map &map = *_vm->_map; Scene &scene = *_vm->_scene; int oldDirection, oldFrame; Common::Point speed, delta; // Flag that player has now walked in the scene scene._walkedInScene = true; // Stop any previous walking, since a new dest is being set _walkCount = 0; oldDirection = _sequenceNumber; oldFrame = _frameNumber; // Set speed to use horizontal and vertical movement if (map._active) { speed = Common::Point(MWALK_SPEED, MWALK_SPEED); } else { speed = Common::Point(XWALK_SPEED, YWALK_SPEED); } // If the player is already close to the given destination that no // walking is needed, move to the next straight line segment in the // overall walking route, if there is one for (;;) { // Since we want the player to be centered on the destination they // clicked, but characters draw positions start at their left, move // the destination half the character width to draw him centered int temp; if (_walkDest.x >= (temp = _imageFrame->_frame.w / 2)) _walkDest.x -= temp; delta = Common::Point( ABS(_position.x / FIXED_INT_MULTIPLIER - _walkDest.x), ABS(_position.y / FIXED_INT_MULTIPLIER - _walkDest.y) ); // If we're ready to move a sufficient distance, that's it. Otherwise, // move onto the next portion of the walk path, if there is one if ((delta.x > 3 || delta.y > 0) || _walkTo.empty()) break; // Pop next walk segment off the walk route stack _walkDest = _walkTo.pop(); } // If a sufficient move is being done, then start the move if (delta.x > 3 || delta.y) { // See whether the major movement is horizontal or vertical if (delta.x >= delta.y) { // Set the initial frame sequence for the left and right, as well // as setting the delta x depending on direction if (_walkDest.x < (_position.x / FIXED_INT_MULTIPLIER)) { _sequenceNumber = (map._active ? (int)MAP_LEFT : (int)WALK_LEFT); _delta.x = speed.x * -FIXED_INT_MULTIPLIER; } else { _sequenceNumber = (map._active ? (int)MAP_RIGHT : (int)WALK_RIGHT); _delta.x = speed.x * FIXED_INT_MULTIPLIER; } // See if the x delta is too small to be divided by the speed, since // this would cause a divide by zero error if (delta.x >= speed.x) { // Det the delta y _delta.y = (delta.y * FIXED_INT_MULTIPLIER) / (delta.x / speed.x); if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER)) _delta.y = -_delta.y; // Set how many times we should add the delta to the player's position _walkCount = delta.x / speed.x; } else { // The delta x was less than the speed (ie. we're really close to // the destination). So set delta to 0 so the player won't move _delta = Point32(0, 0); _position = Point32(_walkDest.x * FIXED_INT_MULTIPLIER, _walkDest.y * FIXED_INT_MULTIPLIER); _walkCount = 1; } // See if the sequence needs to be changed for diagonal walking if (_delta.y > 150) { if (!map._active) { switch (_sequenceNumber) { case WALK_LEFT: _sequenceNumber = WALK_DOWNLEFT; break; case WALK_RIGHT: _sequenceNumber = WALK_DOWNRIGHT; break; } } } else if (_delta.y < -150) { if (!map._active) { switch (_sequenceNumber) { case WALK_LEFT: _sequenceNumber = WALK_UPLEFT; break; case WALK_RIGHT: _sequenceNumber = WALK_UPRIGHT; break; } } } } else { // Major movement is vertical, so set the sequence for up and down, // and set the delta Y depending on the direction if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER)) { _sequenceNumber = WALK_UP; _delta.y = speed.y * -FIXED_INT_MULTIPLIER; } else { _sequenceNumber = WALK_DOWN; _delta.y = speed.y * FIXED_INT_MULTIPLIER; } // If we're on the overhead map, set the sequence so we keep moving // in the same direction if (map._active) _sequenceNumber = (oldDirection == -1) ? MAP_RIGHT : oldDirection; // Set the delta x _delta.x = (delta.x * FIXED_INT_MULTIPLIER) / (delta.y / speed.y); if (_walkDest.x < (_position.x / FIXED_INT_MULTIPLIER)) _delta.x = -_delta.x; _walkCount = delta.y / speed.y; } } // See if the new walk sequence is the same as the old. If it's a new one, // we need to reset the frame number to zero so its animation starts at // its beginning. Otherwise, if it's the same sequence, we can leave it // as is, so it keeps the animation going at wherever it was up to if (_sequenceNumber != _oldWalkSequence) _frameNumber = 0; _oldWalkSequence = _sequenceNumber; if (!_walkCount) gotoStand(); // If the sequence is the same as when we started, then Holmes was // standing still and we're trying to re-stand him, so reset Holmes' // rame to the old frame number from before it was reset to 0 if (_sequenceNumber == oldDirection) _frameNumber = oldFrame; }
void UserInterface::checkAction(ActionType &action, int objNum, FixedTextActionId fixedTextActionId) { Events &events = *_vm->_events; FixedText &fixedText = *_vm->_fixedText; People &people = *_vm->_people; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; Point32 pt(-1, -1); if (action._useFlag) // Automatically set the given flag _vm->setFlags(action._useFlag); if (IS_SERRATED_SCALPEL && objNum >= 1000) // Ignore actions done on characters return; if (IS_SERRATED_SCALPEL && !action._cAnimSpeed) { // Invalid action, to print error message _infoFlag = true; clearInfo(); Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, action._cAnimNum); screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "%s", errorMessage.c_str()); _infoFlag = true; // Set how long to show the message _menuCounter = 30; } else { BaseObject *obj; if (objNum >= 1000) obj = &people[objNum - 1000]; else obj = &scene._bgShapes[objNum]; int cAnimNum; if (action._cAnimNum == 0) // Really a 10 cAnimNum = 9; else cAnimNum = action._cAnimNum - 1; int dir = -1; if (action._cAnimNum != 99) { CAnim &anim = scene._cAnim[cAnimNum]; if (action._cAnimNum != 99) { if (action._cAnimSpeed & REVERSE_DIRECTION) { pt = anim._teleport[0]; dir = anim._teleport[0]._facing; } else { pt = anim._goto[0]; dir = anim._goto[0]._facing; } } } else { pt = Point32(-1, -1); dir = -1; } // Has a value, so do action // Show wait cursor whilst walking to object and doing action events.setCursor(WAIT); bool printed = false; for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2 && toupper(action._names[nameIdx][1]) == 'W') { if (obj->checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), fixedTextActionId)) { if (!talk._talkToAbort) printed = true; } } } bool doCAnim = true; for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) { char ch = toupper(action._names[nameIdx][1]); if (ch == 'T' || ch == 'B') { printed = true; if (pt.x != -1) // Holmes needs to walk to object before the action is done people[HOLMES].walkToCoords(pt, dir); if (!talk._talkToAbort) { // Ensure Holmes is on the exact intended location people[HOLMES]._position = pt; people[HOLMES]._sequenceNumber = dir; people[HOLMES].gotoStand(); talk.talkTo(action._names[nameIdx].c_str() + 2); if (ch == 'T') doCAnim = false; } } } } if (doCAnim && !talk._talkToAbort) { if (pt.x != -1) // Holmes needs to walk to object before the action is done people[HOLMES].walkToCoords(pt, dir); } for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) { if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2 && toupper(action._names[nameIdx][1]) == 'F') { if (obj->checkNameForCodes(action._names[nameIdx].c_str() + 2, fixedTextActionId)) { if (!talk._talkToAbort) printed = true; } } } if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99) scene.startCAnim(cAnimNum, action._cAnimSpeed); if (!talk._talkToAbort) { for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) { if (obj->checkNameForCodes(action._names[nameIdx], fixedTextActionId)) { if (!talk._talkToAbort) printed = true; } } // Unless we're leaving the scene, print a "Done" message unless the printed flag has been set if (IS_SERRATED_SCALPEL && scene._goToScene != 1 && !printed && !talk._talkToAbort) { _infoFlag = true; clearInfo(); screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Done..."); // Set how long to show the message _menuCounter = 30; } } } // Reset cursor back to arrow events.setCursor(ARROW); }