Beispiel #1
0
void loadConfig()
{
	FILE *fp;
	char settingsFile[MAX_PATH_LENGTH], *line, *savePtr;
	unsigned char *buffer;
	long length;

	resetGameSettings();

	game.hasConfig = FALSE;

	snprintf(settingsFile, sizeof(settingsFile), "%sconfig", gameSavePath);

	resetControls(FALSE);

	fp = fopen(settingsFile, "rb");

	if (fp == NULL)
	{
		game.firstRun = TRUE;

		return;
	}

	game.firstRun = FALSE;

	fseek(fp, 0L, SEEK_END);

	length = ftell(fp);

	buffer = malloc((length + 1) * sizeof(unsigned char));

	if (buffer == NULL)
	{
		showErrorAndExit("Failed to allocate a whole %ld bytes for config file...", length);

		exit(1);
	}

	fseek(fp, 0L, SEEK_SET);

	fread(buffer, length, 1, fp);

	buffer[length] = '\0';

	fclose(fp);

	savePtr = NULL;

	line = strtok_r((char *)buffer, "\n", &savePtr);

	while (line != NULL)
	{
		if (strcmpignorecase(line, "CONTROLS") == 0)
		{
			readControlsFromFile(savePtr);
		}

		else if (strcmpignorecase(line, "GAME_SETTINGS") == 0)
		{
			readGameSettingsFromFile(savePtr);
		}

		line = strtok_r(NULL, "\n", &savePtr);
	}

	game.hasConfig = TRUE;

	free(buffer);
}
Beispiel #2
0
SDL_Surface *createDialogBox(char *title, char *msg)
{
    char *text, *token, word[MAX_VALUE_LENGTH], *savePtr, *titleText;
    int i, lines, w, h, maxWidth, lineBreak, *lineBreaks;
    SDL_Surface **surface, *tempSurface;
    SDL_Rect dest;

    savePtr = NULL;

    freeDialogBox();

    text = malloc(strlen(msg) + 1);

    if (text == NULL)
    {
        showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(msg) + 1);
    }

    STRNCPY(text, msg, strlen(msg) + 1);

    titleText = NULL;

    if (title != NULL)
    {
        titleText = malloc(strlen(title) + 1);

        if (titleText == NULL)
        {
            showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(title) + 1);
        }

        STRNCPY(titleText, title, strlen(title) + 1);
    }

    token = strtok_r(text, " ", &savePtr);

    i = 0;

    while (token != NULL)
    {
        i++;

        token = strtok_r(NULL, " ", &savePtr);
    }

    lines = i;

    if (titleText != NULL)
    {
        token = titleText;

        while (*token != '\0')
        {
            if (*token == '_')
            {
                *token = ' ';
            }

            token++;
        }

        lines++;
    }

    surface = malloc(sizeof(SDL_Surface *) * lines);

    if (surface == NULL)
    {
        showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Surfaces", (int)sizeof(SDL_Surface *) * lines);
    }

    lineBreaks = malloc(sizeof(int) * lines);

    if (lineBreaks == NULL)
    {
        showErrorAndExit("Failed to allocate a whole %d bytes for the line breaks", (int)sizeof(int) * lines);
    }

    STRNCPY(text, msg, strlen(msg) + 1);

    token = strtok_r(text, " ", &savePtr);

    i = 0;

    maxWidth = w = h = 0;

    if (titleText != NULL)
    {
        surface[i] = generateTextSurface(titleText, game.font, 255, 255, 0, 0, 0, 0);

        h = surface[i]->h + 5;

        maxWidth = surface[i]->w;

        i++;
    }

    while (token != NULL)
    {
        lineBreak = FALSE;

        snprintf(word, sizeof(word), "%d", game.kills);

        token = replaceString(token, "[GAME_KILLS]", word);

        token = replaceString(token, "[HOURS]", getPlayTimeHours());

        snprintf(word, sizeof(word), "%d", game.continues);

        token = replaceString(token, "[CONTINUE_COUNT]", word);

        token = replaceString(token, "[INPUT_LEFT]", getKeyValue(control.button[CONTROL_LEFT]));

        token = replaceString(token, "[INPUT_RIGHT]", getKeyValue(control.button[CONTROL_RIGHT]));

        token = replaceString(token, "[INPUT_JUMP]", getKeyValue(control.button[CONTROL_JUMP]));

        token = replaceString(token, "[INPUT_BLOCK]", getKeyValue(control.button[CONTROL_BLOCK]));

        token = replaceString(token, "[INPUT_ATTACK]", getKeyValue(control.button[CONTROL_ATTACK]));

        token = replaceString(token, "[INPUT_INTERACT]", getKeyValue(control.button[CONTROL_INTERACT]));

        token = replaceString(token, "[INPUT_ACTIVATE]", getKeyValue(control.button[CONTROL_ACTIVATE]));

        token = replaceString(token, "[INPUT_INVENTORY]", getKeyValue(control.button[CONTROL_INVENTORY]));

        token = replaceString(token, "[INPUT_PREVIOUS]", getKeyValue(control.button[CONTROL_PREVIOUS]));

        token = replaceString(token, "[INPUT_NEXT]", getKeyValue(control.button[CONTROL_NEXT]));

        snprintf(word, sizeof(word), "%s ", token);

        if (word[strlen(word) - 2] == '\n')
        {
            lineBreak = TRUE;

            word[strlen(word) - 2] = '\0';
        }

        token = strtok_r(NULL, " ", &savePtr);

        if (token == NULL)
        {
            word[strlen(word) - 1] = '\0';
        }

        surface[i] = generateTextSurface(word, game.font, 255, 255, 255, 0, 0, 0);

        lineBreaks[i] = lineBreak;

        if (h == 0 || (i == 1 && titleText != NULL))
        {
            h += surface[i]->h + 5;
        }

        if (w + surface[i]->w > MAX_DIALOG_WIDTH)
        {
            w = 0;

            h += surface[i]->h + 5;
        }

        w += surface[i]->w;

        if (w > maxWidth)
        {
            maxWidth = w;
        }

        if (lineBreak == TRUE)
        {
            w = 0;

            h += surface[i]->h + 5;
        }

        i++;
    }

    h -= 5;

    tempSurface = createSurface(maxWidth, h);

    w = h = 0;

    for (i=0; i<lines; i++)
    {
        if (w + surface[i]->w > MAX_DIALOG_WIDTH || (titleText != NULL && i == 1))
        {
            w = 0;

            h += surface[i]->h + 5;
        }

        dest.x = w;
        dest.y = h;
        dest.w = surface[i]->w;
        dest.h = surface[i]->h;

        SDL_BlitSurface(surface[i], NULL, tempSurface, &dest);

        w += surface[i]->w;

        SDL_FreeSurface(surface[i]);

        if (lineBreaks[i] == TRUE)
        {
            w = 0;

            h += surface[i]->h + 5;
        }
    }

    tempSurface = addBorder(tempSurface, 255, 255, 255, 0, 0, 0);

    free(surface);

    free(text);

    if (titleText != NULL)
    {
        free(titleText);
    }

    free(lineBreaks);

    return tempSurface;
}
Beispiel #3
0
static void changeSides()
{
    int side;
    Entity *e, *smoke;
    Target *t;

    self->x += self->dirX;
    self->y += self->dirY;

    if (atTarget())
    {
        self->flags |= NO_DRAW;

        self->takeDamage = NULL;

        self->targetX = self->x;

        self->dirX = 0;

        self->thinkTime = 120;

        side = prand() % 2;

        if (side == 0)
        {
            t = getTargetByName("SNAKE_BOSS_TARGET_LEFT");

            self->face = RIGHT;
        }

        else
        {
            t = getTargetByName("SNAKE_BOSS_TARGET_RIGHT");

            self->face = LEFT;
        }

        if (t == NULL)
        {
            showErrorAndExit("Snake boss cannot find target");
        }

        self->damage = 0;

        setSnakePosition(t->x, t->y);

        self->targetX = self->x;
        self->targetY = self->y - 64;

        self->thinkTime = 120;

        self->action = &riseUpWait;
    }

    else
    {
        e = self->target;

        while (e != NULL)
        {
            if (e->target == NULL)
            {
                smoke = addSmoke(e->x + (prand() % self->w) * (prand() % 2 == 0 ? -1 : 1), e->y + prand() % e->h, "decoration/dust");

                if (smoke != NULL)
                {
                    smoke->dirY = 0;
                }
            }

            e = e->target;
        }
    }

    alignBodyToHead();
}
Beispiel #4
0
static void eatExplode()
{
	int i;
	Entity *e;
	Target *t;

	self->maxThinkTime = 0;

	t = getCenterTarget();

	self->startX = 0;

	for (i=0;i<60;i++)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add a Blob Boss Part");
		}

		loadProperties("boss/blob_boss_part", e);

		setEntityAnimation(e, "STAND");

		e->flags |= LIMIT_TO_SCREEN;

		e->x = self->x;
		e->y = self->y;

		e->x += prand() % self->w;

		e->y += prand() % (self->h - e->h);

		e->dirX = (10 + prand() % 20) * (prand() % 2 == 0 ? 1 : -1);

		e->dirX /= 10;

		e->dirY = -6 - prand() % 4;

		e->touch = &entityTouch;

		e->damage = 0;

		e->health = 600;

		e->action = &partWait;

		e->pain = &enemyPain;

		e->draw = &drawLoopingAnimationToMap;

		e->head = self;

		e->type = ENEMY;

		e->targetX = t->x;

		e->targetY = t->y;

		self->startX++;
	}

	self->target = NULL;

	self->thinkTime = 120;

	self->action = &explodeWait;

	setEntityAnimation(self, "WALK");

	self->flags |= NO_DRAW;

	self->frameSpeed = 0;

	self->maxThinkTime = 1;

	self->touch = NULL;
}
Beispiel #5
0
static unsigned char *uncompressFile(char *name, int writeToFile)
{
	char *filename;
	unsigned long size;
	unsigned char *source, *dest;
	FILE *fp;
	#if DEV != 1
		int i, index;
	#endif

	filename = NULL;

	filename = malloc(MAX_PATH_LENGTH);

	if (filename == NULL)
	{
		showErrorAndExit("Failed to allocate a whole %d bytes for filename", MAX_PATH_LENGTH);
	}

	#if DEV == 1
		fp = fopen(name, "rb");

		if (fp == NULL)
		{
			showErrorAndExit("Failed to open %s", name);
		}

		fseek(fp, 0L, SEEK_END);

		size = ftell(fp);

		fseek(fp, 0L, SEEK_SET);

		dest = malloc((size + 2) * sizeof(unsigned char));

		if (dest == NULL)
		{
			showErrorAndExit("Failed to allocate %ld bytes to load %s", (size + 2) * (int)sizeof(unsigned char), name);
		}

		fread(dest, size, 1, fp);

		dest[size] = '\n';
		dest[size + 1] = '\0';

		source = NULL;
	#else
		index = -1;

		for (i=0;i<fileCount;i++)
		{
			if (strcmpignorecase(fileData[i].filename, name) == 0)
			{
				index = i;

				break;
			}
		}

		if (index == -1)
		{
			showErrorAndExit("Failed to find %s in PAK file", name);
		}

		fp = fopen(pakFile, "rb");

		if (fp == NULL)
		{
			showErrorAndExit("Failed to open PAK file %s", pakFile);
		}

		fseek(fp, fileData[index].offset, SEEK_SET);

		source = malloc(fileData[index].compressedSize * sizeof(unsigned char));

		if (source == NULL)
		{
			showErrorAndExit("Failed to allocate %ld bytes to load %s from PAK", fileData[index].compressedSize * (int)sizeof(unsigned char), name);
		}

		dest = malloc((fileData[index].fileSize + 1) * sizeof(unsigned char));

		if (dest == NULL)
		{
			showErrorAndExit("Failed to allocate %ld bytes to load %s from PAK", fileData[index].fileSize * (int)sizeof(unsigned char), name);
		}

		fread(source, fileData[index].compressedSize, 1, fp);

		size = fileData[index].fileSize;

		uncompress(dest, &size, source, fileData[index].compressedSize);

		dest[size] = '\0';

		if (size != fileData[index].fileSize)
		{
			showErrorAndExit("Failed to decompress %s. Expected %ld, got %ld", fileData[index].filename, fileData[index].fileSize, size);
		}

		if (writeToFile == TRUE)
		{
			fclose(fp);

			snprintf(filename, MAX_PATH_LENGTH, "%spakdata", getGameSavePath());

			printf("Writing to %s\n", filename);

			fp = fopen(filename, "wb");

			if (fp == NULL)
			{
				showErrorAndExit("Failed to write pak data to temp file: %s", strerror(errno));
			}

			fwrite(dest, size, 1, fp);

			free(dest);
		}
	#endif

	if (source != NULL)
	{
		free(source);
	}

	if (filename != NULL && writeToFile == FALSE)
	{
		free(filename);
	}

	fclose(fp);

	if (writeToFile == TRUE)
	{
		return (unsigned char *)filename;
	}

	else
	{
		return dest;
	}
}
Beispiel #6
0
static void disintegrationAttack()
{
	Entity *e;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		if (self->mental == 0)
		{
			self->y = getMapFloor(self->x + self->w / 2, self->y) - self->h;

			self->flags &= ~NO_DRAW;

			addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2);

			self->mental = 1;

			self->thinkTime = 30;
		}

		else
		{
			e = getFreeEntity();

			if (e == NULL)
			{
				showErrorAndExit("No free slots to add the Disintegration Spell");
			}

			setEntityAnimation(self, "ATTACK_2");

			loadProperties("boss/sorceror_disintegration_spell", e);

			setEntityAnimation(e, "STAND");

			e->face = self->face;

			if (self->face == LEFT)
			{
				e->x = self->x + self->w - e->w - e->offsetX;
			}

			else
			{
				e->x = self->x + e->offsetX;
			}

			e->y = self->y + e->offsetY;

			e->action = &disintegrationSpellInit;

			e->thinkTime = 120;

			e->startX = e->x;
			e->startY = e->y;

			e->head = self;

			e->endX = player.x + player.w / 2;
			e->endY = player.y + player.h / 2;

			e->draw = &drawLoopingAnimationToMap;

			self->mental = 1;

			self->action = &disintegrationAttackWait;

			self->thinkTime = 30;
		}
	}
}
Beispiel #7
0
static void splitAttackInit()
{
	int i;
	Entity *e;
	Target *t;

	self->maxThinkTime = 0;

	t = getCenterTarget();

	for (i=0;i<60;i++)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add a Blob Boss Part");
		}

		loadProperties("boss/blob_boss_part", e);

		e->flags |= LIMIT_TO_SCREEN;

		setEntityAnimation(e, "WALK");

		e->x = self->x;
		e->y = self->y;

		e->x += prand() % self->w;

		e->y += prand() % (self->h - e->h);

		e->dirX = (10 + prand() % 20) * (prand() % 2 == 0 ? 1 : -1);

		e->dirX /= 10;

		e->dirY = -6;

		e->action = &partAttack;

		e->touch = &partGrab;

		e->die = &partDie;

		e->pain = &enemyPain;

		e->draw = &drawLoopingAnimationToMap;

		e->takeDamage = &partTakeDamage;

		e->head = self;

		e->type = ENEMY;

		e->thinkTime = 60;

		e->targetX = t->x;

		e->targetY = t->y;
	}

	self->maxThinkTime = 60;

	self->action = &headWait;

	setEntityAnimation(self, "BLOCK");

	self->flags |= NO_DRAW;

	self->frameSpeed = 0;

	self->touch = NULL;
}
Beispiel #8
0
static void entityWait()
{
	int frameCount = getFrameCount(self);
	Entity *e;

	if (self->active == TRUE)
	{
		self->thinkTime--;

		if (self->thinkTime % 120 == 0)
		{
			self->currentFrame++;

			if (self->currentFrame >= frameCount)
			{
				self->currentFrame = frameCount - 1;
			}
		}

		else if (self->thinkTime % 5 == 0)
		{
			e = getFreeEntity();

			if (e == NULL)
			{
				showErrorAndExit("No free slots to add the Fire");
			}

			loadProperties("boss/phoenix_die_fire", e);

			setEntityAnimation(e, "STAND");

			e->x = self->x + prand() % self->w;
			e->y = self->y + self->h - e->h;

			e->action = &fireWait;

			e->draw = &drawLoopingAnimationToMap;

			e->type = ENEMY;

			e->flags |= DO_NOT_PERSIST|FLY;

			e->thinkTime = 30;

			e->health = 0;

			e->maxHealth = 3 + prand() % 3;

			e->mental = 1;

			e->head = self;
		}

		if (self->thinkTime <= 0)
		{
			self->inUse = FALSE;
		}
	}

	else
	{
		self->frameSpeed = 0;

		self->thinkTime = frameCount * 120;
	}

	checkToMap(self);
}
Beispiel #9
0
static void loadMenuLayout()
{
	Medal *medal;
	int i, width, medalCount;
	Texture *texture;

	medal = getMedals();

	medalCount = getMedalCount();

	i = 0;

	width = 0;

	menu.w = 0;

	menu.h = 0;

	menu.startY = 0;

	menu.endY = 0;

	menu.widgetCount = medalCount;

	menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount);

	if (menu.widgets == NULL)
	{
		showErrorAndExit("Ran out of memory when creating Medals Menu");
	}

	for (i=0;i<menu.widgetCount;i++)
	{
		if (medal[i].hidden == TRUE && medal[i].obtained == FALSE)
		{
			menu.widgets[i] = createWidget(_("Hidden Medal"), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 255, 255, 255);
		}

		else
		{
			if (medal[i].obtained == TRUE)
			{
				menu.widgets[i] = createWidget(_(medal[i].description), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 0, 200, 0);
			}

			else
			{
				menu.widgets[i] = createWidget(_(medal[i].description), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 255, 255, 255);
			}
		}

		if (width < menu.widgets[i]->x + menu.widgets[i]->normalState->w)
		{
			width = menu.widgets[i]->x + menu.widgets[i]->normalState->w;
		}

		texture = getMedalImage(medal[i].medalType, medal[i].obtained);

		menu.widgets[i]->label = createImageLabel(texture, menu.widgets[i]->x, menu.widgets[i]->y);

		menu.widgets[i]->label->y = menu.widgets[i]->y + menu.widgets[i]->normalState->h / 2 - menu.widgets[i]->label->text->h / 2;

		menu.endY = menu.widgets[i]->y + menu.widgets[i]->normalState->h - menu.h;
	}

	width += 15;

	menu.h = SCREEN_HEIGHT - BUTTON_PADDING;

	for (i=0;i<menu.widgetCount;i++)
	{
		if (menu.widgets[i]->label != NULL)
		{
			menu.widgets[i]->label->x = width;

			if (menu.w < menu.widgets[i]->label->x + menu.widgets[i]->label->text->w)
			{
				menu.w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w;
			}
		}
	}

	menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0);

	menu.x = (SCREEN_WIDTH - menu.background->w) / 2;
	menu.y = (SCREEN_HEIGHT - menu.background->h) / 2;
}
Beispiel #10
0
static SDL_Surface *createWidgetText(char *msg, TTF_Font *font, int fr, int fg, int fb, int br, int bg, int bb)
{
	char *text, *token, word[MAX_VALUE_LENGTH], *savePtr;
	int i, lines, w, h, maxWidth, lineBreak, *lineBreaks;
	SDL_Surface **surface, *tempSurface;
	SDL_Rect dest;

	savePtr = NULL;

	text = malloc(strlen(msg) + 1);

	if (text == NULL)
	{
		showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(msg) + 1);
	}

	STRNCPY(text, msg, strlen(msg) + 1);

	token = strtok_r(text, " ", &savePtr);

	i = 0;

	while (token != NULL)
	{
		i++;

		token = strtok_r(NULL, " ", &savePtr);
	}

	lines = i;

	surface = malloc(sizeof(SDL_Surface *) * lines);

	if (surface == NULL)
	{
		showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Surfaces", (int)sizeof(SDL_Surface *) * lines);
	}

	lineBreaks = malloc(sizeof(int) * lines);

	if (lineBreaks == NULL)
	{
		showErrorAndExit("Failed to allocate a whole %d bytes for the line breaks", (int)sizeof(int) * lines);
	}

	STRNCPY(text, msg, strlen(msg) + 1);

	token = strtok_r(text, " ", &savePtr);

	i = 0;

	maxWidth = w = h = 0;

	while (token != NULL)
	{
		lineBreak = FALSE;

		snprintf(word, sizeof(word), "%s ", token);

		if (word[strlen(word) - 2] == '\n')
		{
			lineBreak = TRUE;

			word[strlen(word) - 2] = '\0';
		}

		token = strtok_r(NULL, " ", &savePtr);

		if (token == NULL)
		{
			word[strlen(word) - 1] = '\0';
		}

		surface[i] = generateTextSurface(word, game.font, fr, fg, fb, br, bg, bb);

		lineBreaks[i] = lineBreak;

		if (h == 0)
		{
			h += surface[i]->h + 5;
		}

		if (w + surface[i]->w > MAX_SCRIPT_WIDTH)
		{
			w = 0;

			h += surface[i]->h + 5;
		}

		w += surface[i]->w;

		if (w > maxWidth)
		{
			maxWidth = w;
		}

		if (lineBreak == TRUE)
		{
			w = 0;

			h += surface[i]->h + 5;
		}

		i++;
	}

	h -= 5;

	tempSurface = createSurface(maxWidth, h);

	w = h = 0;

	for (i=0;i<lines;i++)
	{
		if (w + surface[i]->w > MAX_SCRIPT_WIDTH)
		{
			w = 0;

			h += surface[i]->h + 5;
		}

		dest.x = w;
		dest.y = h;
		dest.w = surface[i]->w;
		dest.h = surface[i]->h;

		SDL_BlitSurface(surface[i], NULL, tempSurface, &dest);

		w += surface[i]->w;

		SDL_FreeSurface(surface[i]);

		if (lineBreaks[i] == TRUE)
		{
			w = 0;

			h += surface[i]->h + 5;
		}
	}

	free(surface);

	free(text);

	free(lineBreaks);

	return tempSurface;
}
Beispiel #11
0
static void summonEnemies()
{
	char summonList[MAX_VALUE_LENGTH], enemyToSummon[MAX_VALUE_LENGTH];
	char *token;
	int i, summonIndex = 0, summonCount = 0;
	Entity *e;

	for (i=0;i<2;i++)
	{
		summonCount = 0;

		summonIndex = 0;

		STRNCPY(summonList, self->requires, MAX_VALUE_LENGTH);

		token = strtok(summonList, "|");

		while (token != NULL)
		{
			token = strtok(NULL, "|");

			summonCount++;
		}

		if (summonCount == 0)
		{
			showErrorAndExit("Scanner at %f %f has no summon list", self->x, self->y);
		}

		summonIndex = prand() % summonCount;

		STRNCPY(summonList, self->requires, MAX_VALUE_LENGTH);

		summonCount = 0;

		token = strtok(summonList, "|");

		while (token != NULL)
		{
			if (summonCount == summonIndex)
			{
				break;
			}

			token = strtok(NULL, "|");

			summonCount++;
		}

		snprintf(enemyToSummon, MAX_VALUE_LENGTH, "enemy/%s", token);

		e = addEnemy(enemyToSummon, self->x, self->y);

		e->x = self->x;

		e->y = self->y;

		e->targetX = self->x + (i == 0 ? -64 : 64);

		e->targetY = self->y;

		calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY);

		e->flags |= (NO_DRAW|HELPLESS|TELEPORTING);
	}
}
Beispiel #12
0
void saveTemporaryData()
{
	char *line, itemName[MAX_MESSAGE_LENGTH], *savePtr;
	char swapFile[MAX_PATH_LENGTH];
	char *mapName = getMapFilename();
	unsigned char *buffer;
	int skipping = FALSE;
	FILE *read;
	FILE *write;

	savePtr = NULL;

	snprintf(swapFile, sizeof(swapFile), "%sswap", gameSavePath);

	read = fopen(tempFile, "rb");

	write = fopen(swapFile, "wb");

	if (read == NULL)
	{
		if (temporaryDataExists == TRUE)
		{
			showErrorAndExit("SAVE TEMP DATA: Could not find persistance file: %s", strerror(errno));
		}
	}

	else
	{
		fclose(read);

		buffer = decompressFile(tempFile);

		if (strlen((char *)buffer) == 0)
		{
			showErrorAndExit("Something went wrong when decompressing the persistance file");
		}

		line = strtok_r((char *)buffer, "\n", &savePtr);

		while (line != NULL)
		{
			if (line[strlen(line) - 1] == '\n')
			{
				line[strlen(line) - 1] = '\0';
			}

			if (line[strlen(line) - 1] == '\r')
			{
				line[strlen(line) - 1] = '\0';
			}

			if (skipping == FALSE)
			{
				sscanf(line, "%s", itemName);

				if (strcmpignorecase("PLAYER_DATA", line) == 0 || strcmpignorecase("PLAYER_INVENTORY", line) == 0 ||
					strcmpignorecase("GLOBAL_TRIGGER", line) == 0 || strcmpignorecase("OBJECTIVE", line) == 0 ||
					strcmpignorecase("PLAYER_LOCATION", line) == 0 || strcmpignorecase("MAP_TRIGGER", line) == 0)
				{
					skipping = TRUE;
				}

				else if (strcmpignorecase("MAP_NAME", itemName) == 0)
				{
					sscanf(line, "%*s %s\n", itemName);

					if (strcmpignorecase(itemName, mapName) == 0)
					{
						skipping = TRUE;
					}

					else
					{
						fprintf(write, "%s\n", line);
					}
				}

				else
				{
					fprintf(write, "%s\n", line);
				}
			}

			else
			{
				sscanf(line, "%s", itemName);

				if (strcmpignorecase("MAP_NAME", itemName) == 0)
				{
					sscanf(line, "%*s %s\n", itemName);

					if (strcmpignorecase(itemName, mapName) != 0)
					{
						skipping = FALSE;

						fprintf(write, "%s\n", line);
					}
				}
			}

			line = strtok_r(NULL, "\n", &savePtr);
		}

		free(buffer);

		if (remove(tempFile) != 0)
		{
			showErrorAndExit("Could not remove temporary file");
		}
	}

	fprintf(write, "MAP_NAME %s\n", mapName);

	fprintf(write, "ENTITY_DATA\n");

	/* Now write out all of the Entities */

	writeEntitiesToFile(write);

	/* Now the targets */

	writeTargetsToFile(write);

	/* And the triggers */

	writeTriggersToFile(write);

	fclose(write);

	if (rename(swapFile, tempFile) != 0)
	{
		showErrorAndExit("Could not rename temporary file");
	}

	#if DEV == 1
		copyFile(tempFile, "tmpdata");
	#endif

	compressFile(tempFile);

	temporaryDataExists = TRUE;
}
Beispiel #13
0
void saveGame(int slot)
{
	char itemName[MAX_MESSAGE_LENGTH], *line, *savePtr;
	char saveFile[MAX_PATH_LENGTH];
	char *mapName = getMapFilename();
	char tempSaveFile[MAX_PATH_LENGTH];
	int i;
	unsigned char *buffer;
	int skipping = FALSE;
	FILE *read;
	FILE *write;

	savePtr = NULL;

	if (slot == -1)
	{
		for (i=1001;;i++)
		{
			snprintf(saveFile, sizeof(saveFile), "%ssave%d", gameSavePath, i);

			read = fopen(saveFile, "rb");

			if (read == NULL)
			{
				break;
			}

			else
			{
				fclose(read);
			}
		}
	}

	else
	{
		/* Backup older save */

		snprintf(saveFile, sizeof(saveFile), "%ssave%d", gameSavePath, slot);

		snprintf(tempSaveFile, sizeof(tempSaveFile), "%stempsave%d", gameSavePath, slot);
	}

	write = fopen(tempSaveFile, "wb");

	fprintf(write, "VERSION %0.2f\n", VERSION);

	fprintf(write, "PLAY_TIME %ld\n", game.playTime);

	fprintf(write, "PLAYER_KILLS %d\n", game.kills);

	fprintf(write, "BATS_DROWNED %d\n", game.batsDrowned);

	fprintf(write, "TIMES_EATEN %d\n", game.timesEaten);

	fprintf(write, "DISTANCE_TRAVELLED %u\n", game.distanceTravelled);

	fprintf(write, "ATTACKS_BLOCKED %d\n", game.attacksBlocked);

	fprintf(write, "SLIME_TIME %d\n", game.timeSpentAsSlime);

	fprintf(write, "ARROWS_FIRED %d\n", game.arrowsFired);

	fprintf(write, "SECRETS_FOUND %d\n", game.secretsFound);

	fprintf(write, "CONTINUES %d\n", game.continues);

	fprintf(write, "CHEATING %d\n", game.cheating);

	fprintf(write, "PLAYER_LOCATION %s\n", mapName);

	read = fopen(tempFile, "rb");

	if (read == NULL)
	{
		if (temporaryDataExists == TRUE)
		{
			showErrorAndExit("SAVE GAME: Could not find persistance file: %s", strerror(errno));
		}
	}

	else
	{
		fclose(read);

		buffer = decompressFile(tempFile);

		line = strtok_r((char *)buffer, "\n", &savePtr);

		while (line != NULL)
		{
			if (line[strlen(line) - 1] == '\n')
			{
				line[strlen(line) - 1] = '\0';
			}

			if (line[strlen(line) - 1] == '\r')
			{
				line[strlen(line) - 1] = '\0';
			}

			if (skipping == FALSE)
			{
				sscanf(line, "%s", itemName);

				if (strcmpignorecase("PLAYER_DATA", itemName) == 0 || strcmpignorecase("PLAYER_INVENTORY", itemName) == 0 ||
					strcmpignorecase("PLAYER_LOCATION", itemName) == 0 || strcmpignorecase("VERSION", itemName) == 0)
				{
					skipping = TRUE;
				}

				else if (strcmpignorecase("MAP_NAME", itemName) == 0)
				{
					sscanf(line, "%*s %s\n", itemName);

					if (strcmpignorecase(itemName, mapName) == 0)
					{
						skipping = TRUE;
					}

					else
					{
						fprintf(write, "%s\n", line);
					}
				}

				else
				{
					fprintf(write, "%s\n", line);
				}
			}

			else
			{
				sscanf(line, "%s", itemName);

				if (strcmpignorecase("MAP_NAME", itemName) == 0)
				{
					sscanf(line, "%*s %s\n", itemName);

					if (strcmpignorecase(itemName, mapName) != 0)
					{
						skipping = FALSE;

						fprintf(write, "%s\n", line);
					}
				}
			}

			line = strtok_r(NULL, "\n", &savePtr);
		}

		free(buffer);
	}

	/* Save the player's position */

	fprintf(write, "MAP_NAME %s\n", mapName);

	fprintf(write, "PLAYER_DATA\n");

	writePlayerToFile(write);

	fprintf(write, "INVENTORY_INDEX %d\n", getInventoryIndex());

	fprintf(write, "PLAYER_INVENTORY\n");

	writeInventoryToFile(write);

	fprintf(write, "ENTITY_DATA\n");

	/* Now write out all of the Entities */

	writeEntitiesToFile(write);

	/* Now the targets */

	writeTargetsToFile(write);

	/* And the triggers */

	writeTriggersToFile(write);

	/* Add the global triggers */

	writeGlobalTriggersToFile(write);

	/* Add the map triggers */

	writeMapTriggersToFile(write);

	/* Add the objectives */

	writeObjectivesToFile(write);

	/* Save the player data */

	fclose(write);

	#if DEV == 1
		copyFile(tempSaveFile, "savedata");
	#endif

	compressFile(tempSaveFile);

	copyFile(tempSaveFile, saveFile);

	remove(tempSaveFile);

	updateSaveFileIndex(slot);
}
Beispiel #14
0
static void patchSaveGame(char *saveFile, double version)
{
	char location[MAX_VALUE_LENGTH], *line, *savePtr, itemName[MAX_MESSAGE_LENGTH], *returnedName, mapName[MAX_VALUE_LENGTH];
	unsigned char *buffer, *originalBuffer;
	int savedLocation = FALSE, saveMap;
	FILE *newSave;

	savePtr = NULL;

	freeGameResources();

	newSave = fopen(tempFile, "wb");

	buffer = decompressFile(saveFile);

	originalBuffer = malloc((strlen((char *)buffer) + 1) * sizeof(unsigned char));

	if (originalBuffer == NULL)
	{
		showErrorAndExit("Failed to allocate %d bytes to patch save game", (int)((strlen((char *)buffer) + 1) * sizeof(unsigned char)));
	}

	strcpy((char *)originalBuffer, (char *)buffer);

	line = strtok_r((char *)buffer, "\n", &savePtr);

	returnedName = NULL;

	mapName[0] = '\0';

	while (line != NULL)
	{
		if (line[strlen(line) - 1] == '\n')
		{
			line[strlen(line) - 1] = '\0';
		}

		if (line[strlen(line) - 1] == '\r')
		{
			line[strlen(line) - 1] = '\0';
		}

		sscanf(line, "%s", itemName);

		if (strcmpignorecase("PLAYER_LOCATION", itemName) == 0)
		{
			sscanf(line, "%*s %s\n", location);
		}

		else if (strcmpignorecase("MAP_NAME", itemName) == 0)
		{
			saveMap = TRUE;

			if (strlen(mapName) == 0 || strcmpignorecase(line, mapName) == 0)
			{
				sscanf(line, "%*s %s\n", itemName);

				returnedName = loadResources(savePtr);

				if (returnedName != NULL)
				{
					STRNCPY(mapName, returnedName, sizeof(mapName));
				}

				/* Rewind to start */

				free(buffer);

				buffer = malloc((strlen((char *)originalBuffer) + 1) * sizeof(unsigned char));

				if (buffer == NULL)
				{
					showErrorAndExit("Failed to allocate %d bytes to patch save game", (int)((strlen((char *)originalBuffer) + 1) * sizeof(unsigned char)));
				}

				strcpy((char *)buffer, (char *)originalBuffer);

				line = strtok_r((char *)buffer, "\n", &savePtr);

				/* Load up the patch file */

				saveMap = patchEntities(version, itemName);

				if (saveMap == FALSE)
				{
					snprintf(itemName, sizeof(itemName), "%ld_old", game.playTime * SDL_GetTicks());
				}

				if (savedLocation == FALSE)
				{
					fprintf(newSave, "VERSION %0.2f\n", version);

					fprintf(newSave, "PLAY_TIME %ld\n", game.playTime);

					fprintf(newSave, "PLAYER_KILLS %d\n", game.kills);

					fprintf(newSave, "BATS_DROWNED %d\n", game.batsDrowned);

					fprintf(newSave, "TIMES_EATEN %d\n", game.timesEaten);

					fprintf(newSave, "DISTANCE_TRAVELLED %u\n", game.distanceTravelled);

					fprintf(newSave, "ATTACKS_BLOCKED %d\n", game.attacksBlocked);

					fprintf(newSave, "SLIME_TIME %d\n", game.timeSpentAsSlime);

					fprintf(newSave, "ARROWS_FIRED %d\n", game.arrowsFired);

					fprintf(newSave, "SECRETS_FOUND %d\n", game.secretsFound);

					fprintf(newSave, "CONTINUES %d\n", game.continues);

					fprintf(newSave, "CHEATING %d\n", game.cheating);

					fprintf(newSave, "PLAYER_LOCATION %s\n", location);

					savedLocation = TRUE;
				}

				fprintf(newSave, "MAP_NAME %s\n", itemName);

				if (strcmpignorecase(itemName, location) == 0)
				{
					fprintf(newSave, "PLAYER_DATA\n");

					writePlayerToFile(newSave);

					fprintf(newSave, "PLAYER_INVENTORY\n");

					writeInventoryToFile(newSave);
				}

				fprintf(newSave, "ENTITY_DATA\n");

				/* Now write out all of the Entities */

				writeEntitiesToFile(newSave);

				/* Now the targets */

				writeTargetsToFile(newSave);

				/* And the triggers */

				writeTriggersToFile(newSave);

				/* Add the global triggers */

				writeGlobalTriggersToFile(newSave);

				/* Add the map triggers */

				writeMapTriggersToFile(newSave);

				/* Add the objectives */

				writeObjectivesToFile(newSave);

				freeLevelResources();

				if (returnedName == NULL)
				{
					break;
				}
			}
		}

		line = strtok_r(NULL, "\n", &savePtr);
	}

	free(buffer);

	free(originalBuffer);

	fclose(newSave);

	#if DEV == 1
		copyFile(tempFile, "tmpdata");
	#endif

	copyFile(tempFile, saveFile);

	compressFile(saveFile);
}
Beispiel #15
0
static void finalAttack()
{
	Entity *temp;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		switch (self->mental)
		{
			case 0:
				setEntityAnimation(self, "ATTACK_4");

				addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2);

				playSoundToMap("sound/common/spell", -1, self->x, self->y, 0);

				self->flags &= ~NO_DRAW;

				self->face = RIGHT;

				createAutoDialogBox(_("Sorceror"), _("Enough! Prepare to die..."), 180);

				self->thinkTime = 180;

				self->mental = 1;

				temp = getFreeEntity();

				if (temp == NULL)
				{
					showErrorAndExit("No free slots to add a the staff");
				}

				loadProperties("boss/sorceror_staff", temp);

				temp->action = &staffMoveAroundSorceror;

				temp->draw = &drawLoopingAnimationToMap;

				temp->type = ENEMY;

				setEntityAnimationByID(temp, 0);

				temp->x = self->x + self->w / 2 - temp->w / 2;

				temp->y = self->y + self->h / 2 - temp->h / 2;

				temp->startX = temp->x;

				temp->startY = temp->y;

				temp->head = self;

				temp->health = self->health;

				temp->mental = self->box.w;
			break;

			case 1:
				temp = getFreeEntity();

				if (temp == NULL)
				{
					showErrorAndExit("No free slots to add a the Final Attack spell");
				}

				loadProperties("boss/sorceror_final_spell", temp);

				temp->action = &finalSpellWait;

				temp->draw = &drawLoopingAnimationToMap;

				temp->type = ENEMY;

				setEntityAnimationByID(temp, 0);

				temp->x = self->x + temp->offsetX;

				temp->y = self->y + temp->offsetY;

				temp->head = self;

				temp->thinkTime = 60;

				self->thinkTime = 660;

				self->mental = 2;

				temp->health = self->health;
			break;

			default:
				self->mental = 3;

				playSoundToMap("sound/common/massive_explosion", -1, self->x, self->y, 0);

				fadeFromColour(0, 0, 200, 30);

				/* Gib the player */

				temp = self;

				self = &player;

				freeEntityList(playerGib());

				self = temp;

				self->thinkTime = 120;

				self->action = &finalAttackFinish;
			break;
		}
	}

	else if (self->thinkTime <= 420 && self->mental == 2)
	{
		self->startX = 2;
	}
}
Beispiel #16
0
static void init()
{
	int i, x, y, col;
	Entity *e, *prev;

	prev = self;

	x = self->x;
	y = self->y + self->h;

	col = 1;

	if (self->mental != 2)
	{
		for (i=0;i<50;i++)
		{
			/* 4 pegs per row, plus 1 score tile and 10 rows */

			e = getFreeEntity();

			if (e == NULL)
			{
				showErrorAndExit("No free slots to add a Mastermind Peg");
			}

			if (col == 5)
			{
				loadProperties("item/mastermind_score", e);

				col = 0;

				e->mental = 1;
			}

			else
			{
				loadProperties("item/mastermind_peg", e);

				e->mental = 0;
			}

			setEntityAnimation(e, "STAND");

			if (i == 0)
			{
				y -= TILE_SIZE;
			}

			if (i != 0 && i % 5 == 0)
			{
				x = self->x;
				y -= TILE_SIZE;
			}

			else if (i != 0)
			{
				x += TILE_SIZE;
			}

			e->face = RIGHT;

			e->x = x;
			e->y = y;

			e->action = &pegWait;

			e->draw = &drawLoopingAnimationToMap;

			prev->target = e;

			prev = e;

			e->target = NULL;

			col++;
		}

		generateSolution();

		addCursor();
	}

	self->action = &entityWait;
}
Beispiel #17
0
static void riftAttack()
{
	Entity *e;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		if (self->mental == 0)
		{
			self->y = getMapFloor(self->x + self->w / 2, self->y) - self->h;

			self->flags &= ~NO_DRAW;

			addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2);

			self->mental = 1;

			self->thinkTime = 60;
		}

		else
		{
			setEntityAnimation(self, "ATTACK_1");

			e = getFreeEntity();

			if (e == NULL)
			{
				showErrorAndExit("No free slots to add an Energy Rift");
			}

			loadProperties("enemy/energy_rift", e);

			e->damage = 1;

			e->action = &riftMove;

			e->touch = &entityTouch;

			e->draw = &drawLoopingAnimationToMap;

			e->type = ENEMY;

			setEntityAnimation(e, "STAND");

			if (self->face == LEFT)
			{
				e->x = self->x - e->w;
			}

			else
			{
				e->x = self->x + self->w;
			}

			e->thinkTime = 15;

			e->y = self->y;

			e->dirX = self->face == LEFT ? -e->speed : e->speed;

			e->head = self;

			e->targetX = getMapStartX() + SCREEN_WIDTH / 2 - e->w / 2;
			e->targetY = e->y;

			e->health = 0;

			playSoundToMap("sound/common/spell", -1, self->x, self->y, 0);

			self->mental = -1;

			self->action = &riftAttackWait;

			self->thinkTime = 60;
		}
	}

	checkToMap(self);
}
Beispiel #18
0
static void holdPersonSpellMove()
{
	Entity *e;

	if (self->target == NULL)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add the Sorceror's Hold Person");
		}

		loadProperties("boss/sorceror_hold_person_spell", e);

		setEntityAnimation(e, "BACK");

		e->face = RIGHT;

		e->action = &holdPersonBackWait;
		e->draw = &drawLoopingAnimationToMap;

		e->x = self->x;
		e->y = self->y;

		e->layer = BACKGROUND_LAYER;

		self->target = e;

		e->head = self;
	}

	switch (self->mental)
	{
		case 3:
			self->targetY = player.y + player.h / 2 - self->h / 2 - 16;
		break;

		case 2:
			self->targetY = player.y + player.h / 2 - self->h / 2;
		break;

		default:
			self->targetY = player.y + player.h / 2 - self->h / 2 + 16;
		break;
	}

	setCustomAction(&player, &stickToFloor, 3, 0, 0);

	if (self->y < self->targetY)
	{
		self->y += 12;

		if (self->y >= self->targetY)
		{
			self->y = self->targetY;

			self->face = player.face;
		}
	}

	else
	{
		if (self->mental == 3)
		{
			setInfoBoxMessage(0, 255, 255, 255, _("Quickly turn left and right to remove the hold person spell!"));
		}

		if (self->face != player.face)
		{
			self->face = player.face;

			self->health--;

			if (self->health <= 0)
			{
				setEntityAnimation(self, "LEFT_PIECE");

				self->layer = FOREGROUND_LAYER;

				self->dirX = -4;

				self->action = &holdPersonPieceMove;

				self->thinkTime = 30;
			}
		}
	}

	player.x = self->x + self->w / 2 - player.w / 2;
}
Beispiel #19
0
static void loadMenuLayout(char *text)
{
	int y, i, w, maxWidth;

	i = 0;

	menu.widgetCount = 2;

	menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount);

	if (menu.widgets == NULL)
	{
		showErrorAndExit("Ran out of memory when creating OK Menu");
	}

	menu.widgets[0] = createWidget(text, NULL, NULL, NULL, NULL, -1, 10, FALSE, 255, 255, 255);

	menu.widgets[1] = createWidget(_("OK"), NULL, NULL, NULL, &doOK, -1, 10, TRUE, 255, 255, 255);

	y = BUTTON_PADDING + BORDER_PADDING;

	maxWidth = w = 0;

	for (i=0;i<menu.widgetCount;i++)
	{
		if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth)
		{
			maxWidth = menu.widgets[i]->normalState->w;
		}
	}

	for (i=0;i<menu.widgetCount;i++)
	{
		menu.widgets[i]->y = y;

		if (menu.widgets[i]->x != -1)
		{
			menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING;
		}

		if (menu.widgets[i]->label != NULL)
		{
			menu.widgets[i]->label->y = y;

			menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10;

			if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w)
			{
				w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w;
			}
		}

		else
		{
			if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w)
			{
				w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w;
			}
		}

		y += menu.widgets[i]->selectedState->h + BUTTON_PADDING;
	}

	menu.w = w + BUTTON_PADDING;
	menu.h = y - BORDER_PADDING;

	menu.background = addBorder(createSurface(menu.w, menu.h), 255, 255, 255, 0, 0, 0);

	menu.x = (SCREEN_WIDTH - menu.background->w) / 2;
	menu.y = (SCREEN_HEIGHT - menu.background->h) / 2;
}
Beispiel #20
0
static void castLightningBolt()
{
	Entity *e;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add lightning");
		}

		loadProperties("enemy/lightning", e);

		setEntityAnimation(e, "STAND");

		e->x = self->x + self->w / 2;
		e->y = self->y + self->h / 2;

		e->x -= e->w / 2;
		e->y -= e->h / 2;

		e->targetX = player.x + player.w / 2 - e->w / 2;
		e->targetY = getMapCeiling(self->x, self->y);

		e->startY = e->targetY;
		e->endY   = getMapFloor(e->targetX, e->targetY);

		calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY);

		e->flags |= (NO_DRAW|HELPLESS|TELEPORTING|NO_END_TELEPORT_SOUND);

		playSoundToMap("sound/common/spell", -1, self->x, self->y, 0);

		e->head = self;

		e->face = RIGHT;

		e->action = &lightningBolt;

		e->draw = &drawLoopingAnimationToMap;

		e->head = self;

		e->face = self->face;

		e->type = ENEMY;

		e->thinkTime = 0;

		e->flags |= FLY|DO_NOT_PERSIST;

		self->mental--;

		if (self->mental <= 0)
		{
			self->thinkTime = 60;

			self->action = &attackFinished;
		}

		else
		{
			self->thinkTime = 30;
		}
	}

	hover();
}
Beispiel #21
0
static void dieSplit()
{
	Entity *e;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add a Blob Boss Part");
		}

		loadProperties("boss/blob_boss_part", e);

		e->flags |= LIMIT_TO_SCREEN;

		setEntityAnimation(e, "STAND");

		e->draw = &drawLoopingAnimationToMap;

		e->type = ENEMY;

		e->damage = 0;

		e->touch = NULL;

		e->head = self;

		e->action = &partFinalDie;

		e->die = &entityDieNoDrop;

		e->x = self->x + self->box.x + self->box.w / 2 - e->w / 2;

		e->y = self->y + self->box.y + self->box.h / 2 - e->h / 2;

		e->thinkTime = 120;

		e->dirX = 10 + prand() % 80;

		e->dirX /= 10;

		e->dirX *= prand() % 2 == 0 ? -1 : 1;

		e->dirY = -4 - prand() % 12;

		e->targetX = self->x + self->w / 2;

		self->mental--;

		if (self->mental == 0)
		{
			if (self->currentFrame == 0)
			{
				self->flags |= NO_DRAW;

				self->thinkTime = 120;

				self->action = &dieWait;

				return;
			}

			else
			{
				self->mental = 30;

				self->currentFrame--;

				setFrameData(self);
			}
		}

		self->thinkTime = 3;
	}

	checkToMap(self);
}
Beispiel #22
0
static void lightningBolt()
{
	int i, middle;
	Entity *e;

	self->flags |= NO_DRAW;

	self->thinkTime--;

	middle = -1;

	if (self->thinkTime <= 0)
	{
		playSoundToMap("sound/enemy/thunder_cloud/lightning", -1, self->targetX, self->startY, 0);

		for (i=self->startY;i<self->endY;i+=32)
		{
			e = getFreeEntity();

			if (e == NULL)
			{
				showErrorAndExit("No free slots to add lightning");
			}

			loadProperties("enemy/lightning", e);

			setEntityAnimation(e, "STAND");

			if (i == self->startY)
			{
				middle = self->targetX + self->w / 2 - e->w / 2;
			}

			e->x = middle;
			e->y = i;

			e->action = &lightningWait;

			e->draw = &drawLoopingAnimationToMap;
			e->touch = &entityTouch;

			e->head = self;

			e->currentFrame = prand() % 6;

			e->face = RIGHT;

			e->thinkTime = 15;
		}

		e = addSmallRock(self->x, self->endY, "common/small_rock");

		e->x += (self->w - e->w) / 2;
		e->y -= e->h;

		e->dirX = -3;
		e->dirY = -8;

		e = addSmallRock(self->x, self->endY, "common/small_rock");

		e->x += (self->w - e->w) / 2;
		e->y -= e->h;

		e->dirX = 3;
		e->dirY = -8;

		self->inUse = FALSE;
	}
}
Beispiel #23
0
static unsigned char *uncompressFileRW(char *name, unsigned long *size)
{
	unsigned char *source, *dest;
	FILE *fp;
	#if DEV != 1
		int i, index;
	#endif

	#if DEV == 1
		fp = fopen(name, "rb");

		if (fp == NULL)
		{
			showErrorAndExit("Failed to open %s", name);
		}

		fseek(fp, 0L, SEEK_END);

		(*size) = ftell(fp);

		fseek(fp, 0L, SEEK_SET);

		dest = malloc((*size) * sizeof(unsigned char));

		if (dest == NULL)
		{
			showErrorAndExit("Failed to allocate %ld bytes to load %s", (*size) * (int)sizeof(unsigned char), name);
		}

		fread(dest, (*size), 1, fp);

		source = NULL;
	#else
		index = -1;

		for (i=0;i<fileCount;i++)
		{
			if (strcmpignorecase(fileData[i].filename, name) == 0)
			{
				index = i;

				break;
			}
		}

		if (index == -1)
		{
			showErrorAndExit("Failed to find %s in PAK file", name);
		}

		fp = fopen(pakFile, "rb");

		if (fp == NULL)
		{
			showErrorAndExit("Failed to open PAK file %s", pakFile);
		}

		fseek(fp, fileData[index].offset, SEEK_SET);

		source = malloc(fileData[index].compressedSize * sizeof(unsigned char));

		if (source == NULL)
		{
			showErrorAndExit("Failed to allocate %d bytes to load %s from PAK", fileData[index].compressedSize * (int)sizeof(unsigned char), name);
		}

		dest = malloc(fileData[index].fileSize * sizeof(unsigned char));

		if (dest == NULL)
		{
			showErrorAndExit("Failed to allocate %d bytes to load %s from PAK", fileData[index].fileSize * (int)sizeof(unsigned char), name);
		}

		fread(source, fileData[i].compressedSize, 1, fp);

		(*size) = fileData[index].fileSize;

		uncompress(dest, size, source, fileData[index].compressedSize);

		if ((*size) != fileData[index].fileSize)
		{
			showErrorAndExit("Failed to decompress %s. Expected %ld, got %ld", fileData[index].filename, fileData[index].fileSize, (*size));
		}
	#endif

	if (source != NULL)
	{
		free(source);
	}

	fclose(fp);

	return dest;
}
Beispiel #24
0
static void createShield()
{
	int i, x, y;
	Entity *shield, *e;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		if (self->mental == 0)
		{
			setEntityAnimation(self, "ATTACK_1");

			shield = getFreeEntity();

			if (shield == NULL)
			{
				showErrorAndExit("No free slots to add the Sorceror's Shield");
			}

			loadProperties("boss/sorceror_shield", shield);

			shield->x = self->x;
			shield->y = self->y;

			shield->action = &shieldCreateWait;

			shield->draw = &drawLoopingAnimationToMap;

			shield->touch = &entityTouch;

			shield->takeDamage = &shieldTakeDamage;

			shield->pain = &enemyPain;

			shield->die = &shieldDie;

			shield->type = ENEMY;

			shield->head = self;

			shield->alpha = 128;

			shield->face = RIGHT;

			shield->maxHealth = self->health;

			setEntityAnimation(shield, "STAND");

			shield->x = self->x + self->w / 2 - shield->w / 2;
			shield->y = self->y + self->h / 2 - shield->h / 2;

			shield->flags |= NO_DRAW;

			self->startX = 1;

			self->head = shield;

			shield->mental = 6;

			x = shield->x;
			y = shield->y;

			for (i=0;i<6;i++)
			{
				e = getFreeEntity();

				if (e == NULL)
				{
					showErrorAndExit("No free slots to add the Sorceror's Shield Piece");
				}

				loadProperties("boss/sorceror_shield_piece", e);

				setEntityAnimationByID(e, i);

				e->x = x;
				e->y = y;

				e->startX = e->x;
				e->startY = e->y;

				e->action = &pieceMoveToShield;

				e->draw = &drawLoopingAnimationToMap;

				e->type = ENEMY;

				e->alpha = 128;

				e->face = RIGHT;

				e->head = shield;

				if (x == shield->x)
				{
					x += e->w;
				}

				else
				{
					x = shield->x;

					y += e->h;
				}

				switch (i)
				{
					case 0:
						e->dirX = -12;
						e->dirY = -6;
					break;

					case 1:
						e->dirX = 12;
						e->dirY = -6;
					break;

					case 2:
						e->dirX = -12;
						e->dirY = 0;
					break;

					case 3:
						e->dirX = 12;
						e->dirY = 0;
					break;

					case 4:
						e->dirX = -12;
						e->dirY = 6;
					break;

					default:
						e->dirX = 12;
						e->dirY = 6;
					break;
				}

				e->x += e->dirX * 60;
				e->y += e->dirY * 60;

				e->dirX *= -1;
				e->dirY *= -1;
			}

			self->mental = 1;
		}

		else if (self->mental == 2)
		{
			self->thinkTime = 30;

			self->action = &createShieldFinish;
		}
	}
}
Beispiel #25
0
static void loadMenuLayout()
{
	char *text;
	int x, y, w, maxWidth, i;

	menu.widgetCount = 5;

	menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount);

	if (menu.widgets == NULL)
	{
		showErrorAndExit("Ran out of memory when creating Control Menu");
	}

	x = y = 0;

	menu.widgets[0] = createWidget(_("Sound"), &control.button[CONTROL_UP], &toggleSound, &toggleSound, &toggleSound, x, y, TRUE, 255, 255, 255);

	menu.widgets[0]->label = createLabel(game.audio == TRUE || game.audioDisabled == TRUE ? _("Yes") : _("No"), menu.widgets[0]->x + menu.widgets[0]->normalState->w + 10, y);

	menu.widgets[1] = createWidget(_("SFX Volume"), &game.sfxDefaultVolume, &lowerSFXVolume, &raiseSFXVolume, NULL, x, y, TRUE, 255, 255, 255);

	text = getVolumePercent(game.sfxDefaultVolume);

	menu.widgets[1]->label = createLabel(_(text), menu.widgets[1]->x + menu.widgets[1]->normalState->w + 10, y);

	free(text);

	menu.widgets[2] = createWidget(_("Music Volume"), &game.musicDefaultVolume, &lowerMusicVolume, &raiseMusicVolume, NULL, x, y, TRUE, 255, 255, 255);

	text = getVolumePercent(game.musicDefaultVolume);

	menu.widgets[2]->label = createLabel(_(text), menu.widgets[2]->x + menu.widgets[2]->normalState->w + 10, y);

	free(text);

	menu.widgets[3] = createWidget(_("Audio Quality"), &game.audioQuality, &toggleQuality, &toggleQuality, &toggleQuality, x, y, TRUE, 255, 255, 255);

	text = getQuality();

	menu.widgets[3]->label = createLabel(text, menu.widgets[3]->x + menu.widgets[3]->normalState->w + 10, y);

	free(text);

	menu.widgets[4] = createWidget(_("Back"), NULL, NULL, NULL, &showOptionsMenu, -1, y, TRUE, 255, 255, 255);

	y = BUTTON_PADDING + BORDER_PADDING;

	maxWidth = w = 0;

	for (i=0;i<menu.widgetCount;i++)
	{
		if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth)
		{
			maxWidth = menu.widgets[i]->normalState->w;
		}
	}

	for (i=0;i<menu.widgetCount;i++)
	{
		menu.widgets[i]->y = y;

		if (menu.widgets[i]->x != -1)
		{
			menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING;
		}

		if (menu.widgets[i]->label != NULL)
		{
			menu.widgets[i]->label->y = y;

			menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10;

			if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w)
			{
				w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w;
			}
		}

		else
		{
			if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w)
			{
				w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w;
			}
		}

		y += menu.widgets[i]->selectedState->h + BUTTON_PADDING;
	}

	menu.w = w + BUTTON_PADDING;
	menu.h = y - BORDER_PADDING;

	menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0);

	menu.x = (SCREEN_WIDTH - menu.background->w) / 2;
	menu.y = (SCREEN_HEIGHT - menu.background->h) / 2;
}
Beispiel #26
0
static void shieldDie()
{
	int i, x, y;
	Entity *e;

	x = self->x;
	y = self->y;

	playSoundToMap("sound/boss/sorceror/shield_die", -1, self->x, self->y, 0);

	for (i=0;i<6;i++)
	{
		e = getFreeEntity();

		if (e == NULL)
		{
			showErrorAndExit("No free slots to add the Sorceror's Shield Piece");
		}

		loadProperties("boss/sorceror_shield_piece", e);

		e->x = x;
		e->y = y;

		e->action = &pieceWait;

		e->draw = &drawLoopingAnimationToMap;

		e->type = ENEMY;

		e->alpha = 128;

		e->face = RIGHT;

		setEntityAnimationByID(e, i);

		if (x == self->x)
		{
			x += e->w;
		}

		else
		{
			x = self->x;

			y += e->h;
		}

		switch (i)
		{
			case 0:
				e->dirX = -3;
				e->dirY = -1.5f;
			break;

			case 1:
				e->dirX = 3;
				e->dirY = -1.5f;
			break;

			case 2:
				e->dirX = -3;
			break;

			case 3:
				e->dirX = 3;
			break;

			case 4:
				e->dirX = -3;
				e->dirY = 1.5f;
			break;

			default:
				e->dirX = 3;
				e->dirY = 1.5f;
			break;
		}
	}

	self->head->startY = 0;

	self->head->startX = 0;

	self->inUse = FALSE;
}
Beispiel #27
0
static void createBody()
{
    char bodyName[MAX_VALUE_LENGTH];
    int i;
    Entity **body, *head;

    body = malloc(self->mental * sizeof(Entity *));

    if (body == NULL)
    {
        showErrorAndExit("Failed to allocate a whole %d bytes for Snake Boss body...", self->mental * (int)sizeof(Entity *));
    }

    snprintf(bodyName, sizeof(bodyName), "%s_body", self->name);

    for (i=self->mental-1; i>=0; i--)
    {
        body[i] = getFreeEntity();

        if (body[i] == NULL)
        {
            showErrorAndExit("No free slots to add a Snake Boss body part");
        }

        loadProperties(bodyName, body[i]);

        body[i]->x = self->x;
        body[i]->y = self->y;

        body[i]->action = &bodyWait;

        body[i]->draw = &drawLoopingAnimationToMap;
        body[i]->touch = &entityTouch;
        body[i]->die = &entityDieNoDrop;
        body[i]->takeDamage = &bodyTakeDamage;

        body[i]->creditsAction = &bodyWait;

        body[i]->type = ENEMY;

        body[i]->active = FALSE;

        body[i]->flags |= NO_DRAW;

        setEntityAnimation(body[i], "STAND");
    }

    /* Recreate the head so that it's on top */

    head = getFreeEntity();

    if (head == NULL)
    {
        showErrorAndExit("No free slots to add a Snake Boss head");
    }

    *head = *self;

    self->inUse = FALSE;

    self = head;

    /* Link the sections */

    for (i=self->mental-1; i>=0; i--)
    {
        if (i == 0)
        {
            self->target = body[i];
        }

        else
        {
            body[i - 1]->target = body[i];
        }

        body[i]->head = self;
    }

    free(body);
}
Beispiel #28
0
static void callSummoners()
{
	int r;
	Entity *e;
	Target *t;

	self->thinkTime--;

	if (self->thinkTime <= 0)
	{
		setEntityAnimation(self, "ATTACK_1");

		self->mental--;

		playSoundToMap("sound/common/spell", BOSS_CHANNEL, self->x, self->y, 0);

		e = addEnemy("enemy/sorceror_dark_summoner", 0, 0);

		e->x = self->x + self->w / 2 - e->w / 2;
		e->y = self->y + self->h / 2 - e->h / 2;

		r = prand() % 3;

		switch (r)
		{
			case 0:
				t = getTargetByName("DARK_SUMMONER_TARGET_0");
			break;

			case 1:
				t = getTargetByName("DARK_SUMMONER_TARGET_1");
			break;

			default:
				t = getTargetByName("DARK_SUMMONER_TARGET_2");
			break;
		}

		if (t == NULL)
		{
			showErrorAndExit("Sorceror cannot find target");
		}

		e->targetX = t->x;
		e->targetY = t->y;

		e->startX = e->targetX;
		e->startY = e->targetY;

		e->maxThinkTime = self->maxThinkTime;

		calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY);

		e->flags |= (NO_DRAW|HELPLESS|TELEPORTING);

		e->head = self;

		if (self->mental <= 0)
		{
			setEntityAnimation(self, "STAND");

			self->maxThinkTime++;

			self->action = &callSummonersWait;
		}

		self->thinkTime = 30;
	}

	hover();
}
Beispiel #29
0
static void removeItems()
{
	int i, j, size, count, x, allTargets;
	Entity *e;
	Target *t;
	char targetName[MAX_LINE_LENGTH];
	char *items[] = {
		"item/tuning_fork",
		"item/coal",
		"item/invisibility_potion",
		"item/repellent",
		"item/water_purifier",
		"item/extend_o_grab",
		"item/bomb",
		"item/sludge_tentacle",
		"item/gazer_eye",
		"weapon/normal_arrow"
	};

	size = sizeof(items) / sizeof(char *);

	resetInventoryIndex();

	count = 0;

	allTargets = 0;

	/* Remove all the inventory items */

	for (i=0;i<MAX_INVENTORY_ITEMS;i++)
	{
		e = removeInventoryItemAtCursor();

		if (e != NULL)
		{
			for (j=0;j<size;j++)
			{
				if (strcmpignorecase(e->name, items[j]) == 0)
				{
					e->inUse = FALSE;

					break;
				}
			}

			if (e->inUse == FALSE)
			{
				continue;
			}

			if (strcmpignorecase(e->name, "item/health_potion") == 0)
			{
				e->mental = -1;
			}

			/* Ensure that at least 1 item appears at each target */

			j = allTargets < self->mental ? allTargets : prand() % self->mental;

			allTargets++;

			snprintf(targetName, MAX_VALUE_LENGTH, "REMOVER_TARGET_%d", j);

			t = getTargetByName(targetName);

			if (t == NULL)
			{
				showErrorAndExit("Item Remover cannot find target");
			}

			x = t->x;

			x += (prand() % 32) * (prand() % 2 == 0 ? -1 : 1);

			addEntity(*e, x, t->y);

			e->inUse = FALSE;

			snprintf(targetName, MAX_LINE_LENGTH, "\"%s\" 1 UPDATE_TRIGGER \"ITEMS\"", e->objectiveName);

			count++;

			addGlobalTriggerFromScript(targetName);
		}
	}

	freeInventory();

	snprintf(targetName, MAX_LINE_LENGTH, "\"ITEMS\" %d UPDATE_OBJECTIVE \"Retrieve items\"", count);

	addGlobalTriggerFromScript(targetName);

	e = removePlayerWeapon();

	if (e != NULL)
	{
		e->inUse = FALSE;
	}

	e = removePlayerShield();

	if (e != NULL)
	{
		e->inUse = FALSE;
	}

	self->inUse = FALSE;
}
Beispiel #30
0
int loadContinueData()
{
	char itemName[MAX_MESSAGE_LENGTH], mapName[MAX_MESSAGE_LENGTH];
	char saveFile[MAX_PATH_LENGTH], *line, *savePtr;
	unsigned char *buffer;
	FILE *fp;

	savePtr = NULL;

	snprintf(saveFile, sizeof(saveFile), "%scontinuesave", gameSavePath);

	fp = fopen(saveFile, "rb");

	if (fp == NULL)
	{
		return FALSE;
	}

	fclose(fp);

	freeGameResources();

	initGame();

	game.canContinue = TRUE;

	buffer = decompressFile(saveFile);

	if (strlen((char *)buffer) == 0)
	{
		showErrorAndExit("Something went wrong when decompressing the continue file");
	}

	line = strtok_r((char *)buffer, "\n", &savePtr);

	while (line != NULL)
	{
		if (line[strlen(line) - 1] == '\n')
		{
			line[strlen(line) - 1] = '\0';
		}

		if (line[strlen(line) - 1] == '\r')
		{
			line[strlen(line) - 1] = '\0';
		}

		sscanf(line, "%s", itemName);

		if (strcmpignorecase("PLAY_TIME", itemName) == 0)
		{
			sscanf(line, "%*s %ld\n", &game.playTime);
		}

		else if (strcmpignorecase("PLAYER_KILLS", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.kills);
		}

		else if (strcmpignorecase("BATS_DROWNED", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.batsDrowned);
		}

		else if (strcmpignorecase("TIMES_EATEN", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.timesEaten);
		}

		else if (strcmpignorecase("DISTANCE_TRAVELLED", itemName) == 0)
		{
			sscanf(line, "%*s %u\n", &game.distanceTravelled);
		}

		else if (strcmpignorecase("ATTACKS_BLOCKED", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.attacksBlocked);
		}

		else if (strcmpignorecase("SLIME_TIME", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.timeSpentAsSlime);
		}

		else if (strcmpignorecase("ARROWS_FIRED", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.arrowsFired);
		}

		else if (strcmpignorecase("SECRETS_FOUND", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.secretsFound);
		}

		else if (strcmpignorecase("CONTINUES", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.continues);
		}

		else if (strcmpignorecase("CHEATING", itemName) == 0)
		{
			sscanf(line, "%*s %d\n", &game.cheating);
		}

		else if (strcmpignorecase("PLAYER_LOCATION", itemName) == 0)
		{
			sscanf(line, "%*s %s\n", itemName);

			loadMap(itemName, FALSE);

			snprintf(mapName, sizeof(mapName), "MAP_NAME %s", itemName);
		}

		else if (strcmpignorecase(line, mapName) == 0)
		{
			loadResources(savePtr);
		}

		line = strtok_r(NULL, "\n", &savePtr);
	}

	free(buffer);

	copyFile(saveFile, tempFile);

	buffer = decompressFile(tempFile);

	free(buffer);

	cameraSnapToTargetEntity();

	freeMessageQueue();

	return TRUE;
}