diff options
41 files changed, 2125 insertions, 1911 deletions
diff --git a/sword2/anims.cpp b/sword2/anims.cpp index eab9e654ec..e48d3c36e8 100644 --- a/sword2/anims.cpp +++ b/sword2/anims.cpp @@ -40,12 +40,15 @@ namespace Sword2 { -int Router::doAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graphic, int32 animRes, bool reverse) { +int Router::doAnimate(byte *ob_logic, byte *ob_graph, int32 animRes, bool reverse) { + AnimHeader anim_head; byte *anim_file; - AnimHeader *anim_head; - if (ob_logic->looping == 0) { - StandardHeader *head; + ObjectLogic obLogic(ob_logic); + ObjectGraphic obGraph(ob_graph); + + if (obLogic.getLooping() == 0) { + byte *ptr; // This is the start of the anim - set up the first frame @@ -55,32 +58,32 @@ int Router::doAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graphic, int32 an // 'testing_routines' object in George's Player Character // section of linc - if (Logic::_scriptVars[SYSTEM_TESTING_ANIMS]) { + if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { if (!_vm->_resman->checkValid(animRes)) { // Not a valid resource number. Switch off // the sprite. Don't animate - just continue // script next cycle. - setSpriteStatus(ob_graphic, NO_SPRITE); + setSpriteStatus(ob_graph, NO_SPRITE); return IR_STOP; } - head = (StandardHeader *)_vm->_resman->openResource(animRes); + ptr = _vm->_resman->openResource(animRes); // if it's not an animation file - if (head->fileType != ANIMATION_FILE) { + if (_vm->_resman->fetchType(animRes) != ANIMATION_FILE) { _vm->_resman->closeResource(animRes); // switch off the sprite // don't animate - just continue // script next cycle - setSpriteStatus(ob_graphic, NO_SPRITE); + setSpriteStatus(ob_graph, NO_SPRITE); return IR_STOP; } _vm->_resman->closeResource(animRes); // switch on the sprite - setSpriteStatus(ob_graphic, SORT_SPRITE); + setSpriteStatus(ob_graph, SORT_SPRITE); } assert(animRes); @@ -88,88 +91,94 @@ int Router::doAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graphic, int32 an // open anim file anim_file = _vm->_resman->openResource(animRes); - head = (StandardHeader *)anim_file; - assert(head->fileType == ANIMATION_FILE); + assert(_vm->_resman->fetchType(animRes) == ANIMATION_FILE); // point to anim header - anim_head = _vm->fetchAnimHeader(anim_file); + anim_head.read(_vm->fetchAnimHeader(anim_file)); // now running an anim, looping back to this call again - ob_logic->looping = 1; - ob_graphic->anim_resource = animRes; + obLogic.setLooping(1); + obGraph.setAnimResource(animRes); if (reverse) - ob_graphic->anim_pc = anim_head->noAnimFrames - 1; + obGraph.setAnimPc(anim_head.noAnimFrames - 1); else - ob_graphic->anim_pc = 0; + obGraph.setAnimPc(0); } else if (_vm->_logic->getSync() != -1) { // We've received a sync - return to script immediately - debug(5, "**sync stopped %d**", Logic::_scriptVars[ID]); + debug(5, "**sync stopped %d**", _vm->_logic->readVar(ID)); // If sync received, anim finishes right now (remaining on // last frame). Quit animation, but continue script. - ob_logic->looping = 0; + obLogic.setLooping(0); return IR_CONT; } else { // Not first frame, and no sync received - set up the next // frame of the anim. // open anim file and point to anim header - anim_file = _vm->_resman->openResource(ob_graphic->anim_resource); - anim_head = _vm->fetchAnimHeader(anim_file); + anim_file = _vm->_resman->openResource(obGraph.getAnimResource()); + anim_head.read(_vm->fetchAnimHeader(anim_file)); if (reverse) - ob_graphic->anim_pc--; + obGraph.setAnimPc(obGraph.getAnimPc() - 1); else - ob_graphic->anim_pc++; + obGraph.setAnimPc(obGraph.getAnimPc() + 1); } // check for end of anim if (reverse) { - if (ob_graphic->anim_pc == 0) - ob_logic->looping = 0; + if (obGraph.getAnimPc() == 0) + obLogic.setLooping(0); } else { - if (ob_graphic->anim_pc == anim_head->noAnimFrames - 1) - ob_logic->looping = 0; + if (obGraph.getAnimPc() == anim_head.noAnimFrames - 1) + obLogic.setLooping(0); } // close the anim file - _vm->_resman->closeResource(ob_graphic->anim_resource); + _vm->_resman->closeResource(obGraph.getAnimResource()); // check if we want the script to loop back & call this function again - return ob_logic->looping ? IR_REPEAT : IR_STOP; + return obLogic.getLooping() ? IR_REPEAT : IR_STOP; } -int Router::megaTableAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 *animTable, bool reverse) { +int Router::megaTableAnimate(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *animTable, bool reverse) { int32 animRes = 0; // If this is the start of the anim, read the anim table to get the // appropriate anim resource - if (ob_logic->looping == 0) { + ObjectLogic obLogic(ob_logic); + + if (obLogic.getLooping() == 0) { + ObjectMega obMega(ob_mega); + // Appropriate anim resource is in 'table[direction]' - animRes = animTable[ob_mega->current_dir]; + animRes = READ_LE_UINT32(animTable + 4 * obMega.getCurDir()); } return doAnimate(ob_logic, ob_graph, animRes, reverse); } -void Router::setSpriteStatus(ObjectGraphic *ob_graph, uint32 type) { +void Router::setSpriteStatus(byte *ob_graph, uint32 type) { + ObjectGraphic obGraph(ob_graph); + // Remove the previous status, but don't affect the shading upper-word - ob_graph->type = (ob_graph->type & 0xffff0000) | type; + obGraph.setType((obGraph.getType() & 0xffff0000) | type); } -void Router::setSpriteShading(ObjectGraphic *ob_graph, uint32 type) { +void Router::setSpriteShading(byte *ob_graph, uint32 type) { + ObjectGraphic obGraph(ob_graph); + // Remove the previous shading, but don't affect the status lower-word. // Note that mega frames may still be shaded automatically, even when // not sent 'RDSPR_SHADOW'. - ob_graph->type = (ob_graph->type & 0x0000ffff) | type; + obGraph.setType((obGraph.getType() & 0x0000ffff) | type); } void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) { uint32 line; - FrameHeader *frame; uint32 local_text; uint32 text_res; byte *text; @@ -192,7 +201,7 @@ void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) { // open text resource & get the line text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - wavId = (int32) READ_LE_UINT16(text); + wavId = (int32)READ_LE_UINT16(text); // now ok to close the text file _vm->_resman->closeResource(text_res); @@ -250,18 +259,19 @@ void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) { if (_sequenceTextList[line].text_mem) { // now fill out the SpriteInfo structure in the // MovieTextObjectStructure + FrameHeader frame; - frame = (FrameHeader *)_sequenceTextList[line].text_mem; + frame.read(_sequenceTextList[line].text_mem); sequenceText[line]->textSprite = new SpriteInfo; // center text at bottom of screen - sequenceText[line]->textSprite->x = 320 - frame->width / 2; - sequenceText[line]->textSprite->y = 440 - frame->height; - sequenceText[line]->textSprite->w = frame->width; - sequenceText[line]->textSprite->h = frame->height; + sequenceText[line]->textSprite->x = 320 - frame.width / 2; + sequenceText[line]->textSprite->y = 440 - frame.height; + sequenceText[line]->textSprite->w = frame.width; + sequenceText[line]->textSprite->h = frame.height; sequenceText[line]->textSprite->type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION; - sequenceText[line]->textSprite->data = _sequenceTextList[line].text_mem + sizeof(FrameHeader); + sequenceText[line]->textSprite->data = _sequenceTextList[line].text_mem + FrameHeader::size(); } // if we've loaded a speech sample for this line... diff --git a/sword2/build_display.cpp b/sword2/build_display.cpp index 9a81780e67..d483355df6 100644 --- a/sword2/build_display.cpp +++ b/sword2/build_display.cpp @@ -116,7 +116,10 @@ void Screen::buildDisplay() { startRenderCycle(); byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); - MultiScreenHeader *screenLayerTable = (MultiScreenHeader *)(file + sizeof(StandardHeader)); + + MultiScreenHeader screenLayerTable; + + screenLayerTable.read(file + ResHeader::size()); // Render at least one frame, but if the screen is scrolling, and if // there is time left, we will render extra frames to smooth out the @@ -124,13 +127,13 @@ void Screen::buildDisplay() { do { // first background parallax + related anims - if (screenLayerTable->bg_parallax[0]) { + if (screenLayerTable.bg_parallax[0]) { renderParallax(_vm->fetchBackgroundParallaxLayer(file, 0), 0); drawBackPar0Frames(); } // second background parallax + related anims - if (screenLayerTable->bg_parallax[1]) { + if (screenLayerTable.bg_parallax[1]) { renderParallax(_vm->fetchBackgroundParallaxLayer(file, 1), 1); drawBackPar1Frames(); } @@ -145,14 +148,14 @@ void Screen::buildDisplay() { // first foreground parallax + related anims - if (screenLayerTable->fg_parallax[0]) { + if (screenLayerTable.fg_parallax[0]) { renderParallax(_vm->fetchForegroundParallaxLayer(file, 0), 3); drawForePar0Frames(); } // second foreground parallax + related anims - if (screenLayerTable->fg_parallax[1]) { + if (screenLayerTable.fg_parallax[1]) { renderParallax(_vm->fetchForegroundParallaxLayer(file, 1), 4); drawForePar1Frames(); } @@ -199,23 +202,26 @@ void Screen::displayMsg(byte *text, int time) { clearScene(); byte *text_spr = _vm->_fontRenderer->makeTextSprite(text, 640, 187, _vm->_speechFontId); - FrameHeader *frame = (FrameHeader *)text_spr; + + FrameHeader frame; + + frame.read(text_spr); SpriteInfo spriteInfo; - spriteInfo.x = _screenWide / 2 - frame->width / 2; + spriteInfo.x = _screenWide / 2 - frame.width / 2; if (!time) - spriteInfo.y = _screenDeep / 2 - frame->height / 2 - MENUDEEP; + spriteInfo.y = _screenDeep / 2 - frame.height / 2 - MENUDEEP; else - spriteInfo.y = 400 - frame->height; - spriteInfo.w = frame->width; - spriteInfo.h = frame->height; + spriteInfo.y = 400 - frame.height; + spriteInfo.w = frame.width; + spriteInfo.h = frame.height; spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; spriteInfo.blend = 0; - spriteInfo.data = text_spr + sizeof(FrameHeader); + spriteInfo.data = text_spr + FrameHeader::size(); spriteInfo.colourTable = 0; uint32 rv = drawSprite(&spriteInfo); @@ -326,25 +332,27 @@ void Screen::drawForePar1Frames() { } void Screen::processLayer(byte *file, uint32 layer_number) { - LayerHeader *layer_head = _vm->fetchLayerHeader(file, layer_number); + LayerHeader layer_head; + + layer_head.read(_vm->fetchLayerHeader(file, layer_number)); SpriteInfo spriteInfo; - spriteInfo.x = layer_head->x; - spriteInfo.y = layer_head->y; - spriteInfo.w = layer_head->width; + spriteInfo.x = layer_head.x; + spriteInfo.y = layer_head.y; + spriteInfo.w = layer_head.width; spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; - spriteInfo.h = layer_head->height; + spriteInfo.h = layer_head.height; spriteInfo.type = RDSPR_TRANS | RDSPR_RLE256FAST; spriteInfo.blend = 0; - spriteInfo.data = file + sizeof(StandardHeader) + layer_head->offset; + spriteInfo.data = file + ResHeader::size() + layer_head.offset; spriteInfo.colourTable = 0; // check for largest layer for debug info - uint32 current_layer_area = layer_head->width * layer_head->height; + uint32 current_layer_area = layer_head.width * layer_head.height; if (current_layer_area > _largestLayerArea) { byte buf[NAME_LEN]; @@ -352,8 +360,8 @@ void Screen::processLayer(byte *file, uint32 layer_number) { _largestLayerArea = current_layer_area; sprintf(_largestLayerInfo, "largest layer: %s layer(%d) is %dx%d", - _vm->fetchObjectName(_thisScreen.background_layer_id, buf), - layer_number, layer_head->width, layer_head->height); + _vm->_resman->fetchName(_thisScreen.background_layer_id, buf), + layer_number, layer_head.width, layer_head.height); } uint32 rv = drawSprite(&spriteInfo); @@ -365,22 +373,28 @@ void Screen::processImage(BuildUnit *build_unit) { byte *file = _vm->_resman->openResource(build_unit->anim_resource); byte *colTablePtr = NULL; - AnimHeader *anim_head = _vm->fetchAnimHeader(file); - CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, build_unit->anim_pc); - FrameHeader *frame_head = _vm->fetchFrameHeader(file, build_unit->anim_pc); + byte *frame = _vm->fetchFrameHeader(file, build_unit->anim_pc); + + AnimHeader anim_head; + CdtEntry cdt_entry; + FrameHeader frame_head; + + anim_head.read(_vm->fetchAnimHeader(file)); + cdt_entry.read(_vm->fetchCdtEntry(file, build_unit->anim_pc)); + frame_head.read(frame); // so that 0-colour is transparent uint32 spriteType = RDSPR_TRANS; - if (anim_head->blend) + if (anim_head.blend) spriteType |= RDSPR_BLEND; // if the frame is to be flipped (only really applicable to frames // using offsets) - if (cdt_entry->frameType & FRAME_FLIPPED) + if (cdt_entry.frameType & FRAME_FLIPPED) spriteType |= RDSPR_FLIP; - if (cdt_entry->frameType & FRAME_256_FAST) { + if (cdt_entry.frameType & FRAME_256_FAST) { // scaling, shading & blending don't work with RLE256FAST // but the same compression can be decompressed using the // RLE256 routines! @@ -388,12 +402,12 @@ void Screen::processImage(BuildUnit *build_unit) { // NOTE: If this restriction refers to drawSprite(), I don't // think we have it any more. But I'm not sure. - if (build_unit->scale || anim_head->blend || build_unit->shadingFlag) + if (build_unit->scale || anim_head.blend || build_unit->shadingFlag) spriteType |= RDSPR_RLE256; else spriteType |= RDSPR_RLE256FAST; } else { - switch (anim_head->runTimeComp) { + switch (anim_head.runTimeComp) { case NONE: spriteType |= RDSPR_NOCOMPRESSION; break; @@ -404,7 +418,7 @@ void Screen::processImage(BuildUnit *build_unit) { spriteType |= RDSPR_RLE16; // points to just after last cdt_entry, ie. // start of colour table - colTablePtr = (byte *)(anim_head + 1) + anim_head->noAnimFrames * sizeof(CdtEntry); + colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() + anim_head.noAnimFrames * CdtEntry::size(); break; } } @@ -418,19 +432,19 @@ void Screen::processImage(BuildUnit *build_unit) { spriteInfo.x = build_unit->x; spriteInfo.y = build_unit->y; - spriteInfo.w = frame_head->width; - spriteInfo.h = frame_head->height; + spriteInfo.w = frame_head.width; + spriteInfo.h = frame_head.height; spriteInfo.scale = build_unit->scale; spriteInfo.scaledWidth = build_unit->scaled_width; spriteInfo.scaledHeight = build_unit->scaled_height; spriteInfo.type = spriteType; - spriteInfo.blend = anim_head->blend; + spriteInfo.blend = anim_head.blend; // points to just after frame header, ie. start of sprite data - spriteInfo.data = (byte *)(frame_head + 1); - spriteInfo.colourTable = colTablePtr; + spriteInfo.data = frame + FrameHeader::size(); + spriteInfo.colourTable = colTablePtr; // check for largest layer for debug info - uint32 current_sprite_area = frame_head->width * frame_head->height; + uint32 current_sprite_area = frame_head.width * frame_head.height; if (current_sprite_area > _largestSpriteArea) { byte buf[NAME_LEN]; @@ -438,13 +452,13 @@ void Screen::processImage(BuildUnit *build_unit) { _largestSpriteArea = current_sprite_area; sprintf(_largestSpriteInfo, "largest sprite: %s frame(%d) is %dx%d", - _vm->fetchObjectName(build_unit->anim_resource, buf), + _vm->_resman->fetchName(build_unit->anim_resource, buf), build_unit->anim_pc, - frame_head->width, - frame_head->height); + frame_head.width, + frame_head.height); } - if (Logic::_scriptVars[SYSTEM_TESTING_ANIMS]) { // see anims.cpp + if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { // see anims.cpp // bring the anim into the visible screen // but leave extra pixel at edge for box if (spriteInfo.x + spriteInfo.scaledWidth >= 639) @@ -472,7 +486,7 @@ void Screen::processImage(BuildUnit *build_unit) { error("Driver Error %.8x with sprite %s (%d) in processImage", rv, - _vm->fetchObjectName(build_unit->anim_resource, buf), + _vm->_resman->fetchName(build_unit->anim_resource, buf), build_unit->anim_resource); } @@ -501,32 +515,39 @@ void Screen::resetRenderLists() { } } -void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega, BuildUnit *build_unit) { - assert(ob_graph->anim_resource); +void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega, BuildUnit *build_unit) { + ObjectGraphic obGraph(ob_graph); + ObjectMega obMega(ob_mega); - byte *file = _vm->_resman->openResource(ob_graph->anim_resource); + assert(obGraph.getAnimResource()); - AnimHeader *anim_head = _vm->fetchAnimHeader(file); - CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, ob_graph->anim_pc); - FrameHeader *frame_head = _vm->fetchFrameHeader(file, ob_graph->anim_pc); + byte *file = _vm->_resman->openResource(obGraph.getAnimResource()); + + AnimHeader anim_head; + CdtEntry cdt_entry; + FrameHeader frame_head; + + anim_head.read(_vm->fetchAnimHeader(file)); + cdt_entry.read(_vm->fetchCdtEntry(file, obGraph.getAnimPc())); + frame_head.read(_vm->fetchFrameHeader(file, obGraph.getAnimPc())); // update player graphic details for on-screen debug info - if (Logic::_scriptVars[ID] == CUR_PLAYER_ID) { - _vm->_debugger->_playerGraphic.type = ob_graph->type; - _vm->_debugger->_playerGraphic.anim_resource = ob_graph->anim_resource; + if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) { + _vm->_debugger->_graphType = obGraph.getType(); + _vm->_debugger->_graphAnimRes = obGraph.getAnimResource(); // counting 1st frame as 'frame 1' - _vm->_debugger->_playerGraphic.anim_pc = ob_graph->anim_pc + 1; - _vm->_debugger->_playerGraphicNoFrames = anim_head->noAnimFrames; + _vm->_debugger->_graphAnimPc = obGraph.getAnimPc() + 1; + _vm->_debugger->_graphNoFrames = anim_head.noAnimFrames; } // fill in the BuildUnit structure for this frame - build_unit->anim_resource = ob_graph->anim_resource; - build_unit->anim_pc = ob_graph->anim_pc; + build_unit->anim_resource = obGraph.getAnimResource(); + build_unit->anim_pc = obGraph.getAnimPc(); build_unit->layer_number = 0; // Affected by shading mask? - if (ob_graph->type & SHADED_SPRITE) + if (obGraph.getType() & SHADED_SPRITE) build_unit->shadingFlag = true; else build_unit->shadingFlag = false; @@ -535,34 +556,28 @@ void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, Objec int scale = 0; - if (cdt_entry->frameType & FRAME_OFFSET) { - // Calc scale at which to print the sprite, based on feet - // y-coord & scaling constants (NB. 'scale' is actually - // 256 * true_scale, to maintain accuracy) - - // Ay+B gives 256 * scale ie. 256 * 256 * true_scale for even - // better accuracy, ie. scale = (Ay + B) / 256 - scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256; + if (cdt_entry.frameType & FRAME_OFFSET) { + scale = obMega.calcScale(); // calc final render coordinates (top-left of sprite), based // on feet coords & scaled offsets // add scaled offsets to feet coords - build_unit->x = ob_mega->feet_x + (cdt_entry->x * scale) / 256; - build_unit->y = ob_mega->feet_y + (cdt_entry->y * scale) / 256; + build_unit->x = obMega.getFeetX() + (cdt_entry.x * scale) / 256; + build_unit->y = obMega.getFeetY() + (cdt_entry.y * scale) / 256; // Work out new width and height. Always divide by 256 after // everything else, to maintain accurary - build_unit->scaled_width = ((scale * frame_head->width) / 256); - build_unit->scaled_height = ((scale * frame_head->height) / 256); + build_unit->scaled_width = ((scale * frame_head.width) / 256); + build_unit->scaled_height = ((scale * frame_head.height) / 256); } else { // It's a non-scaling anim. Get render coords for sprite, from cdt - build_unit->x = cdt_entry->x; - build_unit->y = cdt_entry->y; + build_unit->x = cdt_entry.x; + build_unit->y = cdt_entry.y; // Get width and height - build_unit->scaled_width = frame_head->width; - build_unit->scaled_height = frame_head->height; + build_unit->scaled_width = frame_head.width; + build_unit->scaled_height = frame_head.height; } // either 0 or required scale, depending on whether 'scale' computed @@ -577,12 +592,14 @@ void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, Objec } - _vm->_resman->closeResource(ob_graph->anim_resource); + _vm->_resman->closeResource(obGraph.getAnimResource()); } -void Screen::registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega) { +void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega) { + ObjectGraphic obGraph(ob_graph); + // check low word for sprite type - switch (ob_graph->type & 0x0000ffff) { + switch (obGraph.getType() & 0x0000ffff) { case BGP0_SPRITE: assert(_curBgp0 < MAX_bgp0_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp0List[_curBgp0]); @@ -861,7 +878,7 @@ void Screen::rollCredits() { // credits. Note that musicTimeRemaining() will return 0 if the music // is muted, so we need a sensible fallback for that case. - uint32 musicLength = MAX((int32) (1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32) scrollSteps); + uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); while (scrollPos < scrollSteps && !_vm->_quit) { bool foundStartLine = false; @@ -892,16 +909,18 @@ void Screen::rollCredits() { creditsLines[i].sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i].str, 600, 14, _vm->_speechFontId, 0); } - FrameHeader *frame = (FrameHeader *)creditsLines[i].sprite; + FrameHeader frame; + + frame.read(creditsLines[i].sprite); spriteInfo.y = creditsLines[i].top - scrollPos; - spriteInfo.w = frame->width; - spriteInfo.h = frame->height; - spriteInfo.data = creditsLines[i].sprite + sizeof(FrameHeader); + spriteInfo.w = frame.width; + spriteInfo.h = frame.height; + spriteInfo.data = creditsLines[i].sprite + FrameHeader::size(); switch (creditsLines[i].type) { case LINE_LEFT: - spriteInfo.x = RENDERWIDE / 2 - 5 - frame->width; + spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width; break; case LINE_RIGHT: spriteInfo.x = RENDERWIDE / 2 + 5; @@ -913,7 +932,7 @@ void Screen::rollCredits() { spriteInfo.w = logoWidth; spriteInfo.h = logoHeight; } else - spriteInfo.x = (RENDERWIDE - frame->width) / 2; + spriteInfo.x = (RENDERWIDE - frame.width) / 2; break; } @@ -978,7 +997,7 @@ void Screen::rollCredits() { if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing()) _vm->_mouse->setMouse(NORMAL_MOUSE_ID); - if (Logic::_scriptVars[DEAD]) + if (_vm->_logic->readVar(DEAD)) _vm->_mouse->buildSystemMenu(); } @@ -1001,32 +1020,38 @@ void Screen::splashScreen() { closeBackgroundLayer(); byte *loadingBar = _vm->_resman->openResource(2951); - AnimHeader *animHead = _vm->fetchAnimHeader(loadingBar); - FrameHeader *frame = _vm->fetchFrameHeader(loadingBar, 0); - CdtEntry *cdt = _vm->fetchCdtEntry(loadingBar, 0); + byte *frame = _vm->fetchFrameHeader(loadingBar, 0); + + AnimHeader animHead; + CdtEntry cdt; + FrameHeader frame_head; + + animHead.read(_vm->fetchAnimHeader(loadingBar)); + cdt.read(_vm->fetchCdtEntry(loadingBar, 0)); + frame_head.read(_vm->fetchFrameHeader(loadingBar, 0)); SpriteInfo barSprite; - barSprite.x = cdt->x; - barSprite.y = cdt->y; - barSprite.w = frame->width; - barSprite.h = frame->height; + barSprite.x = cdt.x; + barSprite.y = cdt.y; + barSprite.w = frame_head.width; + barSprite.h = frame_head.height; barSprite.scale = 0; barSprite.scaledWidth = 0; barSprite.scaledHeight = 0; barSprite.type = RDSPR_RLE256FAST | RDSPR_TRANS; barSprite.blend = 0; barSprite.colourTable = 0; - barSprite.data = (byte *)(frame + 1); + barSprite.data = frame + FrameHeader::size(); drawSprite(&barSprite); fadeUp(); waitForFade(); - for (int i = 0; i < animHead->noAnimFrames; i++) { + for (int i = 0; i < animHead.noAnimFrames; i++) { frame = _vm->fetchFrameHeader(loadingBar, i); - barSprite.data = (byte *)(frame + 1); + barSprite.data = frame + FrameHeader::size(); drawSprite(&barSprite); updateDisplay(); _vm->_system->delayMillis(30); diff --git a/sword2/build_display.h b/sword2/build_display.h index 403fb809e5..77562502bf 100644 --- a/sword2/build_display.h +++ b/sword2/build_display.h @@ -22,6 +22,7 @@ #define _BUILD_DISPLAY #include "common/rect.h" +#include "common/stream.h" #define MAX_bgp0_sprites 6 #define MAX_bgp1_sprites 6 @@ -53,10 +54,6 @@ namespace Sword2 { class Sword2Engine; -struct ObjectMouse; -struct ObjectGraphic; -struct ObjectMega; - // Sprite defines enum { @@ -176,19 +173,31 @@ struct BlockSurface { bool transparent; }; -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - struct Parallax { uint16 w; uint16 h; - uint32 offset[2]; // 2 is arbitrary -} GCC_PACK; -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif + // The dimensions are followed by an offset table, but we don't know in + // advance how big it is. See initializeBackgroundLayer(). + + static const int size() { + return 4; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + w = readS.readUint16LE(); + h = readS.readUint16LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint16LE(w); + writeS.writeUint16LE(h); + } +}; class Screen { private: @@ -310,13 +319,13 @@ private: char _largestLayerInfo[128]; char _largestSpriteInfo[128]; - void registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega, BuildUnit *build_unit); + void registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega, BuildUnit *build_unit); void mirrorSprite(byte *dst, byte *src, int16 w, int16 h); int32 decompressRLE256(byte *dst, byte *src, int32 decompSize); void unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable); int32 decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable); - void renderParallax(Parallax *p, int16 layer); + void renderParallax(byte *ptr, int16 layer); void markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1); @@ -370,13 +379,13 @@ public: void resetRenderLists(); void setLocationMetrics(uint16 w, uint16 h); - int32 initialiseBackgroundLayer(Parallax *p); + int32 initialiseBackgroundLayer(byte *parallax); void closeBackgroundLayer(); void initialiseRenderCycle(); void initBackground(int32 res, int32 new_palette); - void registerFrame(ObjectMouse *ob_mouse, ObjectGraphic *ob_graph, ObjectMega *ob_mega); + void registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega); void setScrollFraction(uint8 f) { _scrollFraction = f; } void setScrollTarget(int16 x, int16 y); diff --git a/sword2/console.cpp b/sword2/console.cpp index de489f3408..a8062fb4aa 100644 --- a/sword2/console.cpp +++ b/sword2/console.cpp @@ -69,7 +69,7 @@ Debugger::Debugger(Sword2Engine *vm) _textNumber = 0; // Current system text line number - _playerGraphicNoFrames = 0; // No. of frames in currently displayed + _graphNoFrames = 0; // No. of frames in currently displayed // anim // Register commands @@ -118,13 +118,13 @@ Debugger::Debugger(Sword2Engine *vm) } void Debugger::varGet(int var) { - DebugPrintf("%d\n", Logic::_scriptVars[var]); + DebugPrintf("%d\n", _vm->_logic->readVar(var)); } void Debugger::varSet(int var, int val) { - DebugPrintf("was %d, ", Logic::_scriptVars[var]); - Logic::_scriptVars[var] = val; - DebugPrintf("now %d\n", Logic::_scriptVars[var]); + DebugPrintf("was %d, ", _vm->_logic->readVar(var)); + _vm->_logic->writeVar(var, val); + DebugPrintf("now %d\n", _vm->_logic->readVar(var)); } void Debugger::preEnter() { @@ -210,10 +210,9 @@ bool Debugger::Cmd_Mem(int argc, const char **argv) { DebugPrintf("---------------------------------------------------------------------------\n"); for (i = 0; i < numBlocks; i++) { - StandardHeader *head = (StandardHeader *)blocks[i]->ptr; const char *type; - switch (head->fileType) { + switch (_vm->_resman->fetchType(blocks[i]->ptr)) { case ANIMATION_FILE: type = "ANIMATION_FILE"; break; @@ -258,7 +257,7 @@ bool Debugger::Cmd_Mem(int argc, const char **argv) { break; } - DebugPrintf("%9ld %-3d %-4d %-20s %s\n", blocks[i]->size, blocks[i]->id, blocks[i]->uid, type, head->name); + DebugPrintf("%9ld %-3d %-4d %-20s %s\n", blocks[i]->size, blocks[i]->id, blocks[i]->uid, type, _vm->_resman->fetchName(blocks[i]->ptr)); } free(blocks); @@ -321,8 +320,7 @@ bool Debugger::Cmd_ResList(int argc, const char **argv) { for (uint i = 0; i < numResFiles; i++) { if (resList[i].ptr && resList[i].refCount >= minCount) { - StandardHeader *head = (StandardHeader *)resList[i].ptr; - DebugPrintf("%-4d: %-35s refCount: %-3d\n", i, head->name, resList[i].refCount); + DebugPrintf("%-4d: %-35s refCount: %-3d\n", i, _vm->_resman->fetchName(resList[i].ptr), resList[i].refCount); } } @@ -369,7 +367,7 @@ bool Debugger::Cmd_Start(int argc, const char **argv) { int start = atoi(argv[1]); - if (start < 0 || start >= (int) numStarts) { + if (start < 0 || start >= (int)numStarts) { DebugPrintf("Not a legal start position\n"); return true; } @@ -434,7 +432,7 @@ bool Debugger::Cmd_ResLook(int argc, const char **argv) { int res = atoi(argv[1]); uint32 numResFiles = _vm->_resman->getNumResFiles(); - if (res < 0 || res >= (int) numResFiles) { + if (res < 0 || res >= (int)numResFiles) { DebugPrintf("Illegal resource %d. There are %d resources, 0-%d.\n", res, numResFiles, numResFiles - 1); return true; @@ -446,48 +444,50 @@ bool Debugger::Cmd_ResLook(int argc, const char **argv) { } // Open up the resource and take a look inside! - StandardHeader *file_header = (StandardHeader *)_vm->_resman->openResource(res); + uint8 type = _vm->_resman->fetchType(res);; + byte name[NAME_LEN]; - switch (file_header->fileType) { + _vm->_resman->fetchName(res, name); + + switch (type) { case ANIMATION_FILE: - DebugPrintf("<anim> %s\n", file_header->name); + DebugPrintf("<anim> %s\n", name); break; case SCREEN_FILE: - DebugPrintf("<layer> %s\n", file_header->name); + DebugPrintf("<layer> %s\n", name); break; case GAME_OBJECT: - DebugPrintf("<game object> %s\n", file_header->name); + DebugPrintf("<game object> %s\n", name); break; case WALK_GRID_FILE: - DebugPrintf("<walk grid> %s\n", file_header->name); + DebugPrintf("<walk grid> %s\n", name); break; case GLOBAL_VAR_FILE: - DebugPrintf("<global variables> %s\n", file_header->name); + DebugPrintf("<global variables> %s\n", name); break; case PARALLAX_FILE_null: - DebugPrintf("<parallax file NOT USED!> %s\n", file_header->name); + DebugPrintf("<parallax file NOT USED!> %s\n", name); break; case RUN_LIST: - DebugPrintf("<run list> %s\n", file_header->name); + DebugPrintf("<run list> %s\n", name); break; case TEXT_FILE: - DebugPrintf("<text file> %s\n", file_header->name); + DebugPrintf("<text file> %s\n", name); break; case SCREEN_MANAGER: - DebugPrintf("<screen manager> %s\n", file_header->name); + DebugPrintf("<screen manager> %s\n", name); break; case MOUSE_FILE: - DebugPrintf("<mouse pointer> %s\n", file_header->name); + DebugPrintf("<mouse pointer> %s\n", name); break; case ICON_FILE: - DebugPrintf("<menu icon> %s\n", file_header->name); + DebugPrintf("<menu icon> %s\n", name); break; default: - DebugPrintf("unrecognised fileType %d\n", file_header->fileType); + DebugPrintf("unrecognised fileType %d\n", type); break; } - _vm->_resman->closeResource(res); return true; } @@ -507,20 +507,23 @@ bool Debugger::Cmd_CurrentInfo(int argc, const char **argv) { } bool Debugger::Cmd_RunList(int argc, const char **argv) { - uint32 *game_object_list; - StandardHeader *file_header; - uint32 runList = _vm->_logic->getRunList(); if (runList) { - game_object_list = (uint32 *)(_vm->_resman->openResource(runList) + sizeof(StandardHeader)); + Common::MemoryReadStream readS(_vm->_resman->openResource(runList), _vm->_resman->fetchLen(runList)); + + readS.seek(ResHeader::size()); DebugPrintf("Runlist number %d\n", runList); - for (int i = 0; game_object_list[i]; i++) { - file_header = (StandardHeader *)_vm->_resman->openResource(game_object_list[i]); - DebugPrintf("%d %s\n", game_object_list[i], file_header->name); - _vm->_resman->closeResource(game_object_list[i]); + while (1) { + uint32 res = readS.readUint32LE(); + if (!res) + break; + + byte name[NAME_LEN]; + + DebugPrintf("%d %s\n", res, _vm->_resman->fetchName(res, name)); } _vm->_resman->closeResource(runList); @@ -539,7 +542,7 @@ bool Debugger::Cmd_Kill(int argc, const char **argv) { int res = atoi(argv[1]); uint32 numResFiles = _vm->_resman->getNumResFiles(); - if (res < 0 || res >= (int) numResFiles) { + if (res < 0 || res >= (int)numResFiles) { DebugPrintf("Illegal resource %d. There are %d resources, 0-%d.\n", res, numResFiles, numResFiles - 1); return true; @@ -797,8 +800,8 @@ bool Debugger::Cmd_Events(int argc, const char **argv) { uint32 target = eventList[i].id; uint32 script = eventList[i].interact_id; - DebugPrintf("slot %2d: id = %s (%d)\n", i, _vm->fetchObjectName(target, buf), target); - DebugPrintf(" script = %s (%d) pos %d\n", _vm->fetchObjectName(script / 65536, buf), script / 65536, script % 65536); + DebugPrintf("slot %2d: id = %s (%d)\n", i, _vm->_resman->fetchName(target, buf), target); + DebugPrintf(" script = %s (%d) pos %d\n", _vm->_resman->fetchName(script / 65536, buf), script / 65536, script % 65536); } } diff --git a/sword2/console.h b/sword2/console.h index 0a2cc4e725..660ab6cc5f 100644 --- a/sword2/console.h +++ b/sword2/console.h @@ -67,8 +67,10 @@ public: int32 _textNumber; - ObjectGraphic _playerGraphic; - uint32 _playerGraphicNoFrames; + int32 _graphType; + int32 _graphAnimRes; + int32 _graphAnimPc; + uint32 _graphNoFrames; void buildDebugText(); void drawDebugGraphics(); diff --git a/sword2/controls.cpp b/sword2/controls.cpp index 47edd52d09..6ff0c876b2 100644 --- a/sword2/controls.cpp +++ b/sword2/controls.cpp @@ -139,19 +139,23 @@ public: FontRendererGui::FontRendererGui(Sword2Engine *vm, int fontId) : _vm(vm), _fontId(fontId) { byte *font = _vm->_resman->openResource(fontId); - FrameHeader *head; SpriteInfo sprite; sprite.type = RDSPR_NOCOMPRESSION | RDSPR_TRANS; for (int i = 0; i < SIZE_OF_CHAR_SET; i++) { - head = (FrameHeader *)_vm->fetchFrameHeader(font, i); - sprite.data = (byte *)(head + 1); - sprite.w = head->width; - sprite.h = head->height; + byte *frame = _vm->fetchFrameHeader(font, i); + + FrameHeader frame_head; + + frame_head.read(frame); + + sprite.data = frame + FrameHeader::size(); + sprite.w = frame_head.width; + sprite.h = frame_head.height; _vm->_screen->createSurface(&sprite, &_glyph[i]._data); - _glyph[i]._width = head->width; - _glyph[i]._height = head->height; + _glyph[i]._width = frame_head.width; + _glyph[i]._height = frame_head.height; } _vm->_resman->closeResource(fontId); @@ -413,27 +417,29 @@ Widget::~Widget() { void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) { byte *file, *colTablePtr = NULL; - AnimHeader *anim_head; - FrameHeader *frame_head; - CdtEntry *cdt_entry; + AnimHeader anim_head; + FrameHeader frame_head; + CdtEntry cdt_entry; uint32 spriteType = RDSPR_TRANS; // open anim resource file, point to base file = _vm->_resman->openResource(res); - anim_head = _vm->fetchAnimHeader(file); - cdt_entry = _vm->fetchCdtEntry(file, pc); - frame_head = _vm->fetchFrameHeader(file, pc); + byte *frame = _vm->fetchFrameHeader(file, pc); + + anim_head.read(_vm->fetchAnimHeader(file)); + cdt_entry.read(_vm->fetchCdtEntry(file, pc)); + frame_head.read(frame); // If the frame is flipped. (Only really applicable to frames using // offsets.) - if (cdt_entry->frameType & FRAME_FLIPPED) + if (cdt_entry.frameType & FRAME_FLIPPED) spriteType |= RDSPR_FLIP; // Which compression was used? - switch (anim_head->runTimeComp) { + switch (anim_head.runTimeComp) { case NONE: spriteType |= RDSPR_NOCOMPRESSION; break; @@ -444,21 +450,21 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) spriteType |= RDSPR_RLE256; // Points to just after last cdt_entry, i.e. start of colour // table - colTablePtr = (byte *)(anim_head + 1) + - anim_head->noAnimFrames * sizeof(CdtEntry); + colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() + + anim_head.noAnimFrames * CdtEntry::size(); break; } _sprites[state].x = x; _sprites[state].y = y; - _sprites[state].w = frame_head->width; - _sprites[state].h = frame_head->height; + _sprites[state].w = frame_head.width; + _sprites[state].h = frame_head.height; _sprites[state].scale = 0; _sprites[state].type = spriteType; - _sprites[state].blend = anim_head->blend; + _sprites[state].blend = anim_head.blend; // Points to just after frame header, ie. start of sprite data - _sprites[state].data = (byte *)(frame_head + 1); + _sprites[state].data = frame + FrameHeader::size(); _vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); _surfaces[state]._original = true; @@ -661,7 +667,7 @@ private: } int valueFromPos(int x) { - return (int) ((double) (_maxValue * (x - _hitRect.left)) / (double) (_hitRect.width() - 38) + 0.5); + return (int)((double)(_maxValue * (x - _hitRect.left)) / (double)(_hitRect.width() - 38) + 0.5); } public: diff --git a/sword2/debug.cpp b/sword2/debug.cpp index 75afc49f04..c3e6d635de 100644 --- a/sword2/debug.cpp +++ b/sword2/debug.cpp @@ -85,7 +85,7 @@ void Debugger::buildDebugText() { // mouse area coords // defining a mouse area the easy way, by creating a box on-screen - if (_draggingRectangle || Logic::_scriptVars[SYSTEM_TESTING_ANIMS]) { + if (_draggingRectangle || _vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { // so we can see what's behind the lines _rectFlicker = !_rectFlicker; @@ -137,8 +137,8 @@ void Debugger::buildDebugText() { if (_displayTextNumbers) { if (_textNumber) { - if (Logic::_scriptVars[SYSTEM_TESTING_TEXT]) { - if (Logic::_scriptVars[SYSTEM_WANT_PREVIOUS_LINE]) + if (_vm->_logic->readVar(SYSTEM_TESTING_TEXT)) { + if (_vm->_logic->readVar(SYSTEM_WANT_PREVIOUS_LINE)) sprintf(buf, "backwards"); else sprintf(buf, "forwards"); @@ -159,8 +159,8 @@ void Debugger::buildDebugText() { // resource number currently being checking for animation - if (Logic::_scriptVars[SYSTEM_TESTING_ANIMS]) { - sprintf(buf, "trying resource %d", Logic::_scriptVars[SYSTEM_TESTING_ANIMS]); + if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { + sprintf(buf, "trying resource %d", _vm->_logic->readVar(SYSTEM_TESTING_ANIMS)); makeDebugTextBlock(buf, 0, 90); } @@ -177,16 +177,16 @@ void Debugger::buildDebugText() { // mouse coords & object pointed to - if (Logic::_scriptVars[CLICKED_ID]) + if (_vm->_logic->readVar(CLICKED_ID)) sprintf(buf, "last click at %d,%d (id %d: %s)", - Logic::_scriptVars[MOUSE_X], - Logic::_scriptVars[MOUSE_Y], - Logic::_scriptVars[CLICKED_ID], - _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], name)); + _vm->_logic->readVar(MOUSE_X), + _vm->_logic->readVar(MOUSE_Y), + _vm->_logic->readVar(CLICKED_ID), + _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), name)); else sprintf(buf, "last click at %d,%d (---)", - Logic::_scriptVars[MOUSE_X], - Logic::_scriptVars[MOUSE_Y]); + _vm->_logic->readVar(MOUSE_X), + _vm->_logic->readVar(MOUSE_Y)); makeDebugTextBlock(buf, 0, 15); @@ -201,7 +201,7 @@ void Debugger::buildDebugText() { mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y, mouseTouching, - _vm->fetchObjectName(mouseTouching, name)); + _vm->_resman->fetchName(mouseTouching, name)); else sprintf(buf, "mouse %d,%d (not touching)", mouseX + screenInfo->scroll_offset_x, @@ -212,19 +212,19 @@ void Debugger::buildDebugText() { // player coords & graphic info // if player objct has a graphic - if (_playerGraphic.anim_resource) + if (_graphAnimRes) sprintf(buf, "player %d,%d %s (%d) #%d/%d", screenInfo->player_feet_x, screenInfo->player_feet_y, - _vm->fetchObjectName(_playerGraphic.anim_resource, name), - _playerGraphic.anim_resource, - _playerGraphic.anim_pc, - _playerGraphicNoFrames); + _vm->_resman->fetchName(_graphAnimRes, name), + _graphAnimRes, + _graphAnimPc, + _graphNoFrames); else sprintf(buf, "player %d,%d --- %d", screenInfo->player_feet_x, screenInfo->player_feet_y, - _playerGraphic.anim_pc); + _graphAnimPc); makeDebugTextBlock(buf, 0, 45); @@ -235,12 +235,12 @@ void Debugger::buildDebugText() { // location number - sprintf(buf, "location=%d", Logic::_scriptVars[LOCATION]); + sprintf(buf, "location=%d", _vm->_logic->readVar(LOCATION)); makeDebugTextBlock(buf, 440, 15); // "result" variable - sprintf(buf, "result=%d", Logic::_scriptVars[RESULT]); + sprintf(buf, "result=%d", _vm->_logic->readVar(RESULT)); makeDebugTextBlock(buf, 440, 30); // no. of events in event list @@ -282,7 +282,7 @@ void Debugger::buildDebugText() { if (_speechScriptWaiting) { sprintf(buf, "script waiting for %s (%d)", - _vm->fetchObjectName(_speechScriptWaiting, name), + _vm->_resman->fetchName(_speechScriptWaiting, name), _speechScriptWaiting); makeDebugTextBlock(buf, 0, 90); } @@ -298,7 +298,7 @@ void Debugger::buildDebugText() { // anyway because it changes throughout the logic loop if (varNo) { - sprintf(buf, "var(%d) = %d", varNo, Logic::_scriptVars[varNo]); + sprintf(buf, "var(%d) = %d", varNo, _vm->_logic->readVar(varNo)); makeDebugTextBlock(buf, 530, showVarPos); showVarPos += 15; // next line down } @@ -345,7 +345,7 @@ void Debugger::drawDebugGraphics() { // mouse area rectangle / sprite box rectangle when testing anims - if (Logic::_scriptVars[SYSTEM_TESTING_ANIMS]) { + if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { // draw box around current frame drawRect(_rectX1, _rectY1, _rectX2, _rectY2, 184); } else if (_draggingRectangle) { diff --git a/sword2/driver/_mouse.cpp b/sword2/driver/_mouse.cpp index 9d153f0c56..80af551f5d 100644 --- a/sword2/driver/_mouse.cpp +++ b/sword2/driver/_mouse.cpp @@ -20,6 +20,7 @@ #include "common/stdafx.h" #include "common/system.h" +#include "common/stream.h" #include "sword2/sword2.h" #include "sword2/defs.h" @@ -33,12 +34,14 @@ namespace Sword2 { #define MOUSEFLASHFRAME 6 -void Mouse::decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff, int yOff) { +void Mouse::decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff, int yOff) { int32 size = width * height; int32 i = 0; int x = 0; int y = 0; + comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE; + while (i < size) { if (*comp > 183) { decomp[(y + yOff) * pitch + x + xOff] = *comp++; @@ -61,7 +64,7 @@ void Mouse::decompressMouse(byte *decomp, byte *comp, int width, int height, int void Mouse::drawMouse() { byte mouseData[MAX_MOUSE_W * MAX_MOUSE_H]; - if (!_mouseAnim && !_luggageAnim) + if (!_mouseAnim.data && !_luggageAnim.data) return; // When an object is used in the game, the mouse cursor should be a @@ -77,27 +80,27 @@ void Mouse::drawMouse() { int deltaX = 0; int deltaY = 0; - if (_mouseAnim) { - hotspot_x = _mouseAnim->xHotSpot; - hotspot_y = _mouseAnim->yHotSpot; - mouse_width = _mouseAnim->mousew; - mouse_height = _mouseAnim->mouseh; + if (_mouseAnim.data) { + hotspot_x = _mouseAnim.xHotSpot; + hotspot_y = _mouseAnim.yHotSpot; + mouse_width = _mouseAnim.mousew; + mouse_height = _mouseAnim.mouseh; } - if (_luggageAnim) { - if (!_mouseAnim) { - hotspot_x = _luggageAnim->xHotSpot; - hotspot_y = _luggageAnim->yHotSpot; + if (_luggageAnim.data) { + if (!_mouseAnim.data) { + hotspot_x = _luggageAnim.xHotSpot; + hotspot_y = _luggageAnim.yHotSpot; } - if (_luggageAnim->mousew > mouse_width) - mouse_width = _luggageAnim->mousew; - if (_luggageAnim->mouseh > mouse_height) - mouse_height = _luggageAnim->mouseh; + if (_luggageAnim.mousew > mouse_width) + mouse_width = _luggageAnim.mousew; + if (_luggageAnim.mouseh > mouse_height) + mouse_height = _luggageAnim.mouseh; } - if (_mouseAnim && _luggageAnim) { - deltaX = _mouseAnim->xHotSpot - _luggageAnim->xHotSpot; - deltaY = _mouseAnim->yHotSpot - _luggageAnim->yHotSpot; + if (_mouseAnim.data && _luggageAnim.data) { + deltaX = _mouseAnim.xHotSpot - _luggageAnim.xHotSpot; + deltaY = _mouseAnim.yHotSpot - _luggageAnim.yHotSpot; } assert(deltaX >= 0); @@ -114,19 +117,21 @@ void Mouse::drawMouse() { mouse_width += deltaX; mouse_height += deltaY; - if ((uint32) (mouse_width * mouse_height) > sizeof(mouseData)) { + if ((uint32)(mouse_width * mouse_height) > sizeof(mouseData)) { warning("Mouse cursor too large"); return; } memset(mouseData, 0, mouse_width * mouse_height); - if (_luggageAnim) - decompressMouse(mouseData, (byte *)_luggageAnim + READ_LE_UINT32(_luggageOffset), _luggageAnim->mousew, - _luggageAnim->mouseh, mouse_width, deltaX, deltaY); + if (_luggageAnim.data) + decompressMouse(mouseData, _luggageAnim.data, 0, + _luggageAnim.mousew, _luggageAnim.mouseh, + mouse_width, deltaX, deltaY); - if (_mouseAnim) - decompressMouse(mouseData, _mouseSprite, _mouseAnim->mousew, _mouseAnim->mouseh, mouse_width); + if (_mouseAnim.data) + decompressMouse(mouseData, _mouseAnim.data, _mouseFrame, + _mouseAnim.mousew, _mouseAnim.mouseh, mouse_width); _vm->_system->setMouseCursor(mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y, 0); } @@ -138,14 +143,12 @@ void Mouse::drawMouse() { int32 Mouse::animateMouse() { uint8 prevMouseFrame = _mouseFrame; - if (!_mouseAnim) + if (!_mouseAnim.data) return RDERR_UNKNOWN; - if (++_mouseFrame == _mouseAnim->noAnimFrames) + if (++_mouseFrame == _mouseAnim.noAnimFrames) _mouseFrame = MOUSEFLASHFRAME; - _mouseSprite = (byte *)_mouseAnim + READ_LE_UINT32(_mouseOffsets + _mouseFrame); - if (_mouseFrame != prevMouseFrame) drawMouse(); @@ -161,10 +164,8 @@ int32 Mouse::animateMouse() { */ int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { - if (_mouseAnim) { - free(_mouseAnim); - _mouseAnim = NULL; - } + free(_mouseAnim.data); + _mouseAnim.data = NULL; if (ma) { if (mouseFlash == RDMOUSE_FLASH) @@ -172,19 +173,27 @@ int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { else _mouseFrame = MOUSEFLASHFRAME; - _mouseAnim = (MouseAnim *)malloc(size); - if (!_mouseAnim) + Common::MemoryReadStream readS(ma, size); + + _mouseAnim.runTimeComp = readS.readByte(); + _mouseAnim.noAnimFrames = readS.readByte(); + _mouseAnim.xHotSpot = readS.readSByte(); + _mouseAnim.yHotSpot = readS.readSByte(); + _mouseAnim.mousew = readS.readByte(); + _mouseAnim.mouseh = readS.readByte(); + + _mouseAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); + if (!_mouseAnim.data) return RDERR_OUTOFMEMORY; - memcpy((byte *)_mouseAnim, ma, size); - _mouseOffsets = (int32 *)((byte *)_mouseAnim + sizeof(MouseAnim)); + readS.read(_mouseAnim.data, size - MOUSE_ANIM_HEADER_SIZE); animateMouse(); drawMouse(); _vm->_system->showMouse(true); } else { - if (_luggageAnim) + if (_luggageAnim.data) drawMouse(); else _vm->_system->showMouse(false); @@ -201,25 +210,31 @@ int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { */ int32 Mouse::setLuggageAnim(byte *ma, int32 size) { - if (_luggageAnim) { - free(_luggageAnim); - _luggageAnim = NULL; - } + free(_luggageAnim.data); + _luggageAnim.data = NULL; if (ma) { - _luggageAnim = (MouseAnim *)malloc(size); - if (!_luggageAnim) + Common::MemoryReadStream readS(ma, size); + + _luggageAnim.runTimeComp = readS.readByte(); + _luggageAnim.noAnimFrames = readS.readByte(); + _luggageAnim.xHotSpot = readS.readSByte(); + _luggageAnim.yHotSpot = readS.readSByte(); + _luggageAnim.mousew = readS.readByte(); + _luggageAnim.mouseh = readS.readByte(); + + _luggageAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); + if (!_luggageAnim.data) return RDERR_OUTOFMEMORY; - memcpy((byte *)_luggageAnim, ma, size); - _luggageOffset = (int32 *)((byte *)_luggageAnim + sizeof(MouseAnim)); + readS.read(_luggageAnim.data, size - MOUSE_ANIM_HEADER_SIZE); animateMouse(); drawMouse(); _vm->_system->showMouse(true); } else { - if (_mouseAnim) + if (_mouseAnim.data) drawMouse(); else _vm->_system->showMouse(false); diff --git a/sword2/driver/animation.cpp b/sword2/driver/animation.cpp index 41987dd2d4..071a88ac1a 100644 --- a/sword2/driver/animation.cpp +++ b/sword2/driver/animation.cpp @@ -176,12 +176,11 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], int32 lea if (leadInRes) { byte *leadIn = _vm->_resman->openResource(leadInRes); - uint32 leadInLen = _vm->_resman->fetchLen(leadInRes) - sizeof(StandardHeader); - StandardHeader *header = (StandardHeader *)leadIn; + uint32 leadInLen = _vm->_resman->fetchLen(leadInRes) - ResHeader::size(); - assert(header->fileType == WAV_FILE); + assert(_vm->_resman->fetchType(leadIn) == WAV_FILE); - leadIn += sizeof(StandardHeader); + leadIn += ResHeader::size(); _vm->_sound->playFx(&leadInHandle, leadIn, leadInLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType); } @@ -191,15 +190,14 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], int32 lea if (leadOutRes) { leadOut = _vm->_resman->openResource(leadOutRes); - leadOutLen = _vm->_resman->fetchLen(leadOutRes) - sizeof(StandardHeader); - StandardHeader *header = (StandardHeader *)leadOut; + leadOutLen = _vm->_resman->fetchLen(leadOutRes) - ResHeader::size(); - assert(header->fileType == WAV_FILE); + assert(_vm->_resman->fetchType(leadOut) == WAV_FILE); - leadOut += sizeof(StandardHeader); + leadOut += ResHeader::size(); } - _leadOutFrame = (uint) -1; + _leadOutFrame = (uint)-1; int i; @@ -420,16 +418,18 @@ void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId); } - FrameHeader *frame = (FrameHeader *)data; + FrameHeader frame_head; SpriteInfo msgSprite; byte *msgSurface; - msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame->width / 2; - msgSprite.y = MENUDEEP / 2 - frame->height / 2; - msgSprite.w = frame->width; - msgSprite.h = frame->height; + frame_head.read(data); + + msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame_head.width / 2; + msgSprite.y = MENUDEEP / 2 - frame_head.height / 2; + msgSprite.w = frame_head.width; + msgSprite.h = frame_head.height; msgSprite.type = RDSPR_NOCOMPRESSION; - msgSprite.data = data + sizeof(FrameHeader); + msgSprite.data = data + FrameHeader::size(); _vm->_screen->createSurface(&msgSprite, &msgSurface); _vm->_screen->drawSurface(&msgSprite, msgSurface); diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp index ed12eaaaf9..8f3426c220 100644 --- a/sword2/driver/d_sound.cpp +++ b/sword2/driver/d_sound.cpp @@ -177,7 +177,7 @@ CLUInputStream::~CLUInputStream() { int CLUInputStream::readBuffer(int16 *buffer, const int numSamples) { int samples = 0; while (samples < numSamples && !eosIntern()) { - const int len = MIN(numSamples - samples, (int) (_bufferEnd - _pos)); + const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); memcpy(buffer, _pos, len * 2); buffer += len; _pos += len; @@ -195,7 +195,7 @@ void CLUInputStream::refill() { _file->seek(_file_pos, SEEK_SET); - uint len_left = _file->read(in, MIN((uint32) BUFFER_SIZE, _end_pos - _file->pos())); + uint len_left = _file->read(in, MIN((uint32)BUFFER_SIZE, _end_pos - _file->pos())); _file_pos = _file->pos(); @@ -270,7 +270,7 @@ int MusicInputStream::readBuffer(int16 *buffer, const int numSamples) { int samples = 0; while (samples < numSamples && !eosIntern()) { - const int len = MIN(numSamples - samples, (int) (_bufferEnd - _pos)); + const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); memcpy(buffer, _pos, len * 2); buffer += len; _pos += len; @@ -290,7 +290,7 @@ void MusicInputStream::refill() { len_left = BUFFER_SIZE; - if (_fading > 0 && (uint32) _fading < len_left) + if (_fading > 0 && (uint32)_fading < len_left) len_left = _fading; if (_samplesLeft < len_left) diff --git a/sword2/driver/palette.cpp b/sword2/driver/palette.cpp index 731c9449c0..2dd4f79343 100644 --- a/sword2/driver/palette.cpp +++ b/sword2/driver/palette.cpp @@ -60,7 +60,7 @@ void Screen::setFullPalette(int32 palRes) { // is apparently needed for the palette to be restored properly when // you turn the light off. (I didn't even notice the light switch!) - if (Logic::_scriptVars[LOCATION] == 13) { + if (_vm->_logic->readVar(LOCATION) == 13) { // unpausing if (palRes == -1) { // restore whatever palette was last set (screen @@ -88,10 +88,9 @@ void Screen::setFullPalette(int32 palRes) { if (palRes) { byte *pal = _vm->_resman->openResource(palRes); - StandardHeader *head = (StandardHeader *)pal; - assert(head->fileType == PALETTE_FILE); + assert(_vm->_resman->fetchType(pal) == PALETTE_FILE); - pal += sizeof(StandardHeader); + pal += ResHeader::size(); // always set colour 0 to black because most background screen // palettes have a bright colour 0 although it should come out @@ -130,7 +129,7 @@ void Screen::setFullPalette(int32 palRes) { // linker complained when I tried to use it in sprite.cpp. uint8 Screen::quickMatch(uint8 r, uint8 g, uint8 b) { - return _paletteMatch[((int32) (r >> 2) << 12) + ((int32) (g >> 2) << 6) + (b >> 2)]; + return _paletteMatch[((int32)(r >> 2) << 12) + ((int32)(g >> 2) << 6) + (b >> 2)]; } /** @@ -174,7 +173,7 @@ int32 Screen::fadeUp(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; - _fadeTotalTime = (int32) (time * 1000); + _fadeTotalTime = (int32)(time * 1000); _fadeStatus = RDFADE_UP; _fadeStartTime = _vm->_system->getMillis(); @@ -190,7 +189,7 @@ int32 Screen::fadeDown(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; - _fadeTotalTime = (int32) (time * 1000); + _fadeTotalTime = (int32)(time * 1000); _fadeStatus = RDFADE_DOWN; _fadeStartTime = _vm->_system->getMillis(); @@ -239,7 +238,7 @@ void Screen::fadeServer() { _fadeStatus = RDFADE_NONE; newPalette = _palette; } else { - fadeMultiplier = (int16) (((int32) (currentTime - _fadeStartTime) * 256) / _fadeTotalTime); + fadeMultiplier = (int16)(((int32)(currentTime - _fadeStartTime) * 256) / _fadeTotalTime); for (i = 0; i < 256; i++) { newPalette[i * 4 + 0] = (_palette[i * 4 + 0] * fadeMultiplier) >> 8; newPalette[i * 4 + 1] = (_palette[i * 4 + 1] * fadeMultiplier) >> 8; @@ -251,7 +250,7 @@ void Screen::fadeServer() { _fadeStatus = RDFADE_BLACK; memset(newPalette, 0, sizeof(fadePalette)); } else { - fadeMultiplier = (int16) (((int32) (_fadeTotalTime - (currentTime - _fadeStartTime)) * 256) / _fadeTotalTime); + fadeMultiplier = (int16)(((int32)(_fadeTotalTime - (currentTime - _fadeStartTime)) * 256) / _fadeTotalTime); for (i = 0; i < 256; i++) { newPalette[i * 4 + 0] = (_palette[i * 4 + 0] * fadeMultiplier) >> 8; newPalette[i * 4 + 1] = (_palette[i * 4 + 1] * fadeMultiplier) >> 8; diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp index 5da110fc40..ae91a5346e 100644 --- a/sword2/driver/render.cpp +++ b/sword2/driver/render.cpp @@ -248,19 +248,22 @@ void Screen::setLocationMetrics(uint16 w, uint16 h) { * parallax can be either foreground, background or the main screen. */ -void Screen::renderParallax(Parallax *p, int16 l) { +void Screen::renderParallax(byte *ptr, int16 l) { + Parallax p; int16 x, y; Common::Rect r; + p.read(ptr); + if (_locationWide == _screenWide) x = 0; else - x = ((int32) ((p->w - _screenWide) * _scrollX) / (int32) (_locationWide - _screenWide)); + x = ((int32)((p.w - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide)); if (_locationDeep == _screenDeep - MENUDEEP * 2) y = 0; else - y = ((int32) ((p->h - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32) (_locationDeep - (_screenDeep - MENUDEEP * 2))); + y = ((int32)((p.h - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2))); Common::Rect clipRect; @@ -315,8 +318,8 @@ void Screen::startRenderCycle() { _scrollY = _scrollYTarget; _renderTooSlow = true; } else { - _scrollX = (int16) (_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16) (_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); + _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); + _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); _renderTooSlow = false; } @@ -377,8 +380,8 @@ bool Screen::endRenderCycle() { _scrollX = _scrollXTarget; _scrollY = _scrollYTarget; } else { - _scrollX = (int16) (_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16) (_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); + _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); + _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); } if (_scrollX != _scrollXOld || _scrollY != _scrollYOld) @@ -410,7 +413,8 @@ void Screen::resetRenderEngine() { * or a NULL pointer in order of background parallax to foreground parallax. */ -int32 Screen::initialiseBackgroundLayer(Parallax *p) { +int32 Screen::initialiseBackgroundLayer(byte *parallax) { + Parallax p; uint16 i, j, k; byte *data; byte *dst; @@ -419,13 +423,15 @@ int32 Screen::initialiseBackgroundLayer(Parallax *p) { assert(_layer < MAXLAYERS); - if (!p) { + if (!parallax) { _layer++; return RD_OK; } - _xBlocks[_layer] = (p->w + BLOCKWIDTH - 1) / BLOCKWIDTH; - _yBlocks[_layer] = (p->h + BLOCKHEIGHT - 1) / BLOCKHEIGHT; + p.read(parallax); + + _xBlocks[_layer] = (p.w + BLOCKWIDTH - 1) / BLOCKWIDTH; + _yBlocks[_layer] = (p.h + BLOCKHEIGHT - 1) / BLOCKHEIGHT; _blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *)); if (!_blockSurfaces[_layer]) @@ -437,19 +443,21 @@ int32 Screen::initialiseBackgroundLayer(Parallax *p) { if (!memchunk) return RDERR_OUTOFMEMORY; - for (i = 0; i < p->h; i++) { - if (!p->offset[i]) + for (i = 0; i < p.h; i++) { + uint32 p_offset = READ_LE_UINT32(parallax + Parallax::size() + 4 * i); + + if (!p_offset) continue; - byte *pLine = (byte *)p + FROM_LE_32(p->offset[i]); + byte *pLine = parallax + p_offset; uint16 packets = READ_LE_UINT16(pLine); uint16 offset = READ_LE_UINT16(pLine + 2); data = pLine + 4; - dst = memchunk + i * p->w + offset; + dst = memchunk + i * p.w + offset; if (!packets) { - memcpy(dst, data, p->w); + memcpy(dst, data, p.w); continue; } @@ -487,12 +495,12 @@ int32 Screen::initialiseBackgroundLayer(Parallax *p) { int x = BLOCKWIDTH * (i % _xBlocks[_layer]); int y = BLOCKHEIGHT * (i / _xBlocks[_layer]); - data = memchunk + p->w * y + x; + data = memchunk + p.w * y + x; for (j = 0; j < BLOCKHEIGHT; j++) { for (k = 0; k < BLOCKWIDTH; k++) { - if (x + k < p->w && y + j < p->h) { - if (data[j * p->w + k]) + if (x + k < p.w && y + j < p.h) { + if (data[j * p.w + k]) block_has_data = true; else block_is_transparent = true; @@ -509,7 +517,7 @@ int32 Screen::initialiseBackgroundLayer(Parallax *p) { dst = _blockSurfaces[_layer][i]->data; for (j = 0; j < BLOCKHEIGHT; j++) { memcpy(dst, data, BLOCKWIDTH); - data += p->w; + data += p.w; dst += BLOCKWIDTH; } diff --git a/sword2/events.cpp b/sword2/events.cpp index 41b61b0fb8..289c60b5cc 100644 --- a/sword2/events.cpp +++ b/sword2/events.cpp @@ -44,7 +44,7 @@ void Logic::setPlayerActionEvent(uint32 id, uint32 interact_id) { int Logic::checkEventWaiting() { for (int i = 0; i < MAX_events; i++) { - if (_eventList[i].id == _scriptVars[ID]) + if (_eventList[i].id == readVar(ID)) return 1; } @@ -56,14 +56,14 @@ void Logic::startEvent() { // you must follow with a return IR_TERMINATE for (int i = 0; i < MAX_events; i++) { - if (_eventList[i].id == _scriptVars[ID]) { + if (_eventList[i].id == readVar(ID)) { logicOne(_eventList[i].interact_id); _eventList[i].id = 0; return; } } - error("startEvent() can't find event for id %d", _scriptVars[ID]); + error("startEvent() can't find event for id %d", readVar(ID)); } void Logic::clearEvent(uint32 id) { diff --git a/sword2/function.cpp b/sword2/function.cpp index d7c2e545f7..9f015f3bac 100644 --- a/sword2/function.cpp +++ b/sword2/function.cpp @@ -19,8 +19,8 @@ */ #include "common/stdafx.h" -#include "common/file.h" #include "common/system.h" +#include "common/file.h" #include "sword2/sword2.h" #include "sword2/defs.h" @@ -81,19 +81,19 @@ int32 Logic::fnSetSession(int32 *params) { int32 Logic::fnBackSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), BACK_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), BACK_SPRITE); return IR_CONT; } int32 Logic::fnSortSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), SORT_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), SORT_SPRITE); return IR_CONT; } int32 Logic::fnForeSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), FORE_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), FORE_SPRITE); return IR_CONT; } @@ -106,7 +106,7 @@ int32 Logic::fnRegisterMouse(int32 *params) { // params: 0 pointer to ObjectMouse or 0 for no write to mouse // list - _vm->_mouse->registerMouse((ObjectMouse *)decodePtr(params[0]), NULL); + _vm->_mouse->registerMouse(decodePtr(params[0]), NULL); return IR_CONT; } @@ -117,8 +117,8 @@ int32 Logic::fnAnim(int32 *params) { // Normal forward animation return _router->doAnimate( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), + decodePtr(params[0]), + decodePtr(params[1]), params[2], false); } @@ -126,7 +126,7 @@ int32 Logic::fnRandom(int32 *params) { // params: 0 min // 1 max - _scriptVars[RESULT] = _vm->_rnd.getRandomNumberRng(params[0], params[1]); + writeVar(RESULT, _vm->_rnd.getRandomNumberRng(params[0], params[1])); return IR_CONT; } @@ -157,7 +157,7 @@ int32 Logic::fnInteract(int32 *params) { // params: 0 id of target from which we derive action script // reference - _scriptVars[PLAYER_ACTION] = 0; // must clear this + writeVar(PLAYER_ACTION, 0); // must clear this logicUp((params[0] << 16) | 2); // 3rd script of clicked on id // Out, up and around again - pc is saved for current level to be @@ -177,7 +177,7 @@ int32 Logic::fnChoose(int32 *params) { uint32 response = _vm->_mouse->chooseMouse(); - if (response == (uint32) -1) + if (response == (uint32)-1) return IR_REPEAT; return IR_CONT | (response << 3); @@ -198,10 +198,10 @@ int32 Logic::fnWalk(int32 *params) { // 6 target direction (8 means end walk on ANY direction) return _router->doWalk( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4], params[5], params[6]); } @@ -217,10 +217,10 @@ int32 Logic::fnWalkToAnim(int32 *params) { // 4 anim resource id return _router->walkToAnim( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4]); } @@ -236,10 +236,10 @@ int32 Logic::fnTurn(int32 *params) { // 4 target direction return _router->doFace( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4]); } @@ -257,8 +257,8 @@ int32 Logic::fnStandAt(int32 *params) { // 4 target direction _router->standAt( - (ObjectGraphic *)decodePtr(params[0]), - (ObjectMega *)decodePtr(params[1]), + decodePtr(params[0]), + decodePtr(params[1]), params[2], params[3], params[4]); return IR_CONT; } @@ -272,11 +272,13 @@ int32 Logic::fnStand(int32 *params) { // params: 0 pointer to object's graphic structure // 1 pointer to object's mega structure // 2 target direction - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[1]); + byte *ob_mega = decodePtr(params[1]); + + ObjectMega obMega(ob_mega); _router->standAt( - (ObjectGraphic *)decodePtr(params[0]), - ob_mega, ob_mega->feet_x, ob_mega->feet_y, params[2]); + decodePtr(params[0]), + ob_mega, obMega.getFeetX(), obMega.getFeetY(), params[2]); return IR_CONT; } @@ -290,8 +292,8 @@ int32 Logic::fnStandAfterAnim(int32 *params) { // 2 anim resource id _router->standAfterAnim( - (ObjectGraphic *)decodePtr(params[0]), - (ObjectMega *)decodePtr(params[1]), + decodePtr(params[0]), + decodePtr(params[1]), params[2]); return IR_CONT; } @@ -303,19 +305,19 @@ int32 Logic::fnPause(int32 *params) { // NB. Pause-value of 0 causes script to continue, 1 causes a 1-cycle // quit, 2 gives 2 cycles, etc. - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[0]); + ObjectLogic obLogic(decodePtr(params[0])); - if (ob_logic->looping == 0) { - ob_logic->looping = 1; - ob_logic->pause = params[1]; + if (obLogic.getLooping() == 0) { + obLogic.setLooping(1); + obLogic.setPause(params[1]); } - if (ob_logic->pause) { - ob_logic->pause--; + if (obLogic.getPause()) { + obLogic.setPause(obLogic.getPause() - 1); return IR_REPEAT; } - ob_logic->looping = 0; + obLogic.setLooping(0); return IR_CONT; } @@ -327,17 +329,17 @@ int32 Logic::fnMegaTableAnim(int32 *params) { // Normal forward anim return _router->megaTableAnimate( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (uint32 *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), false); } int32 Logic::fnAddMenuObject(int32 *params) { // params: 0 pointer to a MenuObject structure to copy down - _vm->_mouse->addMenuObject((MenuObject *)decodePtr(params[0])); + _vm->_mouse->addMenuObject(decodePtr(params[0])); return IR_CONT; } @@ -379,20 +381,21 @@ int32 Logic::fnSetFrame(int32 *params) { // open the resource (& check it's valid) byte *anim_file = _vm->_resman->openResource(res); - StandardHeader *head = (StandardHeader *)anim_file; - assert(head->fileType == ANIMATION_FILE); + assert(_vm->_resman->fetchType(res) == ANIMATION_FILE); // set up pointer to the animation header - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + AnimHeader anim_head; + + anim_head.read(_vm->fetchAnimHeader(anim_file)); // set up anim resource in graphic object - ObjectGraphic *ob_graphic = (ObjectGraphic *)decodePtr(params[0]); + ObjectGraphic obGraph(decodePtr(params[0])); - ob_graphic->anim_resource = res; - ob_graphic->anim_pc = params[2] ? anim_head->noAnimFrames - 1 : 0; + obGraph.setAnimResource(res); + obGraph.setAnimPc(params[2] ? anim_head.noAnimFrames - 1 : 0); // Close the anim file and drop out of script - _vm->_resman->closeResource(ob_graphic->anim_resource); + _vm->_resman->closeResource(obGraph.getAnimResource()); return IR_CONT; } @@ -401,14 +404,14 @@ int32 Logic::fnRandomPause(int32 *params) { // 1 minimum number of game-cycles to pause // 2 maximum number of game-cycles to pause - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[0]); + ObjectLogic obLogic(decodePtr(params[0])); int32 pars[2]; - if (ob_logic->looping == 0) { + if (obLogic.getLooping() == 0) { pars[0] = params[1]; pars[1] = params[2]; fnRandom(pars); - pars[1] = _scriptVars[RESULT]; + pars[1] = readVar(RESULT); } pars[0] = params[0]; @@ -424,17 +427,16 @@ int32 Logic::fnRegisterFrame(int32 *params) { // 1 pointer to graphic structure // 2 pointer to mega structure or NULL if not a mega - ObjectMouse *ob_mouse = (ObjectMouse *)decodePtr(params[0]); - ObjectGraphic *ob_graph = (ObjectGraphic *)decodePtr(params[1]); - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[2]); - - _vm->_screen->registerFrame(ob_mouse, ob_graph, ob_mega); + _vm->_screen->registerFrame( + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2])); return IR_CONT; } int32 Logic::fnNoSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), NO_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), NO_SPRITE); return IR_CONT; } @@ -444,7 +446,7 @@ int32 Logic::fnSendSync(int32 *params) { for (int i = 0; i < MAX_syncs; i++) { if (_syncList[i].id == 0) { - debug(5, "%d sends sync %d to %d", _scriptVars[ID], params[1], params[0]); + debug(5, "%d sends sync %d to %d", readVar(ID), params[1], params[0]); _syncList[i].id = params[0]; _syncList[i].sync = params[1]; return IR_CONT; @@ -463,19 +465,21 @@ int32 Logic::fnUpdatePlayerStats(int32 *params) { // params: 0 pointer to mega structure - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[0]); + ObjectMega obMega(decodePtr(params[0])); + ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - screenInfo->player_feet_x = ob_mega->feet_x; - screenInfo->player_feet_y = ob_mega->feet_y; + screenInfo->player_feet_x = obMega.getFeetX(); + screenInfo->player_feet_y = obMega.getFeetY(); // for the script - _scriptVars[PLAYER_FEET_X] = ob_mega->feet_x; - _scriptVars[PLAYER_FEET_Y] = ob_mega->feet_y; - _scriptVars[PLAYER_CUR_DIR] = ob_mega->current_dir; - _scriptVars[SCROLL_OFFSET_X] = screenInfo->scroll_offset_x; + writeVar(PLAYER_FEET_X, obMega.getFeetX()); + writeVar(PLAYER_FEET_Y, obMega.getFeetY()); + writeVar(PLAYER_CUR_DIR, obMega.getCurDir()); + writeVar(SCROLL_OFFSET_X, screenInfo->scroll_offset_x); - debug(5, "fnUpdatePlayerStats: %d %d", ob_mega->feet_x, ob_mega->feet_y); + debug(5, "fnUpdatePlayerStats: %d %d", + obMega.getFeetX(), obMega.getFeetY()); return IR_CONT; } @@ -496,31 +500,34 @@ int32 Logic::fnPassGraph(int32 *params) { int32 Logic::fnInitFloorMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *)decodePtr(params[0]); + byte *ob_mouse = decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // floor is always lowest priority - ob_mouse->x1 = 0; - ob_mouse->y1 = 0; - ob_mouse->x2 = screenInfo->screen_wide - 1; - ob_mouse->y2 = screenInfo->screen_deep - 1; - ob_mouse->priority = 9; - ob_mouse->pointer = NORMAL_MOUSE_ID; + ObjectMouse mouse; + + mouse.x1 = 0; + mouse.y1 = 0; + mouse.x2 = screenInfo->screen_wide - 1; + mouse.y2 = screenInfo->screen_deep - 1; + mouse.priority = 9; + mouse.pointer = NORMAL_MOUSE_ID; + + mouse.write(ob_mouse); return IR_CONT; } int32 Logic::fnPassMega(int32 *params) { - // makes an engine local copy of passed graphic_structure and - // mega_structure - run script 4 of an object to request this - // used by fnTurnTo(id) etc + // makes an engine local copy of passed mega_structure - run script 4 + // of an object to request this used by fnTurnTo(id) etc // // remember, we cannot simply read a compact any longer but instead // must request it from the object itself // params: 0 pointer to a mega structure - memcpy(&_engineMega, decodePtr(params[0]), sizeof(ObjectMega)); + memcpy(_engineMega, decodePtr(params[0]), ObjectMega::size()); return IR_CONT; } @@ -537,10 +544,10 @@ int32 Logic::fnFaceXY(int32 *params) { // 5 target y-coord return _router->faceXY( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4], params[5]); } @@ -582,22 +589,14 @@ int32 Logic::fnAddHuman(int32 *params) { int32 Logic::fnWeWait(int32 *params) { // params: 0 target - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(params[0]); - assert(head->fileType == GAME_OBJECT); + assert(_vm->_resman->fetchType(params[0]) == GAME_OBJECT); // Run the target's get-speech-state script + runResScript(params[0], 5); - int32 target = params[0]; - char *raw_script_ad = (char *)head; - uint32 null_pc = 5; - - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(target); - - if (_scriptVars[RESULT] == 0) { + if (readVar(RESULT) == 0) { // The target is busy. Try again. - _vm->_debugger->_speechScriptWaiting = target; + _vm->_debugger->_speechScriptWaiting = params[0]; return IR_REPEAT; } @@ -622,60 +621,52 @@ int32 Logic::fnTheyDoWeWait(int32 *params) { // 6 ins4 // 7 ins5 - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(params[1]); - assert(head->fileType == GAME_OBJECT); + assert(_vm->_resman->fetchType(params[1]) == GAME_OBJECT); // Run the target's get-speech-state script + runResScript(params[1], 5); - int32 target = params[1]; - char *raw_script_ad = (char *)head; - uint32 null_pc = 5; + ObjectLogic obLogic(decodePtr(params[0])); - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(target); - - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[0]); - - if (_scriptVars[RESULT] == 1 && !_scriptVars[INS_COMMAND] && ob_logic->looping == 0) { + if (readVar(RESULT) == 1 && readVar(INS_COMMAND) == 0 && obLogic.getLooping() == 0) { // The target is waiting, i.e. not busy, and there is no other // command queued. We haven't sent the command yet, so do it. - debug(5, "fnTheyDoWeWait: sending command to %d", target); + debug(5, "fnTheyDoWeWait: sending command to %d", params[1]); - _vm->_debugger->_speechScriptWaiting = target; - ob_logic->looping = 1; + _vm->_debugger->_speechScriptWaiting = params[1]; + obLogic.setLooping(1); - _scriptVars[SPEECH_ID] = params[1]; - _scriptVars[INS_COMMAND] = params[2]; - _scriptVars[INS1] = params[3]; - _scriptVars[INS2] = params[4]; - _scriptVars[INS3] = params[5]; - _scriptVars[INS4] = params[6]; - _scriptVars[INS5] = params[7]; + writeVar(SPEECH_ID, params[1]); + writeVar(INS_COMMAND, params[2]); + writeVar(INS1, params[3]); + writeVar(INS2, params[4]); + writeVar(INS3, params[5]); + writeVar(INS4, params[6]); + writeVar(INS5, params[7]); return IR_REPEAT; } - if (ob_logic->looping == 0) { + if (obLogic.getLooping() == 0) { // The command has not been sent yet. Keep waiting. - _vm->_debugger->_speechScriptWaiting = target; + _vm->_debugger->_speechScriptWaiting = params[1]; return IR_REPEAT; } - if (_scriptVars[RESULT] == 0) { + if (readVar(RESULT) == 0) { // The command has been sent, and the target is busy doing it. // Wait for it to finish. - debug(5, "fnTheyDoWeWait: Waiting for %d to finish", target); + debug(5, "fnTheyDoWeWait: Waiting for %d to finish", params[1]); - _vm->_debugger->_speechScriptWaiting = target; + _vm->_debugger->_speechScriptWaiting = params[1]; return IR_REPEAT; } - debug(5, "fnTheyDoWeWait: %d finished", target); + debug(5, "fnTheyDoWeWait: %d finished", params[1]); - ob_logic->looping = 0; + obLogic.setLooping(0); _vm->_debugger->_speechScriptWaiting = 0; return IR_CONT; } @@ -694,41 +685,33 @@ int32 Logic::fnTheyDo(int32 *params) { // 5 ins4 // 6 ins5 - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(params[0]); - assert(head->fileType == GAME_OBJECT); + assert(_vm->_resman->fetchType(params[0]) == GAME_OBJECT); // Run the target's get-speech-state script + runResScript(params[0], 5); - int32 target = params[0]; - char *raw_script_ad = (char *)head; - uint32 null_pc = 5; - - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(target); - - if (_scriptVars[RESULT] == 1 && !_scriptVars[INS_COMMAND]) { + if (readVar(RESULT) == 1 && !readVar(INS_COMMAND)) { // The target is waiting, i.e. not busy, and there is no other // command queued. Send the command. - debug(5, "fnTheyDo: sending command to %d", target); + debug(5, "fnTheyDo: sending command to %d", params[0]); _vm->_debugger->_speechScriptWaiting = 0; - _scriptVars[SPEECH_ID] = params[0]; - _scriptVars[INS_COMMAND] = params[1]; - _scriptVars[INS1] = params[2]; - _scriptVars[INS2] = params[3]; - _scriptVars[INS3] = params[4]; - _scriptVars[INS4] = params[5]; - _scriptVars[INS5] = params[6]; + writeVar(SPEECH_ID, params[0]); + writeVar(INS_COMMAND, params[1]); + writeVar(INS1, params[2]); + writeVar(INS2, params[3]); + writeVar(INS3, params[4]); + writeVar(INS4, params[5]); + writeVar(INS5, params[6]); return IR_CONT; } // The target is busy. Come back again next cycle. - _vm->_debugger->_speechScriptWaiting = target; + _vm->_debugger->_speechScriptWaiting = params[0]; return IR_REPEAT; } @@ -745,10 +728,10 @@ int32 Logic::fnWalkToTalkToMega(int32 *params) { // 5 separation return _router->walkToTalkToMega( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4], params[5]); } @@ -801,13 +784,13 @@ int32 Logic::fnISpeak(int32 *params) { // Set up the pointers which we know we'll always need - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[S_OB_LOGIC]); - ObjectGraphic *ob_graphic = (ObjectGraphic *)decodePtr(params[S_OB_GRAPHIC]); + ObjectLogic obLogic(decodePtr(params[S_OB_LOGIC])); + ObjectGraphic obGraph(decodePtr(params[S_OB_GRAPHIC])); // FIRST TIME ONLY: create the text, load the wav, set up the anim, // etc. - if (!ob_logic->looping) { + if (obLogic.getLooping() == 0) { // New fudge to wait for smacker samples to finish // since they can over-run into the game @@ -850,32 +833,30 @@ int32 Logic::fnISpeak(int32 *params) { // See 'testing_routines' object in George's Player Character // section of linc - if (_scriptVars[SYSTEM_TESTING_TEXT]) { + if (readVar(SYSTEM_TESTING_TEXT)) { if (!_vm->_resman->checkValid(text_res)) { // Not a valid resource number - invalid (null // resource) - _scriptVars[RESULT] = 1; + writeVar(RESULT, 1); return IR_CONT; } - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(text_res); - - if (head->fileType != TEXT_FILE) { + if (_vm->_resman->fetchType(text_res) != TEXT_FILE) { // Invalid - not a text resource _vm->_resman->closeResource(text_res); - _scriptVars[RESULT] = 1; + writeVar(RESULT, 1); return IR_CONT; } - if (!_vm->checkTextLine((byte *)head, local_text)) { + if (!_vm->checkTextLine(_vm->_resman->openResource(text_res), local_text)) { // Line number out of range _vm->_resman->closeResource(text_res); - _scriptVars[RESULT] = 2; + writeVar(RESULT, 2); return IR_CONT; } _vm->_resman->closeResource(text_res); - _scriptVars[RESULT] = 0; + writeVar(RESULT, 0); } byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); @@ -885,11 +866,11 @@ int32 Logic::fnISpeak(int32 *params) { // Prevent dud lines from appearing while testing text & speech // since these will not occur in the game anyway - if (_scriptVars[SYSTEM_TESTING_TEXT]) { + if (readVar(SYSTEM_TESTING_TEXT)) { // If actor number is 0 and text line is just a 'dash' // character if (_officialTextNumber == 0 && text[2] == '-' && text[3] == 0) { - _scriptVars[RESULT] = 3; + writeVar(RESULT, 3); return IR_CONT; } } @@ -898,16 +879,16 @@ int32 Logic::fnISpeak(int32 *params) { // left-click past the text after half a second, and // right-click past it after a quarter of a second. - ob_logic->looping = 1; + obLogic.setLooping(1); _leftClickDelay = 6; _rightClickDelay = 3; - if (_scriptVars[PLAYER_ID] != CUR_PLAYER_ID) + if (readVar(PLAYER_ID) != CUR_PLAYER_ID) debug(5, "(%d) Nico: %s", _officialTextNumber, text + 2); else { byte buf[NAME_LEN]; - debug(5, "(%d) %s: %s", _officialTextNumber, _vm->fetchObjectName(_scriptVars[ID], buf), text + 2); + debug(5, "(%d) %s: %s", _officialTextNumber, _vm->_resman->fetchName(readVar(ID), buf), text + 2); } // Set up the speech animation @@ -919,10 +900,10 @@ int32 Logic::fnISpeak(int32 *params) { // Use this direction table to derive the anim // NB. ASSUMES WE HAVE A MEGA OBJECT!! - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[S_OB_MEGA]); - int32 *anim_table = (int32 *)decodePtr(params[S_DIR_TABLE]); + ObjectMega obMega(decodePtr(params[S_OB_MEGA])); + byte *anim_table = decodePtr(params[S_DIR_TABLE]); - _animId = anim_table[ob_mega->current_dir]; + _animId = READ_LE_UINT32(anim_table + 4 * obMega.getCurDir()); } else { // No animation choosen _animId = 0; @@ -932,13 +913,13 @@ int32 Logic::fnISpeak(int32 *params) { // Set the talker's graphic to the first frame of this // speech anim for now. - _speechAnimType = _scriptVars[SPEECHANIMFLAG]; - ob_graphic->anim_resource = _animId; - ob_graphic->anim_pc = 0; + _speechAnimType = readVar(SPEECHANIMFLAG); + obGraph.setAnimResource(_animId); + obGraph.setAnimPc(0); } // Default back to looped lip synced anims. - _scriptVars[SPEECHANIMFLAG] = 0; + writeVar(SPEECHANIMFLAG, 0); // Set up _textX and _textY for speech panning and/or text // sprite position. @@ -959,7 +940,7 @@ int32 Logic::fnISpeak(int32 *params) { // from the 1st 2 chars of the text line. if (!params[S_WAV]) - params[S_WAV] = (int32) _officialTextNumber; + params[S_WAV] = (int32)_officialTextNumber; // Panning goes from -16 (left) to 16 (right) int8 speech_pan = ((_textX - 320) * 16) / 320; @@ -996,32 +977,34 @@ int32 Logic::fnISpeak(int32 *params) { if (_animId) { // There is an animation - Increment the anim frame number. - ob_graphic->anim_pc++; + obGraph.setAnimPc(obGraph.getAnimPc() + 1); + + byte *anim_file = _vm->_resman->openResource(obGraph.getAnimResource()); + AnimHeader anim_head; - byte *anim_file = _vm->_resman->openResource(ob_graphic->anim_resource); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + anim_head.read(_vm->fetchAnimHeader(anim_file)); if (!_speechAnimType) { // ANIM IS TO BE LIP-SYNC'ED & REPEATING - if (ob_graphic->anim_pc == (int32) (anim_head->noAnimFrames)) { + if (obGraph.getAnimPc() == (int32)anim_head.noAnimFrames) { // End of animation - restart from frame 0 - ob_graphic->anim_pc = 0; + obGraph.setAnimPc(0); } else if (speechRunning && _vm->_sound->amISpeaking() == RDSE_QUIET) { // The speech is running, but we're at a quiet // bit. Restart from frame 0 (closed mouth). - ob_graphic->anim_pc = 0; + obGraph.setAnimPc(0); } } else { // ANIM IS TO PLAY ONCE ONLY - if (ob_graphic->anim_pc == (int32) (anim_head->noAnimFrames) - 1) { + if (obGraph.getAnimPc() == (int32)anim_head.noAnimFrames - 1) { // Reached the last frame of the anim. Hold // anim on this last frame _animId = 0; } } - _vm->_resman->closeResource(ob_graphic->anim_resource); + _vm->_resman->closeResource(obGraph.getAnimResource()); } else if (_speechAnimType) { // Placed here so we actually display the last frame of the // anim. @@ -1061,7 +1044,7 @@ int32 Logic::fnISpeak(int32 *params) { // So that we can go to the options panel while text & speech is // being tested - if (_scriptVars[SYSTEM_TESTING_TEXT] == 0 || mouseY > 0) { + if (readVar(SYSTEM_TESTING_TEXT) == 0 || mouseY > 0) { MouseEvent *me = _vm->mouseEvent(); // Note that we now have TWO click-delays - one for LEFT @@ -1073,14 +1056,14 @@ int32 Logic::fnISpeak(int32 *params) { // the speech. // if testing text & speech - if (_scriptVars[SYSTEM_TESTING_TEXT]) { + if (readVar(SYSTEM_TESTING_TEXT)) { // and RB used to click past text if (me->buttons & RD_RIGHTBUTTONDOWN) { // then we want the previous line again - _scriptVars[SYSTEM_WANT_PREVIOUS_LINE] = 1; + writeVar(SYSTEM_WANT_PREVIOUS_LINE, 1); } else { // LB just want next line again - _scriptVars[SYSTEM_WANT_PREVIOUS_LINE] = 0; + writeVar(SYSTEM_WANT_PREVIOUS_LINE, 0); } } @@ -1107,13 +1090,13 @@ int32 Logic::fnISpeak(int32 *params) { // if there is a speech anim, end it on closed mouth frame if (_animId) { _animId = 0; - ob_graphic->anim_pc = 0; + obGraph.setAnimPc(0); } speechRunning = false; // no longer in a script function loop - ob_logic->looping = 0; + obLogic.setLooping(0); _vm->_debugger->_textNumber = 0; @@ -1121,7 +1104,7 @@ int32 Logic::fnISpeak(int32 *params) { // this number comes from the text line) _officialTextNumber = 0; - _scriptVars[RESULT] = 0; + writeVar(RESULT, 0); return IR_CONT; } @@ -1141,16 +1124,15 @@ int32 Logic::fnISpeak(int32 *params) { * Reset the object and restart script 1 on level 0 */ -#define LEVEL (_curObjectHub->logic_level) - int32 Logic::fnTotalRestart(int32 *params) { // mega runs this to restart its base logic again - like being cached // in again // params: none - LEVEL = 0; - _curObjectHub->script_pc[0] = 1; + _curObjectHub.setLogicLevel(0); + _curObjectHub.setScriptPc(0, 1); + return IR_TERMINATE; } @@ -1194,7 +1176,7 @@ int32 Logic::fnSpeechProcess(int32 *params) { // 3 pointer to ob_mega // 4 pointer to ob_walkdata - ObjectSpeech *ob_speech = (ObjectSpeech *)decodePtr(params[1]); + ObjectSpeech obSpeech(decodePtr(params[1])); while (1) { int32 pars[9]; @@ -1209,7 +1191,7 @@ int32 Logic::fnSpeechProcess(int32 *params) { // Note: I can't see that we ever check the value of wait_state // but perhaps it accesses that memory location directly? - switch (ob_speech->command) { + switch (obSpeech.getCommand()) { case 0: break; case INS_talk: @@ -1217,15 +1199,15 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[1] = params[1]; // ob_speech pars[2] = params[2]; // ob_logic pars[3] = params[3]; // ob_mega - pars[4] = ob_speech->ins1; // encoded text number - pars[5] = ob_speech->ins2; // wav res id - pars[6] = ob_speech->ins3; // anim res id - pars[7] = ob_speech->ins4; // anim table res id - pars[8] = ob_speech->ins5; // animation mode - 0 lip synced, 1 just straight animation + pars[4] = obSpeech.getIns1(); // encoded text number + pars[5] = obSpeech.getIns2(); // wav res id + pars[6] = obSpeech.getIns3(); // anim res id + pars[7] = obSpeech.getIns4(); // anim table res id + pars[8] = obSpeech.getIns5(); // animation mode - 0 lip synced, 1 just straight animation if (fnISpeak(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; @@ -1234,11 +1216,11 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega pars[3] = params[4]; // ob_walkdata - pars[4] = ob_speech->ins1; // direction to turn to + pars[4] = obSpeech.getIns1(); // direction to turn to if (fnTurn(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; @@ -1247,33 +1229,33 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega pars[3] = params[4]; // ob_walkdata - pars[4] = ob_speech->ins1; // target + pars[4] = obSpeech.getIns1(); // target if (fnFaceMega(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; case INS_anim: pars[0] = params[2]; // ob_logic pars[1] = params[0]; // ob_graphic - pars[2] = ob_speech->ins1; // anim res + pars[2] = obSpeech.getIns1(); // anim res if (fnAnim(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; case INS_reverse_anim: pars[0] = params[2]; // ob_logic pars[1] = params[0]; // ob_graphic - pars[2] = ob_speech->ins1; // anim res + pars[2] = obSpeech.getIns1(); // anim res if (fnReverseAnim(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; @@ -1281,11 +1263,11 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[0] = params[2]; // ob_logic pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega - pars[3] = ob_speech->ins1; // pointer to anim table + pars[3] = obSpeech.getIns1(); // pointer to anim table if (fnMegaTableAnim(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; @@ -1293,50 +1275,50 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[0] = params[2]; // ob_logic pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega - pars[3] = ob_speech->ins1; // pointer to anim table + pars[3] = obSpeech.getIns1(); // pointer to anim table if (fnReverseMegaTableAnim(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; case INS_no_sprite: fnNoSprite(params); // ob_graphic - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT ; case INS_sort: fnSortSprite(params); // ob_graphic - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT; case INS_foreground: fnForeSprite(params); // ob_graphic - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT; case INS_background: fnBackSprite(params); // ob_graphic - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT; case INS_walk: pars[0] = params[2]; // ob_logic pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega pars[3] = params[4]; // ob_walkdata - pars[4] = ob_speech->ins1; // target x - pars[5] = ob_speech->ins2; // target y - pars[6] = ob_speech->ins3; // target direction + pars[4] = obSpeech.getIns1(); // target x + pars[5] = obSpeech.getIns2(); // target y + pars[6] = obSpeech.getIns3(); // target direction if (fnWalk(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; @@ -1345,69 +1327,69 @@ int32 Logic::fnSpeechProcess(int32 *params) { pars[1] = params[0]; // ob_graphic pars[2] = params[3]; // ob_mega pars[3] = params[4]; // ob_walkdata - pars[4] = ob_speech->ins1; // anim resource + pars[4] = obSpeech.getIns1(); // anim resource if (fnWalkToAnim(pars) != IR_REPEAT) { - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); } return IR_REPEAT; case INS_stand_after_anim: pars[0] = params[0]; // ob_graphic pars[1] = params[3]; // ob_mega - pars[2] = ob_speech->ins1; // anim resource + pars[2] = obSpeech.getIns1(); // anim resource fnStandAfterAnim(pars); - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT; case INS_set_frame: pars[0] = params[0]; // ob_graphic - pars[1] = ob_speech->ins1; // anim_resource - pars[2] = ob_speech->ins2; // FIRST_FRAME or LAST_FRAME + pars[1] = obSpeech.getIns1(); // anim_resource + pars[2] = obSpeech.getIns2(); // FIRST_FRAME or LAST_FRAME fnSetFrame(pars); - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); return IR_REPEAT; case INS_quit: // That's it - we're finished with this - ob_speech->command = 0; - // ob_speech->wait_state = 0; + obSpeech.setCommand(0); + // obSpeech.setWaitState(0); return IR_CONT; default: // Unimplemented command - just cancel - ob_speech->command = 0; - ob_speech->wait_state = 1; + obSpeech.setCommand(0); + obSpeech.setWaitState(1); break; } - if (_scriptVars[SPEECH_ID] == _scriptVars[ID]) { + if (readVar(SPEECH_ID) == readVar(ID)) { // There's a new command for us! Grab the command - // potentially we only have this cycle to do this - and // set things up so that the command will be picked up // on the next iteration of the while loop. - debug(5, "fnSpeechProcess: Received new command %d", _scriptVars[INS_COMMAND]); + debug(5, "fnSpeechProcess: Received new command %d", readVar(INS_COMMAND)); - _scriptVars[SPEECH_ID] = 0; + writeVar(SPEECH_ID, 0); - ob_speech->command = _scriptVars[INS_COMMAND]; - ob_speech->ins1 = _scriptVars[INS1]; - ob_speech->ins2 = _scriptVars[INS2]; - ob_speech->ins3 = _scriptVars[INS3]; - ob_speech->ins4 = _scriptVars[INS4]; - ob_speech->ins5 = _scriptVars[INS5]; - ob_speech->wait_state = 0; + obSpeech.setCommand(readVar(INS_COMMAND)); + obSpeech.setIns1(readVar(INS1)); + obSpeech.setIns2(readVar(INS2)); + obSpeech.setIns3(readVar(INS3)); + obSpeech.setIns4(readVar(INS4)); + obSpeech.setIns5(readVar(INS5)); + obSpeech.setWaitState(0); - _scriptVars[INS_COMMAND] = 0; + writeVar(INS_COMMAND, 0); } else { // No new command. We could run a blink anim (or // something) here. - ob_speech->wait_state = 1; + obSpeech.setWaitState(1); return IR_REPEAT; } } @@ -1423,10 +1405,10 @@ int32 Logic::fnSetScaling(int32 *params) { // Where s is system scale, which itself is (256 * actual_scale) ie. // s == 128 is half size - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[0]); + ObjectMega obMega(decodePtr(params[0])); - ob_mega->scale_a = params[1]; - ob_mega->scale_b = params[2]; + obMega.setScaleA(params[1]); + obMega.setScaleB(params[2]); return IR_CONT; } @@ -1441,7 +1423,7 @@ int32 Logic::fnStartEvent(int32 *params) { int32 Logic::fnCheckEventWaiting(int32 *params) { // params: none - _scriptVars[RESULT] = checkEventWaiting(); + writeVar(RESULT, checkEventWaiting()); return IR_CONT; } @@ -1480,55 +1462,47 @@ int32 Logic::fnTimedWait(int32 *params) { // 1 target // 2 number of cycles before give up - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(params[1]); - assert(head->fileType == GAME_OBJECT); + assert(_vm->_resman->fetchType(params[1]) == GAME_OBJECT); - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[0]); + ObjectLogic obLogic(decodePtr(params[0])); - if (!ob_logic->looping) { + if (obLogic.getLooping() == 0) { // This is the first time, so set up the time-out. - ob_logic->looping = params[2]; + obLogic.setLooping(params[2]); } // Run the target's get-speech-state script + runResScript(params[1], 5); - int32 target = params[1]; - char *raw_script_ad = (char *)head; - uint32 null_pc = 5; - - runScript(raw_script_ad, raw_script_ad, &null_pc); - - _vm->_resman->closeResource(target); - - if (_scriptVars[RESULT] == 1) { + if (readVar(RESULT) == 1) { // The target is waiting, i.e. not busy _vm->_debugger->_speechScriptWaiting = 0; - ob_logic->looping = 0; - _scriptVars[RESULT] = 0; + obLogic.setLooping(0); + writeVar(RESULT, 0); return IR_CONT; } - ob_logic->looping--; + obLogic.setLooping(obLogic.getLooping() - 1); - if (!ob_logic->looping) { + if (obLogic.getLooping() == 0) { // Time's up. - debug(5, "fnTimedWait: Timed out waiting for %d", target); + debug(5, "fnTimedWait: Timed out waiting for %d", params[1]); _vm->_debugger->_speechScriptWaiting = 0; // Clear the event that hasn't been picked up - in theory, // none of this should ever happen. - killAllIdsEvents(target); - _scriptVars[RESULT] = 1; + killAllIdsEvents(params[1]); + writeVar(RESULT, 1); return IR_CONT; } // Target is busy. Keep trying. - _vm->_debugger->_speechScriptWaiting = target; + _vm->_debugger->_speechScriptWaiting = params[1]; return IR_REPEAT; } @@ -1605,9 +1579,9 @@ int32 Logic::fnSetValue(int32 *params) { // params: 0 pointer to object's mega structure // 1 value to set it to - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[0]); + ObjectMega obMega(decodePtr(params[0])); - ob_mega->megaset_res = params[1]; + obMega.setMegasetRes(params[1]); return IR_CONT; } @@ -1617,7 +1591,7 @@ int32 Logic::fnNewScript(int32 *params) { // params: 0 id of script - _scriptVars[PLAYER_ACTION] = 0; // must clear this + writeVar(PLAYER_ACTION, 0); // must clear this logicReplace(params[0]); return IR_TERMINATE; } @@ -1632,7 +1606,7 @@ int32 Logic::fnGetSync(int32 *params) { int slot = getSync(); - _scriptVars[RESULT] = (slot != -1) ? _syncList[slot].sync : 0; + writeVar(RESULT, (slot != -1) ? _syncList[slot].sync : 0); return IR_CONT; } @@ -1644,15 +1618,15 @@ int32 Logic::fnGetSync(int32 *params) { int32 Logic::fnWaitSync(int32 *params) { // params: none - debug(6, "fnWaitSync: %d waits", _scriptVars[ID]); + debug(6, "fnWaitSync: %d waits", readVar(ID)); int slot = getSync(); if (slot == -1) return IR_REPEAT; - debug(5, "fnWaitSync: %d got sync %d", _scriptVars[ID], _syncList[slot].sync); - _scriptVars[RESULT] = _syncList[slot].sync; + debug(5, "fnWaitSync: %d got sync %d", readVar(ID), _syncList[slot].sync); + writeVar(RESULT, _syncList[slot].sync); return IR_CONT; } @@ -1671,10 +1645,10 @@ int32 Logic::fnReverseMegaTableAnim(int32 *params) { // Reverse anim return _router->megaTableAnimate( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (uint32 *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), true); } @@ -1685,8 +1659,8 @@ int32 Logic::fnReverseAnim(int32 *params) { // Reverse anim return _router->doAnimate( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), + decodePtr(params[0]), + decodePtr(params[1]), params[2], true); } @@ -1702,21 +1676,22 @@ int32 Logic::fnReverseAnim(int32 *params) { int32 Logic::fnAddToKillList(int32 *params) { // params: none + uint32 id = readVar(ID); // DON'T EVER KILL GEORGE! - if (_scriptVars[ID] == CUR_PLAYER_ID) + if (id == CUR_PLAYER_ID) return IR_CONT; // Scan the list to see if it's already included for (uint32 i = 0; i < _kills; i++) { - if (_objectKillList[i] == _scriptVars[ID]) + if (_objectKillList[i] == id) return IR_CONT; } assert(_kills < OBJECT_KILL_LIST_SIZE); // no room at the inn - _objectKillList[_kills++] = _scriptVars[ID]; + _objectKillList[_kills++] = id; // "another one bites the dust" @@ -1745,25 +1720,25 @@ int32 Logic::fnSetStandbyCoords(int32 *params) { int32 Logic::fnBackPar0Sprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), BGP0_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), BGP0_SPRITE); return IR_CONT; } int32 Logic::fnBackPar1Sprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), BGP1_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), BGP1_SPRITE); return IR_CONT; } int32 Logic::fnForePar0Sprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), FGP0_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), FGP0_SPRITE); return IR_CONT; } int32 Logic::fnForePar1Sprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteStatus((ObjectGraphic *)decodePtr(params[0]), FGP1_SPRITE); + _router->setSpriteStatus(decodePtr(params[0]), FGP1_SPRITE); return IR_CONT; } @@ -1816,8 +1791,8 @@ int32 Logic::fnStandAtAnim(int32 *params) { // 2 anim resource id _router->standAtAnim( - (ObjectGraphic *)decodePtr(params[0]), - (ObjectMega *)decodePtr(params[1]), + decodePtr(params[0]), + decodePtr(params[1]), params[2]); return IR_CONT; } @@ -1827,50 +1802,56 @@ int32 Logic::fnStandAtAnim(int32 *params) { int32 Logic::fnSetScrollLeftMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *)decodePtr(params[0]); + byte *ob_mouse = decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority - ob_mouse->x1 = 0; - ob_mouse->y1 = 0; - ob_mouse->x2 = screenInfo->scroll_offset_x + SCROLL_MOUSE_WIDTH; - ob_mouse->y2 = screenInfo->screen_deep - 1; - ob_mouse->priority = 0; + ObjectMouse mouse; + + mouse.x1 = 0; + mouse.y1 = 0; + mouse.x2 = screenInfo->scroll_offset_x + SCROLL_MOUSE_WIDTH; + mouse.y2 = screenInfo->screen_deep - 1; + mouse.priority = 0; if (screenInfo->scroll_offset_x > 0) { // not fully scrolled to the left - ob_mouse->pointer = SCROLL_LEFT_MOUSE_ID; + mouse.pointer = SCROLL_LEFT_MOUSE_ID; } else { // so the mouse area doesn't get registered - ob_mouse->pointer = 0; + mouse.pointer = 0; } + mouse.write(ob_mouse); return IR_CONT; } int32 Logic::fnSetScrollRightMouse(int32 *params) { // params: 0 pointer to object's mouse structure - ObjectMouse *ob_mouse = (ObjectMouse *)decodePtr(params[0]); + byte *ob_mouse = decodePtr(params[0]); ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); // Highest priority - ob_mouse->x1 = screenInfo->scroll_offset_x + _vm->_screen->getScreenWide() - SCROLL_MOUSE_WIDTH; - ob_mouse->y1 = 0; - ob_mouse->x2 = screenInfo->screen_wide - 1; - ob_mouse->y2 = screenInfo->screen_deep - 1; - ob_mouse->priority = 0; + ObjectMouse mouse; + + mouse.x1 = screenInfo->scroll_offset_x + _vm->_screen->getScreenWide() - SCROLL_MOUSE_WIDTH; + mouse.y1 = 0; + mouse.x2 = screenInfo->screen_wide - 1; + mouse.y2 = screenInfo->screen_deep - 1; + mouse.priority = 0; if (screenInfo->scroll_offset_x < screenInfo->max_scroll_offset_x) { // not fully scrolled to the right - ob_mouse->pointer = SCROLL_RIGHT_MOUSE_ID; + mouse.pointer = SCROLL_RIGHT_MOUSE_ID; } else { // so the mouse area doesn't get registered - ob_mouse->pointer = 0; + mouse.pointer = 0; } + mouse.write(ob_mouse); return IR_CONT; } @@ -1971,36 +1952,36 @@ int32 Logic::fnGetPlayerSaveData(int32 *params) { // 1 pointer to object's graphic structure // 2 pointer to object's mega structure - byte *logic_ptr = decodePtr(params[0]); - byte *graphic_ptr = decodePtr(params[1]); - byte *mega_ptr = decodePtr(params[2]); + byte *ob_logic = decodePtr(params[0]); + byte *ob_graph = decodePtr(params[1]); + byte *ob_mega = decodePtr(params[2]); - // Copy from savegame header to player object + // Copy from savegame buffers to player object - memcpy(logic_ptr, &_vm->_saveGameHeader.logic, sizeof(ObjectLogic)); - memcpy(graphic_ptr, &_vm->_saveGameHeader.graphic, sizeof(ObjectGraphic)); - memcpy(mega_ptr, &_vm->_saveGameHeader.mega, sizeof(ObjectMega)); + memcpy(ob_logic, _saveLogic, ObjectLogic::size()); + memcpy(ob_graph, _saveGraphic, ObjectGraphic::size()); + memcpy(ob_mega, _saveMega, ObjectMega::size()); // Any walk-data must be cleared - the player will be set to stand if // he was walking when saved. - ObjectMega *ob_mega = (ObjectMega *)mega_ptr; + ObjectMega obMega(ob_mega); + + if (obMega.getIsWalking()) { + ObjectLogic obLogic(ob_logic); - if (ob_mega->currently_walking) { - ob_mega->currently_walking = 0; + obMega.setIsWalking(0); int32 pars[3]; pars[0] = params[1]; // ob_graphic; pars[1] = params[2]; // ob_mega - pars[2] = ob_mega->current_dir; + pars[2] = obMega.getCurDir(); fnStand(pars); // Reset looping flag (which would have been 1 during fnWalk) - ObjectLogic *ob_logic = (ObjectLogic *)logic_ptr; - - ob_logic->looping = 0; + obLogic.setLooping(0); } return IR_CONT; @@ -2019,11 +2000,11 @@ int32 Logic::fnPassPlayerSaveData(int32 *params) { // 1 pointer to object's graphic structure // 2 pointer to object's mega structure - // Copy from player object to savegame header + // Copy from player object to savegame buffers - memcpy(&_vm->_saveGameHeader.logic, decodePtr(params[0]), sizeof(ObjectLogic)); - memcpy(&_vm->_saveGameHeader.graphic, decodePtr(params[1]), sizeof(ObjectGraphic)); - memcpy(&_vm->_saveGameHeader.mega, decodePtr(params[2]), sizeof(ObjectMega)); + memcpy(_saveLogic, decodePtr(params[0]), ObjectLogic::size()); + memcpy(_saveGraphic, decodePtr(params[1]), ObjectGraphic::size()); + memcpy(_saveMega, decodePtr(params[2]), ObjectMega::size()); return IR_CONT; } @@ -2051,7 +2032,7 @@ int32 Logic::fnAddWalkGrid(int32 *params) { // re-enter a location. // DON'T EVER KILL GEORGE! - if (_scriptVars[ID] != 8) { + if (readVar(ID) != CUR_PLAYER_ID) { // Need to call this in case it wasn't called in script! fnAddToKillList(NULL); } @@ -2095,10 +2076,10 @@ int32 Logic::fnPauseForEvent(int32 *params) { // params: 0 pointer to object's logic structure // 1 number of game-cycles to pause - ObjectLogic *ob_logic = (ObjectLogic *)decodePtr(params[0]); + ObjectLogic obLogic(decodePtr(params[0])); if (checkEventWaiting()) { - ob_logic->looping = 0; + obLogic.setLooping(0); startEvent(); return IR_TERMINATE; } @@ -2109,7 +2090,7 @@ int32 Logic::fnPauseForEvent(int32 *params) { int32 Logic::fnClearEvent(int32 *params) { // params: none - clearEvent(_scriptVars[ID]); + clearEvent(readVar(ID)); return IR_CONT; } @@ -2121,10 +2102,10 @@ int32 Logic::fnFaceMega(int32 *params) { // 4 id of target mega to face return _router->faceMega( - (ObjectLogic *)decodePtr(params[0]), - (ObjectGraphic *)decodePtr(params[1]), - (ObjectMega *)decodePtr(params[2]), - (ObjectWalkdata *)decodePtr(params[3]), + decodePtr(params[0]), + decodePtr(params[1]), + decodePtr(params[2]), + decodePtr(params[3]), params[4]); } @@ -2163,7 +2144,7 @@ int32 Logic::fnPlaySequence(int32 *params) { MoviePlayer player(_vm); uint32 rv; - if (_sequenceTextLines && !_scriptVars[DEMO]) + if (_sequenceTextLines && !readVar(DEMO)) rv = player.play(filename, sequenceSpeechArray, _smackerLeadIn, _smackerLeadOut); else rv = player.play(filename, NULL, _smackerLeadIn, _smackerLeadOut); @@ -2201,13 +2182,13 @@ int32 Logic::fnPlaySequence(int32 *params) { int32 Logic::fnShadedSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteShading((ObjectGraphic *)decodePtr(params[0]), SHADED_SPRITE); + _router->setSpriteShading(decodePtr(params[0]), SHADED_SPRITE); return IR_CONT; } int32 Logic::fnUnshadedSprite(int32 *params) { // params: 0 pointer to object's graphic structure - _router->setSpriteShading((ObjectGraphic *)decodePtr(params[0]), UNSHADED_SPRITE); + _router->setSpriteShading(decodePtr(params[0]), UNSHADED_SPRITE); return IR_CONT; } @@ -2243,7 +2224,7 @@ int32 Logic::fnDisplayMsg(int32 *params) { int32 Logic::fnSetObjectHeld(int32 *params) { // params: 0 luggage icon to set - uint32 res = (uint32) params[0]; + uint32 res = (uint32)params[0]; _vm->_mouse->setObjectHeld(res); return IR_CONT; @@ -2271,16 +2252,11 @@ int32 Logic::fnResetGlobals(int32 *params) { ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - int32 size; - uint32 *globals; - - size = _vm->_resman->fetchLen(1); - size -= sizeof(StandardHeader); + byte *globals = _vm->_resman->openResource(1) + ResHeader::size(); + int32 size = _vm->_resman->fetchLen(1) - ResHeader::size(); debug(5, "globals size: %d", size); - globals = (uint32 *)((byte *)_vm->_resman->openResource(1) + sizeof(StandardHeader)); - // blank each global variable memset(globals, 0, size); @@ -2384,7 +2360,7 @@ int32 Logic::fnCheckPlayerActivity(int32 *params) { // params: 0 threshold delay in seconds, ie. what we want to // check the actual delay against - uint32 seconds = (uint32) params[0]; + uint32 seconds = (uint32)params[0]; _vm->_mouse->checkPlayerActivity(seconds); return IR_CONT; @@ -2407,8 +2383,7 @@ int32 Logic::fnCheckMusicPlaying(int32 *params) { // or 0 if no music playing // in seconds, rounded up to the nearest second - _scriptVars[RESULT] = _vm->_sound->musicTimeRemaining(); - + writeVar(RESULT, _vm->_sound->musicTimeRemaining()); return IR_CONT; } @@ -2418,7 +2393,7 @@ int32 Logic::fnPlayCredits(int32 *params) { // params: none - if (_scriptVars[DEMO]) { + if (readVar(DEMO)) { _vm->closeGame(); return IR_STOP; } diff --git a/sword2/header.h b/sword2/header.h index cf630397c6..c64b78263c 100644 --- a/sword2/header.h +++ b/sword2/header.h @@ -21,16 +21,14 @@ #ifndef _HEADER #define _HEADER +#include "common/stream.h" + namespace Sword2 { //---------------------------------------------------------- // SYSTEM FILE & FRAME HEADERS //---------------------------------------------------------- -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - //---------------------------------------------------------- // ALL FILES //---------------------------------------------------------- @@ -39,7 +37,7 @@ namespace Sword2 { #define NAME_LEN 34 -struct StandardHeader { +struct ResHeader { uint8 fileType; // Byte to define file type (see below) uint8 compType; // Type of file compression used ie. // on whole file (see below) @@ -49,7 +47,31 @@ struct StandardHeader { // memory (NB. frames still held // compressed) byte name[NAME_LEN]; // Name of object -} GCC_PACK; + + static const int size() { + return 44; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + fileType = readS.readByte(); + compType = readS.readByte(); + compSize = readS.readUint32LE(); + decompSize = readS.readUint32LE(); + readS.read(name, NAME_LEN); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeByte(fileType); + writeS.writeByte(compType); + writeS.writeUint32LE(compSize); + writeS.writeUint32LE(decompSize); + writeS.write(name, NAME_LEN); + } +}; // fileType @@ -121,7 +143,40 @@ struct AnimHeader { // place from the start) uint8 feetEndDir; // Direction to start in after running anim uint16 blend; -} GCC_PACK; + + static const int size() { + return 15; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + runTimeComp = readS.readByte(); + noAnimFrames = readS.readUint16LE(); + feetStartX = readS.readUint16LE(); + feetStartY = readS.readUint16LE(); + feetStartDir = readS.readByte(); + feetEndX = readS.readUint16LE(); + feetEndY = readS.readUint16LE(); + feetEndDir = readS.readByte(); + blend = readS.readUint16LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeByte(runTimeComp); + writeS.writeUint16LE(noAnimFrames); + writeS.writeUint16LE(feetStartX); + writeS.writeUint16LE(feetStartY); + writeS.writeByte(feetStartDir); + writeS.writeUint16LE(feetEndX); + writeS.writeUint16LE(feetEndY); + writeS.writeByte(feetEndDir); + writeS.writeUint16LE(blend); + } + +}; // runtimeComp - compression used on each frame of the anim @@ -145,7 +200,29 @@ struct CdtEntry { // of file header) uint8 frameType; // 0 = print sprite normally with top-left // corner at (x,y), otherwise see below... -} GCC_PACK; + + static const int size() { + return 9; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + x = readS.readUint16LE(); + y = readS.readUint16LE(); + frameOffset = readS.readUint32LE(); + frameType = readS.readByte(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint16LE(x); + writeS.writeUint16LE(y); + writeS.writeUint32LE(frameOffset); + writeS.writeByte(frameType); + } +}; // 'frameType' bit values @@ -164,7 +241,27 @@ struct FrameHeader { // type is now in Anim Header uint16 width; // Dimensions of frame uint16 height; -} GCC_PACK; + + static const int size() { + return 8; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + compSize = readS.readUint32LE(); + width = readS.readUint16LE(); + height = readS.readUint16LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint32LE(compSize); + writeS.writeUint16LE(width); + writeS.writeUint16LE(height); + } +}; //---------------------------------------------------------- // (2) SCREEN FILES @@ -193,7 +290,39 @@ struct MultiScreenHeader { uint32 layers; uint32 paletteTable; uint32 maskOffset; -} GCC_PACK; + + static const int size() { + return 36; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + palette = readS.readUint32LE(); + bg_parallax[0] = readS.readUint32LE(); + bg_parallax[1] = readS.readUint32LE(); + screen = readS.readUint32LE(); + fg_parallax[0] = readS.readUint32LE(); + fg_parallax[1] = readS.readUint32LE(); + layers = readS.readUint32LE(); + paletteTable = readS.readUint32LE(); + maskOffset = readS.readUint32LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint32LE(palette); + writeS.writeUint32LE(bg_parallax[0]); + writeS.writeUint32LE(bg_parallax[1]); + writeS.writeUint32LE(screen); + writeS.writeUint32LE(fg_parallax[0]); + writeS.writeUint32LE(fg_parallax[1]); + writeS.writeUint32LE(layers); + writeS.writeUint32LE(paletteTable); + writeS.writeUint32LE(maskOffset); + } +}; // Screen Header @@ -201,7 +330,27 @@ struct ScreenHeader { uint16 width; // dimensions of the background screen uint16 height; uint16 noLayers; // number of layer areas -} GCC_PACK; + + static const int size() { + return 6; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + width = readS.readUint16LE(); + height = readS.readUint16LE(); + noLayers = readS.readUint16LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint16LE(width); + writeS.writeUint16LE(height); + writeS.writeUint16LE(noLayers); + } +}; // Layer Header @@ -216,7 +365,33 @@ struct LayerHeader { uint32 maskSize; uint32 offset; // where to find mask data (from start of // standard file header) -} GCC_PACK; + + static const int size() { + return 16; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + x = readS.readUint16LE(); + y = readS.readUint16LE(); + width = readS.readUint16LE(); + height = readS.readUint16LE(); + maskSize = readS.readUint32LE(); + offset = readS.readUint32LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint16LE(x); + writeS.writeUint16LE(y); + writeS.writeUint16LE(width); + writeS.writeUint16LE(height); + writeS.writeUint32LE(maskSize); + writeS.writeUint32LE(offset); + } +}; //---------------------------------------------------------- // (3) SCRIPT OBJECT FILES @@ -228,22 +403,6 @@ struct LayerHeader { // script object data //---------------------------------------------------------- -// (4) WALK-GRID FILES -//---------------------------------------------------------- -// a walk-grid file consists of: -// -// standard file header -// walk-grid file header -// walk-grid data - -// Walk-Grid Header - taken directly from old "header.h" in STD_INC - -struct WalkGridHeader { - int32 numBars; // number of bars on the floor - int32 numNodes; // number of nodes -} GCC_PACK; - -//---------------------------------------------------------- // (5) PALETTE FILES //---------------------------------------------------------- // a palette file consists of: @@ -254,35 +413,89 @@ struct WalkGridHeader { // an object hub - which represents all that remains of the compact concept -#define TREE_SIZE 3 - -struct ObjectHub { - int32 type; // type of object - uint32 logic_level; // what level? - uint32 logic[TREE_SIZE]; // NOT USED - uint32 script_id[TREE_SIZE]; // need this if script - uint32 script_pc[TREE_SIZE]; // need this also -} GCC_PACK; +class ObjectHub { + // int32 type; // type of object + // uint32 logic_level; // what level? + // uint32 logic[3] // NOT USED + // uint32 script_id[3] // need this if script + // uint32 script_pc[3] // need this also + +private: + byte *_addr; + +public: + ObjectHub() { + _addr = NULL; + } + + static const int size() { + return 44; + } + + byte *data() { + return _addr; + } + + void setAddress(byte *addr) { + _addr = addr; + } + + byte *getScriptPcPtr(int level) { + return _addr + 32 + 4 * level; + } + + uint32 getLogicLevel() { + return READ_LE_UINT32(_addr + 4); + } + uint32 getScriptId(int level) { + return READ_LE_UINT32(_addr + 20 + 4 * level); + } + uint32 getScriptPc(int level) { + return READ_LE_UINT32(_addr + 32 + 4 * level); + } + + void setLogicLevel(uint32 x) { + WRITE_LE_UINT32(_addr + 4, x); + } + void setScriptId(int level, uint32 x) { + WRITE_LE_UINT32(_addr + 20 + 4 * level, x); + } + void setScriptPc(int level, uint32 x) { + WRITE_LE_UINT32(_addr + 32 + 4 * level, x); + } +}; // (6) text module header struct TextHeader { uint32 noOfLines; // how many lines of text are there in this // module -} GCC_PACK; + + static const int size() { + return 4; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + noOfLines = readS.readUint32LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint32LE(noOfLines); + } +}; // a text file has: // -// StandardHeader +// ResHeader // TextHeader // look up table, to // line of text,0 // line of text,0 -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - } // End of namespace Sword2 #endif diff --git a/sword2/icons.cpp b/sword2/icons.cpp index 2e6eaedd32..cb44f46697 100644 --- a/sword2/icons.cpp +++ b/sword2/icons.cpp @@ -19,6 +19,7 @@ */ #include "common/stdafx.h" +#include "common/stream.h" #include "sword2/sword2.h" #include "sword2/defs.h" #include "sword2/logic.h" @@ -27,14 +28,20 @@ namespace Sword2 { -void Mouse::addMenuObject(MenuObject *obj) { +void Mouse::addMenuObject(byte *ptr) { assert(_totalTemp < TOTAL_engine_pockets); - memcpy(&_tempList[_totalTemp], obj, sizeof(MenuObject)); + + Common::MemoryReadStream readS(ptr, 2 * sizeof(int32)); + + _tempList[_totalTemp].icon_resource = readS.readSint32LE(); + _tempList[_totalTemp].luggage_resource = readS.readSint32LE(); _totalTemp++; } void Mouse::addSubject(int32 id, int32 ref) { - if (Logic::_scriptVars[IN_SUBJECT] == 0) { + uint32 in_subject = _vm->_logic->readVar(IN_SUBJECT); + + if (in_subject == 0) { // This is the start of the new subject list. Set the default // repsonse id to zero in case we're never passed one. _defaultResponseId = 0; @@ -48,9 +55,9 @@ void Mouse::addSubject(int32 id, int32 ref) { _defaultResponseId = ref; } else { debug(5, "fnAddSubject res %d, uid %d", id, ref); - _subjectList[Logic::_scriptVars[IN_SUBJECT]].res = id; - _subjectList[Logic::_scriptVars[IN_SUBJECT]].ref = ref; - Logic::_scriptVars[IN_SUBJECT]++; + _subjectList[in_subject].res = id; + _subjectList[in_subject].ref = ref; + _vm->_logic->writeVar(IN_SUBJECT, in_subject + 1); } } @@ -72,10 +79,7 @@ void Mouse::buildMenu() { // Run the 'build_menu' script in the 'menu_master' object. This will // register all carried menu objects. - uint32 null_pc = 0; - char *menuScript = (char *)_vm->_resman->openResource(MENU_MASTER_OBJECT); - _vm->_logic->runScript(menuScript, menuScript, &null_pc); - _vm->_resman->closeResource(MENU_MASTER_OBJECT); + _vm->_logic->runResScript(MENU_MASTER_OBJECT, 0); // Create a new master list based on the old master inventory list and // the new temporary inventory list. The purpose of all this is, as @@ -139,23 +143,26 @@ void Mouse::buildMenu() { if (res) { bool icon_coloured; + uint32 object_held = _vm->_logic->readVar(OBJECT_HELD); + uint32 combine_base = _vm->_logic->readVar(COMBINE_BASE); + if (_examiningMenuIcon) { // When examining an object, that object is // coloured. The rest are greyed out. - icon_coloured = (res == Logic::_scriptVars[OBJECT_HELD]); - } else if (Logic::_scriptVars[COMBINE_BASE]) { + icon_coloured = (res == object_held); + } else if (combine_base) { // When combining two menu object (i.e. using // one on another), both are coloured. The rest // are greyed out. - icon_coloured = (res == Logic::_scriptVars[OBJECT_HELD] || res == Logic::_scriptVars[COMBINE_BASE]); + icon_coloured = (res == object_held || combine_base); } else { // If an object is selected but we are not yet // doing anything with it, the selected object // is greyed out. The rest are coloured. - icon_coloured = (res != Logic::_scriptVars[OBJECT_HELD]); + icon_coloured = (res != object_held); } - icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); + icon = _vm->_resman->openResource(res) + ResHeader::size(); // The coloured icon is stored directly after the // greyed out one. @@ -190,12 +197,12 @@ void Mouse::buildSystemMenu() { // rest will grey out. for (int i = 0; i < ARRAYSIZE(icon_list); i++) { - byte *icon = _vm->_resman->openResource(icon_list[i]) + sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(icon_list[i]) + ResHeader::size(); // The only case when an icon is grayed is when the player // is dead. Then SAVE is not available. - if (!Logic::_scriptVars[DEAD] || icon_list[i] != SAVE_ICON) + if (!_vm->_logic->readVar(DEAD) || icon_list[i] != SAVE_ICON) icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP); setMenuIcon(RDMENU_TOP, i, icon); diff --git a/sword2/icons.h b/sword2/icons.h index 84b308a3a9..ae37974036 100644 --- a/sword2/icons.h +++ b/sword2/icons.h @@ -29,19 +29,11 @@ namespace Sword2 { // define these in a script and then register them with the system -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - struct MenuObject { int32 icon_resource; // icon graphic graphic int32 luggage_resource; // luggage icon resource (for attaching to // mouse pointer) -} GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif +}; } // End of namespace Sword2 diff --git a/sword2/interpreter.cpp b/sword2/interpreter.cpp index ea57ae1c89..278834c578 100644 --- a/sword2/interpreter.cpp +++ b/sword2/interpreter.cpp @@ -25,6 +25,7 @@ #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/memory.h" +#include "sword2/resman.h" namespace Sword2 { @@ -205,18 +206,58 @@ do { \ #define pop() (assert(stackPtr < ARRAYSIZE(stack)), stack[--stackPtr]) -uint32 *Logic::_scriptVars = NULL; +int Logic::runResScript(uint32 scriptRes, uint32 offset) { + byte *scriptAddr; + int result; -int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { + scriptAddr = _vm->_resman->openResource(scriptRes); + result = runScript(scriptAddr, scriptAddr, offset); + _vm->_resman->closeResource(scriptRes); + + return result; +} + +int Logic::runResObjScript(uint32 scriptRes, uint32 objRes, uint32 offset) { + byte *scriptAddr, *objAddr; + int result; + + scriptAddr = _vm->_resman->openResource(scriptRes); + objAddr = _vm->_resman->openResource(objRes); + result = runScript(scriptAddr, objAddr, offset); + _vm->_resman->closeResource(objRes); + _vm->_resman->closeResource(scriptRes); + + return result; +} + +int Logic::runScript(byte *scriptData, byte *objectData, uint32 offset) { + byte pc[4]; + + WRITE_LE_UINT32(pc, offset); + return runScript2(scriptData, objectData, pc); +} + +// This form of the runScript function is only called directly from +// the processSession() function, which uses it to update the script PC in the +// current object hub. For reasons which I do not understand, I couldn't get it +// to work if I called the function first with a dummy offset variable, and +// and then updated the object hub myself. + +int Logic::runScript2(byte *scriptData, byte *objectData, byte *offsetPtr) { // Interestingly, unlike our BASS engine the stack is a local variable. - // This has some interesting implications which may or may not be - // necessary to the BS2 engine. + // I don't know whether or not this is relevant to the working of the + // BS2 engine. int32 stack[STACK_SIZE]; int32 stackPtr = 0; - StandardHeader *header = (StandardHeader *)scriptData; - scriptData += sizeof(StandardHeader) + sizeof(ObjectHub); + uint32 offset = READ_LE_UINT32(offsetPtr); + + ResHeader header; + + header.read(scriptData); + + scriptData += ResHeader::size() + ObjectHub::size(); // The script data format: // int32_TYPE 1 Size of variable space in bytes @@ -231,25 +272,25 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // Get the start of variables and start of code - uint32 *localVars = (uint32 *)(scriptData + sizeof(int32)); - char *code = scriptData + READ_LE_UINT32(scriptData) + sizeof(int32); + byte *localVars = scriptData + 4; + byte *code = scriptData + READ_LE_UINT32(scriptData) + 4; uint32 noScripts = READ_LE_UINT32(code); - code += sizeof(int32); + code += 4; - const uint32 *offsetTable = (const uint32 *)code; + byte *offsetTable = code; - if (*offset < noScripts) { - ip = FROM_LE_32(offsetTable[*offset]); - scriptNumber = *offset; - debug(4, "Start script %d with offset %d", *offset, ip); + if (offset < noScripts) { + ip = READ_LE_UINT32(offsetTable + offset * 4); + scriptNumber = offset; + debug(4, "Start script %d with offset %d", offset, ip); } else { uint i; - ip = *offset; + ip = offset; for (i = 1; i < noScripts; i++) { - if (FROM_LE_32(offsetTable[i]) >= ip) + if (READ_LE_UINT32(offsetTable + 4 * i) >= ip) break; } @@ -265,23 +306,23 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { bool checkElevatorBug = false; if (scriptNumber == 2) { - if (strcmp((char *)header->name, "mop_73") == 0) + if (strcmp((char *)header.name, "mop_73") == 0) checkMopBug = true; - else if (strcmp((char *)header->name, "titipoco_81") == 0) + else if (strcmp((char *)header.name, "titipoco_81") == 0) checkPyramidBug = true; - else if (strcmp((char *)header->name, "lift_82") == 0) + else if (strcmp((char *)header.name, "lift_82") == 0) checkElevatorBug = true; } - code += noScripts * sizeof(int32); + code += noScripts * 4; // Code should now be pointing at an identifier and a checksum - const char *checksumBlock = code; + byte *checksumBlock = code; - code += sizeof(int32) * 3; + code += 4 * 3; if (READ_LE_UINT32(checksumBlock) != 12345678) { - error("Invalid script in object %s", header->name); + error("Invalid script in object %s", header.name); return 0; } @@ -291,8 +332,8 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { for (int i = 0; i < codeLen; i++) checksum += (unsigned char) code[i]; - if (checksum != (int32) READ_LE_UINT32(checksumBlock + 8)) { - debug(1, "Checksum error in object %s", header->name); + if (checksum != (int32)READ_LE_UINT32(checksumBlock + 8)) { + debug(1, "Checksum error in object %s", header.name); // This could be bad, but there has been a report about someone // who had problems running the German version because of // checksum errors. Could there be a version where checksums @@ -341,9 +382,9 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // So if his click hander finishes, and variable 913 is // 1, we set it back to 0 manually. - if (checkPyramidBug && _scriptVars[913] == 1) { + if (checkPyramidBug && readVar(913) == 1) { warning("Working around pyramid bug: Resetting Titipoco's state"); - _scriptVars[913] = 0; + writeVar(913, 0); } // WORKAROUND: The not-so-known-but-should-be-dreaded @@ -354,7 +395,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // examining it, the mouse cursor is removed but never // restored. - if (checkElevatorBug && Logic::_scriptVars[RIGHT_BUTTON]) { + if (checkElevatorBug && readVar(RIGHT_BUTTON)) { warning("Working around elevator bug: Restoring mouse pointer"); fnAddHuman(NULL); } @@ -363,7 +404,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { break; case CP_QUIT: // Quit out for a cycle - *offset = ip; + WRITE_LE_UINT32(offsetPtr, ip); debug(9, "CP_QUIT"); return 0; case CP_TERMINATE: @@ -388,16 +429,14 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { case CP_PUSH_LOCAL_VAR32: // Push the contents of a local variable Read16ip(parameter); - parameter /= 4; - push(localVars[parameter]); - debug(9, "CP_PUSH_LOCAL_VAR32: localVars[%d] => %d", parameter, localVars[parameter]); + push(READ_LE_UINT32(localVars + parameter)); + debug(9, "CP_PUSH_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, READ_LE_UINT32(localVars + parameter)); break; case CP_PUSH_GLOBAL_VAR32: // Push a global variable - assert(_scriptVars); Read16ip(parameter); - push(_scriptVars[parameter]); - debug(9, "CP_PUSH_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, _scriptVars[parameter]); + push(readVar(parameter)); + debug(9, "CP_PUSH_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, readVar(parameter)); break; case CP_PUSH_LOCAL_ADDR: // Push the address of a local variable @@ -410,10 +449,8 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // CP_PUSH_DEREFERENCED_STRUCTURE opcode. Read16ip(parameter); - parameter /= 4; - ptr = (byte *)&localVars[parameter]; - push_ptr(ptr); - debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter, ptr); + push_ptr(localVars + parameter); + debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter / 4, localVars + parameter); break; case CP_PUSH_STRING: // Push the address of a string on to the stack @@ -421,7 +458,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { Read8ip(parameter); // ip now points to the string - ptr = (byte *)(code + ip); + ptr = code + ip; push_ptr(ptr); debug(9, "CP_PUSH_STRING: \"%s\"", ptr); ip += (parameter + 1); @@ -429,17 +466,16 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { case CP_PUSH_DEREFERENCED_STRUCTURE: // Push the address of a dereferenced structure Read32ip(parameter); - ptr = (byte *)(objectData + sizeof(int32) + sizeof(StandardHeader) + sizeof(ObjectHub) + parameter); + ptr = objectData + 4 + ResHeader::size() + ObjectHub::size() + parameter; push_ptr(ptr); debug(9, "CP_PUSH_DEREFERENCED_STRUCTURE: %d => %p", parameter, ptr); break; case CP_POP_LOCAL_VAR32: // Pop a value into a local word variable Read16ip(parameter); - parameter /= 4; value = pop(); - localVars[parameter] = value; - debug(9, "CP_POP_LOCAL_VAR32: localVars[%d] = %d", parameter, value); + WRITE_LE_UINT32(localVars + parameter, value); + debug(9, "CP_POP_LOCAL_VAR32: localVars[%d] = %d", parameter / 4, value); break; case CP_POP_GLOBAL_VAR32: // Pop a global variable @@ -472,41 +508,39 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // use that as the signal that Nico's state needs to be // updated as well. - if (checkMopBug && parameter == 1017 && _scriptVars[1003] != 2) { + if (checkMopBug && parameter == 1017 && readVar(1003) != 2) { warning("Working around mop bug: Setting Nico's state"); - _scriptVars[1003] = 2; + writeVar(1003, 2); } - _scriptVars[parameter] = value; + writeVar(parameter, value); debug(9, "CP_POP_GLOBAL_VAR32: scriptsVars[%d] = %d", parameter, value); break; case CP_ADDNPOP_LOCAL_VAR32: Read16ip(parameter); - parameter /= 4; - value = pop(); - localVars[parameter] += value; - debug(9, "CP_ADDNPOP_LOCAL_VAR32: localVars[%d] += %d => %d", parameter, value, localVars[parameter]); + value = READ_LE_UINT32(localVars + parameter) + pop(); + WRITE_LE_UINT32(localVars + parameter, value); + debug(9, "CP_ADDNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value); break; case CP_SUBNPOP_LOCAL_VAR32: Read16ip(parameter); - parameter /= 4; - value = pop(); - localVars[parameter] -= value; - debug(9, "CP_SUBNPOP_LOCAL_VAR32: localVars[%d] -= %d => %d", parameter, value, localVars[parameter]); + value = READ_LE_UINT32(localVars + parameter) - pop(); + WRITE_LE_UINT32(localVars + parameter, value); + debug(9, "CP_SUBNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value); break; case CP_ADDNPOP_GLOBAL_VAR32: // Add and pop a global variable Read16ip(parameter); - value = pop(); - _scriptVars[parameter] += value; - debug(9, "CP_ADDNPOP_GLOBAL_VAR32: scriptVars[%d] += %d => %d", parameter, value, _scriptVars[parameter]); + value = readVar(parameter) + pop(); + writeVar(parameter, value); + debug(9, "CP_ADDNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value); break; case CP_SUBNPOP_GLOBAL_VAR32: // Sub and pop a global variable Read16ip(parameter); - value = pop(); - _scriptVars[parameter] -= value; - debug(9, "CP_SUBNPOP_GLOBAL_VAR32: scriptVars[%d] -= %d => %d", parameter, value, _scriptVars[parameter]); + value = readVar(parameter) - pop(); + writeVar(parameter, value); + debug(9, "CP_SUBNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value); break; // Jump opcodes @@ -516,7 +550,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { Read32ipLeaveip(parameter); value = pop(); if (!value) { - ip += sizeof(int32); + ip += 4; debug(9, "CP_SKIPONTRUE: %d (IS FALSE (NOT SKIPPED))", parameter); } else { ip += parameter; @@ -528,7 +562,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { Read32ipLeaveip(parameter); value = pop(); if (value) { - ip += sizeof(int32); + ip += 4; debug(9, "CP_SKIPONFALSE: %d (IS TRUE (NOT SKIPPED))", parameter); } else { ip += parameter; @@ -549,13 +583,13 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // Search the cases foundCase = false; for (i = 0; i < caseCount && !foundCase; i++) { - if (value == (int32) READ_LE_UINT32(code + ip)) { + if (value == (int32)READ_LE_UINT32(code + ip)) { // We have found the case, so lets // jump to it foundCase = true; - ip += READ_LE_UINT32(code + ip + sizeof(int32)); + ip += READ_LE_UINT32(code + ip + 4); } else - ip += sizeof(int32) * 2; + ip += 4 * 2; } // If we found no matching case then use the default @@ -585,7 +619,7 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { switch (retVal & 7) { case IR_STOP: // Quit out for a cycle - *offset = ip; + WRITE_LE_UINT32(offsetPtr, ip); return 0; case IR_CONT: // Continue as normal @@ -596,11 +630,11 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { case IR_REPEAT: // Return setting offset to start of this // function call - *offset = savedStartOfMcode; + WRITE_LE_UINT32(offsetPtr, savedStartOfMcode); return 0; case IR_GOSUB: // that's really neat - *offset = ip; + WRITE_LE_UINT32(offsetPtr, ip); return 2; default: error("Bad return code (%d) from '%s'", retVal & 7, opcodes[parameter].desc); diff --git a/sword2/interpreter.h b/sword2/interpreter.h index e42e1c1647..c3c05119df 100644 --- a/sword2/interpreter.h +++ b/sword2/interpreter.h @@ -36,10 +36,10 @@ enum { // Get parameter fix so that the playstation version can handle words not on // word boundaries -#define Read8ip(var) { var = *((const int8 *)(code + ip)); ip++; } -#define Read16ip(var) { var = (int16) READ_LE_UINT16(code + ip); ip += sizeof(int16); } -#define Read32ip(var) { var = (int32) READ_LE_UINT32(code + ip); ip += sizeof(int32); } -#define Read32ipLeaveip(var) { var = (int32) READ_LE_UINT32(code + ip); } +#define Read8ip(var) { var = code[ip]; ip++; } +#define Read16ip(var) { var = (int16)READ_LE_UINT16(code + ip); ip += 2; } +#define Read32ip(var) { var = (int32)READ_LE_UINT32(code + ip); ip += 4; } +#define Read32ipLeaveip(var) { var = (int32)READ_LE_UINT32(code + ip); } enum { // Compiled tokens diff --git a/sword2/layers.cpp b/sword2/layers.cpp index 968ee8f621..623eecec14 100644 --- a/sword2/layers.cpp +++ b/sword2/layers.cpp @@ -52,7 +52,7 @@ void Screen::initBackground(int32 res, int32 new_palette) { _vm->_sound->clearFxQueue(); waitForFade(); - debug(1, "CHANGED TO LOCATION \"%s\"", _vm->fetchObjectName(res, buf)); + debug(1, "CHANGED TO LOCATION \"%s\"", _vm->_resman->fetchName(res, buf)); // if last screen was using a shading mask (see below) if (_thisScreen.mask_flag) { @@ -72,36 +72,40 @@ void Screen::initBackground(int32 res, int32 new_palette) { // each cycle byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); - ScreenHeader *screen_head = _vm->fetchScreenHeader(file); + ScreenHeader screen_head; + + screen_head.read(_vm->fetchScreenHeader(file)); // set number of special sort layers - _thisScreen.number_of_layers = screen_head->noLayers; - _thisScreen.screen_wide = screen_head->width; - _thisScreen.screen_deep = screen_head->height; + _thisScreen.number_of_layers = screen_head.noLayers; + _thisScreen.screen_wide = screen_head.width; + _thisScreen.screen_deep = screen_head.height; - debug(2, "layers=%d width=%d depth=%d", screen_head->noLayers, screen_head->width, screen_head->height); + debug(2, "layers=%d width=%d depth=%d", screen_head.noLayers, screen_head.width, screen_head.height); // initialise the driver back buffer - setLocationMetrics(screen_head->width, screen_head->height); + setLocationMetrics(screen_head.width, screen_head.height); - for (i = 0; i < screen_head->noLayers; i++) { + for (i = 0; i < screen_head.noLayers; i++) { debug(3, "init layer %d", i); - LayerHeader *layer = _vm->fetchLayerHeader(file, i); + LayerHeader layer; + + layer.read(_vm->fetchLayerHeader(file, i)); // Add the layer to the sort list. We only provide just enough // information so that it's clear that it's a layer, and where // to sort it in relation to other things in the list. _sortList[i].layer_number = i + 1; - _sortList[i].sort_y = layer->y + layer->height; + _sortList[i].sort_y = layer.y + layer.height; } // reset scroll offsets _thisScreen.scroll_offset_x = 0; _thisScreen.scroll_offset_y = 0; - if (screen_head->width > _screenWide || screen_head->height > _screenDeep) { + if (screen_head.width > _screenWide || screen_head.height > _screenDeep) { // The layer is larger than the physical screen. Switch on // scrolling. (2 means first time on screen) _thisScreen.scroll_flag = 2; @@ -112,8 +116,8 @@ void Screen::initBackground(int32 res, int32 new_palette) { // Calculate the maximum scroll offsets to prevent scrolling // off the edge. The minimum offsets are both 0. - _thisScreen.max_scroll_offset_x = screen_head->width - _screenWide; - _thisScreen.max_scroll_offset_y = screen_head->height - (_screenDeep - (MENUDEEP * 2)); + _thisScreen.max_scroll_offset_x = screen_head.width - _screenWide; + _thisScreen.max_scroll_offset_y = screen_head.height - (_screenDeep - (MENUDEEP * 2)); } else { // The later fits on the phyiscal screen. Switch off scrolling. _thisScreen.scroll_flag = 0; @@ -129,15 +133,17 @@ void Screen::initBackground(int32 res, int32 new_palette) { // shading mask - MultiScreenHeader *screenLayerTable = (MultiScreenHeader *)(file + sizeof(StandardHeader)); + MultiScreenHeader screenLayerTable; + + screenLayerTable.read(file + ResHeader::size()); - if (screenLayerTable->maskOffset) { + if (screenLayerTable.maskOffset) { SpriteInfo spriteInfo; spriteInfo.x = 0; spriteInfo.y = 0; - spriteInfo.w = screen_head->width; - spriteInfo.h = screen_head->height; + spriteInfo.w = screen_head.width; + spriteInfo.h = screen_head.height; spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; @@ -159,7 +165,7 @@ void Screen::initBackground(int32 res, int32 new_palette) { // Background parallax layers for (i = 0; i < 2; i++) { - if (screenLayerTable->bg_parallax[i]) + if (screenLayerTable.bg_parallax[i]) initialiseBackgroundLayer(_vm->fetchBackgroundParallaxLayer(file, i)); else initialiseBackgroundLayer(NULL); @@ -172,7 +178,7 @@ void Screen::initBackground(int32 res, int32 new_palette) { // Foreground parallax layers for (i = 0; i < 2; i++) { - if (screenLayerTable->fg_parallax[i]) + if (screenLayerTable.fg_parallax[i]) initialiseBackgroundLayer(_vm->fetchForegroundParallaxLayer(file, i)); else initialiseBackgroundLayer(NULL); diff --git a/sword2/logic.cpp b/sword2/logic.cpp index 51185a5373..c25ef8270f 100644 --- a/sword2/logic.cpp +++ b/sword2/logic.cpp @@ -26,8 +26,6 @@ #include "sword2/router.h" #include "sword2/sound.h" -#define LEVEL (_curObjectHub->logic_level) - namespace Sword2 { Logic::Logic(Sword2Engine *vm) : @@ -60,34 +58,37 @@ int Logic::processSession() { // processing on the current list while (_pc != 0xffffffff) { - uint32 ret, script; - char *raw_script_ad; + byte *game_object_list, *head, *raw_script_ad, *raw_data_ad; + uint32 level, ret, script, id; - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(run_list); - assert(head->fileType == RUN_LIST); + game_object_list = _vm->_resman->openResource(run_list) + ResHeader::size(); - uint32 *game_object_list = (uint32 *)(head + 1); + assert(_vm->_resman->fetchType(run_list) == RUN_LIST); // read the next id - uint id = game_object_list[_pc++]; - _scriptVars[ID] = id; + id = READ_LE_UINT32(game_object_list + 4 * _pc); + _pc++; + + writeVar(ID, id); _vm->_resman->closeResource(run_list); - if (!_scriptVars[ID]) { + if (!id) { // End of list - end the session naturally return 0; } - head = (StandardHeader *)_vm->_resman->openResource(_scriptVars[ID]); - assert(head->fileType == GAME_OBJECT); + assert(_vm->_resman->fetchType(id) == GAME_OBJECT); + + head = _vm->_resman->openResource(id); + _curObjectHub.setAddress(head + ResHeader::size()); - _curObjectHub = (ObjectHub *)(head + 1); + level = _curObjectHub.getLogicLevel(); debug(5, "Level %d id(%d) pc(%d)", - LEVEL, - _curObjectHub->script_id[LEVEL], - _curObjectHub->script_pc[LEVEL]); + level, + _curObjectHub.getScriptId(level), + _curObjectHub.getScriptPc(level)); // Do the logic for this object. We keep going until a function // says to stop - remember, system operations are run via @@ -97,32 +98,34 @@ int Logic::processSession() { // There is a distinction between running one of our // own scripts and that of another object. - script = _curObjectHub->script_id[LEVEL]; + level = _curObjectHub.getLogicLevel(); + script = _curObjectHub.getScriptId(level); - if (script / SIZE == _scriptVars[ID]) { + if (script / SIZE == readVar(ID)) { // It's our own script debug(5, "Run script %d pc=%d", script / SIZE, - _curObjectHub->script_pc[LEVEL]); + _curObjectHub.getScriptPc(level)); // This is the script data. Script and data // object are the same. - raw_script_ad = (char *)head; + raw_script_ad = head; - ret = runScript(raw_script_ad, raw_script_ad, &_curObjectHub->script_pc[LEVEL]); + ret = runScript2(raw_script_ad, raw_script_ad, _curObjectHub.getScriptPcPtr(level)); } else { // We're running the script of another game // object - get our data object address. - StandardHeader *far_head = (StandardHeader *)_vm->_resman->openResource(script / SIZE); - assert(far_head->fileType == GAME_OBJECT || far_head->fileType == SCREEN_MANAGER); + uint8 type = _vm->_resman->fetchType(script / SIZE); - raw_script_ad = (char *)far_head; - char *raw_data_ad = (char *)head; + assert(type == GAME_OBJECT || type == SCREEN_MANAGER); - ret = runScript(raw_script_ad, raw_data_ad, &_curObjectHub->script_pc[LEVEL]); + raw_script_ad = _vm->_resman->openResource(script / SIZE); + raw_data_ad = head; + + ret = runScript2(raw_script_ad, raw_data_ad, _curObjectHub.getScriptPcPtr(level)); _vm->_resman->closeResource(script / SIZE); @@ -131,10 +134,12 @@ int Logic::processSession() { } if (ret == 1) { + level = _curObjectHub.getLogicLevel(); + // The script finished - drop down a level - if (LEVEL) - LEVEL--; - else { + if (level) { + _curObjectHub.setLogicLevel(level - 1); + } else { // Hmmm, level 0 terminated :-| Let's // be different this time and simply // let it restart next go :-) @@ -145,7 +150,7 @@ int Logic::processSession() { debug(5, "object %d script 0 terminated!", id); // reset to rerun, drop out for a cycle - _curObjectHub->script_pc[LEVEL] = _curObjectHub->script_id[LEVEL] & 0xffff; + _curObjectHub.setScriptPc(level, _curObjectHub.getScriptId(level) & 0xffff); ret = 0; } } else if (ret > 2) { @@ -163,18 +168,17 @@ int Logic::processSession() { // Clear any syncs that were waiting for this character - it // has used them or now looses them - clearSyncs(_scriptVars[ID]); + clearSyncs(readVar(ID)); if (_pc != 0xffffffff) { // The session is still valid so run the graphics/mouse // service script - uint32 null_pc = 0; - runScript(raw_script_ad, raw_script_ad, &null_pc); + runScript(raw_script_ad, raw_script_ad, 0); } // and that's it so close the object resource - _vm->_resman->closeResource(_scriptVars[ID]); + _vm->_resman->closeResource(readVar(ID)); } // Leaving a room so remove all ids that must reboot correctly. Then @@ -198,7 +202,7 @@ void Logic::expressChangeSession(uint32 sesh_id) { _pc = 0xffffffff; // Reset now in case we double-clicked an exit prior to changing screen - _scriptVars[EXIT_FADING] = 0; + writeVar(EXIT_FADING, 0); // We're trashing the list - presumably to change room. In theory, // sync waiting in the list could be left behind and never removed - @@ -228,9 +232,9 @@ void Logic::logicUp(uint32 new_script) { debug(5, "new pc = %d", new_script & 0xffff); // going up a level - and we'll keep going this cycle - LEVEL++; + _curObjectHub.setLogicLevel(_curObjectHub.getLogicLevel() + 1); - assert(LEVEL < 3); // Can be 0, 1, 2 + assert(_curObjectHub.getLogicLevel() < 3); // Can be 0, 1, 2 logicReplace(new_script); } @@ -239,7 +243,7 @@ void Logic::logicUp(uint32 new_script) { */ void Logic::logicOne(uint32 new_script) { - LEVEL = 1; + _curObjectHub.setLogicLevel(1); logicReplace(new_script); } @@ -249,8 +253,10 @@ void Logic::logicOne(uint32 new_script) { */ void Logic::logicReplace(uint32 new_script) { - _curObjectHub->script_id[LEVEL] = new_script; - _curObjectHub->script_pc[LEVEL] = new_script & 0xffff; + uint32 level = _curObjectHub.getLogicLevel(); + + _curObjectHub.setScriptId(level, new_script); + _curObjectHub.setScriptPc(level, new_script & 0xffff); } void Logic::resetKillList() { diff --git a/sword2/logic.h b/sword2/logic.h index 8f5a01b1f4..f41932b188 100644 --- a/sword2/logic.h +++ b/sword2/logic.h @@ -69,7 +69,7 @@ private: uint32 _pc; // each object has one of these tacked onto the beginning - ObjectHub *_curObjectHub; + ObjectHub _curObjectHub; EventUnit _eventList[MAX_events]; @@ -119,18 +119,21 @@ private: bool wantSpeechForLine(uint32 wavId); // Set by fnPassMega() - ObjectMega _engineMega; + byte _engineMega[56]; public: Logic(Sword2Engine *vm); ~Logic(); EventUnit *getEventList() { return _eventList; } + byte *getEngineMega() { return _engineMega; } - ObjectMega *getEngineMega() { return &_engineMega; } + byte _saveLogic[8]; + byte _saveGraphic[12]; + byte _saveMega[56]; // Point to the global variable data - static uint32 *_scriptVars; + byte *_scriptVars; // "TEXT" - current official text line number - will match the wav // filenames @@ -140,7 +143,18 @@ public: // so speech text cleared when running a new start-script uint32 _speechTextBlocNo; - int runScript(char *scriptData, char *objectData, uint32 *offset); + uint32 readVar(int n) { + return READ_LE_UINT32(_scriptVars + 4 * n); + } + + void writeVar(int n, uint32 value) { + WRITE_LE_UINT32(_scriptVars + 4 * n, value); + } + + int runResScript(uint32 scriptRes, uint32 offset); + int runResObjScript(uint32 scriptRes, uint32 objRes, uint32 offset); + int runScript(byte *scriptData, byte *objectData, uint32 offset); + int runScript2(byte *scriptData, byte *objectData, byte *offset); void sendEvent(uint32 id, uint32 interact_id); void setPlayerActionEvent(uint32 id, uint32 interact_id); diff --git a/sword2/maketext.cpp b/sword2/maketext.cpp index 98932b6d2a..c9c4090a83 100644 --- a/sword2/maketext.cpp +++ b/sword2/maketext.cpp @@ -213,22 +213,24 @@ byte *FontRenderer::buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, L // Allocate memory for the text sprite uint32 sizeOfSprite = spriteWidth * spriteHeight; - byte *textSprite = (byte *)malloc(sizeof(FrameHeader) + sizeOfSprite); + byte *textSprite = (byte *)malloc(FrameHeader::size() + sizeOfSprite); // At this stage, textSprite points to an unmovable memory block. Set // up the frame header. - FrameHeader *frameHeadPtr = (FrameHeader *)textSprite; + FrameHeader frame_head; - frameHeadPtr->compSize = 0; - frameHeadPtr->width = spriteWidth; - frameHeadPtr->height = spriteHeight; + frame_head.compSize = 0; + frame_head.width = spriteWidth; + frame_head.height = spriteHeight; + + frame_head.write(textSprite); debug(4, "Text sprite size: %ux%u", spriteWidth, spriteHeight); // Clear the entire sprite to make it transparent. - byte *linePtr = textSprite + sizeof(FrameHeader); + byte *linePtr = textSprite + FrameHeader::size(); memset(linePtr, 0, sizeOfSprite); byte *charSet = _vm->_resman->openResource(fontRes); @@ -246,11 +248,13 @@ byte *FontRenderer::buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, L // width minus the 'overlap' for (uint j = 0; j < line[i].length; j++) { - FrameHeader *charPtr = findChar(sentence[pos++], charSet); + byte *charPtr = findChar(sentence[pos++], charSet); + + frame_head.read(charPtr); - assert(charPtr->height == char_height); + assert(frame_head.height == char_height); copyChar(charPtr, spritePtr, spriteWidth, pen); - spritePtr += charPtr->width + _charSpacing; + spritePtr += frame_head.width + _charSpacing; } // Skip space at end of last word in this line @@ -273,11 +277,12 @@ byte *FontRenderer::buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, L uint16 FontRenderer::charWidth(byte ch, uint32 fontRes) { byte *charSet = _vm->_resman->openResource(fontRes); - FrameHeader *charFrame = findChar(ch, charSet); - uint16 width = charFrame->width; + FrameHeader frame_head; + frame_head.read(findChar(ch, charSet)); _vm->_resman->closeResource(fontRes); - return width; + + return frame_head.width; } /** @@ -293,11 +298,12 @@ uint16 FontRenderer::charWidth(byte ch, uint32 fontRes) { uint16 FontRenderer::charHeight(uint32 fontRes) { byte *charSet = _vm->_resman->openResource(fontRes); - FrameHeader *charFrame = findChar(FIRST_CHAR, charSet); - uint16 height = charFrame->height; + FrameHeader frame_head; + frame_head.read(findChar(FIRST_CHAR, charSet)); _vm->_resman->closeResource(fontRes); - return height; + + return frame_head.height; } /** @@ -307,7 +313,7 @@ uint16 FontRenderer::charHeight(uint32 fontRes) { * 'dud' character (chequered flag) */ -FrameHeader* FontRenderer::findChar(byte ch, byte *charSet) { +byte *FontRenderer::findChar(byte ch, byte *charSet) { if (ch < FIRST_CHAR) ch = DUD; return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR); @@ -323,16 +329,20 @@ FrameHeader* FontRenderer::findChar(byte ch, byte *charSet) { * LETTER_COL to pen. */ -void FontRenderer::copyChar(FrameHeader *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen) { - byte *source = (byte *)charPtr + sizeof(FrameHeader); +void FontRenderer::copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen) { + FrameHeader frame; + + frame.read(charPtr); + + byte *source = charPtr + FrameHeader::size(); byte *rowPtr = spritePtr; - for (uint i = 0; i < charPtr->height; i++) { + for (uint i = 0; i < frame.height; i++) { byte *dest = rowPtr; if (pen) { // Use the specified colours - for (uint j = 0; j < charPtr->width; j++) { + for (uint j = 0; j < frame.width; j++) { switch (*source++) { case LETTER_COL: *dest = pen; @@ -355,8 +365,8 @@ void FontRenderer::copyChar(FrameHeader *charPtr, byte *spritePtr, uint16 sprite // Pen is zero, so just copy character sprites // directly into text sprite without remapping colours. // Apparently overlapping is never considered here? - memcpy(dest, source, charPtr->width); - source += charPtr->width; + memcpy(dest, source, frame.width); + source += frame.width; } rowPtr += spriteWidth; } @@ -387,37 +397,39 @@ uint32 FontRenderer::buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, u // without margin checking - used for debug text if (justification != NO_JUSTIFICATION) { - FrameHeader *frame_head = (FrameHeader *)_blocList[i].text_mem; + FrameHeader frame_head; + + frame_head.read(_blocList[i].text_mem); switch (justification) { case POSITION_AT_CENTRE_OF_BASE: // This one is always used for SPEECH TEXT; possibly // also for pointer text - x -= (frame_head->width / 2); - y -= frame_head->height; + x -= (frame_head.width / 2); + y -= frame_head.height; break; case POSITION_AT_CENTRE_OF_TOP: - x -= (frame_head->width / 2); + x -= (frame_head.width / 2); break; case POSITION_AT_LEFT_OF_TOP: // The given coords are already correct for this! break; case POSITION_AT_RIGHT_OF_TOP: - x -= frame_head->width; + x -= frame_head.width; break; case POSITION_AT_LEFT_OF_BASE: - y -= frame_head->height; + y -= frame_head.height; break; case POSITION_AT_RIGHT_OF_BASE: - x -= frame_head->width; - y -= frame_head->height; + x -= frame_head.width; + y -= frame_head.height; break; case POSITION_AT_LEFT_OF_CENTRE: - y -= (frame_head->height / 2); + y -= (frame_head.height / 2); break; case POSITION_AT_RIGHT_OF_CENTRE: - x -= frame_head->width; - y -= (frame_head->height) / 2; + x -= frame_head.width; + y -= (frame_head.height) / 2; break; } @@ -425,9 +437,9 @@ uint32 FontRenderer::buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, u // remember - it's RDSPR_DISPLAYALIGN uint16 text_left_margin = TEXT_MARGIN; - uint16 text_right_margin = 640 - TEXT_MARGIN - frame_head->width; + uint16 text_right_margin = 640 - TEXT_MARGIN - frame_head.width; uint16 text_top_margin = TEXT_MARGIN; - uint16 text_bottom_margin = 400 - TEXT_MARGIN - frame_head->height; + uint16 text_bottom_margin = 400 - TEXT_MARGIN - frame_head.height; // Move if too far left or too far right @@ -460,19 +472,21 @@ uint32 FontRenderer::buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, u void FontRenderer::printTextBlocs() { for (uint i = 0; i < MAX_text_blocs; i++) { if (_blocList[i].text_mem) { - FrameHeader *frame = (FrameHeader *)_blocList[i].text_mem; + FrameHeader frame_head; SpriteInfo spriteInfo; + frame_head.read(_blocList[i].text_mem); + spriteInfo.x = _blocList[i].x; spriteInfo.y = _blocList[i].y; - spriteInfo.w = frame->width; - spriteInfo.h = frame->height; + spriteInfo.w = frame_head.width; + spriteInfo.h = frame_head.height; spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; spriteInfo.type = _blocList[i].type; spriteInfo.blend = 0; - spriteInfo.data = _blocList[i].text_mem + sizeof(FrameHeader); + spriteInfo.data = _blocList[i].text_mem + FrameHeader::size(); spriteInfo.colourTable = 0; uint32 rv = _vm->_screen->drawSprite(&spriteInfo); @@ -528,7 +542,7 @@ void Sword2Engine::initialiseFontResourceFlags() { // // But we get it from the text resource instead. - if (Logic::_scriptVars[DEMO]) + if (_logic->readVar(DEMO)) textLine = (char *)fetchTextLine(textFile, 451) + 2; else textLine = (char *)fetchTextLine(textFile, 54) + 2; diff --git a/sword2/maketext.h b/sword2/maketext.h index edf57b46e2..c3dc1d4a34 100644 --- a/sword2/maketext.h +++ b/sword2/maketext.h @@ -91,8 +91,8 @@ private: byte *buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines); uint16 charWidth(byte ch, uint32 fontRes); uint16 charHeight(uint32 fontRes); - FrameHeader* findChar(byte ch, byte *charSet); - void copyChar(FrameHeader *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen); + byte *findChar(byte ch, byte *charSet); + void copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen); public: FontRenderer(Sword2Engine *vm) : _vm(vm) { diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp index 7087b36097..c97cbb9fb1 100644 --- a/sword2/mouse.cpp +++ b/sword2/mouse.cpp @@ -74,9 +74,8 @@ Mouse::Mouse(Sword2Engine *vm) { _playerActivityDelay = 0; _realLuggageItem = 0; - _mouseSprite = NULL; - _mouseAnim = NULL; - _luggageAnim = NULL; + _mouseAnim.data = NULL; + _luggageAnim.data = NULL; // For the menus _totalTemp = 0; @@ -103,8 +102,8 @@ Mouse::Mouse(Sword2Engine *vm) { } Mouse::~Mouse() { - free(_mouseAnim); - free(_luggageAnim); + free(_mouseAnim.data); + free(_luggageAnim.data); for (int i = 0; i < 2; i++) for (int j = 0; j < RDMENU_MAXPOCKETS; j++) free(_icons[i][j]); @@ -128,26 +127,30 @@ void Mouse::resetMouseList() { _curMouse = 0; } -void Mouse::registerMouse(ObjectMouse *ob_mouse, BuildUnit *build_unit) { - if (!ob_mouse->pointer) - return; - +void Mouse::registerMouse(byte *ob_mouse, BuildUnit *build_unit) { assert(_curMouse < TOTAL_mouse_list); + ObjectMouse mouse; + + mouse.read(ob_mouse); + + if (!mouse.pointer) + return; + if (build_unit) { _mouseList[_curMouse].rect.left = build_unit->x; _mouseList[_curMouse].rect.top = build_unit->y; _mouseList[_curMouse].rect.right = 1 + build_unit->x + build_unit->scaled_width; _mouseList[_curMouse].rect.bottom = 1 + build_unit->y + build_unit->scaled_height; } else { - _mouseList[_curMouse].rect.left = ob_mouse->x1; - _mouseList[_curMouse].rect.top = ob_mouse->y1; - _mouseList[_curMouse].rect.right = 1 + ob_mouse->x2; - _mouseList[_curMouse].rect.bottom = 1 + ob_mouse->y2; + _mouseList[_curMouse].rect.left = mouse.x1; + _mouseList[_curMouse].rect.top = mouse.y1; + _mouseList[_curMouse].rect.right = 1 + mouse.x2; + _mouseList[_curMouse].rect.bottom = 1 + mouse.y2; } - _mouseList[_curMouse].priority = ob_mouse->priority; - _mouseList[_curMouse].pointer = ob_mouse->pointer; + _mouseList[_curMouse].priority = mouse.priority; + _mouseList[_curMouse].pointer = mouse.pointer; // Change all COGS pointers to CROSHAIR. I'm guessing that this was a // design decision made in mid-development and they didn't want to go @@ -162,11 +165,11 @@ void Mouse::registerMouse(ObjectMouse *ob_mouse, BuildUnit *build_unit) { // If 'pointer_text' field is set, but the 'id' field isn't same is // current id then we don't want this "left over" pointer text - if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32) Logic::_scriptVars[ID]) + if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32)_vm->_logic->readVar(ID)) _mouseList[_curMouse].pointer_text = 0; // Get id from system variable 'id' which is correct for current object - _mouseList[_curMouse].id = Logic::_scriptVars[ID]; + _mouseList[_curMouse].id = _vm->_logic->readVar(ID); _curMouse++; } @@ -177,7 +180,7 @@ void Mouse::registerPointerText(int32 text_id) { // current object id - used for checking pointer_text when mouse area // registered (in fnRegisterMouse and fnRegisterFrame) - _mouseList[_curMouse].id = Logic::_scriptVars[ID]; + _mouseList[_curMouse].id = _vm->_logic->readVar(ID); _mouseList[_curMouse].pointer_text = text_id; } @@ -192,7 +195,7 @@ void Mouse::mouseEngine() { // If George is dead, the system menu is visible all the time, and is // the only thing that can be used. - if (Logic::_scriptVars[DEAD]) { + if (_vm->_logic->readVar(DEAD)) { if (_mouseMode != MOUSE_system_menu) { _mouseMode = MOUSE_system_menu; @@ -239,8 +242,10 @@ void Mouse::mouseEngine() { #if RIGHT_CLICK_CLEARS_LUGGAGE bool Mouse::heldIsInInventory() { + int32 object_held = (int32)_vm->_logic->readVar(OBJECT_HELD); + for (uint i = 0; i < _totalMasters; i++) { - if ((uint32) _masterMenuList[i].icon_resource == Logic::_scriptVars[OBJECT_HELD]) + if (_masterMenuList[i].icon_resource == object_held) return true; } return false; @@ -274,7 +279,7 @@ void Mouse::systemMenuMouse() { // If the mouse is moved off the menu, close it. Unless the player is // dead, in which case the menu should always be visible. - if (_pos.y > 0 && !Logic::_scriptVars[DEAD]) { + if (_pos.y > 0 && !_vm->_logic->readVar(DEAD)) { _mouseMode = MOUSE_normal; hideMenu(RDMENU_TOP); return; @@ -297,14 +302,14 @@ void Mouse::systemMenuMouse() { // No save when dead - if (icon_list[hit] == SAVE_ICON && Logic::_scriptVars[DEAD]) + if (icon_list[hit] == SAVE_ICON && _vm->_logic->readVar(DEAD)) return; // Gray out all he icons, except the one that was clicked for (int i = 0; i < ARRAYSIZE(icon_list); i++) { if (i != hit) { - icon = _vm->_resman->openResource(icon_list[i]) + sizeof(StandardHeader); + icon = _vm->_resman->openResource(icon_list[i]) + ResHeader::size(); setMenuIcon(RDMENU_TOP, i, icon); _vm->_resman->closeResource(icon_list[i]); } @@ -364,7 +369,7 @@ void Mouse::systemMenuMouse() { // Menu stays open on death screen. Otherwise it's closed. - if (!Logic::_scriptVars[DEAD]) { + if (!_vm->_logic->readVar(DEAD)) { _mouseMode = MOUSE_normal; hideMenu(RDMENU_TOP); } else { @@ -432,7 +437,7 @@ void Mouse::dragMouse() { #if RIGHT_CLICK_CLEARS_LUGGAGE if ((me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - Logic::_scriptVars[OBJECT_HELD] = 0; + _vm->_logic->writeVar(OBJECT_HELD, 0); _menuSelectedPos = 0; _mouseMode = MOUSE_menu; setLuggage(0); @@ -458,25 +463,25 @@ void Mouse::dragMouse() { // Set global script variable 'button'. We know that it was the // left button, not the right one. - Logic::_scriptVars[LEFT_BUTTON] = 1; - Logic::_scriptVars[RIGHT_BUTTON] = 0; + _vm->_logic->writeVar(LEFT_BUTTON, 1); + _vm->_logic->writeVar(RIGHT_BUTTON, 0); // These might be required by the action script about to be run ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - Logic::_scriptVars[MOUSE_X] = _pos.x + screenInfo->scroll_offset_x; - Logic::_scriptVars[MOUSE_Y] = _pos.y + screenInfo->scroll_offset_y; + _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); + _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); // For scripts to know what's been clicked. First used for // 'room_13_turning_script' in object 'biscuits_13' - Logic::_scriptVars[CLICKED_ID] = _mouseTouching; + _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); debug(2, "Used \"%s\" on \"%s\"", - _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); + _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), + _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); // Hide menu - back to normal menu mode @@ -499,15 +504,15 @@ void Mouse::dragMouse() { _mouseMode = MOUSE_menu; setLuggage(0); - if ((uint) hit == _menuSelectedPos) { + if ((uint)hit == _menuSelectedPos) { // If we clicked on the same icon again, reset the first icon - Logic::_scriptVars[OBJECT_HELD] = 0; + _vm->_logic->writeVar(OBJECT_HELD, 0); _menuSelectedPos = 0; } else { // Otherwise, combine the two icons - Logic::_scriptVars[COMBINE_BASE] = _masterMenuList[hit].icon_resource; + _vm->_logic->writeVar(COMBINE_BASE, _masterMenuList[hit].icon_resource); _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); // Turn off mouse now, to prevent player trying to click @@ -516,8 +521,8 @@ void Mouse::dragMouse() { hideMouse(); debug(2, "Used \"%s\" on \"%s\"", - _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - _vm->fetchObjectName(Logic::_scriptVars[COMBINE_BASE], buf2)); + _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), + _vm->_resman->fetchName(_vm->_logic->readVar(COMBINE_BASE), buf2)); } // Refresh the menu @@ -555,12 +560,12 @@ void Mouse::menuMouse() { // resource id. _examiningMenuIcon = true; - Logic::_scriptVars[OBJECT_HELD] = _masterMenuList[hit].icon_resource; + _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); // Must clear this so next click on exit becomes 1st click // again - Logic::_scriptVars[EXIT_CLICK_ID] = 0; + _vm->_logic->writeVar(EXIT_CLICK_ID, 0); _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); @@ -574,7 +579,7 @@ void Mouse::menuMouse() { hideMouse(); debug(2, "Right-click on \"%s\" icon", - _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); + _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); return; } @@ -587,13 +592,13 @@ void Mouse::menuMouse() { _mouseMode = MOUSE_drag; _menuSelectedPos = hit; - Logic::_scriptVars[OBJECT_HELD] = _masterMenuList[hit].icon_resource; + _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); _currentLuggageResource = _masterMenuList[hit].luggage_resource; // Must clear this so next click on exit becomes 1st click // again - Logic::_scriptVars[EXIT_CLICK_ID] = 0; + _vm->_logic->writeVar(EXIT_CLICK_ID, 0); // Refresh the menu @@ -602,7 +607,7 @@ void Mouse::menuMouse() { setLuggage(_masterMenuList[hit].luggage_resource); debug(2, "Left-clicked on \"%s\" icon - switch to drag mode", - _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf)); + _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); } } @@ -616,7 +621,7 @@ void Mouse::normalMouse() { // big-object menu lock situation, of if the player is dragging an // object. - if (_pos.y < 0 && !_mouseModeLocked && !Logic::_scriptVars[OBJECT_HELD]) { + if (_pos.y < 0 && !_mouseModeLocked && !_vm->_logic->readVar(OBJECT_HELD)) { _mouseMode = MOUSE_system_menu; if (_mouseTouching) { @@ -644,7 +649,7 @@ void Mouse::normalMouse() { // object, even if the inventory menu was closed after the // first object was selected. - if (!Logic::_scriptVars[OBJECT_HELD]) + if (!_vm->_logic->readVar(OBJECT_HELD)) _mouseMode = MOUSE_menu; else _mouseMode = MOUSE_drag; @@ -686,8 +691,8 @@ void Mouse::normalMouse() { if (button_down) { // set both (x1,y1) and (x2,y2) to this point - _vm->_debugger->_rectX1 = _vm->_debugger->_rectX2 = (uint32) _pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32) _pos.y + screenInfo->scroll_offset_y; + _vm->_debugger->_rectX1 = _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; + _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; _vm->_debugger->_draggingRectangle = 1; } } else if (_vm->_debugger->_draggingRectangle == 1) { @@ -699,8 +704,8 @@ void Mouse::normalMouse() { _vm->_debugger->_draggingRectangle = 2; } else { // drag rectangle - _vm->_debugger->_rectX2 = (uint32) _pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY2 = (uint32) _pos.y + screenInfo->scroll_offset_y; + _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; + _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; } } else { // currently locked to avoid knocking out of place @@ -716,8 +721,8 @@ void Mouse::normalMouse() { } #if RIGHT_CLICK_CLEARS_LUGGAGE - if (Logic::_scriptVars[OBJECT_HELD] && (me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - Logic::_scriptVars[OBJECT_HELD] = 0; + if (_vm->_logic->readVar(OBJECT_HELD) && (me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { + _vm->_logic->writeVar(OBJECT_HELD, 0); _menuSelectedPos = 0; setLuggage(0); return; @@ -743,29 +748,29 @@ void Mouse::normalMouse() { // PLAYER_ACTION script variable - whatever catches this must reset to // 0 again - // Logic::_scriptVars[PLAYER_ACTION] = _mouseTouching; + // _vm->_logic->writeVar(PLAYER_ACTION, _mouseTouching); // Idle or router-anim will catch it // Set global script variable 'button' if (me->buttons & RD_LEFTBUTTONDOWN) { - Logic::_scriptVars[LEFT_BUTTON] = 1; - Logic::_scriptVars[RIGHT_BUTTON] = 0; + _vm->_logic->writeVar(LEFT_BUTTON, 1); + _vm->_logic->writeVar(RIGHT_BUTTON, 0); _buttonClick = 0; // for re-click } else { - Logic::_scriptVars[LEFT_BUTTON] = 0; - Logic::_scriptVars[RIGHT_BUTTON] = 1; + _vm->_logic->writeVar(LEFT_BUTTON, 0); + _vm->_logic->writeVar(RIGHT_BUTTON, 1); _buttonClick = 1; // for re-click } // These might be required by the action script about to be run ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - Logic::_scriptVars[MOUSE_X] = _pos.x + screenInfo->scroll_offset_x; - Logic::_scriptVars[MOUSE_Y] = _pos.y + screenInfo->scroll_offset_y; + _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); + _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); - if (_mouseTouching == Logic::_scriptVars[EXIT_CLICK_ID] && (me->buttons & RD_LEFTBUTTONDOWN)) { + if (_mouseTouching == _vm->_logic->readVar(EXIT_CLICK_ID) && (me->buttons & RD_LEFTBUTTONDOWN)) { // It's the exit double click situation. Let the existing // interaction continue and start fading down. Switch the human // off too @@ -775,8 +780,8 @@ void Mouse::normalMouse() { // Tell the walker - Logic::_scriptVars[EXIT_FADING] = 1; - } else if (_oldButton == _buttonClick && _mouseTouching == Logic::_scriptVars[CLICKED_ID] && _mousePointerRes != NORMAL_MOUSE_ID) { + _vm->_logic->writeVar(EXIT_FADING, 1); + } else if (_oldButton == _buttonClick && _mouseTouching == _vm->_logic->readVar(CLICKED_ID) && _mousePointerRes != NORMAL_MOUSE_ID) { // Re-click. Do nothing, except on floors } else { // For re-click @@ -786,28 +791,28 @@ void Mouse::normalMouse() { // For scripts to know what's been clicked. First used for // 'room_13_turning_script' in object 'biscuits_13' - Logic::_scriptVars[CLICKED_ID] = _mouseTouching; + _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); // Must clear these two double-click control flags - do it here // so reclicks after exit clicks are cleared up - Logic::_scriptVars[EXIT_CLICK_ID] = 0; - Logic::_scriptVars[EXIT_FADING] = 0; + _vm->_logic->writeVar(EXIT_CLICK_ID, 0); + _vm->_logic->writeVar(EXIT_FADING, 0); _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); byte buf1[NAME_LEN], buf2[NAME_LEN]; - if (Logic::_scriptVars[OBJECT_HELD]) + if (_vm->_logic->readVar(OBJECT_HELD)) debug(2, "Used \"%s\" on \"%s\"", - _vm->fetchObjectName(Logic::_scriptVars[OBJECT_HELD], buf1), - _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf2)); - else if (Logic::_scriptVars[LEFT_BUTTON]) + _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), + _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); + else if (_vm->_logic->readVar(LEFT_BUTTON)) debug(2, "Left-clicked on \"%s\"", - _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); + _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); else // RIGHT BUTTON debug(2, "Right-clicked on \"%s\"", - _vm->fetchObjectName(Logic::_scriptVars[CLICKED_ID], buf1)); + _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); } } @@ -817,9 +822,12 @@ uint32 Mouse::chooseMouse() { uint i; - Logic::_scriptVars[AUTO_SELECTED] = 0; + _vm->_logic->writeVar(AUTO_SELECTED, 0); + + uint32 in_subject = _vm->_logic->readVar(IN_SUBJECT); + uint32 object_held = _vm->_logic->readVar(OBJECT_HELD); - if (Logic::_scriptVars[OBJECT_HELD]) { + if (object_held) { // The player used an object on a person. In this case it // triggered a conversation menu. Act as if the user tried to // talk to the person about that object. If the person doesn't @@ -827,8 +835,8 @@ uint32 Mouse::chooseMouse() { uint32 response = _defaultResponseId; - for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { - if (_subjectList[i].res == Logic::_scriptVars[OBJECT_HELD]) { + for (i = 0; i < in_subject; i++) { + if (_subjectList[i].res == object_held) { response = _subjectList[i].ref; break; } @@ -837,12 +845,12 @@ uint32 Mouse::chooseMouse() { // The user won't be holding the object any more, and the // conversation menu will be closed. - Logic::_scriptVars[OBJECT_HELD] = 0; - Logic::_scriptVars[IN_SUBJECT] = 0; + _vm->_logic->writeVar(OBJECT_HELD, 0); + _vm->_logic->writeVar(IN_SUBJECT, 0); return response; } - if (Logic::_scriptVars[CHOOSER_COUNT_FLAG] == 0 && Logic::_scriptVars[IN_SUBJECT] == 1 && _subjectList[0].res == EXIT_ICON) { + if (_vm->_logic->readVar(CHOOSER_COUNT_FLAG) == 0 && in_subject == 1 && _subjectList[0].res == EXIT_ICON) { // This is the first time the chooser is coming up in this // conversation, there is only one subject and that's the // EXIT icon. @@ -853,8 +861,8 @@ uint32 Mouse::chooseMouse() { // The conversation menu will be closed. We set AUTO_SELECTED // because the speech script depends on it. - Logic::_scriptVars[AUTO_SELECTED] = 1; - Logic::_scriptVars[IN_SUBJECT] = 0; + _vm->_logic->writeVar(AUTO_SELECTED, 1); + _vm->_logic->writeVar(IN_SUBJECT, 0); return _subjectList[0].ref; } @@ -863,11 +871,11 @@ uint32 Mouse::chooseMouse() { if (!_choosing) { // This is a new conversation menu. - if (!Logic::_scriptVars[IN_SUBJECT]) + if (!in_subject) error("fnChoose with no subjects"); - for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { - icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP; + for (i = 0; i < in_subject; i++) { + icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size() + RDMENU_ICONWIDE * RDMENU_ICONDEEP; setMenuIcon(RDMENU_BOTTOM, i, icon); _vm->_resman->closeResource(_subjectList[i].res); } @@ -878,7 +886,7 @@ uint32 Mouse::chooseMouse() { showMenu(RDMENU_BOTTOM); setMouse(NORMAL_MOUSE_ID); _choosing = true; - return (uint32) -1; + return (uint32)-1; } // The menu is there - we're just waiting for a click. We only care @@ -890,33 +898,33 @@ uint32 Mouse::chooseMouse() { getPos(mouseX, mouseY); if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || mouseY < 400) - return (uint32) -1; + return (uint32)-1; // Check for click on a menu. - int hit = _vm->_mouse->menuClick(Logic::_scriptVars[IN_SUBJECT]); + int hit = _vm->_mouse->menuClick(in_subject); if (hit < 0) - return (uint32) -1; + return (uint32)-1; // Hilight the clicked icon by greying the others. This can look a bit // odd when you click on the exit icon, but there are also cases when // it looks strange if you don't do it. - for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { - if ((int) i != hit) { - icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader); + for (i = 0; i < in_subject; i++) { + if ((int)i != hit) { + icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size(); _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); _vm->_resman->closeResource(_subjectList[i].res); } } // For non-speech scripts that manually call the chooser - Logic::_scriptVars[RESULT] = _subjectList[hit].res; + _vm->_logic->writeVar(RESULT, _subjectList[hit].res); // The conversation menu will be closed _choosing = false; - Logic::_scriptVars[IN_SUBJECT] = 0; + _vm->_logic->writeVar(IN_SUBJECT, 0); setMouse(0); return _subjectList[hit].ref; @@ -973,13 +981,13 @@ void Mouse::mouseOnOff() { setMouse(pointer_type); // setup luggage icon - if (Logic::_scriptVars[OBJECT_HELD]) { + if (_vm->_logic->readVar(OBJECT_HELD)) { setLuggage(_currentLuggageResource); } } else { byte buf[NAME_LEN]; - error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->fetchObjectName(_mouseTouching, buf)); + error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->_resman->fetchName(_mouseTouching, buf)); } } else if (_oldMouseTouching && !_mouseTouching) { // the cursor has moved off something - reset cursor to @@ -1024,8 +1032,8 @@ void Mouse::setMouse(uint32 res) { _mousePointerRes = res; if (res) { - byte *icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); - uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); + uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); // don't pulse the normal pointer - just do the regular anim // loop @@ -1046,8 +1054,8 @@ void Mouse::setLuggage(uint32 res) { _realLuggageItem = res; if (res) { - byte *icon = _vm->_resman->openResource(res) + sizeof(StandardHeader); - uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader); + byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); + uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); setLuggageAnim(icon, len); _vm->_resman->closeResource(res); @@ -1058,7 +1066,7 @@ void Mouse::setLuggage(uint32 res) { void Mouse::setObjectHeld(uint32 res) { setLuggage(res); - Logic::_scriptVars[OBJECT_HELD] = res; + _vm->_logic->writeVar(OBJECT_HELD, res); _currentLuggageResource = res; // mode locked - no menu available @@ -1263,7 +1271,7 @@ void Mouse::hideMouse() { // it and when combining objects // for logic scripts - Logic::_scriptVars[MOUSE_AVAILABLE] = 0; + _vm->_logic->writeVar(MOUSE_AVAILABLE, 0); // human/mouse off _mouseStatus = true; @@ -1280,7 +1288,7 @@ void Mouse::noHuman() { // special menus use hideMouse() // Don't hide menu in conversations - if (Logic::_scriptVars[TALK_FLAG] == 0) + if (_vm->_logic->readVar(TALK_FLAG) == 0) hideMenu(RDMENU_BOTTOM); if (_mouseMode == MOUSE_system_menu) { @@ -1292,7 +1300,7 @@ void Mouse::noHuman() { void Mouse::addHuman() { // For logic scripts - Logic::_scriptVars[MOUSE_AVAILABLE] = 1; + _vm->_logic->writeVar(MOUSE_AVAILABLE, 1); if (_mouseStatus) { // Force engine to choose a cursor @@ -1301,7 +1309,7 @@ void Mouse::addHuman() { } // Clear this to reset no-second-click system - Logic::_scriptVars[CLICKED_ID] = 0; + _vm->_logic->writeVar(CLICKED_ID, 0); // This is now done outside the OBJECT_HELD check in case it's set to // zero before now! @@ -1311,13 +1319,13 @@ void Mouse::addHuman() { _mouseModeLocked = false; - if (Logic::_scriptVars[OBJECT_HELD]) { + if (_vm->_logic->readVar(OBJECT_HELD)) { // Was dragging something around - need to clear this again - Logic::_scriptVars[OBJECT_HELD] = 0; + _vm->_logic->writeVar(OBJECT_HELD, 0); // And these may also need clearing, just in case _examiningMenuIcon = false; - Logic::_scriptVars[COMBINE_BASE] = 0; + _vm->_logic->writeVar(COMBINE_BASE, 0); setLuggage(0); } @@ -1356,7 +1364,7 @@ void Mouse::addHuman() { void Mouse::refreshInventory() { // Can reset this now - Logic::_scriptVars[COMBINE_BASE] = 0; + _vm->_logic->writeVar(COMBINE_BASE, 0); // Cause 'object_held' icon to be greyed. The rest are coloured. _examiningMenuIcon = true; @@ -1365,9 +1373,9 @@ void Mouse::refreshInventory() { } void Mouse::startConversation() { - if (Logic::_scriptVars[TALK_FLAG] == 0) { + if (_vm->_logic->readVar(TALK_FLAG) == 0) { // See fnChooser & speech scripts - Logic::_scriptVars[CHOOSER_COUNT_FLAG] = 0; + _vm->_logic->writeVar(CHOOSER_COUNT_FLAG, 0); } noHuman(); @@ -1382,7 +1390,7 @@ void Mouse::endConversation() { } // In case DC forgets - Logic::_scriptVars[TALK_FLAG] = 0; + _vm->_logic->writeVar(TALK_FLAG, 0); } void Mouse::monitorPlayerActivity() { @@ -1405,9 +1413,9 @@ void Mouse::checkPlayerActivity(uint32 seconds) { if (_playerActivityDelay >= threshold) { _playerActivityDelay = 0; - Logic::_scriptVars[RESULT] = 1; + _vm->_logic->writeVar(RESULT, 1); } else - Logic::_scriptVars[RESULT] = 0; + _vm->_logic->writeVar(RESULT, 0); } void Mouse::pauseGame() { @@ -1421,7 +1429,7 @@ void Mouse::pauseGame() { } void Mouse::unpauseGame() { - if (Logic::_scriptVars[OBJECT_HELD] && _realLuggageItem) + if (_vm->_logic->readVar(OBJECT_HELD) && _realLuggageItem) setLuggage(_realLuggageItem); } diff --git a/sword2/mouse.h b/sword2/mouse.h index a1b8268eeb..b8e94afa0c 100644 --- a/sword2/mouse.h +++ b/sword2/mouse.h @@ -27,7 +27,6 @@ namespace Sword2 { -struct ObjectMouse; struct BuildUnit; // Menubar defines. @@ -62,10 +61,8 @@ enum { #define RDMENU_ICONSPACING 5 #define RDMENU_MAXPOCKETS 15 -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - +#define MOUSE_ANIM_HEADER_SIZE 6 + struct MouseAnim { uint8 runTimeComp; // type of runtime compression used for the // frame data @@ -74,11 +71,9 @@ struct MouseAnim { int8 yHotSpot; uint8 mousew; uint8 mouseh; -} GCC_PACK; -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif + byte *data; +}; // The MOUSE_holding mode is entered when the conversation menu is closed, and // exited when the mouse cursor moves off that menu area. I don't know why yet. @@ -145,13 +140,10 @@ private: uint32 _mousePointerRes; - struct MouseAnim *_mouseAnim; - struct MouseAnim *_luggageAnim; + MouseAnim _mouseAnim; + MouseAnim _luggageAnim; uint8 _mouseFrame; - byte *_mouseSprite; - int32 *_mouseOffsets; - int32 *_luggageOffset; uint32 _mouseMode; @@ -177,7 +169,7 @@ private: uint32 _menuSelectedPos; - void decompressMouse(byte *decomp, byte *comp, int width, int height, int pitch, int xOff = 0, int yOff = 0); + void decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff = 0, int yOff = 0); int32 setMouseAnim(byte *ma, int32 size, int32 mouseFlash); int32 setLuggageAnim(byte *la, int32 size); @@ -208,7 +200,7 @@ public: void resetMouseList(); - void registerMouse(ObjectMouse *ob_mouse, BuildUnit *build_unit); + void registerMouse(byte *ob_mouse, BuildUnit *build_unit); void registerPointerText(int32 text_id); void createPointerText(uint32 text_id, uint32 pointer_res); @@ -219,7 +211,7 @@ public: void processMenu(); - void addMenuObject(MenuObject *obj); + void addMenuObject(byte *ptr); void addSubject(int32 id, int32 ref); void buildMenu(); diff --git a/sword2/object.h b/sword2/object.h index 6f33ae80d8..19c1ddc1b5 100644 --- a/sword2/object.h +++ b/sword2/object.h @@ -21,11 +21,9 @@ #ifndef _SCRIPT_STRUCTURES #define _SCRIPT_STRUCTURES -namespace Sword2 { +#include "common/stream.h" -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif +namespace Sword2 { // these structures represent the broken up compact components // these here declared to the system must be the same as those declared to @@ -41,15 +39,64 @@ struct ObjectMouse { int32 y2; int32 priority; int32 pointer; // type (or resource id?) of pointer used over this area -} GCC_PACK; + + static const int size() { + return 24; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + x1 = readS.readSint32LE(); + y1 = readS.readSint32LE(); + x2 = readS.readSint32LE(); + y2 = readS.readSint32LE(); + priority = readS.readSint32LE(); + pointer = readS.readSint32LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeSint32LE(x1); + writeS.writeSint32LE(y1); + writeS.writeSint32LE(x2); + writeS.writeSint32LE(y2); + writeS.writeSint32LE(priority); + writeS.writeSint32LE(pointer); + } +}; // logic structure - contains fields used in logic script processing -struct ObjectLogic { - int32 looping; // 0 when first calling fn<function>; - // 1 when calling subsequent times in same loop - int32 pause; // pause count, used by fnPause() -} GCC_PACK; +class ObjectLogic { + // int32 looping; // 0 when first calling fn<function>; + // 1 when calling subsequent times in + // same loop + // int32 pause; // pause count, used by fnPause() + +private: + byte *_addr; + +public: + ObjectLogic(byte *addr) { + _addr = addr; + } + + static const int size() { + return 8; + } + + byte *data() { + return _addr; + } + + int32 getLooping() { return READ_LE_UINT32(_addr); } + int32 getPause() { return READ_LE_UINT32(_addr + 4); } + + void setLooping(int32 x) { WRITE_LE_UINT32(_addr, x); } + void setPause(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } +}; // status bits for 'type' field of ObjectGraphic) @@ -71,50 +118,161 @@ struct ObjectLogic { // graphic structure - contains fields appropriate to sprite output -struct ObjectGraphic { - int32 type; // see above - int32 anim_resource; // resource id of animation file - int32 anim_pc; // current frame number of animation -} GCC_PACK; +class ObjectGraphic { + // int32 type; // see above + // int32 anim_resource; // resource id of animation file + // int32 anim_pc; // current frame number of animation + +private: + byte *_addr; + +public: + ObjectGraphic(byte *addr) { + _addr = addr; + } + + static const int size() { + return 12; + } + + byte *data() { + return _addr; + } + + int32 getType() { return READ_LE_UINT32(_addr); } + int32 getAnimResource() { return READ_LE_UINT32(_addr + 4); } + int32 getAnimPc() { return READ_LE_UINT32(_addr + 8); } + + void setType(int32 x) { WRITE_LE_UINT32(_addr, x); } + void setAnimResource(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } + void setAnimPc(int32 x) { WRITE_LE_UINT32(_addr + 8, x); } +}; // speech structure - contains fields used by speech scripts & text output -struct ObjectSpeech { - int32 pen; // colour to use for body of characters - int32 width; // max width of text sprite - int32 command; // speech script command id - int32 ins1; // speech script instruction parameters (may need more now?) - int32 ins2; - int32 ins3; - int32 ins4; - int32 ins5; - int32 wait_state; // 0 not waiting, 1 waiting for next speech command -} GCC_PACK; +class ObjectSpeech { + // int32 pen; // colour to use for body of characters + // int32 width; // max width of text sprite + // int32 command; // speech script command id + // int32 ins1; // speech script instruction parameters + // int32 ins2; + // int32 ins3; + // int32 ins4; + // int32 ins5; + // int32 wait_state; // 0 not waiting, + // 1 waiting for next speech command + +private: + byte *_addr; + +public: + ObjectSpeech(byte *addr) { + _addr = addr; + } + + static const int size() { + return 36; + } + + byte *data() { + return _addr; + } + + int32 getPen() { return READ_LE_UINT32(_addr); } + int32 getWidth() { return READ_LE_UINT32(_addr + 4); } + int32 getCommand() { return READ_LE_UINT32(_addr + 8); } + int32 getIns1() { return READ_LE_UINT32(_addr + 12); } + int32 getIns2() { return READ_LE_UINT32(_addr + 16); } + int32 getIns3() { return READ_LE_UINT32(_addr + 20); } + int32 getIns4() { return READ_LE_UINT32(_addr + 24); } + int32 getIns5() { return READ_LE_UINT32(_addr + 28); } + int32 getWaitState() { return READ_LE_UINT32(_addr + 32); } + + void setPen(int32 x) { WRITE_LE_UINT32(_addr, x); } + void setWidth(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } + void setCommand(int32 x) { WRITE_LE_UINT32(_addr + 8, x); } + void setIns1(int32 x) { WRITE_LE_UINT32(_addr + 12, x); } + void setIns2(int32 x) { WRITE_LE_UINT32(_addr + 16, x); } + void setIns3(int32 x) { WRITE_LE_UINT32(_addr + 20, x); } + void setIns4(int32 x) { WRITE_LE_UINT32(_addr + 24, x); } + void setIns5(int32 x) { WRITE_LE_UINT32(_addr + 28, x); } + void setWaitState(int32 x) { WRITE_LE_UINT32(_addr + 32, x); } +}; // mega structure - contains fields used for mega-character & mega-set // processing -struct ObjectMega { - int32 NOT_USED_1; // only free roaming megas need to check this before registering their graphics for drawing - int32 NOT_USED_2; // id of floor on which we are standing - int32 NOT_USED_3; // id of object which we are getting to - int32 NOT_USED_4; // pixel distance to stand from player character when in conversation - int32 currently_walking; // number given us by the auto router - int32 walk_pc; // current frame number of walk-anim - int32 scale_a; // current scale factors, taken from floor data - int32 scale_b; - int32 feet_x; // mega feet coords - frame-offsets are added to these position mega frames - int32 feet_y; - int32 current_dir; // current dirction faced by mega; used by autorouter to determine turns required - int32 NOT_USED_5; // means were currently avoiding a collision (see fnWalk) - int32 megaset_res; // resource id of mega-set file - int32 NOT_USED_6; // NOT USED -} GCC_PACK; +class ObjectMega { + // int32 NOT_USED_1; // only free roaming megas need to + // check this before registering their + // graphics for drawing + // int32 NOT_USED_2; // id of floor on which we are standing + // int32 NOT_USED_3; // id of object which we are getting to + // int32 NOT_USED_4; // pixel distance to stand from player + // character when in conversation + // int32 currently_walking; // number given us by the auto router + // int32 walk_pc; // current frame number of walk-anim + // int32 scale_a; // current scale factors, taken from + // int32 scale_b; // floor data + // int32 feet_x; // mega feet coords - frame-offsets are + // int32 feet_y; // added to these position mega frames + // int32 current_dir; // current dirction faced by mega; used + // by autorouter to determine turns + // required + // int32 NOT_USED_5; // means were currently avoiding a + // collision (see fnWalk) + // int32 megaset_res; // resource id of mega-set file + // int32 NOT_USED_6; // NOT USED + +private: + byte *_addr; + +public: + ObjectMega(byte *addr) { + _addr = addr; + } + + static const int size() { + return 56; + } + + byte *data() { + return _addr; + } + + int32 getIsWalking() { return READ_LE_UINT32(_addr + 16); } + int32 getWalkPc() { return READ_LE_UINT32(_addr + 20); } + int32 getScaleA() { return READ_LE_UINT32(_addr + 24); } + int32 getScaleB() { return READ_LE_UINT32(_addr + 28); } + int32 getFeetX() { return READ_LE_UINT32(_addr + 32); } + int32 getFeetY() { return READ_LE_UINT32(_addr + 36); } + int32 getCurDir() { return READ_LE_UINT32(_addr + 40); } + int32 getMegasetRes() { return READ_LE_UINT32(_addr + 48); } + + void setIsWalking(int32 x) { WRITE_LE_UINT32(_addr + 16, x); } + void setWalkPc(int32 x) { WRITE_LE_UINT32(_addr + 20, x); } + void setScaleA(int32 x) { WRITE_LE_UINT32(_addr + 24, x); } + void setScaleB(int32 x) { WRITE_LE_UINT32(_addr + 28, x); } + void setFeetX(int32 x) { WRITE_LE_UINT32(_addr + 32, x); } + void setFeetY(int32 x) { WRITE_LE_UINT32(_addr + 36, x); } + void setCurDir(int32 x) { WRITE_LE_UINT32(_addr + 40, x); } + void setMegasetRes(int32 x) { WRITE_LE_UINT32(_addr + 48, x); } + + int32 calcScale() { + // Calc scale at which to print the sprite, based on feet + // y-coord & scaling constants (NB. 'scale' is actually + // 256 * true_scale, to maintain accuracy) + + // Ay+B gives 256 * scale ie. 256 * 256 * true_scale for even + // better accuracy, ie. scale = (Ay + B) / 256 + return (getScaleA() * getFeetY() + getScaleB()) / 256; + } +}; // walk-data structure - contains details of layout of frames in the // mega-set, and how they are to be used -struct ObjectWalkdata { +struct ObjectWalkdata { int32 nWalkFrames; // no. of frames per walk-cycle int32 usingStandingTurnFrames; // 0 = no 1 = yes int32 usingWalkingTurnFrames; // 0 = no 1 = yes @@ -124,11 +282,59 @@ struct ObjectWalkdata { int32 leadingLeg[8]; // leading leg for walk in each direction (0 = left 1 = right) int32 dx[8 * (12 + 1)]; // walk step distances in x direction int32 dy[8 * (12 + 1)]; // walk step distances in y direction -} GCC_PACK; -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif + static const int size() { + return 916; + } + + void read(byte *addr) { + Common::MemoryReadStream readS(addr, size()); + + nWalkFrames = readS.readUint32LE(); + usingStandingTurnFrames = readS.readUint32LE(); + usingWalkingTurnFrames = readS.readUint32LE(); + usingSlowInFrames = readS.readUint32LE(); + usingSlowOutFrames = readS.readUint32LE(); + + int i; + + for (i = 0; i < ARRAYSIZE(nSlowInFrames); i++) + nSlowInFrames[i] = readS.readUint32LE(); + + for (i = 0; i < ARRAYSIZE(leadingLeg); i++) + leadingLeg[i] = readS.readUint32LE(); + + for (i = 0; i < ARRAYSIZE(dx); i++) + dx[i] = readS.readUint32LE(); + + for (i = 0; i < ARRAYSIZE(dy); i++) + dy[i] = readS.readUint32LE(); + } + + void write(byte *addr) { + Common::MemoryWriteStream writeS(addr, size()); + + writeS.writeUint32LE(nWalkFrames); + writeS.writeUint32LE(usingStandingTurnFrames); + writeS.writeUint32LE(usingWalkingTurnFrames); + writeS.writeUint32LE(usingSlowInFrames); + writeS.writeUint32LE(usingSlowOutFrames); + + int i; + + for (i = 0; i < ARRAYSIZE(nSlowInFrames); i++) + writeS.writeUint32LE(nSlowInFrames[i]); + + for (i = 0; i < ARRAYSIZE(leadingLeg); i++) + writeS.writeUint32LE(leadingLeg[i]); + + for (i = 0; i < ARRAYSIZE(dx); i++) + writeS.writeUint32LE(dx[i]); + + for (i = 0; i < ARRAYSIZE(dy); i++) + writeS.writeUint32LE(dy[i]); + } +}; } // End of namespace Sword2 diff --git a/sword2/protocol.cpp b/sword2/protocol.cpp index 872b7d8063..f93f1f0b3c 100644 --- a/sword2/protocol.cpp +++ b/sword2/protocol.cpp @@ -30,9 +30,11 @@ namespace Sword2 { */ byte *Sword2Engine::fetchPalette(byte *screenFile) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); + MultiScreenHeader mscreenHeader; - byte *palette = (byte *)mscreenHeader + mscreenHeader->palette; + mscreenHeader.read(screenFile + ResHeader::size()); + + byte *palette = screenFile + ResHeader::size() + mscreenHeader.palette; // Always set colour 0 to black, because while most background screen // palettes have a bright colour 0 it should come out as black in the @@ -52,9 +54,11 @@ byte *Sword2Engine::fetchPalette(byte *screenFile) { */ byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); + MultiScreenHeader mscreenHeader; + + mscreenHeader.read(screenFile + ResHeader::size()); - return (byte *)mscreenHeader + mscreenHeader->paletteTable; + return screenFile + ResHeader::size() + mscreenHeader.paletteTable; } /** @@ -62,11 +66,12 @@ byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) { * the screen file. */ -ScreenHeader *Sword2Engine::fetchScreenHeader(byte *screenFile) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); - ScreenHeader *screenHeader = (ScreenHeader *)((byte *)mscreenHeader + mscreenHeader->screen); +byte *Sword2Engine::fetchScreenHeader(byte *screenFile) { + MultiScreenHeader mscreenHeader; + + mscreenHeader.read(screenFile + ResHeader::size()); - return screenHeader; + return screenFile + ResHeader::size() + mscreenHeader.screen; } /** @@ -75,19 +80,19 @@ ScreenHeader *Sword2Engine::fetchScreenHeader(byte *screenFile) { * the number of layers on this screen. */ -LayerHeader *Sword2Engine::fetchLayerHeader(byte *screenFile, uint16 layerNo) { +byte *Sword2Engine::fetchLayerHeader(byte *screenFile, uint16 layerNo) { #ifdef SWORD2_DEBUG - ScreenHeader *screenHead = fetchScreenHeader(screenFile); + ScreenHeader screenHead; - if (layerNo > screenHead->noLayers - 1) - error("fetchLayerHeader(%d) invalid layer number!", layerNo); + screenHead.read(fetchScreenHeader(screenFile)); + assert(layerNo < screenHead.noLayers); #endif - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); + MultiScreenHeader mscreenHeader; - LayerHeader *layerHeader = (LayerHeader *)((byte *)mscreenHeader + mscreenHeader->layers + (layerNo * sizeof(LayerHeader))); + mscreenHeader.read(screenFile + ResHeader::size()); - return layerHeader; + return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size(); } /** @@ -96,9 +101,11 @@ LayerHeader *Sword2Engine::fetchLayerHeader(byte *screenFile, uint16 layerNo) { */ byte *Sword2Engine::fetchShadingMask(byte *screenFile) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); + MultiScreenHeader mscreenHeader; - return (byte *)mscreenHeader + mscreenHeader->maskOffset; + mscreenHeader.read(screenFile + ResHeader::size()); + + return screenFile + ResHeader::size() + mscreenHeader.maskOffset; } /** @@ -106,8 +113,8 @@ byte *Sword2Engine::fetchShadingMask(byte *screenFile) { * anim file. */ -AnimHeader *Sword2Engine::fetchAnimHeader(byte *animFile) { - return (AnimHeader *)(animFile + sizeof(StandardHeader)); +byte *Sword2Engine::fetchAnimHeader(byte *animFile) { + return animFile + ResHeader::size(); } /** @@ -116,15 +123,17 @@ AnimHeader *Sword2Engine::fetchAnimHeader(byte *animFile) { * number exceeds the number of frames in this anim. */ -CdtEntry *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) { - AnimHeader *animHead = fetchAnimHeader(animFile); - +byte *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) { #ifdef SWORD2_DEBUG + AnimHeader animHead; + + animHead.read(fetchAnimHeader(animFile)); + if (frameNo > animHead->noAnimFrames - 1) - error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead->noAnimFrames); + error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead.noAnimFrames); #endif - return (CdtEntry *)((byte *)animHead + sizeof(AnimHeader) + frameNo * sizeof(CdtEntry)); + return fetchAnimHeader(animFile) + AnimHeader::size() + frameNo * CdtEntry::size(); } /** @@ -133,60 +142,54 @@ CdtEntry *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) { * exceeds the number of frames in this anim */ -FrameHeader *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) { +byte *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) { // required address = (address of the start of the anim header) + frameOffset - return (FrameHeader *)(animFile + sizeof(StandardHeader) + fetchCdtEntry(animFile, frameNo)->frameOffset); + CdtEntry cdt; + + cdt.read(fetchCdtEntry(animFile, frameNo)); + + return animFile + ResHeader::size() + cdt.frameOffset; } /** * Returns a pointer to the requested parallax layer data. */ -Parallax *Sword2Engine::fetchBackgroundParallaxLayer(byte *screenFile, int layer) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); +byte *Sword2Engine::fetchBackgroundParallaxLayer(byte *screenFile, int layer) { + MultiScreenHeader mscreenHeader; -#ifdef SWORD2_DEBUG - if (mscreenHeader->bg_parallax[layer] == 0) - error("fetchBackgroundParallaxLayer(%d) - No parallax layer exists", layer); -#endif + mscreenHeader.read(screenFile + ResHeader::size()); + assert(mscreenHeader.bg_parallax[layer]); - return (Parallax *)((byte *)mscreenHeader + mscreenHeader->bg_parallax[layer]); + return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer]; } -Parallax *Sword2Engine::fetchBackgroundLayer(byte *screenFile) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); +byte *Sword2Engine::fetchBackgroundLayer(byte *screenFile) { + MultiScreenHeader mscreenHeader; -#ifdef SWORD2_DEBUG - if (mscreenHeader->screen == 0) - error("fetchBackgroundLayer (%d) - No background layer exists"); -#endif + mscreenHeader.read(screenFile + ResHeader::size()); + assert(mscreenHeader.screen); - return (Parallax *)((byte *)mscreenHeader + mscreenHeader->screen + sizeof(ScreenHeader)); + return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size(); } -Parallax *Sword2Engine::fetchForegroundParallaxLayer(byte *screenFile, int layer) { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)(screenFile + sizeof(StandardHeader)); +byte *Sword2Engine::fetchForegroundParallaxLayer(byte *screenFile, int layer) { + MultiScreenHeader mscreenHeader; -#ifdef SWORD2_DEBUG - if (mscreenHeader->fg_parallax[layer] == 0) - error("fetchForegroundParallaxLayer(%d) - No parallax layer exists", layer); -#endif + mscreenHeader.read(screenFile + ResHeader::size()); + assert(mscreenHeader.fg_parallax[layer]); - return (Parallax *)((byte *)mscreenHeader + mscreenHeader->fg_parallax[layer]); + return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer]; } -static byte errorLine[128]; - byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) { - StandardHeader *fileHeader; - uint32 *point; - - TextHeader *text_header = (TextHeader *)(file + sizeof(StandardHeader)); + TextHeader text_header; + static byte errorLine[128]; - if (text_line >= text_header->noOfLines) { - fileHeader = (StandardHeader *)file; - sprintf((char *)errorLine, "xxMissing line %d of %s (only 0..%d)", text_line, fileHeader->name, text_header->noOfLines - 1); + text_header.read(file + ResHeader::size()); + if (text_line >= text_header.noOfLines) { + sprintf((char *)errorLine, "xxMissing line %d of %s (only 0..%d)", text_line, _resman->fetchName(file), text_header.noOfLines - 1); // first 2 chars are NULL so that actor-number comes out as '0' errorLine[0] = 0; @@ -194,27 +197,19 @@ byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) { return errorLine; } - // point to the lookup table - point = (uint32 *)text_header + 1; + // The "number of lines" field is followed by a lookup table - return (byte *)(file + READ_LE_UINT32(point + text_line)); + return file + READ_LE_UINT32(file + ResHeader::size() + 4 + 4 * text_line); } - // Used for testing text & speech (see fnISpeak in speech.cpp) bool Sword2Engine::checkTextLine(byte *file, uint32 text_line) { - TextHeader *text_header = (TextHeader *)(file + sizeof(StandardHeader)); - - return text_line < text_header->noOfLines; -} + TextHeader text_header; -byte *Sword2Engine::fetchObjectName(int32 resourceId, byte *buf) { - StandardHeader *header = (StandardHeader *)_resman->openResource(resourceId); + text_header.read(file + ResHeader::size()); - memcpy(buf, header->name, NAME_LEN); - _resman->closeResource(resourceId); - return buf; + return text_line < text_header.noOfLines; } } // End of namespace Sword2 diff --git a/sword2/resman.cpp b/sword2/resman.cpp index 70bc5cf7df..dfb6d1690e 100644 --- a/sword2/resman.cpp +++ b/sword2/resman.cpp @@ -43,18 +43,10 @@ namespace Sword2 { // resource.tab which is a table which tells us which cluster a resource // is located in and the number within the cluster -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - struct CdInf { uint8 clusterName[20]; // Null terminated cluster name. uint8 cd; // Cd cluster is on and whether it is on the local drive or not. -} GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif +}; ResourceManager::ResourceManager(Sword2Engine *vm) { _vm = vm; @@ -201,192 +193,6 @@ ResourceManager::~ResourceManager() { free(_resConvTable); } -// Quick macro to make swapping in-place easier to write - -#define SWAP16(x) x = SWAP_BYTES_16(x) -#define SWAP32(x) x = SWAP_BYTES_32(x) - -void convertEndian(byte *file, uint32 len) { - int i; - StandardHeader *hdr = (StandardHeader *)file; - - file += sizeof(StandardHeader); - - SWAP32(hdr->compSize); - SWAP32(hdr->decompSize); - - switch (hdr->fileType) { - case ANIMATION_FILE: { - AnimHeader *animHead = (AnimHeader *)file; - - SWAP16(animHead->noAnimFrames); - SWAP16(animHead->feetStartX); - SWAP16(animHead->feetStartY); - SWAP16(animHead->feetEndX); - SWAP16(animHead->feetEndY); - SWAP16(animHead->blend); - - CdtEntry *cdtEntry = (CdtEntry *)(file + sizeof(AnimHeader)); - for (i = 0; i < animHead->noAnimFrames; i++, cdtEntry++) { - SWAP16(cdtEntry->x); - SWAP16(cdtEntry->y); - SWAP32(cdtEntry->frameOffset); - - FrameHeader *frameHeader = (FrameHeader *)(file + cdtEntry->frameOffset); - // Quick trick to prevent us from incorrectly applying the endian - // fixes multiple times. This assumes that frames are less than 1 MB - // and have height/width less than 4096. - if ((frameHeader->compSize & 0xFFF00000) || - (frameHeader->width & 0xF000) || - (frameHeader->height & 0xF000)) { - SWAP32(frameHeader->compSize); - SWAP16(frameHeader->width); - SWAP16(frameHeader->height); - } - } - break; - } - case SCREEN_FILE: { - MultiScreenHeader *mscreenHeader = (MultiScreenHeader *)file; - - SWAP32(mscreenHeader->palette); - SWAP32(mscreenHeader->bg_parallax[0]); - SWAP32(mscreenHeader->bg_parallax[1]); - SWAP32(mscreenHeader->screen); - SWAP32(mscreenHeader->fg_parallax[0]); - SWAP32(mscreenHeader->fg_parallax[1]); - SWAP32(mscreenHeader->layers); - SWAP32(mscreenHeader->paletteTable); - SWAP32(mscreenHeader->maskOffset); - - // screenHeader - ScreenHeader *screenHeader = (ScreenHeader *)(file + mscreenHeader->screen); - - SWAP16(screenHeader->width); - SWAP16(screenHeader->height); - SWAP16(screenHeader->noLayers); - - // layerHeader - LayerHeader *layerHeader = (LayerHeader *)(file + mscreenHeader->layers); - for (i = 0; i < screenHeader->noLayers; i++, layerHeader++) { - SWAP16(layerHeader->x); - SWAP16(layerHeader->y); - SWAP16(layerHeader->width); - SWAP16(layerHeader->height); - SWAP32(layerHeader->maskSize); - SWAP32(layerHeader->offset); - } - - // backgroundParallaxLayer - Parallax *parallax; - int offset; - offset = mscreenHeader->bg_parallax[0]; - if (offset > 0) { - parallax = (Parallax *)(file + offset); - SWAP16(parallax->w); - SWAP16(parallax->h); - } - - offset = mscreenHeader->bg_parallax[1]; - if (offset > 0) { - parallax = (Parallax *)(file + offset); - SWAP16(parallax->w); - SWAP16(parallax->h); - } - - // backgroundLayer - offset = mscreenHeader->screen + sizeof(ScreenHeader); - if (offset > 0) { - parallax = (Parallax *)(file + offset); - SWAP16(parallax->w); - SWAP16(parallax->h); - } - - // foregroundParallaxLayer - offset = mscreenHeader->fg_parallax[0]; - if (offset > 0) { - parallax = (Parallax *)(file + offset); - SWAP16(parallax->w); - SWAP16(parallax->h); - } - - offset = mscreenHeader->fg_parallax[1]; - if (offset > 0) { - parallax = (Parallax *)(file + offset); - SWAP16(parallax->w); - SWAP16(parallax->h); - } - break; - } - case GAME_OBJECT: { - ObjectHub *objectHub = (ObjectHub *)file; - - objectHub->type = (int) SWAP_BYTES_32(objectHub->type); - SWAP32(objectHub->logic_level); - - for (i = 0; i < TREE_SIZE; i++) { - SWAP32(objectHub->logic[i]); - SWAP32(objectHub->script_id[i]); - SWAP32(objectHub->script_pc[i]); - } - break; - } - case WALK_GRID_FILE: { - WalkGridHeader *walkGridHeader = (WalkGridHeader *)file; - - SWAP32(walkGridHeader->numBars); - SWAP32(walkGridHeader->numNodes); - - BarData *barData = (BarData *)(file + sizeof(WalkGridHeader)); - for (i = 0; i < walkGridHeader->numBars; i++) { - SWAP16(barData->x1); - SWAP16(barData->y1); - SWAP16(barData->x2); - SWAP16(barData->y2); - SWAP16(barData->xmin); - SWAP16(barData->ymin); - SWAP16(barData->xmax); - SWAP16(barData->ymax); - SWAP16(barData->dx); - SWAP16(barData->dy); - SWAP32(barData->co); - barData++; - } - - uint16 *node = (uint16 *)(file + sizeof(WalkGridHeader) + walkGridHeader->numBars * sizeof(BarData)); - for (i = 0; i < walkGridHeader->numNodes * 2; i++) { - SWAP16(*node); - node++; - } - - break; - } - case GLOBAL_VAR_FILE: - break; - case PARALLAX_FILE_null: - break; - case RUN_LIST: { - uint32 *list = (uint32 *)file; - while (*list) { - SWAP32(*list); - list++; - } - break; - } - case TEXT_FILE: { - TextHeader *textHeader = (TextHeader *)file; - SWAP32(textHeader->noOfLines); - break; - } - case SCREEN_MANAGER: - break; - case MOUSE_FILE: - break; - case ICON_FILE: - break; - } -} - /** * Returns the address of a resource. Loads if not in memory. Retains a count. */ @@ -440,12 +246,11 @@ byte *ResourceManager::openResource(uint32 res, bool dump) { file->read(_resList[res].ptr, len); if (dump) { - StandardHeader *header = (StandardHeader *)_resList[res].ptr; char buf[256]; const char *tag; Common::File out; - switch (header->fileType) { + switch (fetchType(_resList[res].ptr)) { case ANIMATION_FILE: tag = "anim"; break; @@ -508,10 +313,6 @@ byte *ResourceManager::openResource(uint32 res, bool dump) { _usedMem += len; checkMemUsage(); - -#ifdef SCUMM_BIG_ENDIAN - convertEndian(_resList[res].ptr, len); -#endif } else if (_resList[res].refCount == 0) removeFromCacheList(_resList + res); @@ -732,10 +533,8 @@ void ResourceManager::killAll(bool wantInfo) { continue; if (_resList[i].ptr) { - StandardHeader *header = (StandardHeader *)_resList[i].ptr; - if (wantInfo) - Debug_Printf("Nuked %5d: %s\n", i, header->name); + Debug_Printf("Nuked %5d: %s\n", i, fetchName(_resList[i].ptr)); remove(i); nuked++; @@ -764,11 +563,9 @@ void ResourceManager::killAllObjects(bool wantInfo) { continue; if (_resList[i].ptr) { - StandardHeader *header = (StandardHeader *)_resList[i].ptr; - - if (header->fileType == GAME_OBJECT) { + if (fetchType(_resList[i].ptr) == GAME_OBJECT) { if (wantInfo) - Debug_Printf("Nuked %5d: %s\n", i, header->name); + Debug_Printf("Nuked %5d: %s\n", i, fetchName(_resList[i].ptr)); remove(i); nuked++; diff --git a/sword2/resman.h b/sword2/resman.h index e9d1e40c4b..7fabf907c7 100644 --- a/sword2/resman.h +++ b/sword2/resman.h @@ -91,6 +91,29 @@ public: bool checkValid(uint32 res); uint32 fetchLen(uint32 res); + uint8 fetchType(uint32 res) { + byte *ptr = openResource(res); + uint8 type = ptr[0]; + closeResource(res); + + return type; + } + + uint8 fetchType(byte *ptr) { + return ptr[0]; + } + + byte *fetchName(uint32 res, byte *buf) { + byte *ptr = openResource(res); + memcpy(buf, ptr + 10, NAME_LEN); + closeResource(res); + + return buf; + } + + byte *fetchName(byte *ptr) { + return ptr + 10; + } // Prompts the user for the specified CD. void getCd(int cd); diff --git a/sword2/router.cpp b/sword2/router.cpp index 663001e557..ab3c2a9f66 100644 --- a/sword2/router.cpp +++ b/sword2/router.cpp @@ -74,6 +74,7 @@ ****************************************************************************/ #include "common/stdafx.h" +#include "common/stream.h" #include "sword2/sword2.h" #include "sword2/defs.h" #include "sword2/logic.h" @@ -82,8 +83,24 @@ namespace Sword2 { +//---------------------------------------------------------- +// (4) WALK-GRID FILES +//---------------------------------------------------------- +// a walk-grid file consists of: +// +// standard file header +// walk-grid file header +// walk-grid data + +// Walk-Grid Header - taken directly from old "header.h" in STD_INC + +struct WalkGridHeader { + int32 numBars; // number of bars on the floor + int32 numNodes; // number of nodes +}; + uint8 Router::returnSlotNo(uint32 megaId) { - if (Logic::_scriptVars[ID] == CUR_PLAYER_ID) { + if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) { // George (8) return 0; } else { @@ -101,7 +118,7 @@ void Router::allocateRouteMem() { // in middle of route, the old route will be safely cleared from // memory just before they create a new one - slotNo = returnSlotNo(Logic::_scriptVars[ID]); + slotNo = returnSlotNo(_vm->_logic->readVar(ID)); // if this slot is already used, then it can't be needed any more // because this id is creating a new route! @@ -125,13 +142,13 @@ void Router::allocateRouteMem() { } WalkData *Router::getRouteMem() { - uint8 slotNo = returnSlotNo(Logic::_scriptVars[ID]); + uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); return (WalkData *)_routeSlots[slotNo]; } void Router::freeRouteMem() { - uint8 slotNo = returnSlotNo(Logic::_scriptVars[ID]); + uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); free(_routeSlots[slotNo]); _routeSlots[slotNo] = NULL; @@ -144,7 +161,7 @@ void Router::freeAllRouteMem() { } } -int32 Router::routeFinder(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int32 x, int32 y, int32 dir) { +int32 Router::routeFinder(byte *ob_mega, byte *ob_walkdata, int32 x, int32 y, int32 dir) { /********************************************************************* * RouteFinder.C polygon router with modular walks * 21 august 94 @@ -677,8 +694,8 @@ void Router::slidyPath() { // SLOW IN bool Router::addSlowInFrames(WalkData *walkAnim) { - if (_usingSlowInFrames && _modularPath[1].num > 0) { - for (uint slowInFrameNo = 0; slowInFrameNo < _numberOfSlowInFrames[_currentDir]; slowInFrameNo++) { + if (_walkData.usingSlowInFrames && _modularPath[1].num > 0) { + for (int slowInFrameNo = 0; slowInFrameNo < _walkData.nSlowInFrames[_currentDir]; slowInFrameNo++) { walkAnim[_stepCount].frame = _firstSlowInFrame[_currentDir] + slowInFrameNo; walkAnim[_stepCount].step = 0; walkAnim[_stepCount].dir = _currentDir; @@ -692,11 +709,13 @@ bool Router::addSlowInFrames(WalkData *walkAnim) { return false; } -void Router::earlySlowOut(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata) { +void Router::earlySlowOut(byte *ob_mega, byte *ob_walkdata) { int32 slowOutFrameNo; int32 walk_pc; WalkData *walkAnim; + ObjectMega obMega(ob_mega); + debug(5, "EARLY SLOW-OUT"); loadWalkData(ob_walkdata); @@ -709,12 +728,12 @@ void Router::earlySlowOut(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata) { debug(5, "_firstSlowOutFrame = %d", _firstSlowOutFrame); debug(5, "********************************"); - walk_pc = ob_mega->walk_pc; + walk_pc = obMega.getWalkPc(); walkAnim = getRouteMem(); // if this mega does actually have slow-out frames - if (_usingSlowOutFrames) { + if (_walkData.usingSlowOutFrames) { // overwrite the next step (half a cycle) of the walk // (ie .step - 0..5) @@ -787,7 +806,7 @@ void Router::addSlowOutFrames(WalkData *walkAnim) { // if the mega did actually walk, we overwrite the last step (half a // cycle) with slow-out frames + add any necessary stationary frames - if (_usingSlowOutFrames && _lastCount >= _framesPerStep) { + if (_walkData.usingSlowOutFrames && _lastCount >= _framesPerStep) { // place stop frames here // slowdown at the end of the last walk @@ -904,7 +923,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // rotate to new walk direction // for george and nico put in a head turn at the start - if (_usingStandingTurnFrames) { + if (_walkData.usingStandingTurnFrames) { // new frames for turn frames 29oct95jps if (turnDir < 0) module = _firstStandingTurnLeftFrame + lastDir; @@ -964,7 +983,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // (0 = left; 1 = right) - if (_leadingLeg[_currentDir] == 0) { + if (_walkData.leadingLeg[_currentDir] == 0) { // start the walk on the left leg (ie. at beginning of the // first step of the walk cycle) left = 0; @@ -1010,8 +1029,8 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { scale = (_scaleA * _moduleY + _scaleB); do { - module16X += _dx[module] * scale; - module16Y += _dy[module] * scale; + module16X += _walkData.dx[module] * scale; + module16Y += _walkData.dy[module] * scale; _moduleX = module16X >> 16; _moduleY = module16Y >> 16; walkAnim[_stepCount].frame = module; @@ -1109,7 +1128,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // check each turn condition in turn // only for george - if (lastDir != 99 && _currentDir != 99 && _usingWalkingTurnFrames) { + if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { // 1 and -7 going right -1 and 7 going // left lastDir = _currentDir - lastDir; @@ -1199,7 +1218,7 @@ void Router::slidyWalkAnimator(WalkData *walkAnim) { // rotate to target direction // for george and nico put in a head turn at the start - if (_usingStandingTurnFrames) { + if (_walkData.usingStandingTurnFrames) { // new frames for turn frames 29oct95jps if (turnDir < 0) module = _firstStandingTurnLeftFrame + lastDir; @@ -1410,7 +1429,7 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { // rotate to new walk direction // for george and nico put in a head turn at the start - if (_usingStandingTurnFrames) { + if (_walkData.usingStandingTurnFrames) { // new frames for turn frames 29oct95jps if (turnDir < 0) module = _firstStandingTurnLeftFrame + lastDir; @@ -1468,7 +1487,7 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { // slow-in frames were drawn // (0 = left; 1 = right) - if (_leadingLeg[_currentDir] == 0) { + if (_walkData.leadingLeg[_currentDir] == 0) { // start the walk on the left leg (ie. at beginning of the // first step of the walk cycle) left = 0; @@ -1504,8 +1523,8 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { scale = (_scaleA * _moduleY + _scaleB); do { - module16X += _dx[module] * scale; - module16Y += _dy[module] * scale; + module16X += _walkData.dx[module] * scale; + module16Y += _walkData.dy[module] * scale; _moduleX = module16X >> 16; _moduleY = module16Y >> 16; walkAnim[_stepCount].frame = module; @@ -1551,8 +1570,8 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { // walk if (slowStart) { - _stepCount -= _numberOfSlowInFrames[_currentDir]; - _lastCount -= _numberOfSlowInFrames[_currentDir]; + _stepCount -= _walkData.nSlowInFrames[_currentDir]; + _lastCount -= _walkData.nSlowInFrames[_currentDir]; slowStart = false; } @@ -1564,7 +1583,7 @@ int32 Router::solidWalkAnimator(WalkData *walkAnim) { } // check each turn condition in turn - if (lastDir != 99 && _currentDir != 99 && _usingWalkingTurnFrames) { + if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { // only for george // 1 and -7 going right -1 and // 7 going left @@ -2091,38 +2110,30 @@ int32 Router::checkTarget(int32 x, int32 y) { // THE SETUP ROUTINES -void Router::loadWalkData(ObjectWalkdata *ob_walkdata) { +void Router::loadWalkData(byte *ob_walkdata) { uint16 firstFrameOfDirection; uint16 walkFrameNo; uint32 frameCounter = 0; // starts at frame 0 of mega set + int i; - _nWalkFrames = ob_walkdata->nWalkFrames; - _usingStandingTurnFrames = ob_walkdata->usingStandingTurnFrames; - _usingWalkingTurnFrames = ob_walkdata->usingWalkingTurnFrames; - _usingSlowInFrames = ob_walkdata->usingSlowInFrames; - _usingSlowOutFrames = ob_walkdata->usingSlowOutFrames; + _walkData.read(ob_walkdata); // 0 = not using slow out frames; non-zero = using that many frames // for each leading leg for each direction - _numberOfSlowOutFrames = _usingSlowOutFrames; + _numberOfSlowOutFrames = _walkData.usingSlowOutFrames; - memcpy(&_numberOfSlowInFrames[0], ob_walkdata->nSlowInFrames, NO_DIRECTIONS * sizeof(_numberOfSlowInFrames[0])); - memcpy(&_leadingLeg[0], ob_walkdata->leadingLeg, NO_DIRECTIONS * sizeof(_leadingLeg[0])); - memcpy(&_dx[0], ob_walkdata->dx, NO_DIRECTIONS * (_nWalkFrames + 1) * sizeof(_dx[0])); - memcpy(&_dy[0], ob_walkdata->dy, NO_DIRECTIONS * (_nWalkFrames + 1) * sizeof(_dy[0])); - - for (int i = 0; i < NO_DIRECTIONS; i++) { - firstFrameOfDirection = i * _nWalkFrames; + for (i = 0; i < NO_DIRECTIONS; i++) { + firstFrameOfDirection = i * _walkData.nWalkFrames; _modX[i] = 0; _modY[i] = 0; - for (walkFrameNo = firstFrameOfDirection; walkFrameNo < firstFrameOfDirection + _nWalkFrames / 2; walkFrameNo++) { + for (walkFrameNo = firstFrameOfDirection; walkFrameNo < firstFrameOfDirection + _walkData.nWalkFrames / 2; walkFrameNo++) { // eg. _modX[0] is the sum of the x-step sizes for the // first half of the walk cycle for direction 0 - _modX[i] += _dx[walkFrameNo]; - _modY[i] += _dy[walkFrameNo]; + _modX[i] += _walkData.dx[walkFrameNo]; + _modY[i] += _walkData.dy[walkFrameNo]; } } @@ -2131,8 +2142,8 @@ void Router::loadWalkData(ObjectWalkdata *ob_walkdata) { // interpret the walk data - _framesPerStep = _nWalkFrames / 2; - _framesPerChar = _nWalkFrames * NO_DIRECTIONS; + _framesPerStep = _walkData.nWalkFrames / 2; + _framesPerChar = _walkData.nWalkFrames * NO_DIRECTIONS; // offset pointers added Oct 30 95 JPS // mega id references removed 16sep96 by JEL @@ -2155,7 +2166,7 @@ void Router::loadWalkData(ObjectWalkdata *ob_walkdata) { // standing turn-left frames come after the standing turn-right frames // one for each direction - if (_usingStandingTurnFrames) { + if (_walkData.usingStandingTurnFrames) { _firstStandingTurnLeftFrame = frameCounter; frameCounter += NO_DIRECTIONS; @@ -2171,7 +2182,7 @@ void Router::loadWalkData(ObjectWalkdata *ob_walkdata) { // walking left-turn frames come after the stand frames // walking right-turn frames come after the walking left-turn frames - if (_usingWalkingTurnFrames) { + if (_walkData.usingWalkingTurnFrames) { _firstWalkingTurnLeftFrame = frameCounter; frameCounter += _framesPerChar; @@ -2185,21 +2196,21 @@ void Router::loadWalkData(ObjectWalkdata *ob_walkdata) { // SLOW-IN FRAMES - OPTIONAL! // slow-in frames come after the walking right-turn frames - if (_usingSlowInFrames) { + if (_walkData.usingSlowInFrames) { // Make note of frame number of first slow-in frame for each // direction. There may be a different number of slow-in // frames in each direction - for (int i = 0; i < NO_DIRECTIONS; i++) { + for (i = 0; i < NO_DIRECTIONS; i++) { _firstSlowInFrame[i] = frameCounter; - frameCounter += _numberOfSlowInFrames[i]; + frameCounter += _walkData.nSlowInFrames[i]; } } // SLOW-OUT FRAMES - OPTIONAL! // slow-out frames come after the slow-in frames - if (_usingSlowOutFrames) + if (_walkData.usingSlowOutFrames) _firstSlowOutFrame = frameCounter; } @@ -2316,22 +2327,24 @@ void Router::extractRoute() { return; } -void Router::setUpWalkGrid(ObjectMega *ob_mega, int32 x, int32 y, int32 dir) { +void Router::setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir) { + ObjectMega obMega(ob_mega); + // get walk grid file + extra grid into 'bars' & 'node' arrays loadWalkGrid(); // copy the mega structure into the local variables for use in all // subroutines - _startX = ob_mega->feet_x; - _startY = ob_mega->feet_y; - _startDir = ob_mega->current_dir; + _startX = obMega.getFeetX(); + _startY = obMega.getFeetY(); + _startDir = obMega.getCurDir(); _targetX = x; _targetY = y; _targetDir = dir; - _scaleA = ob_mega->scale_a; - _scaleB = ob_mega->scale_b; + _scaleA = obMega.getScaleA(); + _scaleB = obMega.getScaleB(); // mega's current position goes into first node @@ -2383,8 +2396,7 @@ void Router::plotCross(int16 x, int16 y, uint8 colour) { void Router::loadWalkGrid() { WalkGridHeader floorHeader; byte *fPolygrid; - uint32 theseBars; - uint32 theseNodes; + uint16 fPolygridLen; _nBars = 0; // reset counts _nNodes = 1; // leave node 0 for start-node @@ -2394,37 +2406,47 @@ void Router::loadWalkGrid() { // go through walkgrid list for (int i = 0; i < MAX_WALKGRIDS; i++) { if (_walkGridList[i]) { + int j; + // open walk grid file fPolygrid = _vm->_resman->openResource(_walkGridList[i]); - fPolygrid += sizeof(StandardHeader); - memcpy((byte *)&floorHeader, fPolygrid, sizeof(WalkGridHeader)); - fPolygrid += sizeof(WalkGridHeader); + fPolygridLen = _vm->_resman->fetchLen(_walkGridList[i]); - // how many bars & nodes are we getting from this - // walkgrid file + Common::MemoryReadStream readS(fPolygrid, fPolygridLen); - theseBars = floorHeader.numBars; - theseNodes = floorHeader.numNodes; + readS.seek(ResHeader::size()); + + floorHeader.numBars = readS.readSint32LE(); + floorHeader.numNodes = readS.readSint32LE(); // check that we're not going to exceed the max // allowed in the complete walkgrid arrays - assert(_nBars + theseBars < O_GRID_SIZE); - assert(_nNodes + theseNodes < O_GRID_SIZE); + assert(_nBars + floorHeader.numBars < O_GRID_SIZE); + assert(_nNodes + floorHeader.numNodes < O_GRID_SIZE); // lines - memcpy((byte *)&_bars[_nBars], fPolygrid, theseBars * sizeof(BarData)); - - // move pointer to start of node data - fPolygrid += theseBars * sizeof(BarData); + for (j = 0; j < floorHeader.numBars; j++) { + _bars[_nBars + j].x1 = readS.readSint16LE(); + _bars[_nBars + j].y1 = readS.readSint16LE(); + _bars[_nBars + j].x2 = readS.readSint16LE(); + _bars[_nBars + j].y2 = readS.readSint16LE(); + _bars[_nBars + j].xmin = readS.readSint16LE(); + _bars[_nBars + j].ymin = readS.readSint16LE(); + _bars[_nBars + j].xmax = readS.readSint16LE(); + _bars[_nBars + j].ymax = readS.readSint16LE(); + _bars[_nBars + j].dx = readS.readSint16LE(); + _bars[_nBars + j].dy = readS.readSint16LE(); + _bars[_nBars + j].co = readS.readSint32LE(); + } // nodes // leave node 0 for start node - for (uint j = 0; j < theseNodes; j++) { - memcpy((byte *)&_node[_nNodes + j].x, fPolygrid, 2 * sizeof(int16)); - fPolygrid += 2 * sizeof(int16); + for (j = 0; j < floorHeader.numNodes; j++) { + _node[_nNodes + j].x = readS.readSint16LE(); + _node[_nNodes + j].y = readS.readSint16LE(); } // close walk grid file @@ -2433,8 +2455,8 @@ void Router::loadWalkGrid() { // increment counts of total bars & nodes in whole // walkgrid - _nBars += theseBars; - _nNodes += theseNodes; + _nBars += floorHeader.numBars; + _nNodes += floorHeader.numNodes; } } } diff --git a/sword2/router.h b/sword2/router.h index e48a4ce22f..c7fd8dd6e3 100644 --- a/sword2/router.h +++ b/sword2/router.h @@ -33,17 +33,13 @@ namespace Sword2 { -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - struct WalkData { uint16 frame; int16 x; int16 y; uint8 step; uint8 dir; -} GCC_PACK; +}; struct BarData { int16 x1; @@ -58,7 +54,7 @@ struct BarData { int16 dy; // y2 - y1 int32 co; // co = (y1 * dx) - (x1 * dy) from an equation for a // line y * dx = x * dy + co -} GCC_PACK; +}; struct NodeData { int16 x; @@ -66,11 +62,7 @@ struct NodeData { int16 level; int16 prev; int16 dist; -} GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif +}; // because we only have 2 megas in the game! #define TOTAL_ROUTE_SLOTS 2 @@ -137,13 +129,8 @@ private: int32 _framesPerStep; int32 _framesPerChar; - uint8 _nWalkFrames; // no. of frames per walk cycle - uint8 _usingStandingTurnFrames; // any standing turn frames? - uint8 _usingWalkingTurnFrames; // any walking turn frames? - uint8 _usingSlowInFrames; // any slow-in frames? - uint8 _usingSlowOutFrames; // any slow-out frames? - int32 _dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR]; - int32 _dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR]; + ObjectWalkdata _walkData; + int8 _modX[NO_DIRECTIONS]; int8 _modY[NO_DIRECTIONS]; int32 _diagonalx; @@ -158,9 +145,6 @@ private: int32 _firstWalkingTurnRightFrame; // right walking turn uint32 _firstSlowInFrame[NO_DIRECTIONS]; - uint32 _numberOfSlowInFrames[NO_DIRECTIONS]; - - uint32 _leadingLeg[NO_DIRECTIONS]; int32 _firstSlowOutFrame; @@ -183,8 +167,8 @@ private: int32 getRoute(); void extractRoute(); void loadWalkGrid(); - void setUpWalkGrid(ObjectMega *ob_mega, int32 x, int32 y, int32 dir); - void loadWalkData(ObjectWalkdata *ob_walkdata); + void setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir); + void loadWalkData(byte *ob_walkdata); bool scan(int32 level); int32 newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2); @@ -219,44 +203,40 @@ public: memset(_route, 0, sizeof(_route)); memset(_smoothPath, 0, sizeof(_smoothPath)); memset(_modularPath, 0, sizeof(_modularPath)); - memset(_dx, 0, sizeof(_dx)); - memset(_dy, 0, sizeof(_dy)); memset(_modX, 0, sizeof(_modX)); memset(_modY, 0, sizeof(_modY)); memset(_firstSlowInFrame, 0, sizeof(_firstSlowInFrame)); - memset(_numberOfSlowInFrames, 0, sizeof(_numberOfSlowInFrames)); - memset(_leadingLeg, 0, sizeof(_leadingLeg)); } void setStandbyCoords(int16 x, int16 y, uint8 dir); int whatTarget(int startX, int startY, int destX, int destY); // Sprites - void setSpriteStatus(ObjectGraphic *ob_graph, uint32 type); - void setSpriteShading(ObjectGraphic *ob_graph, uint32 type); + void setSpriteStatus(byte *ob_graph, uint32 type); + void setSpriteShading(byte *ob_graph, uint32 type); // Animation - int doAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, int32 animRes, bool reverse); - int megaTableAnimate(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 *animTable, bool reverse); + int doAnimate(byte *ob_logic, byte *ob_graph, int32 animRes, bool reverse); + int megaTableAnimate(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *animTable, bool reverse); // Walking - int doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir); - int walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 animRes); - int walkToTalkToMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId, uint32 separation); + int doWalk(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir); + int walkToAnim(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 animRes); + int walkToTalkToMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId, uint32 separation); // Turning - int doFace(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint8 target_dir); - int faceXY(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y); - int faceMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId); + int doFace(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint8 target_dir); + int faceXY(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y); + int faceMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId); // Standing - void standAt(ObjectGraphic *ob_graph, ObjectMega *ob_mega, int32 x, int32 y, int32 dir); - void standAfterAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes); - void standAtAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes); + void standAt(byte *ob_graph, byte *ob_mega, int32 x, int32 y, int32 dir); + void standAfterAnim(byte *ob_graph, byte *ob_mega, uint32 animRes); + void standAtAnim(byte *ob_graph, byte *ob_mega, uint32 animRes); - int32 routeFinder(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int32 x, int32 y, int32 dir); + int32 routeFinder(byte *ob_mega, byte *ob_walkdata, int32 x, int32 y, int32 dir); - void earlySlowOut(ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata); + void earlySlowOut(byte *ob_mega, byte *ob_walkdata); void allocateRouteMem(); WalkData *getRouteMem(); diff --git a/sword2/save_rest.cpp b/sword2/save_rest.cpp index 0332fa2f6a..cf948b7c14 100644 --- a/sword2/save_rest.cpp +++ b/sword2/save_rest.cpp @@ -43,63 +43,58 @@ namespace Sword2 { // Max length of a savegame filename #define MAX_FILENAME_LEN 128 -#ifdef SCUMM_BIG_ENDIAN -// Quick macro to make swapping in-place easier to write -#define SWAP32(x) x = SWAP_BYTES_32(x) - -static void convertHeaderEndian(Sword2Engine::SaveGameHeader &header) { - // SaveGameHeader - SWAP32(header.checksum); - SWAP32(header.varLength); - SWAP32(header.screenId); - SWAP32(header.runListId); - SWAP32(header.feet_x); - SWAP32(header.feet_y); - SWAP32(header.music_id); - - // ObjectHub - SWAP32(header.player_hub.type); - SWAP32(header.player_hub.logic_level); - for (int i = 0; i < TREE_SIZE; i++) { - SWAP32(header.player_hub.logic[i]); - SWAP32(header.player_hub.script_id[i]); - SWAP32(header.player_hub.script_pc[i]); - } +/** + * Calculate size of required savegame buffer + */ - // ObjectLogic - SWAP32(header.logic.looping); - SWAP32(header.logic.pause); - - // ObjectGraphic - SWAP32(header.graphic.type); - SWAP32(header.graphic.anim_resource); - SWAP32(header.graphic.anim_pc); - - // ObjectMega - SWAP32(header.mega.currently_walking); - SWAP32(header.mega.walk_pc); - SWAP32(header.mega.scale_a); - SWAP32(header.mega.scale_b); - SWAP32(header.mega.feet_x); - SWAP32(header.mega.feet_y); - SWAP32(header.mega.current_dir); - SWAP32(header.mega.megaset_res); +uint32 Sword2Engine::findBufferSize() { + // Size of savegame header + size of global variables + return 212 + _resman->fetchLen(1); } -#endif /** * Save the game. */ uint32 Sword2Engine::saveGame(uint16 slotNo, byte *desc) { + char description[SAVE_DESCRIPTION_LEN]; uint32 bufferSize = findBufferSize(); - byte *saveBufferMem = (byte *)malloc(bufferSize); + byte *saveBuffer = (byte *)malloc(bufferSize); + ScreenInfo *screenInfo = _screen->getScreenInfo(); + + memset(description, 0, sizeof(description)); + strncpy(description, (char *)desc, SAVE_DESCRIPTION_LEN - 1); + + Common::MemoryWriteStream writeS(saveBuffer, bufferSize); + + byte *globalVars = _resman->openResource(1); + byte *objectHub = _resman->openResource(CUR_PLAYER_ID) + ResHeader::size(); - fillSaveBuffer(saveBufferMem, bufferSize, desc); + // Script no. 7 - 'george_savedata_request' calls fnPassPlayerSaveData + _logic->runResScript(CUR_PLAYER_ID, 7); + + writeS.writeUint32LE(0); // Checksum + writeS.write(description, SAVE_DESCRIPTION_LEN); + writeS.writeUint32LE(_resman->fetchLen(1)); + writeS.writeUint32LE(screenInfo->background_layer_id); + writeS.writeUint32LE(_logic->getRunList()); + writeS.writeUint32LE(screenInfo->feet_x); + writeS.writeUint32LE(screenInfo->feet_y); + writeS.writeUint32LE(_sound->getLoopingMusicId()); + writeS.write(objectHub, ObjectHub::size()); + writeS.write(_logic->_saveLogic, ObjectLogic::size()); + writeS.write(_logic->_saveGraphic, ObjectGraphic::size()); + writeS.write(_logic->_saveMega, ObjectMega::size()); + writeS.write(globalVars, _resman->fetchLen(1)); + + WRITE_LE_UINT32(saveBuffer, calcChecksum(saveBuffer + 4, bufferSize - 4)); + + _resman->closeResource(CUR_PLAYER_ID); + _resman->closeResource(1); - uint32 errorCode = saveData(slotNo, saveBufferMem, bufferSize); + uint32 errorCode = saveData(slotNo, saveBuffer, bufferSize); - free(saveBufferMem); + free(saveBuffer); if (errorCode != SR_OK) { uint32 textId; @@ -119,65 +114,6 @@ uint32 Sword2Engine::saveGame(uint16 slotNo, byte *desc) { return errorCode; } -/** - * Calculate size of required savegame buffer - */ - -uint32 Sword2Engine::findBufferSize() { - // Size of savegame header + size of global variables - return sizeof(_saveGameHeader) + _resman->fetchLen(1); -} - -void Sword2Engine::fillSaveBuffer(byte *buffer, uint32 size, byte *desc) { - // Set up the _saveGameHeader. Checksum gets filled in last of all. - ScreenInfo *screenInfo = _screen->getScreenInfo(); - - strcpy(_saveGameHeader.description, (char *)desc); - _saveGameHeader.varLength = _resman->fetchLen(1); - _saveGameHeader.screenId = screenInfo->background_layer_id; - _saveGameHeader.runListId = _logic->getRunList(); - _saveGameHeader.feet_x = screenInfo->feet_x; - _saveGameHeader.feet_y = screenInfo->feet_y; - _saveGameHeader.music_id = _sound->getLoopingMusicId(); - - memcpy(&_saveGameHeader.player_hub, _resman->openResource(CUR_PLAYER_ID) + sizeof(StandardHeader), sizeof(ObjectHub)); - - _resman->closeResource(CUR_PLAYER_ID); - - // Get the logic, graphic and mega structures - getPlayerStructures(); - -#ifdef SCUMM_BIG_ENDIAN - convertHeaderEndian(_saveGameHeader); -#endif - - // Copy the header to the buffer, even though it isn't quite complete - memcpy(buffer, &_saveGameHeader, sizeof(_saveGameHeader)); - - // Get the global variables - - byte *varsRes = _resman->openResource(1); - memcpy(buffer + sizeof(_saveGameHeader), varsRes, FROM_LE_32(_saveGameHeader.varLength)); - -#ifdef SCUMM_BIG_ENDIAN - uint32 *globalVars = (uint32 *)(buffer + sizeof(_saveGameHeader) + sizeof(StandardHeader)); - const uint numVars = (FROM_LE_32(_saveGameHeader.varLength) - sizeof(StandardHeader)) / 4; - - for (uint i = 0; i < numVars; i++) - globalVars[i] = SWAP_BYTES_32(globalVars[i]); -#endif - - _resman->closeResource(1); - - // Finally, get the checksum - - _saveGameHeader.checksum = TO_LE_32(calcChecksum(buffer + sizeof(_saveGameHeader.checksum), size - sizeof(_saveGameHeader.checksum))); - - // All done - - memcpy(buffer, &_saveGameHeader.checksum, sizeof(_saveGameHeader.checksum)); -} - uint32 Sword2Engine::saveData(uint16 slotNo, byte *buffer, uint32 bufferSize) { char saveFileName[MAX_FILENAME_LEN]; @@ -284,20 +220,17 @@ uint32 Sword2Engine::restoreData(uint16 slotNo, byte *buffer, uint32 bufferSize) } uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { - // Get a copy of the header from the savegame buffer - memcpy(&_saveGameHeader, buffer, sizeof(_saveGameHeader)); - -#ifdef SCUMM_BIG_ENDIAN - convertHeaderEndian(_saveGameHeader); -#endif + Common::MemoryReadStream readS(buffer, size); // Calc checksum & check that aginst the value stored in the header - if (_saveGameHeader.checksum != calcChecksum(buffer + sizeof(_saveGameHeader.checksum), size - sizeof(_saveGameHeader.checksum))) { + if (readS.readUint32LE() != calcChecksum(buffer + 4, size - 4)) { free(buffer); return SR_ERR_INCOMPATIBLE; } + readS.seek(SAVE_DESCRIPTION_LEN, SEEK_CUR); + // Check savegame against length of current global variables resource // This would most probably be trapped by the checksum test anyway, // but it doesn't do any harm to check this as well. @@ -305,49 +238,75 @@ uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { // Historical note: During development, earlier savegames would often // be shorter than the current expected length. - if (_saveGameHeader.varLength != _resman->fetchLen(1)) { + if (readS.readUint32LE() != _resman->fetchLen(1)) { free(buffer); return SR_ERR_INCOMPATIBLE; } - // Clean out system + byte *globalVars = _resman->openResource(1); + byte *objectHub = _resman->openResource(CUR_PLAYER_ID) + ResHeader::size(); + + uint32 screenId = readS.readUint32LE(); + uint32 runListId = readS.readUint32LE(); + uint32 feetX = readS.readUint32LE(); + uint32 feetY = readS.readUint32LE(); + uint32 musicId = readS.readUint32LE(); // Trash all resources from memory except player object & global vars _resman->killAll(false); - - // Clean out the system kill list (no more objects to kill) _logic->resetKillList(); - // Object hub is just after the standard header - memcpy(_resman->openResource(CUR_PLAYER_ID) + sizeof(StandardHeader), &_saveGameHeader.player_hub, sizeof(ObjectHub)); + readS.read(objectHub, ObjectHub::size()); + readS.read(_logic->_saveLogic, ObjectLogic::size()); + readS.read(_logic->_saveGraphic, ObjectGraphic::size()); + readS.read(_logic->_saveMega, ObjectMega::size()); - _resman->closeResource(CUR_PLAYER_ID); + // Fill out the player object structures from the savegame structures. + // Also run the appropriate scripts to set up George's anim tables and + // walkdata, and Nico's anim tables. - // Fill in the player object structures from the header - putPlayerStructures(); + // Script no. 8 - 'george_savedata_return' calls fnGetPlayerSaveData + _logic->runResScript(CUR_PLAYER_ID, 8); - // Copy variables from savegame buffer to memory - byte *varsRes = _resman->openResource(1); + // Script no. 14 - 'set_up_nico_anim_tables' + _logic->runResScript(CUR_PLAYER_ID, 14); - memcpy(varsRes, buffer + sizeof(_saveGameHeader), _saveGameHeader.varLength); + // Which megaset was the player at the time of saving? + ObjectMega obMega(_logic->_saveMega); -#ifdef SCUMM_BIG_ENDIAN - uint32 *globalVars = (uint32 *)(varsRes + sizeof(StandardHeader)); - const uint numVars = (_saveGameHeader.varLength - sizeof(StandardHeader)) / 4; + uint32 scriptNo = 0; - for (uint i = 0; i < numVars; i++) - globalVars[i] = SWAP_BYTES_32(globalVars[i]); -#endif + switch (obMega.getMegasetRes()) { + case 36: // GeoMega: + scriptNo = 9; // script no.9 - 'player_is_george' + break; + case 2003: // GeoMegaB: + scriptNo = 13; // script no.13 - 'player_is_georgeB' + break; + case 1366: // NicMegaA: + scriptNo = 11; // script no.11 - 'player_is_nicoA' + break; + case 1437: // NicMegaB: + scriptNo = 12; // script no.12 - 'player_is_nicoB' + break; + case 1575: // NicMegaC: + scriptNo = 10; // script no.10 - 'player_is_nicoC' + break; + } + + _logic->runResScript(CUR_PLAYER_ID, scriptNo); + + // Copy variables from savegame buffer to memory + readS.read(globalVars, _resman->fetchLen(1)); + _resman->closeResource(CUR_PLAYER_ID); _resman->closeResource(1); - // Free it now, rather than in RestoreGame, to unblock memory before - // new screen & runlist loaded free(buffer); int32 pars[2]; - pars[0] = _saveGameHeader.screenId; + pars[0] = screenId; pars[1] = 1; _logic->fnInitBackground(pars); @@ -361,19 +320,19 @@ uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { // Remember that these can change through the game, so need saving & // restoring too. - screenInfo->feet_x = _saveGameHeader.feet_x; - screenInfo->feet_y = _saveGameHeader.feet_y; + screenInfo->feet_x = feetX; + screenInfo->feet_y = feetY; // Start the new run list - _logic->expressChangeSession(_saveGameHeader.runListId); + _logic->expressChangeSession(runListId); // Force in the new scroll position, so unsightly scroll-catch-up does // not occur when screen first draws after returning from restore panel // Set the screen record of player position - ready for setScrolling() - screenInfo->player_feet_x = _saveGameHeader.mega.feet_x; - screenInfo->player_feet_y = _saveGameHeader.mega.feet_y; + screenInfo->player_feet_x = obMega.getFeetX(); + screenInfo->player_feet_y = obMega.getFeetY(); // if this screen is wide, recompute the scroll offsets now if (screenInfo->scroll_flag) @@ -386,8 +345,8 @@ uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { // in systemMenuMouse(), but with ScummVM we have other ways of // restoring savegames so it's easier to put it here as well. - if (_saveGameHeader.music_id) { - pars[0] = _saveGameHeader.music_id; + if (musicId) { + pars[0] = musicId; pars[1] = FX_LOOP; _logic->fnPlayMusic(pars); } else @@ -411,12 +370,10 @@ uint32 Sword2Engine::getSaveDescription(uint16 slotNo, byte *description) { return SR_ERR_FILEOPEN; } - SaveGameHeader dummy; + in->readUint32LE(); + in->read(description, SAVE_DESCRIPTION_LEN); - in->read(&dummy, sizeof(dummy)); delete in; - - strcpy((char *)description, dummy.description); return SR_OK; } @@ -442,71 +399,6 @@ bool Sword2Engine::saveExists(uint16 slotNo) { return true; } -/** - * Request the player object structures which need saving. - */ - -void Sword2Engine::getPlayerStructures() { - StandardHeader *head = (StandardHeader *)_resman->openResource(CUR_PLAYER_ID); - - assert(head->fileType == GAME_OBJECT); - - char *raw_script_ad = (char *)head; - - // Script no. 7 - 'george_savedata_request' calls fnPassPlayerSaveData - uint32 null_pc = 7; - - _logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - _resman->closeResource(CUR_PLAYER_ID); -} - -/** - * Fill out the player object structures from the savegame structures also run - * the appropriate scripts to set up george's anim tables and walkdata, and - * Nico's anim tables. - */ - -void Sword2Engine::putPlayerStructures() { - StandardHeader *head = (StandardHeader *)_resman->openResource(CUR_PLAYER_ID); - - assert(head->fileType == GAME_OBJECT); - - char *raw_script_ad = (char *)head; - - // Script no. 8 - 'george_savedata_return' calls fnGetPlayerSaveData - - uint32 null_pc = 8; - _logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - - // Script no. 14 - 'set_up_nico_anim_tables' - - null_pc = 14; - _logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - - // Which megaset was the player at the time of saving? - - switch (_saveGameHeader.mega.megaset_res) { - case 36: // GeoMega: - null_pc = 9; // script no.9 - 'player_is_george' - break; - case 2003: // GeoMegaB: - null_pc = 13; // script no.13 - 'player_is_georgeB' - break; - case 1366: // NicMegaA: - null_pc = 11; // script no.11 - 'player_is_nicoA' - break; - case 1437: // NicMegaB: - null_pc = 12; // script no.12 - 'player_is_nicoB' - break; - case 1575: // NicMegaC: - null_pc = 10; // script no.10 - 'player_is_nicoC' - break; - } - - _logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - _resman->closeResource(CUR_PLAYER_ID); -} - uint32 Sword2Engine::calcChecksum(byte *buffer, uint32 size) { uint32 total = 0; diff --git a/sword2/scroll.cpp b/sword2/scroll.cpp index bc999de926..fd960caa2b 100644 --- a/sword2/scroll.cpp +++ b/sword2/scroll.cpp @@ -54,10 +54,12 @@ void Screen::setScrolling() { // If the scroll offsets are being forced in script, ensure that they // are neither too far to the right nor too far down. + uint32 scrollX = _vm->_logic->readVar(SCROLL_X); + uint32 scrollY = _vm->_logic->readVar(SCROLL_Y); - if (Logic::_scriptVars[SCROLL_X] || Logic::_scriptVars[SCROLL_Y]) { - _thisScreen.scroll_offset_x = MIN((uint16) Logic::_scriptVars[SCROLL_X], _thisScreen.max_scroll_offset_x); - _thisScreen.scroll_offset_y = MIN((uint16) Logic::_scriptVars[SCROLL_Y], _thisScreen.max_scroll_offset_y); + if (scrollX || scrollY) { + _thisScreen.scroll_offset_x = MIN((uint16)scrollX, _thisScreen.max_scroll_offset_x); + _thisScreen.scroll_offset_y = MIN((uint16)scrollY, _thisScreen.max_scroll_offset_y); return; } diff --git a/sword2/sound.cpp b/sword2/sound.cpp index d8ac958f08..3b8a4ff354 100644 --- a/sword2/sound.cpp +++ b/sword2/sound.cpp @@ -199,17 +199,16 @@ void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) byte buf[NAME_LEN]; - debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->fetchObjectName(res, buf), volume, pan, delay, typeStr); + debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->_resman->fetchName(res, buf), volume, pan, delay, typeStr); } for (int i = 0; i < FXQ_LENGTH; i++) { if (!_fxQueue[i].resource) { byte *data = _vm->_resman->openResource(res); - StandardHeader *header = (StandardHeader *)data; - assert(header->fileType == WAV_FILE); + assert(_vm->_resman->fetchType(data) == WAV_FILE); - uint32 len = _vm->_resman->fetchLen(res) - sizeof(StandardHeader); + uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); if (type == FX_RANDOM) { // For spot effects and loops the delay is the @@ -227,7 +226,7 @@ void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) pan = -pan; _fxQueue[i].resource = res; - _fxQueue[i].data = data + sizeof(StandardHeader); + _fxQueue[i].data = data + ResHeader::size(); _fxQueue[i].len = len; _fxQueue[i].delay = delay; _fxQueue[i].volume = volume; @@ -238,7 +237,7 @@ void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) // fnStopFx() can be used later to kill this sound. // Mainly for FX_LOOP and FX_RANDOM. - Logic::_scriptVars[RESULT] = i; + _vm->_logic->writeVar(RESULT, i); return; } } diff --git a/sword2/speech.cpp b/sword2/speech.cpp index 25d8c841c2..21516210a5 100644 --- a/sword2/speech.cpp +++ b/sword2/speech.cpp @@ -80,39 +80,35 @@ void Logic::locateTalker(int32 *params) { // '0' means 1st frame - CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, 0); - FrameHeader *frame_head = _vm->fetchFrameHeader(file, 0); + CdtEntry cdt_entry; + FrameHeader frame_head; + + cdt_entry.read(_vm->fetchCdtEntry(file, 0)); + frame_head.read(_vm->fetchFrameHeader(file, 0)); // Note: This part of the code is quite similar to registerFrame(). - if (cdt_entry->frameType & FRAME_OFFSET) { + if (cdt_entry.frameType & FRAME_OFFSET) { // The frame has offsets, i.e. it's a scalable mega frame - ObjectMega *ob_mega = (ObjectMega *)decodePtr(params[S_OB_MEGA]); - - // Calculate scale at which to print the sprite, based on feet - // y-coord and scaling constants (NB. 'scale' is actually - // 256 * true_scale, to maintain accuracy) + ObjectMega obMega(decodePtr(params[S_OB_MEGA])); - // Ay+B gives 256 * scale ie. 256 * 256 * true_scale for even - // better accuracy, ie. scale = (Ay + B) / 256 - - uint16 scale = (uint16) ((ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256); + uint16 scale = obMega.calcScale(); // Calc suitable centre point above the head, based on scaled // height // just use 'feet_x' as centre - _textX = (int16) ob_mega->feet_x; + _textX = obMega.getFeetX(); // Add scaled y-offset to feet_y coord to get top of sprite - _textY = (int16) (ob_mega->feet_y + (cdt_entry->y * scale) / 256); + _textY = obMega.getFeetY() + (cdt_entry.y * scale) / 256; } else { // It's a non-scaling anim - calc suitable centre point above // the head, based on scaled width // x-coord + half of width - _textX = cdt_entry->x + (frame_head->width) / 2; - _textY = cdt_entry->y; + _textX = cdt_entry.x + frame_head.width / 2; + _textY = cdt_entry.y; } _vm->_resman->closeResource(_animId); @@ -158,10 +154,13 @@ void Logic::formText(int32 *params) { return; } - ObjectSpeech *ob_speech = (ObjectSpeech *)decodePtr(params[S_OB_SPEECH]); + ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH])); // Establish the max width allowed for this text sprite. - uint32 textWidth = ob_speech->width ? ob_speech->width : 400; + uint32 textWidth = obSpeech.getWidth(); + + if (!textWidth) + textWidth = 400; // Pull out the text line, and make the sprite and text block @@ -174,7 +173,7 @@ void Logic::formText(int32 *params) { _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc( text + 2, _textX, _textY, - textWidth, ob_speech->pen, + textWidth, obSpeech.getPen(), RDSPR_TRANS | RDSPR_DISPLAYALIGN, _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE); diff --git a/sword2/startup.cpp b/sword2/startup.cpp index a03e624338..f64111c23a 100644 --- a/sword2/startup.cpp +++ b/sword2/startup.cpp @@ -117,11 +117,7 @@ bool Sword2Engine::initStartMenu() { // start list if (_resman->checkValid(_startRes)) { - char *raw_script = (char *)_resman->openResource(_startRes); - uint32 null_pc = 0; - - _logic->runScript(raw_script, raw_script, &null_pc); - _resman->closeResource(_startRes); + _logic->runResScript(_startRes, 0); } else warning("Start menu resource %d invalid", _startRes); } @@ -166,17 +162,7 @@ void Sword2Engine::runStart(int start) { _logic->_speechTextBlocNo = 0; } - // Open George - char *raw_data_ad = (char *)_resman->openResource(CUR_PLAYER_ID); - char *raw_script = (char *)_resman->openResource(_startList[start].start_res_id); - - // Denotes script to run - uint32 null_pc = _startList[start].key & 0xffff; - - _logic->runScript(raw_script, raw_data_ad, &null_pc); - - _resman->closeResource(_startList[start].start_res_id); - _resman->closeResource(CUR_PLAYER_ID); + _logic->runResObjScript(_startList[start].start_res_id, CUR_PLAYER_ID, _startList[start].key & 0xffff); // Make sure there's a mouse, in case restarting while mouse not // available diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 846885216f..f413f95a5a 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -222,7 +222,7 @@ void Sword2Engine::writeSettings() { */ void Sword2Engine::setupPersistentResources() { - Logic::_scriptVars = (uint32 *)(_resman->openResource(1) + sizeof(StandardHeader)); + _logic->_scriptVars = _resman->openResource(1) + ResHeader::size(); _resman->openResource(CUR_PLAYER_ID); } @@ -266,9 +266,9 @@ int Sword2Engine::init(GameDetector &detector) { initialiseFontResourceFlags(); if (_features & GF_DEMO) - Logic::_scriptVars[DEMO] = 1; + _logic->writeVar(DEMO, 1); else - Logic::_scriptVars[DEMO] = 0; + _logic->writeVar(DEMO, 0); if (_saveSlot != -1) { if (saveExists(_saveSlot)) @@ -332,7 +332,7 @@ int Sword2Engine::go() { pauseGame(); break; case 'c': - if (!Logic::_scriptVars[DEMO] && !_mouse->isChoosing()) { + if (!_logic->readVar(DEMO) && !_mouse->isChoosing()) { ScreenInfo *screenInfo = _screen->getScreenInfo(); _logic->fnPlayCredits(NULL); screenInfo->new_palette = 99; @@ -401,10 +401,10 @@ void Sword2Engine::restartGame() { _sound->stopMusic(true); // In case we were dead - well we're not anymore! - Logic::_scriptVars[DEAD] = 0; + _logic->writeVar(DEAD, 0); // Restart the game. Clear all memory and reset the globals - temp_demo_flag = Logic::_scriptVars[DEMO]; + temp_demo_flag = _logic->readVar(DEMO); // Remove all resources from memory, including player object and // global variables @@ -413,7 +413,7 @@ void Sword2Engine::restartGame() { // Reopen global variables resource and player object setupPersistentResources(); - Logic::_scriptVars[DEMO] = temp_demo_flag; + _logic->writeVar(DEMO, temp_demo_flag); // Free all the route memory blocks from previous game _logic->_router->freeAllRouteMem(); @@ -605,7 +605,7 @@ void Sword2Engine::startGame() { debug(5, "startGame() STARTING:"); if (!_bootParam) { - if (Logic::_scriptVars[DEMO]) + if (_logic->readVar(DEMO)) screen_manager_id = 19; // DOCKS SECTION START else screen_manager_id = 949; // INTRO & PARIS START @@ -617,15 +617,7 @@ void Sword2Engine::startGame() { screen_manager_id = _bootParam; } - uint32 null_pc = 1; - - char *raw_data_ad = (char *)_resman->openResource(CUR_PLAYER_ID); - char *raw_script = (char *)_resman->openResource(screen_manager_id); - - _logic->runScript(raw_script, raw_data_ad, &null_pc); - - _resman->closeResource(screen_manager_id); - _resman->closeResource(CUR_PLAYER_ID); + _logic->runResObjScript(screen_manager_id, CUR_PLAYER_ID, 1); } // FIXME: Move this to some better place? diff --git a/sword2/sword2.h b/sword2/sword2.h index 48031be064..5145e3d060 100644 --- a/sword2/sword2.h +++ b/sword2/sword2.h @@ -184,58 +184,25 @@ public: #endif byte *fetchPalette(byte *screenFile); - ScreenHeader *fetchScreenHeader(byte *screenFile); - LayerHeader *fetchLayerHeader(byte *screenFile, uint16 layerNo); + byte *fetchScreenHeader(byte *screenFile); + byte *fetchLayerHeader(byte *screenFile, uint16 layerNo); byte *fetchShadingMask(byte *screenFile); - AnimHeader *fetchAnimHeader(byte *animFile); - CdtEntry *fetchCdtEntry(byte *animFile, uint16 frameNo); - FrameHeader *fetchFrameHeader(byte *animFile, uint16 frameNo); - Parallax *fetchBackgroundParallaxLayer(byte *screenFile, int layer); - Parallax *fetchBackgroundLayer(byte *screenFile); - Parallax *fetchForegroundParallaxLayer(byte *screenFile, int layer); + byte *fetchAnimHeader(byte *animFile); + byte *fetchCdtEntry(byte *animFile, uint16 frameNo); + byte *fetchFrameHeader(byte *animFile, uint16 frameNo); + byte *fetchBackgroundParallaxLayer(byte *screenFile, int layer); + byte *fetchBackgroundLayer(byte *screenFile); + byte *fetchForegroundParallaxLayer(byte *screenFile, int layer); byte *fetchTextLine(byte *file, uint32 text_line); bool checkTextLine(byte *file, uint32 text_line); byte *fetchPaletteMatchTable(byte *screenFile); - byte *fetchObjectName(int32 resourceId, byte *buf); - - // savegame file header - -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - - struct SaveGameHeader { - // sum of all bytes in file, excluding this uint32 - uint32 checksum; - - // player's description of savegame - char description[SAVE_DESCRIPTION_LEN]; - - uint32 varLength; // length of global variables resource - uint32 screenId; // resource id of screen file - uint32 runListId; // resource id of run list - uint32 feet_x; // copy of _thisScreen.feet_x - uint32 feet_y; // copy of _thisScreen.feet_y - uint32 music_id; // copy of 'looping_music_id' - ObjectHub player_hub; // copy of player object's object_hub structure - ObjectLogic logic; // copy of player character logic structure - ObjectGraphic graphic; // copy of player character graphic structure - ObjectMega mega; // copy of player character mega structure - } GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - - SaveGameHeader _saveGameHeader; uint32 saveGame(uint16 slotNo, byte *description); uint32 restoreGame(uint16 slotNo); uint32 getSaveDescription(uint16 slotNo, byte *description); bool saveExists(); bool saveExists(uint16 slotNo); - void fillSaveBuffer(byte *buffer, uint32 size, byte *desc); uint32 restoreFromBuffer(byte *buffer, uint32 size); uint32 findBufferSize(); diff --git a/sword2/sync.cpp b/sword2/sync.cpp index d5fb75105f..256ecf5097 100644 --- a/sword2/sync.cpp +++ b/sword2/sync.cpp @@ -46,8 +46,10 @@ void Logic::clearSyncs(uint32 id) { */ int Logic::getSync() { + uint32 id = readVar(ID); + for (int i = 0; i < MAX_syncs; i++) { - if (_syncList[i].id == _scriptVars[ID]) + if (_syncList[i].id == id) return i; } diff --git a/sword2/walker.cpp b/sword2/walker.cpp index 1bc65146c6..7312c51ddd 100644 --- a/sword2/walker.cpp +++ b/sword2/walker.cpp @@ -79,10 +79,14 @@ int Router::whatTarget(int startX, int startY, int destX, int destY) { * RESULT to 1. Return true if the mega has finished walking. */ -int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir) { +int Router::doWalk(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir) { + ObjectLogic obLogic(ob_logic); + ObjectGraphic obGraph(ob_graph); + ObjectMega obMega(ob_mega); + // If this is the start of the walk, calculate the route. - if (!ob_logic->looping) { + if (obLogic.getLooping() == 0) { // If we're already there, don't even bother allocating // memory and calling the router, just quit back & continue // the script! This avoids an embarassing mega stand frame @@ -91,14 +95,14 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o // an anim - no mega frame will appear in between runs of the // anim. - if (ob_mega->feet_x == target_x && ob_mega->feet_y == target_y && ob_mega->current_dir == target_dir) { - Logic::_scriptVars[RESULT] = 0; + if (obMega.getFeetX() == target_x && obMega.getFeetY() == target_y && obMega.getCurDir() == target_dir) { + _vm->_logic->writeVar(RESULT, 0); return IR_CONT; } assert(target_dir <= 8); - ob_mega->walk_pc = 0; + obMega.setWalkPc(0); // Set up mem for _walkData in route_slots[] & set mega's // 'route_slot_id' accordingly @@ -112,16 +116,16 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o if (route != 1 && route != 2) { freeRouteMem(); - Logic::_scriptVars[RESULT] = 1; + _vm->_logic->writeVar(RESULT, 1); return IR_CONT; } // Walk is about to start - ob_mega->currently_walking = 1; - ob_logic->looping = 1; - ob_graph->anim_resource = ob_mega->megaset_res; - } else if (Logic::_scriptVars[EXIT_FADING] && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { + obMega.setIsWalking(1); + obLogic.setLooping(1); + obGraph.setAnimResource(obMega.getMegasetRes()); + } else if (_vm->_logic->readVar(EXIT_FADING) && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { // Double clicked an exit, and the screen has faded down to // black. Ok, that's it. Back to script and change screen. @@ -130,10 +134,10 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o freeRouteMem(); - ob_logic->looping = 0; - ob_mega->currently_walking = 0; - Logic::_scriptVars[EXIT_CLICK_ID] = 0; - Logic::_scriptVars[RESULT] = 0; + obLogic.setLooping(0); + obMega.setIsWalking(0); + _vm->_logic->writeVar(EXIT_CLICK_ID, 0); + _vm->_logic->writeVar(RESULT, 0); return IR_CONT; } @@ -141,7 +145,7 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o // Get pointer to walkanim & current frame position WalkData *walkAnim = getRouteMem(); - int32 walk_pc = ob_mega->walk_pc; + int32 walk_pc = obMega.getWalkPc(); // If stopping the walk early, overwrite the next step with a // slow-out, then finish @@ -153,17 +157,17 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o // Get new frame of walk - ob_graph->anim_pc = walkAnim[walk_pc].frame; - ob_mega->current_dir = walkAnim[walk_pc].dir; - ob_mega->feet_x = walkAnim[walk_pc].x; - ob_mega->feet_y = walkAnim[walk_pc].y; + obGraph.setAnimPc(walkAnim[walk_pc].frame); + obMega.setCurDir(walkAnim[walk_pc].dir); + obMega.setFeetX(walkAnim[walk_pc].x); + obMega.setFeetY(walkAnim[walk_pc].y); // Is the NEXT frame is the end-marker (512) of the walk sequence? if (walkAnim[walk_pc + 1].frame != 512) { // No, it wasn't. Increment the walk-anim frame number and // come back next cycle. - ob_mega->walk_pc++; + obMega.setWalkPc(obMega.getWalkPc() + 1); return IR_REPEAT; } @@ -171,8 +175,8 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o // script just as the final (stand) frame of the walk is set. freeRouteMem(); - ob_logic->looping = 0; - ob_mega->currently_walking = 0; + obLogic.setLooping(0); + obMega.setIsWalking(0); // If George's walk has been interrupted to run a new action script for // instance or Nico's walk has been interrupted by player clicking on @@ -184,11 +188,11 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o if (_vm->_logic->checkEventWaiting()) { _vm->_logic->startEvent(); - Logic::_scriptVars[RESULT] = 1; + _vm->_logic->writeVar(RESULT, 1); return IR_TERMINATE; } - Logic::_scriptVars[RESULT] = 0; + _vm->_logic->writeVar(RESULT, 0); // CONTINUE the script so that RESULT can be checked! Also, if an anim // command follows the fnWalk command, the 1st frame of the anim (which @@ -203,7 +207,7 @@ int Router::doWalk(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o * Walk mega to start position of anim */ -int Router::walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 animRes) { +int Router::walkToAnim(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 animRes) { int16 target_x = 0; int16 target_y = 0; uint8 target_dir = 0; @@ -213,13 +217,17 @@ int Router::walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMeg // If this is the start of the walk, read anim file to get start coords - if (!ob_logic->looping) { + ObjectLogic obLogic(ob_logic); + + if (obLogic.getLooping() == 0) { byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + AnimHeader anim_head; - target_x = anim_head->feetStartX; - target_y = anim_head->feetStartY; - target_dir = anim_head->feetStartDir; + anim_head.read(_vm->fetchAnimHeader(anim_file)); + + target_x = anim_head.feetStartX; + target_y = anim_head.feetStartY; + target_dir = anim_head.feetStartDir; _vm->_resman->closeResource(animRes); @@ -242,53 +250,47 @@ int Router::walkToAnim(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMeg * Route to the left or right hand side of target id, if possible. */ -int Router::walkToTalkToMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId, uint32 separation) { +int Router::walkToTalkToMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId, uint32 separation) { + ObjectMega obMega(ob_mega); + int16 target_x = 0; int16 target_y = 0; uint8 target_dir = 0; // If this is the start of the walk, calculate the route. - if (!ob_logic->looping) { - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(megaId); + ObjectLogic obLogic(ob_logic); - assert(head->fileType == GAME_OBJECT); + if (obLogic.getLooping() == 0) { + assert(_vm->_resman->fetchType(megaId) == GAME_OBJECT); // Call the base script. This is the graphic/mouse service // call, and will set _engineMega to the ObjectMega of mega we // want to route to. - char *raw_script_ad = (char *)head; - uint32 null_pc = 3; + _vm->_logic->runResScript(megaId, 3); - _vm->_logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - _vm->_resman->closeResource(megaId); - - ObjectMega *targetMega = _vm->_logic->getEngineMega(); + ObjectMega targetMega(_vm->_logic->getEngineMega()); // Stand exactly beside the mega, ie. at same y-coord - target_y = targetMega->feet_y; - - // Apply scale factor to walk distance. Ay+B gives 256 * scale - // ie. 256 * 256 * true_scale for even better accuracy, ie. - // scale = (Ay + B) / 256 + target_y = targetMega.getFeetY(); - int scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256; + int scale = obMega.calcScale(); int mega_separation = (separation * scale) / 256; - debug(4, "Target is at (%d, %d), separation %d", targetMega->feet_x, targetMega->feet_y, mega_separation); + debug(4, "Target is at (%d, %d), separation %d", targetMega.getFeetX(), targetMega.getFeetY(), mega_separation); - if (targetMega->feet_x < ob_mega->feet_x) { + if (targetMega.getFeetX() < obMega.getFeetX()) { // Target is left of us, so aim to stand to their // right. Face down_left - target_x = targetMega->feet_x + mega_separation; + target_x = targetMega.getFeetX() + mega_separation; target_dir = 5; } else { // Ok, must be right of us so aim to stand to their // left. Face down_right. - target_x = targetMega->feet_x - mega_separation; + target_x = targetMega.getFeetX() - mega_separation; target_dir = 3; } } @@ -300,18 +302,22 @@ int Router::walkToTalkToMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, Obj * current feet coords, so router can produce anim of turn frames. */ -int Router::doFace(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint8 target_dir) { +int Router::doFace(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint8 target_dir) { int16 target_x = 0; int16 target_y = 0; // If this is the start of the turn, get the mega's current feet // coords + the required direction - if (!ob_logic->looping) { + ObjectLogic obLogic(ob_logic); + + if (obLogic.getLooping() == 0) { assert(target_dir <= 7); - target_x = ob_mega->feet_x; - target_y = ob_mega->feet_y; + ObjectMega obMega(ob_mega); + + target_x = obMega.getFeetX(); + target_y = obMega.getFeetY(); } return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); @@ -321,14 +327,18 @@ int Router::doFace(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o * Turn mega to face point (x,y) on the floor */ -int Router::faceXY(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, int16 target_x, int16 target_y) { +int Router::faceXY(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y) { uint8 target_dir = 0; // If this is the start of the turn, get the mega's current feet // coords + the required direction - if (!ob_logic->looping) { - target_dir = whatTarget(ob_mega->feet_x, ob_mega->feet_y, target_x, target_y); + ObjectLogic obLogic(ob_logic); + + if (obLogic.getLooping() == 0) { + ObjectMega obMega(ob_mega); + + target_dir = whatTarget(obMega.getFeetX(), obMega.getFeetY(), target_x, target_y); } return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); @@ -338,29 +348,26 @@ int Router::faceXY(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *o * Turn mega to face another mega. */ -int Router::faceMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega *ob_mega, ObjectWalkdata *ob_walkdata, uint32 megaId) { +int Router::faceMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId) { uint8 target_dir = 0; // If this is the start of the walk, decide where to walk to. - if (!ob_logic->looping) { - StandardHeader *head = (StandardHeader *)_vm->_resman->openResource(megaId); + ObjectLogic obLogic(ob_logic); - assert(head->fileType == GAME_OBJECT); + if (obLogic.getLooping() == 0) { + assert(_vm->_resman->fetchType(megaId) == GAME_OBJECT); // Call the base script. This is the graphic/mouse service // call, and will set _engineMega to the ObjectMega of mega we // want to turn to face. - char *raw_script_ad = (char *)head; - uint32 null_pc = 3; - - _vm->_logic->runScript(raw_script_ad, raw_script_ad, &null_pc); - _vm->_resman->closeResource(megaId); + _vm->_logic->runResScript(megaId, 3); - ObjectMega *targetMega = _vm->_logic->getEngineMega(); + ObjectMega obMega(ob_mega); + ObjectMega targetMega(_vm->_logic->getEngineMega()); - target_dir = whatTarget(ob_mega->feet_x, ob_mega->feet_y, targetMega->feet_x, targetMega->feet_y); + target_dir = whatTarget(obMega.getFeetX(), obMega.getFeetY(), targetMega.getFeetX(), targetMega.getFeetY()); } return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); @@ -372,33 +379,38 @@ int Router::faceMega(ObjectLogic *ob_logic, ObjectGraphic *ob_graph, ObjectMega * the mega object, so the router knows in future */ -void Router::standAt(ObjectGraphic *ob_graph, ObjectMega *ob_mega, int32 x, int32 y, int32 dir) { +void Router::standAt(byte *ob_graph, byte *ob_mega, int32 x, int32 y, int32 dir) { assert(dir >= 0 && dir <= 7); + ObjectGraphic obGraph(ob_graph); + ObjectMega obMega(ob_mega); + // Set up the stand frame & set the mega's new direction - ob_mega->feet_x = x; - ob_mega->feet_y = y; - ob_mega->current_dir = dir; + obMega.setFeetX(x); + obMega.setFeetY(y); + obMega.setCurDir(dir); // Mega-set animation file - ob_graph->anim_resource = ob_mega->megaset_res; + obGraph.setAnimResource(obMega.getMegasetRes()); // Dir + first stand frame (always frame 96) - ob_graph->anim_pc = dir + 96; + obGraph.setAnimPc(dir + 96); } /** - * stand mega at end position of anim + * Stand mega at end position of anim */ -void Router::standAfterAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes) { +void Router::standAfterAnim(byte *ob_graph, byte *ob_mega, uint32 animRes) { byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + AnimHeader anim_head; + + anim_head.read(_vm->fetchAnimHeader(anim_file)); - int32 x = anim_head->feetEndX; - int32 y = anim_head->feetEndY; - int32 dir = anim_head->feetEndDir; + int32 x = anim_head.feetEndX; + int32 y = anim_head.feetEndY; + int32 dir = anim_head.feetEndDir; _vm->_resman->closeResource(animRes); @@ -414,13 +426,15 @@ void Router::standAfterAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 standAt(ob_graph, ob_mega, x, y, dir); } -void Router::standAtAnim(ObjectGraphic *ob_graph, ObjectMega *ob_mega, uint32 animRes) { +void Router::standAtAnim(byte *ob_graph, byte *ob_mega, uint32 animRes) { byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file); + AnimHeader anim_head; + + anim_head.read(_vm->fetchAnimHeader(anim_file)); - int32 x = anim_head->feetStartX; - int32 y = anim_head->feetStartY; - int32 dir = anim_head->feetStartDir; + int32 x = anim_head.feetStartX; + int32 y = anim_head.feetStartY; + int32 dir = anim_head.feetStartDir; _vm->_resman->closeResource(animRes); |