Made icons configurable.

This commit is contained in:
johns 2001-03-23 17:07:58 +00:00
parent 7339e8dcdf
commit ea48a0f765
7 changed files with 490 additions and 97 deletions

View file

@ -569,6 +569,7 @@
<LI>Some more menu code for network menus - unfinished yet.
<LI>Let the AI workers only harvest reachable trees. (very great
performance increase.)
<LI>Made icons configurable.
<LI>+++
<LI>TODO: Fixed bug: Unit does not return to starting point, if attacking.
</UL>

View file

@ -10,7 +10,7 @@
//
/**@name icons.h - The icons headerfile. */
//
// (c) Copyright 1998-2000 by Lutz Sammer
// (c) Copyright 1998-2001 by Lutz Sammer
//
// $Id$
@ -19,10 +19,109 @@
//@{
/*----------------------------------------------------------------------------
-- Documentation
----------------------------------------------------------------------------*/
/**
** @struct _icon_ icons.h
**
** \#include "icons.h"
**
** typedef struct _icon_ Icon;
**
** typedef Icon* IconId;
**
** This structure contains all informations about an icon.
** Currently only rectangular static icons of 46x38 pixels are supported.
** In the future it is planned to support animated and not rectangular
** icons and icons of different sizes.
**
** Icon::Ident
**
** Unique identifier of the icon, used to reference it in config
** files and during startup. Don't use this in game, use instead
** the pointer to this structure.
**
** Icon::Tileset
**
** Unique identifier of the tileset, used to allow different
** graphics for the same icons depending on the tileset. Resolved
** during startup in InitIcons().
** @see Tileset::Ident
**
** Icon::File
**
** Pointer to icon file (file containing the graphics), each icon
** could have an own icon file or some up to all icons could share
** the same icon file.
**
** Icon::Index
**
** Index into the icon file. You know one up to all icons could
** be in the same file. This index distinguishes them.
**
** Icon::X
**
** X pixel index into the graphic image.
** (Icon::Index%5)*ICON_WIDTH.
**
** Icon::Y
**
** Y pixel index into the graphic image.
** (Icon::Index/5)*ICON_HEIGHT.
**
** Icon::Width
**
** Icon width in pixels, defaults to ICON_WIDTH.
**
** Icon::Height
**
** Icon height in pixels, defaults to ICON_WIDTH.
**
** Icon::Graphic
**
** Graphic image containing the loaded graphics. Loaded by
** LoadIcons(). All icons belonging to the same icon file shares
** this structure.
**
** @todo
** IconId can be removed, use Icon* for it.
*/
/**
** @struct _icon_config_ icons.h
**
** \#include "icons.h"
**
** typedef struct _icon_config_ IconConfig;
**
** This structure contains all configuration informations about an icon.
**
** IconConfig::Name
**
** Unique identifier of the icon, used to reference icons in config
** files and during startup. The name is resolved during game
** start and the pointer placed in the next field.
** @see Icon::Ident
**
** IconConfig::Icon
**
** Pointer to an icon. This pointer is resolved during game start.
**
** Example how this can be used in C initializers:
**
** @code
** { "icon-peasant" },
** @endcode
*/
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include "video.h"
/*----------------------------------------------------------------------------
-- Defines
----------------------------------------------------------------------------*/
@ -31,43 +130,84 @@
#define IconClicked 2 /// mouse button down on icon
#define IconSelected 4 /// this the selected icon
#define ICON_WIDTH 46 /// icon width in panels
#define ICON_HEIGHT 38 /// icon height in panels
#define ICON_WIDTH 46 /// default icon width in panels
#define ICON_HEIGHT 38 /// default icon height in panels
/*----------------------------------------------------------------------------
-- Declarations
----------------------------------------------------------------------------*/
typedef unsigned IconId; /// Icon referencing
#define NoIcon -1 /// used for errors = no valid icon
/**
** Icon definition (used in config tables)
** A structure describing an icon file, which could contain one or more
** icons. @internal use only.
**
** @todo
** IconFile::Icons member isn't setup and used.
*/
typedef struct _icon_file_ {
char* FileName; /// Icon file name/path
unsigned Width; /// Icon width
unsigned Height; /// Icon height
/** FIXME: unsed */
unsigned Icons; /// Number of icons in this file
// --- FILLED UP ---
Graphic* Graphic; /// Graphic data loaded
} IconFile;
/// Icon: rectangle image used in menus.
typedef struct _icon_ {
char* Ident; /// Icon identifier
char* Tileset; /// Tileset identifier
IconFile* File; /// File containing the data
unsigned Index; /// Index into file
unsigned X; /// X index into graphic
unsigned Y; /// Y index into graphic
unsigned Width; /// Icon width
unsigned Height; /// Icon height
// --- FILLED UP ---
Graphic* Graphic; /// Graphic data loaded
} Icon;
typedef Icon* IconId; /// Icon referencing
#define NoIcon NULL /// used for errors == no valid icon
/// Icon reference (used in config tables)
typedef struct _icon_config_ {
char* Name; /// config icon name
IconId Icon; /// identifier to use to run time
IconId Icon; /// icon pointer to use to run time
} IconConfig;
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
extern char** IconWcNames; /// pud original -> internal
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
extern void InitIcons(void); /// init icons
extern void LoadIcons(void); /// load icons
extern void CleanIcons(void); /// cleanup
extern void InitIcons(void); /// init icons
extern void LoadIcons(void); /// load icons
extern void CleanIcons(void); /// cleanup icons
extern IconId IconByIdent(const char* ident); /// name -> icon
extern const char* IdentOfIcon(IconId icon); /// icon -> name
extern IconId IconByIdent(const char* ident); /// name -> icon
extern const char* IdentOfIcon(IconId icon); /// icon -> name
/// draw icons of an unit
/// draw icon of an unit
extern void DrawUnitIcon(const void*,IconId,unsigned,unsigned,unsigned);
extern void SaveIcons(FILE*); /// Save icons
extern void IconCclRegister(void); /// register CCL features
//@}
#endif // !__ICONS_H__

