// ////////////////////////////////////////////////////////////////////////////
// return a players name.
const char* getPlayerName(int player)
{
	ASSERT_OR_RETURN(NULL, player < MAX_PLAYERS , "Wrong player index: %u", player);

	if (game.type != CAMPAIGN)
	{
		if (strcmp(playerName[player], "") != 0)
		{
			return (char*)&playerName[player];
		}
	}

	if (strlen(NetPlay.players[player].name) == 0)
	{
		// make up a name for this player.
		return getPlayerColourName(player);
	}
	else if (NetPlay.players[player].ai >= 0 && !NetPlay.players[player].allocated)
	{
		static char names[MAX_PLAYERS][StringSize];  // Must be static, since the getPlayerName() return value is used in tool tips... Long live the widget system.
		// Add colour to player name.
		sstrcpy(names[player], getPlayerColourName(player));
		sstrcat(names[player], "-");
		sstrcat(names[player], NetPlay.players[player].name);
		return names[player];
	}

	return NetPlay.players[player].name;
}
Beispiel #2
0
static void poptPrintHelp(poptContext ctx, FILE *output, WZ_DECL_UNUSED int unused)
{
	int i;

	fprintf(output, "Usage: %s [OPTION...]\n", ctx->argv[0]);
	for (i = 0; i < ctx->size; i++)
	{
		char txt[128];

		if (ctx->table[i].short_form != '\0')
		{
			ssprintf(txt, "  -%c, --%s", ctx->table[i].short_form, ctx->table[i].string);
		}
		else
		{
			ssprintf(txt, "  --%s", ctx->table[i].string);
		}

		if (ctx->table[i].argument)
		{
			sstrcat(txt, "=");
			sstrcat(txt, ctx->table[i].argDescrip);
		}

		fprintf(output, "%-40s", txt);
		if (ctx->table[i].descrip)
		{
			fprintf(output, "%s", ctx->table[i].descrip);
		}
		fprintf(output, "\n");
	}
}
Beispiel #3
0
static void poptPrintHelp(poptContext ctx, FILE *output, bool show_all)
{
	fprintf(output, "Usage: %s [OPTION...]\n", ctx->argv[0]);
	for (int i = 0; i < ctx->size; i++)
	{
		char txt[128];

		if (ctx->table[i].hidden && !show_all)
		{
			continue;
		}

		if (ctx->table[i].short_form != '\0')
		{
			ssprintf(txt, "  -%c, --%s", ctx->table[i].short_form, ctx->table[i].string);
		}
		else
		{
			ssprintf(txt, "  --%s", ctx->table[i].string);
		}

		if (ctx->table[i].argument)
		{
			sstrcat(txt, "=");
			sstrcat(txt, ctx->table[i].argDescrip);
		}

		fprintf(output, "%-40s", txt);
		if (ctx->table[i].descrip)
		{
			fprintf(output, "%s", ctx->table[i].descrip);
		}
		fprintf(output, "\n");
	}
}
void printConsoleNameChange(const char *oldName, const char *newName)
{
	char msg[MAX_CONSOLE_STRING_LENGTH];

	// Player changed name.
	sstrcpy(msg, oldName);                               // Old name.
	sstrcat(msg, " → ");                                 // Separator
	sstrcat(msg, newName);  // New name.

	addConsoleMessage(msg, DEFAULT_JUSTIFY, selectedPlayer);  // display
}
// Write a message to the console.
bool recvTextMessage(NETQUEUE queue)
{
	UDWORD	playerIndex;
	char	msg[MAX_CONSOLE_STRING_LENGTH];
	char newmsg[MAX_CONSOLE_STRING_LENGTH];

	memset(msg, 0x0, sizeof(msg));
	memset(newmsg, 0x0, sizeof(newmsg));

	NETbeginDecode(queue, NET_TEXTMSG);
		// Who this msg is from
		NETuint32_t(&playerIndex);
		// The message to send
		NETstring(newmsg, MAX_CONSOLE_STRING_LENGTH);
	NETend();

	if (whosResponsible(playerIndex) != queue.index)
	{
		playerIndex = queue.index;  // Fix corrupted playerIndex.
	}

	if (playerIndex >= MAX_PLAYERS || (!NetPlay.players[playerIndex].allocated && NetPlay.players[playerIndex].ai == AI_OPEN))
	{
		return false;
	}

	sstrcpy(msg, NetPlay.players[playerIndex].name);
	// Seperator
	sstrcat(msg, ": ");
	// Add message
	sstrcat(msg, newmsg);

	addConsoleMessage(msg, DEFAULT_JUSTIFY, playerIndex);

	// Multiplayer message callback
	// Received a console message from a player, save
	MultiMsgPlayerFrom = playerIndex;
	MultiMsgPlayerTo = selectedPlayer;

	sstrcpy(MultiplayMsg, newmsg);
	eventFireCallbackTrigger((TRIGGER_TYPE)CALL_AI_MSG);

	// make some noise!
	if (titleMode == MULTIOPTION || titleMode == MULTILIMIT)
	{
		audio_PlayTrack(FE_AUDIO_MESSAGEEND);
	}
	else if (!ingame.localJoiningInProgress)
	{
		audio_PlayTrack(ID_SOUND_MESSAGEEND);
	}

	return true;
}
Beispiel #6
0
void initI18n(void)
{
	const char *textdomainDirectory = NULL;

	if (!setLanguage("")) // set to system default
	{
		// no system default?
		debug(LOG_ERROR, "initI18n: No system language found");
	}
#if defined(WZ_OS_WIN)
	{
		// Retrieve an absolute path to the locale directory
		char localeDir[PATH_MAX];
		sstrcpy(localeDir, PHYSFS_getBaseDir());
		sstrcat(localeDir, "\\" LOCALEDIR);

		// Set locale directory and translation domain name
		textdomainDirectory = bindtextdomain(PACKAGE, localeDir);
	}
#else
	#ifdef WZ_OS_MAC
	{
		char resourcePath[PATH_MAX];
		CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
		if( CFURLGetFileSystemRepresentation( resourceURL, true, (UInt8 *) resourcePath, PATH_MAX) )
		{
			sstrcat(resourcePath, "/locale");
			textdomainDirectory = bindtextdomain(PACKAGE, resourcePath);
		}
		else
		{
			debug( LOG_ERROR, "Could not change to resources directory." );
		}

		if (resourceURL != NULL)
		{
			CFRelease(resourceURL);
		}

		debug(LOG_INFO, "resourcePath is %s", resourcePath);
	}
	#else
	textdomainDirectory = bindtextdomain(PACKAGE, LOCALEDIR);
	#endif
#endif
	if (!textdomainDirectory)
	{
		debug(LOG_ERROR, "initI18n: bindtextdomain failed!");
	}

	(void)bind_textdomain_codeset(PACKAGE, "UTF-8");
	(void)textdomain(PACKAGE);
}
FILE *MacFopen(const char *path, const char *mode)
{
static char TruncPath[NAME_MAX];
OSErr   err = 0;

AssertStr(path,path)

            /* open zipfile or tempzip */
if (strcmp(zipfile,path) == 0)
    {
    GetCompletePath(MacZip.ZipFullPath,path,&MacZip.ZipFileSpec,&err);
    err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
    printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
    if (CheckMountedVolumes(MacZip.ZipFullPath) > 1)
        DoWarnUserDupVol(MacZip.ZipFullPath);

    /* tempfile should appear in the same directory of the zipfile
       -> save path of zipfile */
    TruncFilename(TruncPath, MacZip.ZipFullPath);
    return fopen(MacZip.ZipFullPath, mode);
    }

if (strcmp(tempzip,path) == 0)
    {  /* add path of zipfile */
    sstrcat(TruncPath,tempzip);
    GetCompletePath(MacZip.TempZipFullPath,TruncPath,&MacZip.TempZipFileSpec,&err);
    err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
    printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);

    return fopen(MacZip.TempZipFullPath, mode);
    }

