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'. obGraph.setType((obGraph.getType() & 0x0000ffff) | type); }
void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega) { ObjectGraphic obGraph(ob_graph); // check low word for sprite type switch (obGraph.getType() & 0x0000ffff) { case BGP0_SPRITE: assert(_curBgp0 < MAX_bgp0_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp0List[_curBgp0]); _curBgp0++; break; case BGP1_SPRITE: assert(_curBgp1 < MAX_bgp1_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp1List[_curBgp1]); _curBgp1++; break; case BACK_SPRITE: assert(_curBack < MAX_back_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_backList[_curBack]); _curBack++; break; case SORT_SPRITE: assert(_curSort < MAX_sort_sprites); _sortOrder[_curSort] = _curSort; registerFrame(ob_mouse, ob_graph, ob_mega, &_sortList[_curSort]); _curSort++; break; case FORE_SPRITE: assert(_curFore < MAX_fore_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_foreList[_curFore]); _curFore++; break; case FGP0_SPRITE: assert(_curFgp0 < MAX_fgp0_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp0List[_curFgp0]); _curFgp0++; break; case FGP1_SPRITE: assert(_curFgp1 < MAX_fgp1_sprites); registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp1List[_curFgp1]); _curFgp1++; break; default: // NO_SPRITE no registering! break; } }
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 obMega.setFeetX(x); obMega.setFeetY(y); obMega.setCurDir(dir); // Mega-set animation file obGraph.setAnimResource(obMega.getMegasetRes()); // Dir + first stand frame (always frame 96) obGraph.setAnimPc(dir + 96); }
void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega, BuildUnit *build_unit) { ObjectGraphic obGraph(ob_graph); ObjectMega obMega(ob_mega); assert(obGraph.getAnimResource()); 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 (_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->_graphAnimPc = obGraph.getAnimPc() + 1; _vm->_debugger->_graphNoFrames = anim_head.noAnimFrames; } // fill in the BuildUnit structure for this frame build_unit->anim_resource = obGraph.getAnimResource(); build_unit->anim_pc = obGraph.getAnimPc(); build_unit->layer_number = 0; // Affected by shading mask? if (obGraph.getType() & SHADED_SPRITE) build_unit->shadingFlag = true; else build_unit->shadingFlag = false; // Check if this frame has offsets ie. this is a scalable mega frame int scale = 0; 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 = 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); } 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; // Get width and 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 build_unit->scale = scale; // calc the bottom y-coord for sorting purposes build_unit->sort_y = build_unit->y + build_unit->scaled_height - 1; if (ob_mouse) { // passed a mouse structure, so add to the _mouseList _vm->_mouse->registerMouse(ob_mouse, build_unit); } _vm->_resman->closeResource(obGraph.getAnimResource()); }
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 (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 // appearing for one cycle when we're already in position for // an anim eg. repeatedly clicking on same object to repeat // an anim - no mega frame will appear in between runs of the // anim. 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); obMega.setWalkPc(0); // Set up mem for _walkData in route_slots[] & set mega's // 'route_slot_id' accordingly allocateRouteMem(); int32 route = routeFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir); // 0 = can't make route to target // 1 = created route // 2 = zero route but may need to turn if (route != 1 && route != 2) { freeRouteMem(); _vm->_logic->writeVar(RESULT, 1); return IR_CONT; } // Walk is about to start 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. // We have to clear te EXIT_CLICK_ID variable in case there's a // walk instruction on the new screen, or it'd be cut short. freeRouteMem(); obLogic.setLooping(0); obMega.setIsWalking(0); _vm->_logic->writeVar(EXIT_CLICK_ID, 0); _vm->_logic->writeVar(RESULT, 0); return IR_CONT; } // Get pointer to walkanim & current frame position WalkData *walkAnim = getRouteMem(); int32 walk_pc = obMega.getWalkPc(); // If stopping the walk early, overwrite the next step with a // slow-out, then finish if (_vm->_logic->checkEventWaiting() && walkAnim[walk_pc].step == 0 && walkAnim[walk_pc + 1].step == 1) { // At the beginning of a step earlySlowOut(ob_mega, ob_walkdata); } // Get new frame of walk 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. obMega.setWalkPc(obMega.getWalkPc() + 1); return IR_REPEAT; } // We have reached the end-marker, which means we can return to the // script just as the final (stand) frame of the walk is set. freeRouteMem(); 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 // her to talk // There used to be code here for checking if two megas were colliding, // but it had been commented out, and it was only run if a function // that always returned zero returned non-zero. if (_vm->_logic->checkEventWaiting()) { _vm->_logic->startEvent(); _vm->_logic->writeVar(RESULT, 1); return IR_TERMINATE; } _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 // is always a stand frame itself) can replace the final stand frame of // the walk, to hide the slight difference between the shrinking on the // mega frames and the pre-shrunk anim start-frame. return IR_CONT; }
int Router::doAnimate(byte *ob_logic, byte *ob_graph, int32 animRes, bool reverse) { AnimHeader anim_head; byte *anim_file; ObjectLogic obLogic(ob_logic); ObjectGraphic obGraph(ob_graph); if (obLogic.getLooping() == 0) { // This is the start of the anim - set up the first frame // For testing all anims! // A script loop can send every resource number to the anim // function & it will only run the valid ones. See // 'testing_routines' object in George's Player Character // section of linc 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_graph, NO_SPRITE); return IR_STOP; } // if it's not an animation file if (_vm->_resman->fetchType(animRes) != ANIMATION_FILE) { // switch off the sprite // don't animate - just continue // script next cycle setSpriteStatus(ob_graph, NO_SPRITE); return IR_STOP; } // switch on the sprite setSpriteStatus(ob_graph, SORT_SPRITE); } assert(animRes); // open anim file anim_file = _vm->_resman->openResource(animRes); assert(_vm->_resman->fetchType(animRes) == ANIMATION_FILE); // point to anim header anim_head.read(_vm->fetchAnimHeader(anim_file)); // now running an anim, looping back to this call again obLogic.setLooping(1); obGraph.setAnimResource(animRes); if (reverse) obGraph.setAnimPc(anim_head.noAnimFrames - 1); else obGraph.setAnimPc(0); } else if (_vm->_logic->getSync() != -1) { // We've received a sync - return to script immediately 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. 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(obGraph.getAnimResource()); anim_head.read(_vm->fetchAnimHeader(anim_file)); if (reverse) obGraph.setAnimPc(obGraph.getAnimPc() - 1); else obGraph.setAnimPc(obGraph.getAnimPc() + 1); } // check for end of anim if (reverse) { if (obGraph.getAnimPc() == 0) obLogic.setLooping(0); } else { if (obGraph.getAnimPc() == anim_head.noAnimFrames - 1) obLogic.setLooping(0); } // close the anim file _vm->_resman->closeResource(obGraph.getAnimResource()); // check if we want the script to loop back & call this function again return obLogic.getLooping() ? IR_REPEAT : IR_STOP; }
void Router::setSpriteStatus(byte *ob_graph, uint32 type) { ObjectGraphic obGraph(ob_graph); // Remove the previous status, but don't affect the shading upper-word obGraph.setType((obGraph.getType() & 0xffff0000) | type); }