View file

@ -116,7 +116,8 @@ typedef struct _upgrade_ {
const void* OType; /// Object type (future extensions)
char* Ident; /// identifier
int Costs[MaxCosts]; /// costs for the upgrade
IconId Icon; /// icon to display to the user
// FIXME: not used by buttons
IconConfig Icon; /// icon to display to the user
} Upgrade;
/**

View file

@ -748,6 +748,7 @@ global void CclInit(void)
init_subr_1("speed-research",CclSpeedResearch);
init_subr_1("speeds",CclSpeeds);
IconCclRegister();
MissileCclRegister();
TilesetCclRegister();
MapCclRegister();

View file

@ -42,7 +42,6 @@
#include "interface.h"
#include "ui.h"
#include "image.h"
#include "missile.h"
#include "sound.h"
#include "actions.h"
#include "cursor.h"
@ -187,7 +186,7 @@ int AddButton(int pos, int level, const char *IconIdent,
ba->UMask = strdup(buf);
UnitButtonTable[UnitButtonCount++] = ba;
DebugCheck(ba->Icon.Icon == -1); // just checks, that's why at the end
DebugCheck(ba->Icon.Icon == NoIcon);// just checks, that's why at the end
return 1;
}

View file

@ -26,10 +26,11 @@
#include "freecraft.h"
#include "tileset.h"
#include "video.h"
#include "map.h"
#include "video.h"
#include "icons.h"
#include "player.h"
#include "ccl.h"
#include "etlib/hash.h"
@ -37,43 +38,36 @@
-- Variables
----------------------------------------------------------------------------*/
#ifndef laterUSE_CCL
#ifndef USE_CCL
/**
** Unit icons
*/
local struct _icons_ {
local struct _icons_files_ {
char* File[TilesetMax]; /// file name
unsigned Width; /// icon width
unsigned Height; /// icon height
// --- FILLED UP ---
Graphic* IconGraphic; /// graphic data loaded
} Icons[] = {
} IconsFiles[] = {
#ifdef NEW_NAMES
{ { "tilesets/summer/icons.png"
,"tilesets/winter/icons.png"
,"tilesets/wasteland/icons.png"
,"tilesets/swamp/icons.png" }
, ICON_WIDTH, ICON_HEIGHT },
#else
{ { "icons (summer).png"
,"icons (winter).png"
,"icons (wasteland).png"
,"icons (swamp).png" }
#endif
, ICON_WIDTH, ICON_HEIGHT },
#endif
};
#endif
local hashtable(int,61) IconHash; /// lookup table for icon names
#ifndef laterUSE_CCL
/**
** Table icon id -> string.
** Default without CCL support.
** Table mapping the original icon numbers in puds to our internal string.
*/
local const char* IconNames[] = {
local char* DefaultIconWcNames[] = {
"icon-peasant",
"icon-peon",
"icon-footman",
@ -269,112 +263,226 @@ local const char* IconNames[] = {
"icon-deathwing",
"icon-khadgar",
"icon-dentarg",
"icon-turalyon"
"icon-turalyon",
NULL
};
#endif
#ifndef laterUSE_CCL
/**
** Table aliases for icons.
*/
local const char* IconAliases[][2] = {
local const char* DefaultIconAliases[][2] = {
{ "icon-raise-dead", "icon-skeleton" },
{ "icon-polymorph", "icon-critter" },
};
#endif
/**
** Maps the original icon numbers in puds to our internal strings.
*/
global char** IconWcNames
#ifndef USE_CCL
= DefaultIconWcNames
#endif
;
local Icon** Icons; /// Table of all icons.
local int IconsCount; /// Number of icons in Icons.
local char** IconAliases; /// Table of all aliases for icons.
local int IconAliasesCount; /// Number of icons aliases in Aliases.
#ifdef DOXYGEN
local IconFile* IconFileHash[31]; /// lookup table for icon file names
local Icon* IconHash[61]; /// lookup table for icon names
#else
local hashtable(IconFile*,31) IconFileHash;/// lookup table for icon file names
local hashtable(Icon*,61) IconHash; /// lookup table for icon names
#endif
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** @brief Add an icon definition.
**
** @bug Redefining an icon isn't supported.
**
** @param ident Icon identifier.
** @param tileset Tileset identifier.
** @param index Index into file.
** @param file Graphic file containing the icons.
*/
local void AddIcon(char* ident,char* tileset,int index,char* file)
{
void** ptr;
char* str;
IconFile* iconfile;
Icon* icon;
ptr=hash_find(IconFileHash,file);
if( ptr ) {
iconfile=*ptr;
} else { // new file
iconfile=malloc(sizeof(IconFile));
iconfile->FileName=strdup(file);
iconfile->Width=ICON_WIDTH;
iconfile->Height=ICON_HEIGHT;
iconfile->Icons=0;
iconfile->Graphic=NULL;
*(IconFile**)hash_add(IconFileHash,iconfile->FileName)=iconfile;
}
str=strdcat(ident,tileset);
ptr=hash_find(IconHash,str);
if( ptr ) {
DebugLevel0Fn("FIXME: Icon already defined `%s'\n",str);
free(str);
return;
} else {
icon=malloc(sizeof(Icon));
icon->Ident=strdup(ident);
icon->Tileset=strdup(tileset);
icon->File=iconfile;
icon->Index=index;
icon->X=(index%5)*iconfile->Width;
icon->Y=(index/5)*iconfile->Height;
icon->Width=iconfile->Width;
icon->Height=iconfile->Height;
icon->Graphic=NULL;
*(Icon**)hash_add(IconHash,str)=icon;
}
Icons=realloc(Icons,sizeof(Icon*)*(IconsCount+1));
Icons[IconsCount++]=icon;
}
/**
** Init the icons.
**
** Add the short name and icon aliases to hash table.
*/
global void InitIcons(void)
{
unsigned i;
static int done;
if( done ) {
return;
}
DebugCheck( done );
done=1;
DebugLevel0Fn("Must use CCL only\n");
DebugLevel0Fn("Init icons %s\n",TheMap.Tileset->Ident);
#ifndef USE_CCL
//
// Add icons name to hash table
//
for( i=0; i<sizeof(IconNames)/sizeof(*IconNames); ++i ) {
*(IconId*)hash_add(IconHash,(char*)IconNames[i])=i;
for( i=0; IconWcNames[i]; ++i ) {
unsigned j;
for( j=0; j<4; ++j ) {
AddIcon(IconWcNames[i],Tilesets[j].Ident,i,IconsFiles[0].File[j]);
}
}
#endif
//
// Add icons of the current tileset, with shortcut to hash.
//
for( i=0; i<IconsCount; ++i ) {
if( !strcmp(Icons[i]->Tileset,TheMap.Tileset->Ident) ) {
*(Icon**)hash_add(IconHash,Icons[i]->Ident)=Icons[i];
}
}
#ifndef USE_CCL
//
// Different names for the same thing
//
for( i=0; i<sizeof(IconAliases)/sizeof(*IconAliases); ++i ) {
for( i=0; i<sizeof(DefaultIconAliases)/sizeof(*DefaultIconAliases); ++i ) {
IconId id;
id=IconByIdent(IconAliases[i][1]);
if( id==NoIcon ) {
abort();
}
id=IconByIdent(DefaultIconAliases[i][1]);
DebugCheck( id==NoIcon );
*(IconId*)hash_add(IconHash,(char*)IconAliases[i][0])=id;
*(Icon**)hash_add(IconHash,(char*)DefaultIconAliases[i][0])=id;
}
#else
//
// Different names for the same thing
//
for( i=0; i<IconAliasesCount; ++i ) {
IconId id;
id=IconByIdent(IconAliases[i*2+1]);
DebugCheck( id==NoIcon );
*(Icon**)hash_add(IconHash,IconAliases[i*2+0])=id;
}
#endif
}
/**
** Load the graphics for the icons.
** Load the graphics for the icons. Graphic data is only loaded once
** and than shared.
*/
global void LoadIcons(void)
{
unsigned i;
const char* file;
InitIcons();
//
// Load all icon files.
//
for( i=0; i<sizeof(Icons)/sizeof(*Icons); ++i ) {
file=Icons[i].File[TheMap.Terrain];
if( !file ) { // default one
file=Icons[i].File[0];
}
if( *file ) {
char* buf;
for( i=0; i<IconsCount; ++i ) {
if( !strcmp(Icons[i]->Tileset,TheMap.Tileset->Ident) ) {
if( !Icons[i]->File->Graphic ) {
char* buf;
char* file;
buf=alloca(strlen(file)+9+1);
file=strcat(strcpy(buf,"graphic/"),file);
ShowLoadProgress("\tIcons %s\n",file);
Icons[i].IconGraphic=LoadGraphic(file);
file=Icons[i]->File->FileName;
buf=alloca(strlen(file)+9+1);
#ifdef NEW_NAMES
file=strcat(strcpy(buf,"graphics/"),file);
#else
file=strcat(strcpy(buf,"graphic/"),file);
#endif
ShowLoadProgress("\tIcons %s\n",file);
Icons[i]->File->Graphic=LoadGraphic(file);
}
Icons[i]->Graphic=Icons[i]->File->Graphic;
}
}
}
/**
** Cleanup memory used by the icons.
**
** @todo
** Write this cleanup function. Needed if we want to play more
** than one level without new start of the program.
*/
global void CleanIcons(void)
{
int i;
// FIXME: only the graphics or also the complete hash?
for( i=0; i<sizeof(Icons)/sizeof(*Icons); ++i ) {
VideoSaveFree(Icons[i].IconGraphic);
Icons[i].IconGraphic=NULL;
}
DebugLevel0Fn("FIXME: cleanup not supported\n");
}
/**
** Find icon by identifier.
** Find the icon by identifier.
**
** @param ident The icon identifier.
** @return Icon id or -1 if not found.
**
** @return Icon pointer or NoIcon == NULL if not found.
*/
global IconId IconByIdent(const char* ident)
{
@ -391,21 +499,21 @@ global IconId IconByIdent(const char* ident)
}
/**
** Get identifier of icon.
** Get the identifier of an icon.
**
** @param icon Icon pointer
**
** @param icon Icon identifier
** @return The identifier for the icon
**
*/
global const char* IdentOfIcon(IconId icon)
{
DebugCheck( icon<0 || icon>sizeof(IconNames)/sizeof(*IconNames) );
DebugCheck( !icon );
return IconNames[icon];
return icon->Ident;
}
/**
** Draw icon 'icon' with border on x,y
** Draw unit icon 'icon' with border on x,y
**
** @param icon Icon identifier
** @param flags State of icon (clicked, mouse over...)
@ -417,7 +525,7 @@ global void DrawUnitIcon(const void* player,IconId icon,unsigned flags
{
int color;
DebugCheck( icon<0 || icon>sizeof(IconNames)/sizeof(*IconNames) );
DebugCheck( !icon );
color= (flags&IconActive) ? ColorGray : ColorBlack;
@ -439,27 +547,170 @@ global void DrawUnitIcon(const void* player,IconId icon,unsigned flags
++x; ++y;
}
GraphicPlayerPixels(player,Icons[0].IconGraphic);
VideoDrawSub(Icons[0].IconGraphic
,(icon%5)*Icons[0].Width,(icon/5)*Icons[0].Height
,Icons[0].Width,Icons[0].Height,x+4,y+4);
x+=4;
y+=4;
GraphicPlayerPixels(player,icon->Graphic);
VideoDrawSub(icon->Graphic,icon->X,icon->Y,icon->Width,icon->Height,x,y);
if( flags&IconSelected ) {
VideoDrawRectangleClip(ColorGreen,x+4,y+4,ICON_WIDTH-1,ICON_HEIGHT-1);
VideoDrawRectangleClip(ColorGreen,x,y,ICON_WIDTH-1,ICON_HEIGHT-1);
}
}
// FIXME: The icon files must be configurable by ccl
// FIXME: The icon names must be configurable by ccl
// FIXME: The icon alias must be configurable by ccl
/*
** FIXME:
** I want to support more icon files, this should make it
** possible that the user can use the original icons and
** his own icons for his extensions.
/**
** Save state of the icons to file.
**
** Even loading and adding single icons I want to support.
** @param file Output file.
*/
global void SaveIcons(FILE* file)
{
char** cp;
int i;
fprintf(file,"\n;;; -----------------------------------------\n");
fprintf(file,";;; MODULE: icons $Id$\n\n");
if( (cp=IconWcNames) ) {
fprintf(file,"(define-icon-wc-names");
i=90;
while( *cp ) {
if( i+strlen(*cp)>79 ) {
i=fprintf(file,"\n ");
}
i+=fprintf(file," '%s",*cp++);
}
fprintf(file,")\n\n");
}
for( i=0; i<IconsCount; ++i ) {
fprintf(file,"(define-icon '%s '%s\n",
Icons[i]->Ident,Icons[i]->Tileset);
fprintf(file," 'normal %d \"%s\")\n",
Icons[i]->Index,Icons[i]->File->FileName);
}
}
#ifdef USE_CCL
/**
** @brief Parse icon definition.
**
** @param list Icon definition list.
*/
local SCM CclDefineIcon(SCM list)
{
SCM value;
char* ident;
char* tileset;
char* str;
int n;
IfDebug( n=0; );
// Identifier
ident=gh_scm2newstr(gh_car(list),NULL);
list=gh_cdr(list);
// Tileset
tileset=gh_scm2newstr(gh_car(list),NULL);
list=gh_cdr(list);
// Type
value=gh_car(list);
list=gh_cdr(list);
if( gh_eq_p(value,gh_symbol2scm("normal")) ) {
// Normal icon - index, file
n=gh_scm2int(gh_car(list));
list=gh_cdr(list);
str=gh_scm2newstr(gh_car(list),NULL);
list=gh_cdr(list);
} else {
str=gh_scm2newstr(value,NULL);
fprintf(stderr,"%s: Wrong tag `%s'\n",ident,str);
}
if( !gh_null_p(list) ) {
fprintf(stderr,"too much arguments\n");
}
DebugLevel3Fn("icon %s/%s %d of %s\n",ident,tileset,n,str);
AddIcon(ident,tileset,n,str);
free(ident);
free(tileset);
free(str);
return SCM_UNSPECIFIED;
}
/**
** @brief Parse icon alias definition.
**
** @todo
** Should check if alias is free and icon already defined.
**
** @param alias Icon alias name.
** @param icon Original icon.
*/
local SCM CclDefineIconAlias(SCM alias,SCM icon)
{
IconAliases=realloc(IconAliases,sizeof(char*)*2*(IconAliasesCount+1));
IconAliases[IconAliasesCount*2+0]=gh_scm2newstr(alias,NULL);
IconAliases[IconAliasesCount*2+1]=gh_scm2newstr(icon,NULL);
IconAliasesCount++;
return SCM_UNSPECIFIED;
}
/**
** @brief Define icon mapping from original number to internal symbol
**
** @param list List of all names.
*/
local SCM CclDefineIconWcNames(SCM list)
{
int i;
char** cp;
if( (cp=IconWcNames) ) { // Free all old names
while( *cp ) {
free(*cp++);
}
free(IconWcNames);
}
//
// Get new table.
//
i=gh_length(list);
IconWcNames=cp=malloc((i+1)*sizeof(char*));
while( i-- ) {
*cp++=gh_scm2newstr(gh_car(list),NULL);
list=gh_cdr(list);
}
*cp=NULL;
return SCM_UNSPECIFIED;
}
/**
** Register CCL features for icons.
**
** @todo
** Add more functions for CCL. (draw-icon)
*/
global void IconCclRegister(void)
{
gh_new_procedureN("define-icon",CclDefineIcon);
gh_new_procedure2_0("define-icon-alias",CclDefineIconAlias);
gh_new_procedureN("define-icon-wc-names",CclDefineIconWcNames);
}
#endif
//@}

View file

@ -273,7 +273,7 @@ global void DrawUnitInfo(const Unit* unit)
if( unit->Orders[0].Action==UnitActionResearch ) {
DrawText(16,y+8+78,GameFont,"Researching:");
DrawUnitIcon(unit->Player
,unit->Data.Research.Upgrade->Icon
,unit->Data.Research.Upgrade->Icon.Icon
,0,x+107,y+8+70);
DrawCompleted(