printerr("MacFopen:",err,err,__LINE__,__FILE__,path);
return NULL;
}
Beispiel #8
0
int bm_printboardapi(struct boardmanager *bm,char *farg)
{
	if (getboard(bm->board)){
		sstrcat(farg, "\"%s\",",bm->board);
	}
	return 0;
}
Beispiel #9
0
static inline void iV_printFontList(void)
{
	unsigned int i;
	unsigned int font_count = glcGeti(GLC_CURRENT_FONT_COUNT);
	debug(LOG_NEVER, "GLC_CURRENT_FONT_COUNT = %d", font_count);

	if (font_count == 0)
	{
		debug(LOG_ERROR, "The required font (%s) isn't loaded", font_family);

		// Fall back to unselected fonts since the requested font apparently
		// isn't available.
		glcEnable(GLC_AUTO_FONT);
	}

	for (i = 0; i < font_count; ++i)
	{
		GLint font = glcGetListi(GLC_CURRENT_FONT_LIST, i);
		/* The output of the family name and the face is printed using 2 steps
		 * because glcGetFontc and glcGetFontFace return their result in the
		 * same buffer (according to GLC specs).
		 */
		char prBuffer[1024];
		snprintf(prBuffer, sizeof(prBuffer), "Font #%d : %s ", (int)font, (const char *)glcGetFontc(font, GLC_FAMILY));
		prBuffer[sizeof(prBuffer) - 1] = 0;
		sstrcat(prBuffer, (char const *)glcGetFontFace(font));
		debug(LOG_NEVER, "%s", prBuffer);
	}
}
Beispiel #10
0
char *pstrcat(pool *p, ...) {
  char *argp, *ptr, *res;
  size_t len = 0;
  va_list ap;

  if (p == NULL) {
    errno = EINVAL;
    return NULL;
  }

  va_start(ap, p);

  while ((res = va_arg(ap, char *)) != NULL) {
    len += strlen(res);
  }

  va_end(ap);

  ptr = res = pcalloc(p, len + 1);

  va_start(ap, p);

  while ((argp = va_arg(ap, char *)) != NULL) {
    size_t arglen;

    arglen = strlen(argp);
    sstrcat(ptr, argp, len + 1);
    ptr += arglen;
  }

  va_end(ap);

  return res;
}
Beispiel #11
0
/** Retrieve the texture number for a given texture resource.
 *
 *  @note We keep textures in a separate data structure _TEX_PAGE apart from the
 *        normal resource system.
 *
 *  @param filename The filename of the texture page to search for.
 *  @param compression If we need to load it, should we use texture compression?
 *
 *  @return a non-negative index number for the texture, negative if no texture
 *          with the given filename could be found
 */
int iV_GetTexture(const char *filename, bool compression)
{
	iV_Image sSprite;
	char path[PATH_MAX];

	/* Have we already loaded this one then? */
	sstrcpy(path, filename);
	pie_MakeTexPageName(path);
	for (int i = 0; i < _TEX_PAGE.size(); i++)
	{
		if (strncmp(path, _TEX_PAGE[i].name, iV_TEXNAME_MAX) == 0)
		{
			return i;
		}
	}

	// Try to load it
	sstrcpy(path, "texpages/");
	sstrcat(path, filename);
	if (!iV_loadImage_PNG(path, &sSprite))
	{
		debug(LOG_ERROR, "Failed to load %s", path);
		return -1;
	}
	sstrcpy(path, filename);
	pie_MakeTexPageName(path);
	return pie_AddTexPage(&sSprite, path, compression);
}
Beispiel #12
0
/** Retrieve the texture number for a given texture resource.
 *
 *  @note We keep textures in a separate data structure _TEX_PAGE apart from the
 *        normal resource system.
 *
 *  @param filename The filename of the texture page to search for.
 *
 *  @return a non-negative index number for the texture, negative if no texture
 *          with the given filename could be found
 */
int iV_GetTexture(const char *filename)
{
    unsigned int i = 0;
    iV_Image sSprite;
    char path[PATH_MAX];

    /* Have we already loaded this one then? */
    sstrcpy(path, filename);
    pie_MakeTexPageName(path);
    for (i = 0; i < iV_TEX_MAX; i++)
    {
        if (strncmp(path, _TEX_PAGE[i].name, iV_TEXNAME_MAX) == 0)
        {
            return i;
        }
    }

    // Try to load it
    sstrcpy(path, "texpages/");
    sstrcat(path, filename);
    if (!iV_loadImage_PNG(path, &sSprite))
    {
        debug(LOG_ERROR, "Failed to load %s", path);
        return -1;
    }
    sstrcpy(path, filename);
    pie_MakeTexPageName(path);
    return pie_AddTexPage(&sSprite, path, 0, -1, true);	// FIXME, -1, use getTextureSize()
}
Beispiel #13
0
//add a sequence to the list to be played
void seq_AddSeqToList(const char *pSeqName, const char *pAudioName, const char *pTextName, bool bLoop)
{
	currentSeq++;

	ASSERT_OR_RETURN(, currentSeq < MAX_SEQ_LIST, "too many sequences");

	//OK so add it to the list
	aSeqList[currentSeq].pSeq = pSeqName;
	aSeqList[currentSeq].pAudio = pAudioName;
	aSeqList[currentSeq].bSeqLoop = bLoop;
	if (pTextName != NULL)
	{
		// Ordinary text shouldn't be justified
		seq_AddTextFromFile(pTextName, SEQ_TEXT_POSITION);
	}

	if (bSeqSubtitles)
	{
		char aSubtitleName[MAX_STR_LENGTH];
		sstrcpy(aSubtitleName, pSeqName);

		// check for a subtitle file
		char *extension = strrchr(aSubtitleName, '.');
		if (extension)
		{
			*extension = '\0';
		}
		sstrcat(aSubtitleName, ".txt");

		// Subtitles should be center justified
		seq_AddTextFromFile(aSubtitleName, SEQ_TEXT_JUSTIFY);
	}
}
Beispiel #14
0
/**
 * Send the command to initialize the gprs of the modem.
 */
static void do_modem_init(gprs_t * gprs)
{
	UNTIMEOUT();

    gprs_set_state(gprs,GPRS_STATE_MODEM_INIT);
    sstrcpy(gprs->replyBuffer,"AT+CGDCONT=1,\"IP\",\"",sizeof(gprs->replyBuffer));

#if	GPRS_RUNTIME_APN
    sstrcat(gprs->replyBuffer,gprs->apn,sizeof(gprs->replyBuffer));
#else
    sstrcat(gprs->replyBuffer,GPRS_APN,sizeof(gprs->replyBuffer));
#endif

    sstrcat(gprs->replyBuffer,"\"",sizeof(gprs->replyBuffer));

    gprs_command(gprs,gprs->replyBuffer,'\r');

}
Beispiel #15
0
void debug_callback_win32debug(WZ_DECL_UNUSED void ** data, const char * outputBuffer)
{
    char tmpStr[MAX_LEN_LOG_LINE];

    sstrcpy(tmpStr, outputBuffer);
    if (!strchr(tmpStr, '\n'))
    {
        sstrcat(tmpStr, "\n");
    }

    OutputDebugStringA( tmpStr );
}
Beispiel #16
0
void show_special_api(char *id2, char *output){
	FILE *fp;
	char id1[80], name[80], buf[256];
	fp=fopen("etc/special", "r");
	if(fp!=0){
		while(1){
			if(fgets(buf, 256, fp)==0) break;
			if(sscanf(buf, "%s %s", id1, name)<2) continue;
			if(!strcasecmp(id1, id2)) sstrcat(output, "\"Title\":\"%s\",", name);
		}
	}
	close(fp);
}
Beispiel #17
0
// show a background piccy (currently used for version and mods labels)
static void displayTitleBitmap(WZ_DECL_UNUSED WIDGET *psWidget, WZ_DECL_UNUSED UDWORD xOffset, WZ_DECL_UNUSED UDWORD yOffset, WZ_DECL_UNUSED PIELIGHT *pColours)
{
	char modListText[MAX_STR_LENGTH] = "";

	iV_SetFont(font_regular);
	iV_SetTextColour(WZCOL_GREY);
	iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 9, pie_GetVideoBufferHeight() - 14, 270.f);

	if (*getModList())
	{
		sstrcat(modListText, _("Mod: "));
		sstrcat(modListText, getModList());
		iV_DrawText(modListText, 9, 14);
	}

	iV_SetTextColour(WZCOL_TEXT_BRIGHT);
	iV_DrawTextRotated(version_getFormattedVersionString(), pie_GetVideoBufferWidth() - 10, pie_GetVideoBufferHeight() - 15, 270.f);

	if (*getModList())
	{
		iV_DrawText(modListText, 10, 15);
	}
}
Beispiel #18
0
/*!
 * Register searchPath above the path with next lower priority
 * For information about what can be a search path, refer to PhysFS documentation
 */
