scummvm/sword2/build_display.cpp

1246 lines
38 KiB
C++

/* Copyright (C) 1994-2003 Revolution Software Ltd
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
//------------------------------------------------------------------------------------
// BUILD_DISPLAY.CPP like the old spr_engi but slightly more aptly named
//------------------------------------------------------------------------------------
//#include <mmsystem.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//#include <windows.h>
//#include <windowsx.h>
#include "stdafx.h"
#include "driver/driver96.h"
#include "build_display.h"
#include "console.h"
#include "debug.h"
#include "defs.h"
#include "events.h"
#include "function.h"
#include "header.h"
#include "interpreter.h"
#include "layers.h"
#include "logic.h"
#include "maketext.h"
#include "memory.h"
#include "mouse.h"
#include "object.h"
#include "protocol.h"
#include "resman.h"
#include "router.h"
#include "save_rest.h"
#include "scroll.h"
#include "sword2.h"
//------------------------------------------------------------------------------------
buildit bgp0_list[MAX_bgp0_sprites];
buildit bgp1_list[MAX_bgp1_sprites];
buildit back_list[MAX_back_sprites];
buildit sort_list[MAX_sort_sprites];
buildit fore_list[MAX_fore_sprites];
buildit fgp0_list[MAX_fgp0_sprites];
buildit fgp1_list[MAX_fgp1_sprites];
uint16 sort_order[MAX_sort_sprites]; //holds the order of the sort list - i.e the list stays static and we sort this
uint32 cur_bgp0;
uint32 cur_bgp1;
uint32 cur_back;
uint32 cur_sort;
uint32 cur_fore;
uint32 cur_fgp0;
uint32 cur_fgp1;
#ifdef _SWORD2_DEBUG
uint32 largest_layer_area=0; // should be reset to zero at start of each screen change
uint32 largest_sprite_area=0; // - " -
char largest_layer_info[128] = {"largest layer: none registered"};
char largest_sprite_info[128] = {"largest sprite: none registered"};
#endif
//------------------------------------------------------------------------------------
// last palette used - so that we can restore the correct one after a pause (which dims the screen)
// - and it's not always the main screen palette that we want, eg. during the eclipse
// This flag gets set in Start_new_palette() and SetFullPalette()
uint32 lastPaletteRes=0;
//------------------------------------------------------------------------------------
// 'frames per second' counting stuff
uint32 fps=0;
uint32 cycleTime=0;
uint32 frameCount=0;
extern uint32 mouse_status; // So I know if the control Panel can be activated - CJR 1-5-97
//------------------------------------------------------------------------------------
// function prototypes not needed externally
void Start_new_palette(void); //Tony25Sept96
void Register_frame(int32 *params, buildit *build_unit); // (1nov96JEL)
void Process_layer(uint32 layer_number); //Tony24Sept96
void Sort_the_sort_list(void); //Tony18Sept96
void Send_back_par0_frames(void); //James23Jan97
void Send_back_par1_frames(void); //James23Jan97
void Send_back_frames(void); //Tony23Sept96
void Send_sort_frames(void);
void Send_fore_frames(void);
void Send_fore_par0_frames(void); //James23Jan97
void Send_fore_par1_frames(void); //James23Jan97
//------------------------------------------------------------------------------------
//
// PC Build_display
//
//------------------------------------------------------------------------------------
void Build_display(void) //Tony21Sept96
{
BOOL end;
#ifdef _SWORD2_DEBUG
uint8 pal[12]={0,0,0,0,0,0,0,0,0,255,0,0};
#endif
uint8 *file;
_multiScreenHeader *screenLayerTable;
#ifdef _SWORD2_DEBUG // only used by console
_spriteInfo spriteInfo;
uint32 rv; // drivers error return value
#endif
if ((!console_status)&&(this_screen.new_palette))
{
Start_new_palette(); // start the layer palette fading up
#ifdef _SWORD2_DEBUG // (James23jun97)
largest_layer_area=0; // should be reset to zero at start of each screen change
largest_sprite_area=0; // - " -
#endif
}
if ((!console_status)&&(this_screen.background_layer_id)) // there is a valid screen to run
{
SetScrollTarget(this_screen.scroll_offset_x, this_screen.scroll_offset_y); // set the scroll position
AnimateMouse(); // increment the mouse frame
StartRenderCycle();
while (1) // START OF RENDER CYCLE
{
//----------------------------------------------------
// clear the back buffer, before building up the new screen
// from the back forwards
EraseBackBuffer();
//----------------------------------------------------
// first background parallax + related anims
file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
if (screenLayerTable->bg_parallax[0])
{
RenderParallax(FetchBackgroundParallaxLayer(file, 0), 0);
res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
Send_back_par0_frames();
}
else
res_man.Res_close(this_screen.background_layer_id); // release the screen resource
//----------------------------------------------------
// second background parallax + related anims
file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
if (screenLayerTable->bg_parallax[1])
{
RenderParallax(FetchBackgroundParallaxLayer(file, 1), 1);
res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
Send_back_par1_frames();
}
else
res_man.Res_close(this_screen.background_layer_id); // release the screen resource
//----------------------------------------------------
// normal backround layer (just the one!)
file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
RenderParallax(FetchBackgroundLayer(file), 2);
res_man.Res_close(this_screen.background_layer_id); // release the screen resource
//----------------------------------------------------
// sprites & layers
Send_back_frames(); // background sprites
Sort_the_sort_list();
Send_sort_frames(); // sorted sprites & layers
Send_fore_frames(); // foreground sprites
//----------------------------------------------------
// first foreground parallax + related anims
file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
if (screenLayerTable->fg_parallax[0])
{
RenderParallax(FetchForegroundParallaxLayer(file, 0), 3);
res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
Send_fore_par0_frames();
}
else
res_man.Res_close(this_screen.background_layer_id); // release the screen resource
//----------------------------------------------------
// second foreground parallax + related anims
file = res_man.Res_open(this_screen.background_layer_id); // open the screen resource
screenLayerTable = (_multiScreenHeader *) ((uint8 *) file + sizeof(_standardHeader));
if (screenLayerTable->fg_parallax[1])
{
RenderParallax(FetchForegroundParallaxLayer(file, 1), 4);
res_man.Res_close(this_screen.background_layer_id); // release the screen resource before cacheing the sprites
Send_fore_par1_frames();
}
else
res_man.Res_close(this_screen.background_layer_id); // release the screen resource
//----------------------------------------------------
// walkgrid, mouse & player markers & mouse area rectangle
Draw_debug_graphics(); // JAMES (08apr97)
//----------------------------------------------------
// text blocks
Print_text_blocs(); // speech blocks and headup debug text
//----------------------------------------------------
// menu bar & icons
ProcessMenu();
//----------------------------------------------------
// ready - blit to screen
CopyScreenBuffer();
//----------------------------------------------------
// update our fps reading
frameCount += 1;
if (SVM_timeGetTime() > cycleTime)
{
fps = frameCount;
frameCount = 0;
cycleTime = SVM_timeGetTime()+1000;
}
//----------------------------------------------------
// check if we've got time to render the screen again this cycle
// (so drivers can smooth out the scrolling in between normal game cycles)
EndRenderCycle(&end);
if (end) // if we haven't got time to render again this cycle, drop out of 'render cycle' while-loop
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if the game is being shut down, drop out
break;
//----------------------------------------------------
} // END OF RENDER CYCLE
}
#ifdef _SWORD2_DEBUG
else if (console_status)
{
spriteInfo.x = 0;
spriteInfo.y = con_y;
spriteInfo.w = con_width;
spriteInfo.h = con_depth;
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
spriteInfo.type = RDSPR_DISPLAYALIGN+RDSPR_NOCOMPRESSION; // no compression!
spriteInfo.blend = 0;
spriteInfo.data = console_sprite->ad;
spriteInfo.colourTable = 0;
rv = DrawSprite( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x (drawing console) [%s line %u]", rv, __FILE__, __LINE__);
CopyScreenBuffer();
}
else
{
StartConsole();
SetPalette(0, 3, pal, RDPAL_INSTANT); //force the palette
Print_to_console("no valid screen?");
}
#endif // _SWORD2_DEBUG
}
//------------------------------------------------------------------------------------
//
// Fades down and displays a message on the screen for time seconds
//
void DisplayMsg( uint8 *text, int time ) // Chris 15May97
{
mem *text_spr;
_frameHeader *frame;
_spriteInfo spriteInfo;
_palEntry pal[256];
_palEntry oldPal[256];
int16 oldY;
int16 oldX;
uint32 rv; // drivers error return value
warning("DisplayMsg: %s", (char *) text);
if (GetFadeStatus() != RDFADE_BLACK)
{
FadeDown((float) 0.75);
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(GetFadeStatus()==RDFADE_DOWN);
}
Set_mouse(0);
Set_luggage(0); //tw28Aug
EraseBackBuffer(); // for hardware rendering
EraseSoftwareScreenBuffer(); // for software rendering
text_spr = MakeTextSprite( text, 640, 187, speech_font_id );
frame = (_frameHeader*) text_spr->ad;
spriteInfo.x = screenWide/2 - frame->width/2;
if (!time)
spriteInfo.y = screenDeep/2 - frame->height/2 - RDMENU_MENUDEEP;
else
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->ad + sizeof(_frameHeader);
spriteInfo.colourTable = 0;
oldX = spriteInfo.x;
oldY = spriteInfo.y;
rv = DrawSprite( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x (in DisplayMsg) [%s line %u]", rv, __FILE__, __LINE__);
spriteInfo.x = oldX;
spriteInfo.y = oldY;
memcpy((char *) oldPal, (char *) palCopy, 256*sizeof(_palEntry));
memset(pal, 0, 256*sizeof(_palEntry));
pal[187].red = 255;
pal[187].green = 255;
pal[187].blue = 255;
SetPalette(0, 256, (uint8 *) pal, RDPAL_FADE);
CopyScreenBuffer();
FadeUp((float)0.75);
Free_mem(text_spr);
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(GetFadeStatus()==RDFADE_UP);
uint32 targetTime = SVM_timeGetTime() + (time*1000);
while(SVM_timeGetTime() < targetTime)
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
EraseBackBuffer(); // for hardware rendering
EraseSoftwareScreenBuffer(); // for software rendering
rv = DrawSprite( &spriteInfo ); // Keep the message there even when the user task swaps.
if (rv)
ExitWithReport("Driver Error %.8x (in DisplayMsg) [%s line %u]", rv, __FILE__, __LINE__);
spriteInfo.y = oldY; // Drivers change the y co-ordinate, don't know why...
spriteInfo.x = oldX;
CopyScreenBuffer();
}
SetPalette(0, 256, (uint8 *) oldPal, RDPAL_FADE);
}
//------------------------------------------------------------------------------------
//
// Fades message down and removes it, fading up again afterwards
//
void RemoveMsg( void ) // Chris 15May97
{
FadeDown((float)0.75);
do
{
//--------------------------------------------------
// Service windows
while (!gotTheFocus)
if (ServiceWindows() == RDERR_APPCLOSED)
break;
if (ServiceWindows() == RDERR_APPCLOSED) // if we pressed Ctrl-Q
{
Close_game(); //close engine systems down
CloseAppWindow();
exit(0); //quit the game
}
//--------------------------------------------------
}
while(GetFadeStatus()==RDFADE_DOWN);
EraseBackBuffer(); // for hardware rendering
EraseSoftwareScreenBuffer(); // for software rendering
CopyScreenBuffer();
// FadeUp((float)0.75);
// removed by JEL (08oct97) to prevent "eye" smacker corruption when restarting game from CD2
// and also to prevent palette flicker when restoring game to a different CD
// - since the "insert CD" message uses this routine to clean up!
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
void Send_back_par0_frames(void) //James23Jan97
{
uint32 j;
for (j=0; j<cur_bgp0; j++) // could be none at all - theoretically at least
{
Process_image(&bgp0_list[j]); // frame attached to 1st background parallax
}
}
//------------------------------------------------------------------------------------
void Send_back_par1_frames(void) //James23Jan97
{
uint32 j;
for (j=0; j<cur_bgp1; j++) // could be none at all - theoretically at least
{
Process_image(&bgp1_list[j]); // frame attached to 1nd background parallax
}
}
//------------------------------------------------------------------------------------
void Send_back_frames(void) //Tony23Sept96
{
uint32 j;
for (j=0; j<cur_back; j++) // could be none at all - theoretically at least
{
Process_image(&back_list[j]);
}
}
//------------------------------------------------------------------------------------
void Send_sort_frames(void) //Tony23Sept96
{
//send the sort frames for printing - layers, shrinkers & normal flat sprites
uint32 j;
for (j=0; j<cur_sort; j++) // could be none at all - theoretically at least
{
if (sort_list[sort_order[j]].layer_number) //its a layer - minus 1 for true layer number
Process_layer(sort_list[sort_order[j]].layer_number-1); //we need to know from the buildit because the layers will have been sorted in random order
else
Process_image(&sort_list[sort_order[j]]); // sprite
}
}
//------------------------------------------------------------------------------------
void Send_fore_frames(void) //Tony23Sept96
{
uint32 j;
for (j=0; j<cur_fore; j++) // could be none at all - theoretically at least
{
Process_image(&fore_list[j]);
}
}
//------------------------------------------------------------------------------------
void Send_fore_par0_frames(void) //James23Jan97
{
uint32 j;
for (j=0; j<cur_fgp0; j++) // could be none at all - theoretically at least
{
Process_image(&fgp0_list[j]); // frame attached to 1st foreground parallax
}
}
//------------------------------------------------------------------------------------
void Send_fore_par1_frames(void) //James23Jan97
{
uint32 j;
for (j=0; j<cur_fgp1; j++) // could be none at all - theoretically at least
{
Process_image(&fgp1_list[j]); // frame attached to 2nd foreground parallax
}
}
//------------------------------------------------------------------------------------
void Process_layer(uint32 layer_number) //Tony24Sept96
{
uint8 *file;
_layerHeader *layer_head;
_spriteInfo spriteInfo;
uint32 rv;
#ifdef _SWORD2_DEBUG
uint32 current_layer_area=0;
#endif
file = res_man.Res_open(this_screen.background_layer_id); // file points to 1st byte in the layer file
layer_head = FetchLayerHeader(file,layer_number); // point to layer header
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.type = RDSPR_TRANS + RDSPR_RLE256FAST;
spriteInfo.blend = 0;
spriteInfo.data = file+sizeof(_standardHeader)+layer_head->offset;
spriteInfo.colourTable = 0;
//------------------------------------------
// check for largest layer for debug info
#ifdef _SWORD2_DEBUG
current_layer_area = layer_head->width * layer_head->height;
if (current_layer_area > largest_layer_area)
{
largest_layer_area = current_layer_area;
sprintf (largest_layer_info, "largest layer: %s layer(%d) is %dx%d", FetchObjectName(this_screen.background_layer_id), layer_number, layer_head->width, layer_head->height);
}
#endif
//------------------------------------------
rv = DrawSprite( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x in Process_layer(%d) [%s line %u]", rv, layer_number, __FILE__, __LINE__);
res_man.Res_close(this_screen.background_layer_id);
}
//------------------------------------------------------------------------------------
void Process_image(buildit *build_unit) // (5nov96 JEL)
{
uint8 *file, *colTablePtr=NULL;
_animHeader *anim_head;
_frameHeader *frame_head;
_cdtEntry *cdt_entry;
_spriteInfo spriteInfo;
uint32 spriteType;
uint32 rv;
#ifdef _SWORD2_DEBUG
uint32 current_sprite_area=0;
#endif
file = res_man.Res_open(build_unit->anim_resource); // open anim resource file & point to base
anim_head = FetchAnimHeader( file );
cdt_entry = FetchCdtEntry( file, build_unit->anim_pc );
frame_head = FetchFrameHeader( file, build_unit->anim_pc );
spriteType = RDSPR_TRANS; // so that 0-colour is transparent
if (anim_head->blend)
spriteType += RDSPR_BLEND;
if ((cdt_entry->frameType) & FRAME_FLIPPED) // if the frame is to be flipped (only really applicable to frames using offsets)
spriteType += RDSPR_FLIP;
if ((cdt_entry->frameType) & FRAME_256_FAST)
{
if ((build_unit->scale)||(anim_head->blend)||(build_unit->shadingFlag)) // scaling, shading & blending don't work with RLE256FAST
spriteType += RDSPR_RLE256; // but the same compression can be decompressed using the RLE256 routines!
else
spriteType += RDSPR_RLE256FAST;
}
else
{
switch (anim_head->runTimeComp) // what compression was used?
{
case NONE:
spriteType += RDSPR_NOCOMPRESSION;
break;
case RLE256:
spriteType += RDSPR_RLE256;
break;
case RLE16:
spriteType += RDSPR_RLE16;
colTablePtr = (uint8*)(anim_head+1) + anim_head->noAnimFrames*sizeof(_cdtEntry);
// points to just after last cdt_entry, ie. start of colour table
break;
}
}
if (build_unit->shadingFlag==1) // if we want this frame to be affected by the shading mask
spriteType += RDSPR_SHADOW; // add the status bit
spriteInfo.x = build_unit->x;
spriteInfo.y = build_unit->y;
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.data = (uint8*)(frame_head+1); // points to just after frame header, ie. start of sprite data
spriteInfo.colourTable = colTablePtr;
//------------------------------------------
// check for largest layer for debug info
#ifdef _SWORD2_DEBUG
current_sprite_area = frame_head->width * frame_head->height;
if (current_sprite_area > largest_sprite_area)
{
largest_sprite_area = current_sprite_area;
sprintf (largest_sprite_info, "largest sprite: %s frame(%d) is %dx%d", FetchObjectName(build_unit->anim_resource), build_unit->anim_pc, frame_head->width, frame_head->height);
}
#endif
//------------------------------------------
//-----------------------------------------------------------
#ifdef _SWORD2_DEBUG
if (SYSTEM_TESTING_ANIMS) // see anims.cpp
{
if ((spriteInfo.x + spriteInfo.scaledWidth) >= 639) // bring the anim into the visible screen
spriteInfo.x = 639-spriteInfo.scaledWidth; // but leave extra pixel at edge for box
if ((spriteInfo.y + spriteInfo.scaledHeight) >= 399)
spriteInfo.y = 399-spriteInfo.scaledHeight;
if (spriteInfo.x < 1)
spriteInfo.x = 1;
if (spriteInfo.y < 1)
spriteInfo.y = 1;
rect_x1 = spriteInfo.x - 1; // create box to surround sprite - just outside sprite box
rect_y1 = spriteInfo.y - 1;
rect_x2 = spriteInfo.x + spriteInfo.scaledWidth;
rect_y2 = spriteInfo.y + spriteInfo.scaledHeight;
}
#endif
//-----------------------------------------------------------
//--------------------------------------------------
// #ifdef _SWORD2_DEBUG
// if (frame_head->width <= 1)
// {
// Zdebug(8,"WARNING: 1-pixel-wide frame found in %s (%d)", FetchObjectName(build_unit->anim_resource), build_unit->anim_resource);
// }
// #endif
//--------------------------------------------------
rv = DrawSprite( &spriteInfo );
if (rv)
ExitWithReport("Driver Error %.8x with sprite %s (%d) in Process_image [%s line %u]", rv, FetchObjectName(build_unit->anim_resource), build_unit->anim_resource, __FILE__, __LINE__);
res_man.Res_close(build_unit->anim_resource); // release the anim resource
}
//------------------------------------------------------------------------------------
void Reset_render_lists(void) //Tony18Sept96
{
//reset the sort lists - do this before a logic loop
//takes into account the fact that the start of the list is pre-built with the special sortable layers
uint32 j;
cur_bgp0=0;
cur_bgp1=0;
cur_back=0;
cur_sort=this_screen.number_of_layers; //beginning of sort list is setup with the special sort layers
cur_fore=0;
cur_fgp0=0;
cur_fgp1=0;
if (cur_sort) //there are some layers - so rebuild the sort order positioning
for (j=0;j<cur_sort;j++)
sort_order[j]=j; //rebuild the order list
}
//------------------------------------------------------------------------------------
void Sort_the_sort_list(void) //Tony18Sept96
{
//sort the list
uint16 i,j,swap;
//sort the list
if (cur_sort>1) //cannot bubble sort 0 or 1 items!
for (i=0; i<cur_sort-1; i++)
for (j=0; j<cur_sort-1; j++)
if (sort_list[sort_order[j]].sort_y > sort_list[sort_order[j+1]].sort_y) //this > next then swap
{ swap=sort_order[j];
sort_order[j]=sort_order[j+1];
sort_order[j+1]=swap;
}
}
//------------------------------------------------------------------------------------
void Register_frame(int32 *params, buildit *build_unit) // (1nov96JEL)
{
// params: 0 pointer to mouse structure or NULL for no write to mouse list (non-zero means write sprite-shape to mouse list)
// 1 pointer to graphic structure
// 2 pointer to mega structure
Object_mega *ob_mega;
Object_graphic *ob_graph;
Object_mouse *ob_mouse;
uint8 *file;
_frameHeader *frame_head;
_animHeader *anim_head;
_cdtEntry *cdt_entry;
int scale=0;
//-------------------------------------------
// open animation file & set up the necessary pointers
ob_graph = (Object_graphic *) params[1];
#ifdef _SWORD2_DEBUG
if (ob_graph->anim_resource == 0)
Con_fatal_error("ERROR: %s(%d) has no anim resource in Register_frame [line=%d file=%s]", FetchObjectName(ID), ID, __LINE__, __FILE__);
#endif
file = res_man.Res_open(ob_graph->anim_resource);
anim_head = FetchAnimHeader( file );
cdt_entry = FetchCdtEntry( file, ob_graph->anim_pc );
frame_head = FetchFrameHeader( file, ob_graph->anim_pc );
#ifdef _SWORD2_DEBUG
if (ID == CUR_PLAYER_ID) // update player graphic details for on-screen debug info
{
playerGraphic.type = ob_graph->type;
playerGraphic.anim_resource = ob_graph->anim_resource;
playerGraphic.anim_pc = ob_graph->anim_pc+1; // counting 1st frame as 'frame 1'
player_graphic_no_frames = anim_head->noAnimFrames;
}
#endif
//-------------------------------------------
// fill in the buildit structure for this frame
build_unit->anim_resource = ob_graph->anim_resource; //retrieve the resource
build_unit->anim_pc = ob_graph->anim_pc; //retrieve the frame
build_unit->layer_number = 0; //not a layer
if (ob_graph->type & SHADED_SPRITE)
build_unit->shadingFlag = 1; // affected by shading mask
else
build_unit->shadingFlag = 0; // not shaded
//-------------------------------------------
// check if this frame has offsets ie. this is a scalable mega frame
if ((cdt_entry->frameType) & FRAME_OFFSET)
{
ob_mega = (Object_mega *) params[2]; // param 2 is pointer to mega structure
// 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)
scale = (ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b)/256; // Ay+B gives 256*scale ie. 256*256*true_scale for even better accuracy, ie. scale = (Ay+B)/256
// calc final render coordinates (top-left of sprite), based on feet coords & scaled offsets
build_unit->x = ob_mega->feet_x + (cdt_entry->x * scale)/256; // add scaled offsets to feet coords
build_unit->y = ob_mega->feet_y + (cdt_entry->y * scale)/256;
// work out new width and height
build_unit->scaled_width = ((scale * frame_head->width) / 256); // always divide by 256 after everything else, to maintain accurary
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; //retrieve the x
build_unit->y = cdt_entry->y; //retrieve the y
// get width and height
build_unit->scaled_width = frame_head->width;
build_unit->scaled_height = frame_head->height;
}
//-------------------------------------------
build_unit->scale = scale; // either 0 or required scale, depending on whether 'scale' computed
// calc the bottom y-coord for sorting purposes
build_unit->sort_y = build_unit->y + build_unit->scaled_height - 1;
//-------------------------------------------
if (params[0]) // passed a mouse structure, so add to the mouse_list
{
ob_mouse = (Object_mouse *) params[0];
if (ob_mouse->pointer) // only if 'pointer' isn't NULL (James13feb97)
{
#ifdef _SWORD2_DEBUG
if (cur_mouse==TOTAL_mouse_list)
Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
#endif
mouse_list[cur_mouse].x1 = build_unit->x;
mouse_list[cur_mouse].y1 = build_unit->y;
mouse_list[cur_mouse].x2 = build_unit->x + build_unit->scaled_width;
mouse_list[cur_mouse].y2 = build_unit->y + build_unit->scaled_height;
mouse_list[cur_mouse].priority = ob_mouse->priority;
mouse_list[cur_mouse].pointer = ob_mouse->pointer;
//-----------------------------------------------
// (James17jun97)
// check if pointer text field is set due to previous object using this slot (ie. not correct for this one)
if ((mouse_list[cur_mouse].pointer_text) && (mouse_list[cur_mouse].id != (int32)ID)) // if 'pointer_text' field is set, but the 'id' field isn't same is current id
mouse_list[cur_mouse].pointer_text=0; // then we don't want this "left over" pointer text
//-----------------------------------------------
mouse_list[cur_mouse].id = ID;
mouse_list[cur_mouse].anim_resource = 0; // not using sprite as detection mask
mouse_list[cur_mouse].anim_pc = 0;
cur_mouse++;
}
}
//-------------------------------------------
res_man.Res_close(ob_graph->anim_resource); // close animation file
}
//------------------------------------------------------------------------------------
int32 FN_register_frame(int32 *params) // (27nov96 JEL)
{
//this call would be made from an objects service script 0
// params: 0 pointer to mouse structure or NULL for no write to mouse list (non-zero means write sprite-shape to mouse list)
// 1 pointer to graphic structure
// 2 pointer to mega structure or NULL if not a mega
Object_graphic *ob_graph = (Object_graphic *) params[1];
switch (ob_graph->type & 0x0000ffff) // check low word for sprite type
{
//---------------
case BGP0_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_bgp0==MAX_bgp0_sprites)
Con_fatal_error("ERROR: bgp0_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &bgp0_list[cur_bgp0]);
cur_bgp0++;
}
break;
//---------------
case BGP1_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_bgp1==MAX_bgp1_sprites)
Con_fatal_error("ERROR: bgp1_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &bgp1_list[cur_bgp1]);
cur_bgp1++;
}
break;
//---------------
case BACK_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_back==MAX_back_sprites)
Con_fatal_error("ERROR: back_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &back_list[cur_back]);
cur_back++;
}
break;
//---------------
case SORT_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_sort==MAX_sort_sprites)
Con_fatal_error("ERROR: sort_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
sort_order[cur_sort]=cur_sort;
Register_frame(params, &sort_list[cur_sort]);
cur_sort++;
}
break;
//---------------
case FORE_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_fore==MAX_fore_sprites)
Con_fatal_error("ERROR: fore_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &fore_list[cur_fore]);
cur_fore++;
}
break;
//---------------
case FGP0_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_fgp0==MAX_fgp0_sprites)
Con_fatal_error("ERROR: fgp0_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &fgp0_list[cur_fgp0]);
cur_fgp0++;
}
break;
//---------------
case FGP1_SPRITE:
{
#ifdef _SWORD2_DEBUG
if (cur_fgp1==MAX_fgp1_sprites)
Con_fatal_error("ERROR: fgp1_list full in FN_register_frame [line=%d file=%s]",__LINE__,__FILE__);
#endif
Register_frame(params, &fgp1_list[cur_fgp1]);
cur_fgp1++;
}
break;
//---------------
// NO_SPRITE no registering!
}
return(IR_CONT);
}
//------------------------------------------------------------------------------------
void Start_new_palette(void) //Tony25Sept96
{
//start layer palette fading up
uint8 *screenFile;
//if the screen is still fading down then wait for black - could happen when everythings cached into a large memory model
do
{
ServiceWindows();
}
while(GetFadeStatus()==RDFADE_DOWN);
screenFile = res_man.Res_open(this_screen.background_layer_id); // open the screen file
UpdatePaletteMatchTable((uint8 *) FetchPaletteMatchTable(screenFile));
SetPalette(0, 256, FetchPalette(screenFile), RDPAL_FADE);
lastPaletteRes=0; // indicating that it's a screen palette
res_man.Res_close(this_screen.background_layer_id); // close screen file
//FadeUp((float)1.75); // start fade up
FadeUp((float)0.75); // start fade up
this_screen.new_palette=0; // reset
}
//------------------------------------------------------------------------------------
int32 FN_update_player_stats(int32 *params) //Tony28Nov96
{
//engine needs to know certain info about the player
Object_mega *ob_mega = (Object_mega *) params[0];
this_screen.player_feet_x = ob_mega->feet_x;
this_screen.player_feet_y = ob_mega->feet_y;
PLAYER_FEET_X=ob_mega->feet_x; //for the script
PLAYER_FEET_Y=ob_mega->feet_y;
PLAYER_CUR_DIR=ob_mega->current_dir;
SCROLL_OFFSET_X=this_screen.scroll_offset_x;
//Zdebug(42,"%d %d", ob_mega->feet_x, ob_mega->feet_y);
return(IR_CONT);
}
//------------------------------------------------------------------------------------
int32 FN_fade_down(int32 *params) //Tony5Dec96
{
if (GetFadeStatus()==RDFADE_NONE) //NONE means up! can only be called when screen is fully faded up - multiple calls wont have strange effects
{
FadeDown((float)0.75);
return(IR_CONT);
}
return(IR_CONT);
}
int32 FN_fade_up(int32 *params) //Chris 15May97
{
do
{
ServiceWindows();
}
while(GetFadeStatus()==RDFADE_DOWN);
if (GetFadeStatus()==RDFADE_BLACK)
{
FadeUp((float)0.75);
return(IR_CONT);
}
return(IR_CONT);
}
//------------------------------------------------------------------------------------
// typedef struct
// {
// uint8 red;
// uint8 green;
// uint8 blue;
// uint8 alpha;
// } _palEntry;
//------------------------------------------------------------
// typedef struct
// {
// uint8 firstEntry; // first colour number in this palette (0..255)
// uint8 noEntries; // number of Entries-1 (0..255) to be taken as (1..256)
// } _paletteHeader;
//------------------------------------------------------------
int32 FN_set_palette(int32 *params) // James05jun97
{
SetFullPalette(params[0]);
return(IR_CONT);
}
//------------------------------------------------------------
void SetFullPalette(int32 palRes) // James17jun97
{
// params 0 resource number of palette file
// or 0 if it's to be the palette from the current screen
uint8 *file;
_standardHeader *head;
//----------------------------------
// fudge for hut interior
// - unpausing should restore last palette as normal (could be screen palette or 'dark_palette_13')
// - but restoring the screen palette after 'dark_plaette_13' should now work properly too!
if (LOCATION==13) // hut interior
{
if (palRes==-1) // unpausing
palRes = lastPaletteRes; // restore whatever palette was last set (screen palette or 'dark_palette_13')
}
else
{
// (James 03sep97)
// check if we're just restoring the current screen palette
// because we might actually need to use a separate palette file anyway
// eg. for pausing & unpausing during the eclipse
if (palRes==-1) // unpausing (fudged for location 13)
palRes=0; // we really meant '0'
if ((palRes==0) && (lastPaletteRes))
palRes = lastPaletteRes;
}
//----------------------------------
if (palRes) // non-zero: set palette to this separate palette file
{
head = (_standardHeader*)res_man.Res_open(palRes); // open the palette file
#ifdef _SWORD2_DEBUG
if (head->fileType != PALETTE_FILE)
Con_fatal_error("FN_set_palette() called with invalid resource! (%s line %u)",__FILE__,__LINE__);
#endif
file = (uint8*)(head+1);
file[0] = 0; // always set colour 0 to black
file[1] = 0; // because most background screen palettes have a bright colour 0
file[2] = 0; // although it should come out as black in the game!
file[3] = 0;
// UpdatePaletteMatchTable(file+(256*4)); // not yet in separate palette files
SetPalette(0, 256, file, RDPAL_INSTANT);
if (palRes != CONTROL_PANEL_PALETTE) // (James 03sep97)
lastPaletteRes=palRes; // indicating that it's a separate palette resource
res_man.Res_close(palRes); // close palette file
}
else // 0: set palette to current screen palette
{
if (this_screen.background_layer_id)
{
file = res_man.Res_open(this_screen.background_layer_id); // open the screen file
UpdatePaletteMatchTable((uint8 *) FetchPaletteMatchTable(file));
SetPalette(0, 256, FetchPalette(file), RDPAL_INSTANT);
lastPaletteRes=0; // indicating that it's a screen palette
res_man.Res_close(this_screen.background_layer_id); // close screen file
}
else
Con_fatal_error("FN_set_palette(0) called, but no current screen available! (%s line %u)",__FILE__,__LINE__);
}
}
//------------------------------------------------------------
int32 FN_restore_game(int32 *params)
{
return (IR_CONT);
}
//------------------------------------------------------------
int32 FN_change_shadows(int32 *params)
{
uint32 rv;
if (this_screen.mask_flag) // if last screen was using a shading mask (see below) (James 08apr97)
{
rv = CloseLightMask();
if (rv)
ExitWithReport("Driver Error %.8x [%s line %u]", rv, __FILE__, __LINE__);
this_screen.mask_flag = 0;
}
return (IR_CONT);
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------