void registerSearchPath(const char path[], unsigned int priority)
{
	wzSearchPath *curSearchPath = searchPathRegistry, * tmpSearchPath = nullptr;

	tmpSearchPath = (wzSearchPath *)malloc(sizeof(*tmpSearchPath));
	sstrcpy(tmpSearchPath->path, path);
	if (path[strlen(path) - 1] != *PHYSFS_getDirSeparator())
	{
		sstrcat(tmpSearchPath->path, PHYSFS_getDirSeparator());
	}
	tmpSearchPath->priority = priority;

	debug(LOG_WZ, "registerSearchPath: Registering %s at priority %i", path, priority);
	if (!curSearchPath)
	{
		searchPathRegistry = tmpSearchPath;
		searchPathRegistry->lowerPriority = nullptr;
		searchPathRegistry->higherPriority = nullptr;
		return;
	}

	while (curSearchPath->higherPriority && priority > curSearchPath->priority)
	{
		curSearchPath = curSearchPath->higherPriority;
	}
	while (curSearchPath->lowerPriority && priority < curSearchPath->priority)
	{
		curSearchPath = curSearchPath->lowerPriority;
	}

	if (priority < curSearchPath->priority)
	{
		tmpSearchPath->lowerPriority = curSearchPath->lowerPriority;
		tmpSearchPath->higherPriority = curSearchPath;
	}
	else
	{
		tmpSearchPath->lowerPriority = curSearchPath;
		tmpSearchPath->higherPriority = curSearchPath->higherPriority;
	}

	if (tmpSearchPath->lowerPriority)
	{
		tmpSearchPath->lowerPriority->higherPriority = tmpSearchPath;
	}
	if (tmpSearchPath->higherPriority)
	{
		tmpSearchPath->higherPriority->lowerPriority = tmpSearchPath;
	}
}
static bool recvBeacon(NETQUEUE queue)
{
	int32_t sender, receiver,locX, locY;
	char    msg[MAX_CONSOLE_STRING_LENGTH];

	NETbeginDecode(queue, NET_BEACONMSG);
	    NETint32_t(&sender);            // the actual sender
	    NETint32_t(&receiver);          // the actual receiver (might not be the same as the one we are actually sending to, in case of AIs)
	    NETint32_t(&locX);
	    NETint32_t(&locY);
	    NETstring(msg, sizeof(msg));    // Receive the actual message
	NETend();

	debug(LOG_WZ, "Received beacon for player: %d, from: %d",receiver, sender);

	sstrcat(msg, NetPlay.players[sender].name);    // name
	sstrcpy(beaconReceiveMsg[sender], msg);

	return addBeaconBlip(locX, locY, receiver, sender, beaconReceiveMsg[sender]);
}
VOID SetWinTitle(HWND hwnd, PATTMAN pam) {
   CHAR buf[LPATH + 32];

   dprintf("Settaggio titolo finestra\n");
   DlgLboxQueryItemText(hwnd, LB_FILE, pam->fsp.psSel[1], buf, LPATH + 32);
   // se Š una dir ed Š attiva opzione Selez All files in directory legge
   // attr primo file selezionato e titolo = nomedir\*.*
   if (pam->pro.sel.extsel && pam->pro.sel.dir &&
       pam->fsp.pszFile[0] == '\\' && pam->fsp.psSel[0]) {
      sstrcpy(pam->fsp.pszFile, buf); //copia in pszFile nome Iø file selez
      sprintf(buf, "%s%s%s & *.*", pam->fsp.pszPath,
              (pam->fsp.pszPath[3]? "\\": ""), pam->fsp.pszFile);
   // se Š una dir con opzione SelectAll non attiva o non ci sono file selez
   // legge attr dir corrente e titolo = nomedir\.
   } else if (pam->fsp.pszFile[0] == '\\' || !pam->fsp.psSel[0]) {
      if (!pam->fsp.psSel[0]) MyDlgLboxSelectItem(hwnd, LB_FILE, 0);
      pam->fsp.pszFile[0] = '.'; pam->fsp.pszFile[1] = 0;
      sstrcpy(buf, pam->fsp.pszPath);
      sstrcat(buf, pam->fsp.pszPath[3]? "\\.": ".");
   // se Š un file specificato con una mask di wildchar e ci sono + file
   // selez legge attr primo file e titolo = nomefile & mask
   } else if (isWildCh(pam->fsp.pszFile) && pam->fsp.psSel[0] > 1) {
      char tmp[256];
      sstrcpy(tmp, buf);
      sprintf(buf, "%s%s%s & %s", pam->fsp.pszPath,
              (pam->fsp.pszPath[3]? "\\": ""), tmp, pam->fsp.pszFile);
      sstrcpy(pam->fsp.pszFile, tmp);
   // pi— file selezionati non secondo una mask di wildchars
   } else if (pam->fsp.psSel[0] > 1) {
      sstrcpy(pam->fsp.pszFile, buf);
      sprintf(buf, "%s%s%s & ...", pam->fsp.pszPath,
              (pam->fsp.pszPath[3]? "\\": ""), pam->fsp.pszFile);
   // un solo file selezionato
   } else {
      sstrcpy(pam->fsp.pszFile, buf);
      sprintf(buf, "%s%s%s", pam->fsp.pszPath,
              (pam->fsp.pszPath[3]? "\\": ""), pam->fsp.pszFile);
   } // endif   ---  se Š autoimport e subject e comment sono vuoti
   WinSetWindowText(hwnd, buf);
}
Beispiel #21
0
//add a sequence to the list to be played
void seq_AddSeqToList(const char *pSeqName, const char *pAudioName, const char *pTextName, BOOL bLoop)
{
	currentSeq++;

	ASSERT(currentSeq < MAX_SEQ_LIST, "too many sequences");
	if (currentSeq >=  MAX_SEQ_LIST)
	{
		return;
	}

	//OK so add it to the list
	aSeqList[currentSeq].pSeq = pSeqName;
	aSeqList[currentSeq].pAudio = pAudioName;
	aSeqList[currentSeq].bSeqLoop = bLoop;
	if (pTextName != NULL)
	{
		// Ordinary text shouldn't be justified
		seq_AddTextFromFile(pTextName, SEQ_TEXT_POSITION);
	}

	if (bSeqSubtitles)
	{
		char aSubtitleName[MAX_STR_LENGTH];
		size_t check_len = sstrcpy(aSubtitleName, pSeqName);
		char* extension;

		ASSERT(check_len < sizeof(aSubtitleName), "given sequence name (%s) longer (%lu) than buffer (%lu)", pSeqName, (unsigned long) check_len, (unsigned long) sizeof(aSubtitleName));

		// check for a subtitle file
		extension = strrchr(aSubtitleName, '.');
		if (extension)
			*extension = '\0';
		check_len = sstrcat(aSubtitleName, ".txt");
		ASSERT(check_len < sizeof(aSubtitleName), "sequence name to long to attach an extension too");

		// Subtitles should be center justified
		seq_AddTextFromFile(aSubtitleName, SEQ_TEXT_JUSTIFY);
	}
}
Beispiel #22
0
// ////////////////////////////////////////////////////////////////////////////
// display a keymap on the interface.
static void displayKeyMap(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, WZ_DECL_UNUSED PIELIGHT *pColours)
{
	UDWORD		x = xOffset+psWidget->x;
	UDWORD		y = yOffset+psWidget->y;
	UDWORD		w = psWidget->width;
	UDWORD		h = psWidget->height;
	KEY_MAPPING *psMapping = (KEY_MAPPING*)psWidget->pUserData;
	char		sKey[MAX_STR_LENGTH];

	if(psMapping == selectedKeyMap)
	{
		pie_BoxFill(x, y, x + w, y + h, WZCOL_KEYMAP_ACTIVE);
	}
	else if(psMapping->status == KEYMAP_ALWAYS || psMapping->status == KEYMAP_ALWAYS_PROCESS)
	{
		// when user can't edit something...
		pie_BoxFill(x, y , x + w, y + h, WZCOL_KEYMAP_FIXED);
	}
	else
	{
		drawBlueBox(x,y,w,h);
	}

	// draw name
	iV_SetFont(font_regular);											// font type
	iV_SetTextColour(WZCOL_FORM_TEXT);

	iV_DrawText(_(psMapping->pName), x + 2, y + (psWidget->height / 2) + 3);

	// draw binding
	keyMapToString(sKey, psMapping);
	// Check to see if key is on the numpad, if so tell user and change color
	if (psMapping->subKeyCode >= KEY_KP_0 && psMapping->subKeyCode <= KEY_KPENTER)
	{
		iV_SetTextColour(WZCOL_YELLOW);
		sstrcat(sKey, " (numpad)");
	}
	iV_DrawText(sKey, x + 364, y + (psWidget->height / 2) + 3);
}
Beispiel #23
0
/*!
 * \brief Rebuilds the PHYSFS searchPath with mode specific subdirs
 *
 * Priority:
 * maps > mods > base > base.wz
 */
bool rebuildSearchPath( searchPathMode mode, bool force )
{
	static searchPathMode current_mode = mod_clean;
	static std::string current_current_map;
	wzSearchPath * curSearchPath = searchPathRegistry;
	char tmpstr[PATH_MAX] = "\0";

	if (mode != current_mode || (current_map != NULL? current_map : "") != current_current_map || force ||
	    (use_override_mods && strcmp(override_mod_list, getModList())))
	{
		if (mode != mod_clean)
		{
			rebuildSearchPath( mod_clean, false );
		}

		current_mode = mode;
		current_current_map = current_map != NULL? current_map : "";

		// Start at the lowest priority
		while( curSearchPath->lowerPriority )
			curSearchPath = curSearchPath->lowerPriority;

		switch ( mode )
		{
			case mod_clean:
				debug(LOG_WZ, "Cleaning up");
				clearLoadedMods();

				while( curSearchPath )
				{
#ifdef DEBUG
					debug(LOG_WZ, "Removing [%s] from search path", curSearchPath->path);
#endif // DEBUG
					// Remove maps and mods
					removeSubdirs( curSearchPath->path, "maps", NULL );
					removeSubdirs( curSearchPath->path, "mods/music", NULL );
					removeSubdirs( curSearchPath->path, "mods/global", NULL );
					removeSubdirs( curSearchPath->path, "mods/campaign", NULL );
					removeSubdirs( curSearchPath->path, "mods/multiplay", NULL );
					removeSubdirs( curSearchPath->path, "mods/autoload", NULL );

					// Remove multiplay patches
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "mp");
					PHYSFS_removeFromSearchPath( tmpstr );
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "mp.wz");
					PHYSFS_removeFromSearchPath( tmpstr );

					// Remove plain dir
					PHYSFS_removeFromSearchPath( curSearchPath->path );

					// Remove base files
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base");
					PHYSFS_removeFromSearchPath( tmpstr );
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base.wz");
					PHYSFS_removeFromSearchPath( tmpstr );

					// remove video search path as well
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "sequences.wz");
					PHYSFS_removeFromSearchPath( tmpstr );
					curSearchPath = curSearchPath->higherPriority;
				}
				break;
			case mod_campaign:
				debug(LOG_WZ, "*** Switching to campaign mods ***");
				clearLoadedMods();

				while (curSearchPath)
				{
					// make sure videos override included files
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "sequences.wz");
					PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND);
					curSearchPath = curSearchPath->higherPriority;
				}
				curSearchPath = searchPathRegistry;
				while (curSearchPath->lowerPriority)
					curSearchPath = curSearchPath->lowerPriority;
				while( curSearchPath )
				{
#ifdef DEBUG
					debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path);
#endif // DEBUG
					// Add global and campaign mods
					PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND );

					addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false );
					addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true );
					addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true );
					addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true );
					addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods?override_mods:campaign_mods, true );
					if (!PHYSFS_removeFromSearchPath( curSearchPath->path ))
					{
						debug(LOG_WZ, "* Failed to remove path %s again", curSearchPath->path);
					}

					// Add plain dir
					PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND );

					// Add base files
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base.wz");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );

					curSearchPath = curSearchPath->higherPriority;
				}
				break;
			case mod_multiplay:
				debug(LOG_WZ, "*** Switching to multiplay mods ***");
				clearLoadedMods();

				while (curSearchPath)
				{
					// make sure videos override included files
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "sequences.wz");
					PHYSFS_addToSearchPath(tmpstr, PHYSFS_APPEND);
					curSearchPath = curSearchPath->higherPriority;
				}
				// Add the selected map first, for mapmod support
				if (current_map != NULL)
				{
					std::string realPathAndDir = std::string(PHYSFS_getRealDir(current_map)) + current_map;
					PHYSFS_addToSearchPath(realPathAndDir.c_str(), PHYSFS_APPEND);
				}
				curSearchPath = searchPathRegistry;
				while (curSearchPath->lowerPriority)
					curSearchPath = curSearchPath->lowerPriority;
				while( curSearchPath )
				{
#ifdef DEBUG
					debug(LOG_WZ, "Adding [%s] to search path", curSearchPath->path);
#endif // DEBUG
					// Add global and multiplay mods
					PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND );
					addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false );
					addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true );
					addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true );
					addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true );
					addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods?override_mods:multiplay_mods, true );
					PHYSFS_removeFromSearchPath( curSearchPath->path );

					// Add multiplay patches
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "mp");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "mp.wz");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );

					// Add plain dir
					PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND );

					// Add base files
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );
					sstrcpy(tmpstr, curSearchPath->path);
					sstrcat(tmpstr, "base.wz");
					PHYSFS_addToSearchPath( tmpstr, PHYSFS_APPEND );

					curSearchPath = curSearchPath->higherPriority;
				}
				break;
			default:
				debug(LOG_ERROR, "Can't switch to unknown mods %i", mode);
				return false;
		}
		if (use_override_mods && mode != mod_clean)
		{
			if (strcmp(getModList(),override_mod_list))
			{
				debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list);
			}
			clearOverrideMods();
			current_mode = mod_override;
		}

		// User's home dir must be first so we allways see what we write
		PHYSFS_removeFromSearchPath(PHYSFS_getWriteDir());
		PHYSFS_addToSearchPath( PHYSFS_getWriteDir(), PHYSFS_PREPEND );

#ifdef DEBUG
		printSearchPath();
#endif // DEBUG
	}
	else if (use_override_mods)
	{
		// override mods are already the same as current mods, so no need to do anything
		clearOverrideMods();
	}
	return true;
}
Beispiel #24
0
/*!
 * \brief Adds default data dirs
 *
 * Priority:
 * Lower loads first. Current:
 * -datadir > User's home dir > source tree data > AutoPackage > BaseDir > DEFAULT_DATADIR
 *
 * Only -datadir and home dir are allways examined. Others only if data still not found.
 *
 * We need ParseCommandLine, before we can add any mods...
 *
 * \sa rebuildSearchPath
 */
static void scanDataDirs( void )
{
	char tmpstr[PATH_MAX], prefix[PATH_MAX];
	char* separator;

#if defined(WZ_OS_MAC)
	// version-independent location for video files
	registerSearchPath("/Library/Application Support/Warzone 2100/", 1);
#endif

	// Find out which PREFIX we are in...
	sstrcpy(prefix, PHYSFS_getBaseDir());

	separator = strrchr(prefix, *PHYSFS_getDirSeparator());
	if (separator)
	{
		*separator = '\0'; // Trim ending '/', which getBaseDir always provides

		separator = strrchr(prefix, *PHYSFS_getDirSeparator());
		if (separator)
		{
			*separator = '\0'; // Skip the last dir from base dir
		}
	}

	// Commandline supplied datadir
	if( strlen( datadir ) != 0 )
		registerSearchPath( datadir, 1 );

	// User's home dir
	registerSearchPath( PHYSFS_getWriteDir(), 2 );
	rebuildSearchPath( mod_multiplay, true );

	if( !PHYSFS_exists("gamedesc.lev") )
	{
		// Data in source tree
		sstrcpy(tmpstr, prefix);
		sstrcat(tmpstr, "/data/");
		registerSearchPath( tmpstr, 3 );
		rebuildSearchPath( mod_multiplay, true );

		if( !PHYSFS_exists("gamedesc.lev") )
		{
			// Relocation for AutoPackage
			sstrcpy(tmpstr, prefix);
			sstrcat(tmpstr, "/share/warzone2100/");
			registerSearchPath( tmpstr, 4 );
			rebuildSearchPath( mod_multiplay, true );

			if( !PHYSFS_exists("gamedesc.lev") )
			{
				// Program dir
				registerSearchPath( PHYSFS_getBaseDir(), 5 );
				rebuildSearchPath( mod_multiplay, true );

				if( !PHYSFS_exists("gamedesc.lev") )
				{
					// Guessed fallback default datadir on Unix
					registerSearchPath( WZ_DATADIR, 6 );
					rebuildSearchPath( mod_multiplay, true );
				}
			}
		}
	}

#ifdef WZ_OS_MAC
	if( !PHYSFS_exists("gamedesc.lev") ) {
		CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
		char resourcePath[PATH_MAX];
		if( CFURLGetFileSystemRepresentation( resourceURL, true,
							(UInt8 *) resourcePath,
							PATH_MAX) ) {
			chdir( resourcePath );
			registerSearchPath( "data", 7 );
			rebuildSearchPath( mod_multiplay, true );
		} else {
			debug( LOG_ERROR, "Could not change to resources directory." );
		}

		if( resourceURL != NULL ) {
			CFRelease( resourceURL );
		}
	}
#endif

	/** Debugging and sanity checks **/

	printSearchPath();

	if( PHYSFS_exists("gamedesc.lev") )
	{
		debug( LOG_WZ, "gamedesc.lev found at %s", PHYSFS_getRealDir( "gamedesc.lev" ) );
	}
	else
	{
		debug( LOG_FATAL, "Could not find game data. Aborting." );
		exit(1);
	}
}
Beispiel #25
0
static void getPlatformUserDir(char * const tmpstr, size_t const size)
{
#if defined(WZ_OS_WIN)
//  When WZ_PORTABLE is passed, that means we want the config directory at the same location as the program file
	DWORD dwRet;
	wchar_t tmpWStr[MAX_PATH];
#ifndef WZ_PORTABLE
	if ( SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, tmpWStr ) ) )
	{
#else
	if (dwRet = GetCurrentDirectoryW(MAX_PATH, tmpWStr))
	{
		if(dwRet > MAX_PATH)
		{
			debug(LOG_FATAL, "Buffer exceeds maximum path to create directory. Exiting.");
			exit(1);
		}
#endif
		if (WideCharToMultiByte(CP_UTF8, 0, tmpWStr, -1, tmpstr, size, NULL, NULL) == 0)
		{
			debug(LOG_FATAL, "Config directory encoding conversion error.");
			exit(1);
		}
		strlcat(tmpstr, PHYSFS_getDirSeparator(), size);
	}
	else
#elif defined(WZ_OS_MAC)
	FSRef fsref;
	OSErr error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, false, &fsref);
	if (!error)
		error = FSRefMakePath(&fsref, (UInt8 *) tmpstr, size);
	if (!error)
		strlcat(tmpstr, PHYSFS_getDirSeparator(), size);
	else
#endif
	if (PHYSFS_getUserDir())
	{
		strlcpy(tmpstr, PHYSFS_getUserDir(), size); // Use PhysFS supplied UserDir (As fallback on Windows / Mac, default on Linux)
	}
	// If PhysicsFS fails (might happen if environment variable HOME is unset or wrong) then use the current working directory
	else if (getCurrentDir(tmpstr, size))
	{
		strlcat(tmpstr, PHYSFS_getDirSeparator(), size);
	}
	else
	{
		debug(LOG_FATAL, "Can't get UserDir?");
		abort();
	}
}


static void initialize_ConfigDir(void)
{
	char tmpstr[PATH_MAX] = { '\0' };

	if (strlen(configdir) == 0)
	{
		getPlatformUserDir(tmpstr, sizeof(tmpstr));

		if (!PHYSFS_setWriteDir(tmpstr)) // Workaround for PhysFS not creating the writedir as expected.
		{
			debug(LOG_FATAL, "Error setting write directory to \"%s\": %s",
			      tmpstr, PHYSFS_getLastError());
			exit(1);
		}

		if (!PHYSFS_mkdir(WZ_WRITEDIR)) // s.a.
		{
			debug(LOG_FATAL, "Error creating directory \"%s\": %s",
			      WZ_WRITEDIR, PHYSFS_getLastError());
			exit(1);
		}

		// Append the Warzone subdir
		sstrcat(tmpstr, WZ_WRITEDIR);
		sstrcat(tmpstr, PHYSFS_getDirSeparator());

		if (!PHYSFS_setWriteDir(tmpstr))
		{
			debug( LOG_FATAL, "Error setting write directory to \"%s\": %s",
			tmpstr, PHYSFS_getLastError() );
			exit(1);
		}
	}
	else
	{
		sstrcpy(tmpstr, configdir);

		// Make sure that we have a directory separator at the end of the string
		if (tmpstr[strlen(tmpstr) - 1] != PHYSFS_getDirSeparator()[0])
			sstrcat(tmpstr, PHYSFS_getDirSeparator());

		debug(LOG_WZ, "Using custom configuration directory: %s", tmpstr);

		if (!PHYSFS_setWriteDir(tmpstr)) // Workaround for PhysFS not creating the writedir as expected.
		{
			debug(LOG_FATAL, "Error setting write directory to \"%s\": %s",
			      tmpstr, PHYSFS_getLastError());
			exit(1);
		}

		// NOTE: This is currently only used for mingw builds for now.
#if defined (WZ_CC_MINGW)
		if (!OverrideRPTDirectory(tmpstr))
		{
			// since it failed, we just use our default path, and not the user supplied one.
			debug(LOG_ERROR, "Error setting exception hanlder to use directory %s", tmpstr);
		}
#endif
	}

	// User's home dir first so we allways see what we write
	PHYSFS_addToSearchPath( PHYSFS_getWriteDir(), PHYSFS_PREPEND );

	PHYSFS_permitSymbolicLinks(1);

	debug(LOG_WZ, "Write dir: %s", PHYSFS_getWriteDir());
	debug(LOG_WZ, "Base dir: %s", PHYSFS_getBaseDir());
}
Beispiel #26
0
//****************************************************************************************
// Challenge menu
//*****************************************************************************************
bool addChallenges()
{
    char			sPath[PATH_MAX];
    const char *sSearchPath	= "challenges";
    UDWORD			slotCount;
    static char		sSlotCaps[totalslots][totalslotspace];
    static char		sSlotTips[totalslots][totalslotspace];
    static char		sSlotFile[totalslots][totalslotspace];
    char **i, **files;

    (void) PHYSFS_mkdir(sSearchPath); // just in case

    psRequestScreen = widgCreateScreen(); // init the screen
    widgSetTipFont(psRequestScreen, font_regular);

    /* add a form to place the tabbed form on */
    W_FORMINIT sFormInit;
    sFormInit.formID = 0;				//this adds the blue background, and the "box" behind the buttons -Q
    sFormInit.id = CHALLENGE_FORM;
    sFormInit.style = WFORM_PLAIN;
    sFormInit.x = (SWORD) CHALLENGE_X;
    sFormInit.y = (SWORD) CHALLENGE_Y;
    sFormInit.width = CHALLENGE_W;
    // we need the form to be long enough for all resolutions, so we take the total number of items * height
    // and * the gaps, add the banner, and finally, the fudge factor ;)
    sFormInit.height = (slotsInColumn * CHALLENGE_ENTRY_H + CHALLENGE_HGAP * slotsInColumn) + CHALLENGE_BANNER_DEPTH + 20;
    sFormInit.disableChildren = true;
    sFormInit.pDisplay = intOpenPlainForm;
    widgAddForm(psRequestScreen, &sFormInit);

    // Add Banner
    sFormInit.formID = CHALLENGE_FORM;
    sFormInit.id = CHALLENGE_BANNER;
    sFormInit.x = CHALLENGE_HGAP;
    sFormInit.y = CHALLENGE_VGAP;
    sFormInit.width = CHALLENGE_W - (2 * CHALLENGE_HGAP);
    sFormInit.height = CHALLENGE_BANNER_DEPTH;
    sFormInit.disableChildren = false;
    sFormInit.pDisplay = displayLoadBanner;
    sFormInit.UserData = 0;
    widgAddForm(psRequestScreen, &sFormInit);

    // Add Banner Label
    W_LABINIT sLabInit;
    sLabInit.formID		= CHALLENGE_BANNER;
    sLabInit.id		= CHALLENGE_LABEL;
    sLabInit.style		= WLAB_ALIGNCENTRE;
    sLabInit.x		= 0;
    sLabInit.y		= 3;
    sLabInit.width		= CHALLENGE_W - (2 * CHALLENGE_HGAP);	//CHALLENGE_W;
    sLabInit.height		= CHALLENGE_BANNER_DEPTH;		//This looks right -Q
    sLabInit.pText		= "Challenge";
    widgAddLabel(psRequestScreen, &sLabInit);

    // add cancel.
    W_BUTINIT sButInit;
    sButInit.formID = CHALLENGE_BANNER;
    sButInit.x = 8;
    sButInit.y = 8;
    sButInit.width		= iV_GetImageWidth(IntImages, IMAGE_NRUTER);
    sButInit.height		= iV_GetImageHeight(IntImages, IMAGE_NRUTER);
    sButInit.UserData	= PACKDWORD_TRI(0, IMAGE_NRUTER , IMAGE_NRUTER);

    sButInit.id = CHALLENGE_CANCEL;
    sButInit.pTip = _("Close");
    sButInit.pDisplay = intDisplayImageHilight;
    widgAddButton(psRequestScreen, &sButInit);

    // add slots
    sButInit = W_BUTINIT();
    sButInit.formID		= CHALLENGE_FORM;
    sButInit.width		= CHALLENGE_ENTRY_W;
    sButInit.height		= CHALLENGE_ENTRY_H;
    sButInit.pDisplay	= displayLoadSlot;

    for (slotCount = 0; slotCount < totalslots; slotCount++)
    {
        sButInit.id		= slotCount + CHALLENGE_ENTRY_START;

        if (slotCount < slotsInColumn)
        {
            sButInit.x	= 22 + CHALLENGE_HGAP;
            sButInit.y	= (SWORD)((CHALLENGE_BANNER_DEPTH + (2 * CHALLENGE_VGAP)) + (
                                      slotCount * (CHALLENGE_VGAP + CHALLENGE_ENTRY_H)));
        }
        else if (slotCount >= slotsInColumn && (slotCount < (slotsInColumn *2)))
        {
            sButInit.x	= 22 + (2 * CHALLENGE_HGAP + CHALLENGE_ENTRY_W);
            sButInit.y	= (SWORD)((CHALLENGE_BANNER_DEPTH + (2 * CHALLENGE_VGAP)) + (
                                      (slotCount % slotsInColumn) * (CHALLENGE_VGAP + CHALLENGE_ENTRY_H)));
        }
        else
        {
            sButInit.x	= 22 + (3 * CHALLENGE_HGAP + (2 * CHALLENGE_ENTRY_W));
            sButInit.y	= (SWORD)((CHALLENGE_BANNER_DEPTH + (2 * CHALLENGE_VGAP)) + (
                                      (slotCount % slotsInColumn) * (CHALLENGE_VGAP + CHALLENGE_ENTRY_H)));
        }
        widgAddButton(psRequestScreen, &sButInit);
    }

    // fill slots.
    slotCount = 0;

    sstrcpy(sPath, sSearchPath);
    sstrcat(sPath, "/*.ini");

    debug(LOG_SAVE, "Searching \"%s\" for challenges", sPath);

    // add challenges to buttons
    files = PHYSFS_enumerateFiles(sSearchPath);
    for (i = files; *i != NULL; ++i)
    {
        W_BUTTON *button;
        char description[totalslotspace];
        char highscore[totalslotspace];
        const char *name, *difficulty, *map, *givendescription;
        inifile *inif;

        // See if this filename contains the extension we're looking for
        if (!strstr(*i, ".ini"))
        {
            // If it doesn't, move on to the next filename
            continue;
        }

        /* First grab any high score associated with this challenge */
        inif = inifile_load(CHALLENGE_SCORES);
        sstrcpy(sPath, *i);
        sPath[strlen(sPath) - 4] = '\0';	// remove .ini
        sstrcpy(highscore, "no score");
        if (inif)
        {
            char key[64];
            bool victory;
            int seconds;

            ssprintf(key, "%s:Player", sPath);
            name = inifile_get(inif, key, "NO NAME");
            ssprintf(key, "%s:Victory", sPath);
            victory = inifile_get_as_bool(inif, key, false);
            ssprintf(key, "%s:Seconds", sPath);
            seconds = inifile_get_as_int(inif, key, -1);
            if (seconds > 0)
            {
                getAsciiTime(key, seconds * GAME_TICKS_PER_SEC);
                ssprintf(highscore, "%s by %s (%s)", key, name, victory ? "Victory" : "Survived");
            }
            inifile_delete(inif);
        }

        ssprintf(sPath, "%s/%s", sSearchPath, *i);
        inif = inifile_load(sPath);
        inifile_set_current_section(inif, "challenge");
        if (!inif)
        {
            debug(LOG_ERROR, "Could not open \"%s\"", sPath);
            continue;
        }
        name = inifile_get(inif, "Name", "BAD NAME");
        map = inifile_get(inif, "Map", "BAD MAP");
        difficulty = inifile_get(inif, "difficulty", "BAD DIFFICULTY");
        givendescription = inifile_get(inif, "description", "");
        ssprintf(description, "%s, %s, %s. %s", map, difficulty, highscore, givendescription);

        button = (W_BUTTON*)widgGetFromID(psRequestScreen, CHALLENGE_ENTRY_START + slotCount);

        debug(LOG_SAVE, "We found [%s]", *i);

        /* Set the button-text */
        sstrcpy(sSlotCaps[slotCount], name);		// store it!
        sstrcpy(sSlotTips[slotCount], description);	// store it, too!
        sstrcpy(sSlotFile[slotCount], sPath);		// store filename
        inifile_delete(inif);

        /* Add button */
        button->pTip = sSlotTips[slotCount];
        button->pText = sSlotCaps[slotCount];
        button->pUserData = (void *)sSlotFile[slotCount];
        slotCount++;		// go to next button...
        if (slotCount == totalslots)
        {
            break;
        }
    }
    PHYSFS_freeList(files);

    challengesUp = true;

    return true;
}
Beispiel #27
0
static int poptGetNextOpt(poptContext ctx)
{
	static char match[PATH_MAX];		// static for bad function
	static char parameter[PATH_MAX];	// static for arg function
	char *pparam;
	int i;

	ctx->bad = NULL;
	ctx->parameter = NULL;
	parameter[0] = '\0';
	match[0] = '\0';

	if (ctx->current >= ctx->argc)	// counts from 1
	{
		return 0;
	}

	if (strstr(ctx->argv[ctx->current], "-psn_"))
	{
		ctx->current++;	// skip mac -psn_*  Yum!
		return POPT_SKIP_MAC_PSN;
	}

	sstrcpy(match, ctx->argv[ctx->current]);
	ctx->current++;
	pparam = strrchr(match, '=');
	if (pparam)									// option's got a parameter
	{
		*pparam++ = '\0';							// split option from parameter and increment past '='
		if (pparam[0] == '"')							// found scary quotes
		{
			pparam++;							// skip start quote
			sstrcpy(parameter, pparam);					// copy first parameter
			if (!strrchr(pparam, '"'))					// if no end quote, then find it
			{
				while (!strrchr(parameter, '"') && ctx->current < ctx->argc)
				{
					sstrcat(parameter, " ");			// insert space
					sstrcat(parameter, ctx->argv[ctx->current]);
					ctx->current++;					// next part, please!
				}
			}
			if (strrchr(parameter, '"'))					// its not an else for above!
			{
				*strrchr(parameter, '"') = '\0';			// remove end qoute
			}
		}
		else
		{
			sstrcpy(parameter, pparam);					// copy parameter
		}
	}

	for (i = 0; i < ctx->size; i++)
	{
		char sshort[3];
		char slong[64];

		ssprintf(sshort, "-%c", ctx->table[i].short_form);
		ssprintf(slong, "--%s", ctx->table[i].string);
		if ((strcmp(sshort, match) == 0 && ctx->table[i].short_form != '\0') || strcmp(slong, match) == 0)
		{
			if (ctx->table[i].argument && pparam)
			{
				ctx->parameter = parameter;
			}
			return ctx->table[i].enumeration;
		}
	}
	ctx->bad = match;
	ctx->current++;
	return POPT_ERROR_BADOPT;
}
Beispiel #28
0
static GAMECODE renderLoop()
{
	if (bMultiPlayer && !NetPlay.isHostAlive && NetPlay.bComms && !NetPlay.isHost)
	{
		intAddInGamePopup();
	}

	int clearMode = 0;
	if(getDrawShadows())
	{
		clearMode |= CLEAR_SHADOW;
	}
	if (loopMissionState == LMS_SAVECONTINUE)
	{
		pie_SetFogStatus(false);
		clearMode = CLEAR_BLACK;
	}
	pie_ScreenFlip(clearMode);//gameloopflip

	HandleClosingWindows();	// Needs to be done outside the pause case.

	audio_Update();

	wzShowMouse(true);

	INT_RETVAL intRetVal = INT_NONE;
	if (!paused)
	{
		/* Run the in game interface and see if it grabbed any mouse clicks */
		if (!rotActive && getWidgetsStatus() && dragBox3D.status != DRAG_DRAGGING && wallDrag.status != DRAG_DRAGGING)
		{
			intRetVal = intRunWidgets();
		}

		//don't process the object lists if paused or about to quit to the front end
		if (!gameUpdatePaused() && intRetVal != INT_QUIT)
		{
			if( dragBox3D.status != DRAG_DRAGGING
				&& wallDrag.status != DRAG_DRAGGING
				&& ( intRetVal == INT_INTERCEPT
					|| ( radarOnScreen
						 && CoordInRadar(mouseX(), mouseY())
						 && getHQExists(selectedPlayer) ) ) )
			{
				// Using software cursors (when on) for these menus due to a bug in SDL's SDL_ShowCursor()
				wzSetCursor(CURSOR_DEFAULT);

				intRetVal = INT_INTERCEPT;
			}

#ifdef DEBUG
			// check all flag positions for duplicate delivery points
			checkFactoryFlags();
#endif

			//handles callbacks for positioning of DP's
			process3DBuilding();

			//ajl. get the incoming netgame messages and process them.
			// FIXME Previous comment is deprecated. multiPlayerLoop does some other weird stuff, but not that anymore.
			if (bMultiPlayer)
			{
				multiPlayerLoop();
			}

			for (unsigned i = 0; i < MAX_PLAYERS; i++)
			{
				for (DROID *psCurr = apsDroidLists[i]; psCurr; psCurr = psCurr->psNext)
				{
					// Don't copy the next pointer - if droids somehow get destroyed in the graphics rendering loop, who cares if we crash.
					calcDroidIllumination(psCurr);
				}
			}

			/* update animations */
			animObj_Update();
		}

		if (!consolePaused())
		{
			/* Process all the console messages */
			updateConsoleMessages();
		}
		if (!scrollPaused() && !getWarCamStatus() && dragBox3D.status != DRAG_DRAGGING && intMode != INT_INGAMEOP )
		{
			scroll();
		}
	}
	else  // paused
	{
		// Using software cursors (when on) for these menus due to a bug in SDL's SDL_ShowCursor()
		wzSetCursor(CURSOR_DEFAULT);

		if(dragBox3D.status != DRAG_DRAGGING)
		{
			scroll();
		}

		if(InGameOpUp || isInGamePopupUp)		// ingame options menu up, run it!
		{
			unsigned widgval = widgRunScreen(psWScreen);
			intProcessInGameOptions(widgval);
			if(widgval == INTINGAMEOP_QUIT_CONFIRM || widgval == INTINGAMEOP_POPUP_QUIT)
			{
				if(gamePaused())
				{
					kf_TogglePauseMode();
				}
				intRetVal = INT_QUIT;
			}
		}

		if(bLoadSaveUp && runLoadSave(true) && strlen(sRequestResult))
		{
			debug( LOG_NEVER, "Returned %s", sRequestResult );
			if(bRequestLoad)
			{
				loopMissionState = LMS_LOADGAME;
				NET_InitPlayers();			// otherwise alliances were not cleared
				sstrcpy(saveGameName, sRequestResult);
			}
			else
			{
				char msgbuffer[256]= {'\0'};

				if (saveInMissionRes())
				{
					if (saveGame(sRequestResult, GTYPE_SAVE_START))
					{
						sstrcpy(msgbuffer, _("GAME SAVED: "));
						sstrcat(msgbuffer, sRequestResult);
						addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE);
					}
					else
					{
						ASSERT( false,"Mission Results: saveGame Failed" );
						sstrcpy(msgbuffer, _("Could not save game!"));
						addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE);
						deleteSaveGame(sRequestResult);
					}
				}
				else if (bMultiPlayer || saveMidMission())
				{
					if (saveGame(sRequestResult, GTYPE_SAVE_MIDMISSION))//mid mission from [esc] menu
					{
						sstrcpy(msgbuffer, _("GAME SAVED: "));
						sstrcat(msgbuffer, sRequestResult);
						addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE);
					}
					else
					{
						ASSERT(!"saveGame(sRequestResult, GTYPE_SAVE_MIDMISSION) failed", "Mid Mission: saveGame Failed" );
						sstrcpy(msgbuffer, _("Could not save game!"));
						addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE);
						deleteSaveGame(sRequestResult);
					}
				}
				else
				{
					ASSERT( false, "Attempt to save game with incorrect load/save mode" );
				}
			}
		}
	}

	/* Check for quit */
	bool quitting = false;
	if (intRetVal == INT_QUIT)
	{
		if (!loop_GetVideoStatus())
		{
			//quitting from the game to the front end
			//so get a new backdrop
			quitting = true;

			pie_LoadBackDrop(SCREEN_RANDOMBDROP);
		}
	}
	if (!loop_GetVideoStatus() && !quitting)
	{
		if (!gameUpdatePaused())
		{
			if (dragBox3D.status != DRAG_DRAGGING
			 && wallDrag.status != DRAG_DRAGGING)
			{
				ProcessRadarInput();
			}
			processInput();

			//no key clicks or in Intelligence Screen
			if (intRetVal == INT_NONE && !InGameOpUp && !isInGamePopupUp)
			{
				processMouseClickInput();
			}
			displayWorld();
		}
		/* Display the in game interface */
		pie_SetDepthBufferStatus(DEPTH_CMP_ALWAYS_WRT_ON);
		pie_SetFogStatus(false);

		if(bMultiPlayer && bDisplayMultiJoiningStatus)
		{
			intDisplayMultiJoiningStatus(bDisplayMultiJoiningStatus);
			setWidgetsStatus(false);
		}

		if(getWidgetsStatus())
		{
			intDisplayWidgets();
		}
		pie_SetDepthBufferStatus(DEPTH_CMP_LEQ_WRT_ON);
		pie_SetFogStatus(true);
	}

	pie_GetResetCounts(&loopPieCount, &loopPolyCount, &loopStateChanges);

	if ((fogStatus & FOG_BACKGROUND) && (loopMissionState == LMS_SAVECONTINUE))
	{
		pie_SetFogStatus(false);
	}

	if (!quitting)
	{
			/* Check for toggling display mode */
			if ((keyDown(KEY_LALT) || keyDown(KEY_RALT)) && keyPressed(KEY_RETURN))
			{
				screenToggleMode();
			}
	}

	// deal with the mission state
	switch (loopMissionState)
	{
		case LMS_CLEAROBJECTS:
			missionDestroyObjects();
			setScriptPause(true);
			loopMissionState = LMS_SETUPMISSION;
			break;

		case LMS_NORMAL:
			// default
			break;
		case LMS_SETUPMISSION:
			setScriptPause(false);
			if (!setUpMission(nextMissionType))
			{
				return GAMECODE_QUITGAME;
			}
			break;
		case LMS_SAVECONTINUE:
			// just wait for this to be changed when the new mission starts
			break;
		case LMS_NEWLEVEL:
			//nextMissionType = MISSION_NONE;
			nextMissionType = LDS_NONE;
			return GAMECODE_NEWLEVEL;
			break;
		case LMS_LOADGAME:
			return GAMECODE_LOADGAME;
			break;
		default:
			ASSERT( false, "unknown loopMissionState" );
			break;
	}

	if (quitting)
	{
		pie_SetFogStatus(false);
		pie_ScreenFlip(CLEAR_BLACK);//gameloopflip
		/* Check for toggling display mode */
		if ((keyDown(KEY_LALT) || keyDown(KEY_RALT)) && keyPressed(KEY_RETURN))
		{
			screenToggleMode();
		}
		return GAMECODE_QUITGAME;
	}
	else if (loop_GetVideoStatus())
	{
		audio_StopAll();
		return GAMECODE_PLAYVIDEO;
	}

	return GAMECODE_CONTINUE;
}
/**
 * Exception handling on Windows.
 * Ask the user whether he wants to safe a Minidump and then dump it into the temp directory.
 * NOTE: This is only for MSVC compiled programs.
 *
 * \param pExceptionInfo Information on the exception, passed from Windows
 * \return whether further exception handlers (i.e. the Windows internal one) should be invoked
 */
static LONG WINAPI windowsExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
	LPCSTR applicationName = "Warzone 2100";

	char miniDumpPath[PATH_MAX] = {'\0'}, resultMessage[PATH_MAX] = {'\0'};

	// Write to temp dir, to support unprivileged users
	if (!GetTempPathA(sizeof(miniDumpPath), miniDumpPath))
	{
		sstrcpy(miniDumpPath, "c:\\temp\\");
	}

	// Append the filename
	sstrcat(miniDumpPath, "warzone2100.mdmp");

	/*
	Alternative:
	GetModuleFileName( NULL, miniDumpPath, MAX_PATH );

	// Append extension
	sstrcat(miniDumpPath, ".mdmp");
	*/

	if ( MessageBoxA( NULL, "Warzone crashed unexpectedly, would you like to save a diagnostic file?", applicationName, MB_YESNO ) == IDYES )
	{
		HANDLE miniDumpFile = CreateFileA( miniDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

		if (miniDumpFile != INVALID_HANDLE_VALUE)
		{
			MINIDUMP_USER_STREAM uStream = { LastReservedStream+1, strlen(PACKAGE_VERSION), PACKAGE_VERSION };
			MINIDUMP_USER_STREAM_INFORMATION uInfo = { 1, &uStream };
			MINIDUMP_EXCEPTION_INFORMATION eInfo = { GetCurrentThreadId(), pExceptionInfo, false };

			if ( MiniDumpWriteDump(
				 	GetCurrentProcess(),
					GetCurrentProcessId(),
					miniDumpFile,
					MiniDumpNormal,
					pExceptionInfo ? &eInfo : NULL,
					&uInfo,
					NULL ) )
			{
				snprintf(resultMessage, sizeof(resultMessage), "Saved dump file to '%s'", miniDumpPath);
			}
			else
			{
				snprintf(resultMessage, sizeof(resultMessage), "Failed to save dump file to '%s' (error %d)", miniDumpPath, (int)GetLastError());
			}

			CloseHandle(miniDumpFile);
		}
		else
		{
			snprintf(resultMessage, sizeof(resultMessage), "Failed to create dump file '%s' (error %d)", miniDumpPath, (int)GetLastError());
		}

		MessageBoxA( NULL, resultMessage, applicationName, MB_OK );
	}

	if (prevExceptionHandler)
		return prevExceptionHandler(pExceptionInfo);
	else
		return EXCEPTION_CONTINUE_SEARCH;
}
Beispiel #30
0
// ppFileData is incremented to the end of the file on exit!
static iIMDShape *iV_ProcessIMD(const QString &filename, const char **ppFileData, const char *FileDataEnd)
{
	const char *pFileData = *ppFileData;
	char buffer[PATH_MAX], texfile[PATH_MAX], normalfile[PATH_MAX], specfile[PATH_MAX];
	int cnt, nlevels;
	iIMDShape *shape;
	UDWORD level;
	int32_t imd_version;
	uint32_t imd_flags;
	bool bTextured = false;
	iIMDShape *objanimpie[ANIM_EVENT_COUNT];

	memset(normalfile, 0, sizeof(normalfile));
	memset(specfile, 0, sizeof(specfile));

	if (sscanf(pFileData, "%255s %d%n", buffer, &imd_version, &cnt) != 2)
	{
		debug(LOG_ERROR, "%s: bad PIE version: (%s)", filename.toUtf8().constData(), buffer);
		assert(false);
		return nullptr;
	}
	pFileData += cnt;

	if (strcmp(PIE_NAME, buffer) != 0)
	{
		debug(LOG_ERROR, "%s: Not an IMD file (%s %d)", filename.toUtf8().constData(), buffer, imd_version);
		return nullptr;
	}

	//Now supporting version PIE_VER and PIE_FLOAT_VER files
	if (imd_version != PIE_VER && imd_version != PIE_FLOAT_VER)
	{
		debug(LOG_ERROR, "%s: Version %d not supported", filename.toUtf8().constData(), imd_version);
		return nullptr;
	}

	// Read flag
	if (sscanf(pFileData, "%255s %x%n", buffer, &imd_flags, &cnt) != 2)
	{
		debug(LOG_ERROR, "%s: bad flags: %s", filename.toUtf8().constData(), buffer);
		return nullptr;
	}
	pFileData += cnt;

	/* This can be either texture or levels */
	if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
	{
		debug(LOG_ERROR, "%s: Expecting TEXTURE or LEVELS: %s", filename.toUtf8().constData(), buffer);
		return nullptr;
	}
	pFileData += cnt;

	// get texture page if specified
	if (strncmp(buffer, "TEXTURE", 7) == 0)
	{
		int i, pwidth, pheight;
		char ch, texType[PATH_MAX];

		/* the first parameter for textures is always ignored; which is why we ignore
		 * nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			texfile[i] = ch;
		}
		texfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "%s: Texture info corrupt: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "%s: Only png textures supported", filename.toUtf8().constData());
			return nullptr;
		}
		sstrcat(texfile, ".png");

		if (sscanf(pFileData, "%d %d%n", &pwidth, &pheight, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s: Bad texture size: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		/* Now read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s: Bad levels info: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		bTextured = true;
	}

	if (strncmp(buffer, "NORMALMAP", 9) == 0)
	{
		char ch, texType[PATH_MAX];
		int i;

		/* the first parameter for textures is always ignored; which is why we ignore
		 * nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			normalfile[i] = ch;
		}
		normalfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "%s: Normal map info corrupt: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "%s: Only png normal maps supported", filename.toUtf8().constData());
			return nullptr;
		}
		sstrcat(normalfile, ".png");

		/* Now read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s: Bad levels info: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;
	}

	if (strncmp(buffer, "SPECULARMAP", 11) == 0)
	{
		char ch, texType[PATH_MAX];
		int i;

		/* the first parameter for textures is always ignored; which is why we ignore nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			specfile[i] = ch;
		}
		specfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "%s specular map info corrupt: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "%s: only png specular maps supported", filename.toUtf8().constData());
			return nullptr;
		}
		sstrcat(specfile, ".png");

		/* Try -again- to read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s: Bad levels info: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;
	}

	for (int i = 0; i < ANIM_EVENT_COUNT; i++)
	{
		objanimpie[i] = nullptr;
	}
	while (strncmp(buffer, "EVENT", 5) == 0)
	{
		char animpie[PATH_MAX];

		ASSERT(nlevels < ANIM_EVENT_COUNT && nlevels >= 0, "Invalid event type %d", nlevels);
		pFileData++;
		if (sscanf(pFileData, "%255s%n", animpie, &cnt) != 1)
		{
			debug(LOG_ERROR, "%s animation model corrupt: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;

		objanimpie[nlevels] = modelGet(animpie);

		/* Try -yet again- to read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s: Bad levels info: %s", filename.toUtf8().constData(), buffer);
			return nullptr;
		}
		pFileData += cnt;
	}

	if (strncmp(buffer, "LEVELS", 6) != 0)
	{
		debug(LOG_ERROR, "%s: Expecting 'LEVELS' directive (%s)", filename.toUtf8().constData(), buffer);
		return nullptr;
	}

	/* Read first LEVEL directive */
	if (sscanf(pFileData, "%255s %d%n", buffer, &level, &cnt) != 2)
	{
		debug(LOG_ERROR, "(_load_level) file corrupt -J");
		return nullptr;
	}
	pFileData += cnt;

	if (strncmp(buffer, "LEVEL", 5) != 0)
	{
		debug(LOG_ERROR, "%s: Expecting 'LEVEL' directive (%s)", filename.toUtf8().constData(), buffer);
		return nullptr;
	}

	shape = _imd_load_level(filename, &pFileData, FileDataEnd, nlevels, imd_version, level);
	if (shape == nullptr)
	{
		debug(LOG_ERROR, "%s: Unsuccessful", filename.toUtf8().constData());
		return nullptr;
	}

	// load texture page if specified
	if (bTextured)
	{
		int texpage = iV_GetTexture(texfile);
		int normalpage = iV_TEX_INVALID;
		int specpage = iV_TEX_INVALID;

		ASSERT_OR_RETURN(nullptr, texpage >= 0, "%s could not load tex page %s", filename.toUtf8().constData(), texfile);

		if (normalfile[0] != '\0')
		{
			debug(LOG_TEXTURE, "Loading normal map %s for %s", normalfile, filename.toUtf8().constData());
			normalpage = iV_GetTexture(normalfile, false);
			ASSERT_OR_RETURN(nullptr, normalpage >= 0, "%s could not load tex page %s", filename.toUtf8().constData(), normalfile);
		}

		if (specfile[0] != '\0')
		{
			debug(LOG_TEXTURE, "Loading specular map %s for %s", specfile, filename.toUtf8().constData());
			specpage = iV_GetTexture(specfile, false);
			ASSERT_OR_RETURN(nullptr, specpage >= 0, "%s could not load tex page %s", filename.toUtf8().constData(), specfile);
		}

		// assign tex pages and flags to all levels
		for (iIMDShape *psShape = shape; psShape != nullptr; psShape = psShape->next)
		{
			psShape->texpage = texpage;
			psShape->normalpage = normalpage;
			psShape->specularpage = specpage;
			psShape->flags = imd_flags;
		}

		// check if model should use team colour mask
		if (imd_flags & iV_IMD_TCMASK)
		{
			int texpage_mask;

			pie_MakeTexPageTCMaskName(texfile);
			sstrcat(texfile, ".png");
			texpage_mask = iV_GetTexture(texfile);

			ASSERT_OR_RETURN(shape, texpage_mask >= 0, "%s could not load tcmask %s", filename.toUtf8().constData(), texfile);

			// Propagate settings through levels
			for (iIMDShape *psShape = shape; psShape != nullptr; psShape = psShape->next)
			{
				psShape->tcmaskpage = texpage_mask;
			}
		}
	}

	// copy over model-wide animation information, stored only in the first level
	for (int i = 0; i < ANIM_EVENT_COUNT; i++)
	{
		shape->objanimpie[i] = objanimpie[i];
	}

	*ppFileData = pFileData;
	return shape;
}