コード例 #1
0
ファイル: editor_ui_common.c プロジェクト: evktalo/cdogs-sdl
bool ConfirmScreen(const char *info, const char *msg)
{
	int w = gGraphicsDevice.cachedConfig.Res.x;
	int h = gGraphicsDevice.cachedConfig.Res.y;
	ClearScreen(&gGraphicsDevice);
	FontStr(info, Vec2iNew((w - FontStrW(info)) / 2, (h - FontH()) / 2));
	FontStr(msg, Vec2iNew((w - FontStrW(msg)) / 2, (h + FontH()) / 2));
	BlitFlip(&gGraphicsDevice, &gConfig.Graphics);

	int c = GetKey(&gEventHandlers);
	return (c == 'Y' || c == 'y');
}
コード例 #2
0
bool ConfirmScreen(const char *info, const char *msg)
{
	int w = gGraphicsDevice.cachedConfig.Res.x;
	int h = gGraphicsDevice.cachedConfig.Res.y;
	ClearScreen(&gGraphicsDevice);
	FontStr(info, Vec2iNew((w - FontStrW(info)) / 2, (h - FontH()) / 2));
	FontStr(msg, Vec2iNew((w - FontStrW(msg)) / 2, (h + FontH()) / 2));
	BlitFlip(&gGraphicsDevice);

	SDL_Keycode k = SDL_GetKeyFromScancode(GetKey(&gEventHandlers));
	return k == SDLK_y;
}
コード例 #3
0
ファイル: briefing_screens.c プロジェクト: Wuzzy2/cdogs-sdl
static void DeathmatchFinalScoresDraw(void *data)
{
	UNUSED(data);

	// This will only draw once
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;

	GraphicsBlitBkg(&gGraphicsDevice);

	// Work out the highest kills
	int maxKills = 0;
	for (int i = 0; i < (int)gPlayerDatas.size; i++)
	{
		const PlayerData *p = CArrayGet(&gPlayerDatas, i);
		if (p->kills > maxKills)
		{
			maxKills = p->kills;
		}
	}

	// Draw players and their names spread evenly around the screen.
	CASSERT(
		gPlayerDatas.size >= 2 && gPlayerDatas.size <= 4,
		"Unimplemented number of players for deathmatch");
#define LAST_MAN_TEXT	"Last man standing!"
	for (int i = 0; i < (int)gPlayerDatas.size; i++)
	{
		const Vec2i pos = Vec2iNew(
			w / 4 + (i & 1) * w / 2,
			gPlayerDatas.size == 2 ? h / 2 : h / 4 + (i / 2) * h / 2);
		const PlayerData *p = CArrayGet(&gPlayerDatas, i);
		DisplayCharacterAndName(pos, &p->Char, p->name);
		
		// Kills
		char s[16];
		sprintf(s, "Kills: %d", p->kills);
		FontStrMask(
			s, Vec2iNew(pos.x - FontStrW(s) / 2, pos.y + 20),
			p->kills == maxKills ? colorGreen : colorWhite);

		// Last man standing?
		if (p->Lives > 0)
		{
			FontStrMask(
				LAST_MAN_TEXT,
				Vec2iNew(pos.x - FontStrW(LAST_MAN_TEXT) / 2, pos.y + 30),
				colorGreen);
		}
	}
}
コード例 #4
0
ファイル: editor_ui_common.c プロジェクト: cxong/cdogs-sdl
bool ConfirmScreen(const char *info, const char *msg)
{
	int w = gGraphicsDevice.cachedConfig.Res.x;
	int h = gGraphicsDevice.cachedConfig.Res.y;
	ClearScreen(&gGraphicsDevice);
	FontStr(info, svec2i((w - FontStrW(info)) / 2, (h - FontH()) / 2));
	FontStr(msg, svec2i((w - FontStrW(msg)) / 2, (h + FontH()) / 2));
	WindowContextPreRender(&gGraphicsDevice.gameWindow);
	BlitUpdateFromBuf(&gGraphicsDevice, gGraphicsDevice.screen);
	WindowContextPostRender(&gGraphicsDevice.gameWindow);

	SDL_Keycode k = SDL_GetKeyFromScancode(GetKey(&gEventHandlers));
	return k == SDLK_y;
}
コード例 #5
0
ファイル: briefing_screens.c プロジェクト: Wuzzy2/cdogs-sdl
static void ShowPlayerScore(const Vec2i pos, const int score)
{
	char s[16];
	sprintf(s, "Score: %d", score);
	const Vec2i scorePos = Vec2iNew(pos.x - FontStrW(s) / 2, pos.y + 20);
	FontStr(s, scorePos);
}
コード例 #6
0
ファイル: draw.c プロジェクト: CliffsDover/cdogs-sdl
static void DrawSpawnerName(
	const TObject *obj, DrawBuffer *b, const Vec2i offset)
{
	const char *name = obj->Class->u.PickupClass->Name;
	const Vec2i textPos = Vec2iNew(
		obj->tileItem.x - b->xTop + offset.x - FontStrW(name) / 2,
		obj->tileItem.y - b->yTop + offset.y);
	FontStr(name, textPos);
}
コード例 #7
0
ファイル: briefing_screens.c プロジェクト: Wuzzy2/cdogs-sdl
static void DogfightFinalScoresDraw(void *data)
{
	UNUSED(data);

	// This will only draw once
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;

	GraphicsBlitBkg(&gGraphicsDevice);

	// Work out who's the winner, or if it's a tie
	int maxScore = 0;
	int playersWithMaxScore = 0;
	for (int i = 0; i < (int)gPlayerDatas.size; i++)
	{
		const PlayerData *p = CArrayGet(&gPlayerDatas, i);
		if (p->RoundsWon > maxScore)
		{
			maxScore = p->RoundsWon;
			playersWithMaxScore = 1;
		}
		else if (p->RoundsWon == maxScore)
		{
			playersWithMaxScore++;
		}
	}
	const bool isTie = playersWithMaxScore == (int)gPlayerDatas.size;

	// Draw players and their names spread evenly around the screen.
	// If it's a tie, display the message in the centre,
	// otherwise display the winner just below the winning player
#define DRAW_TEXT	"It's a draw!"
#define WINNER_TEXT	"Winner!"
	CASSERT(
		gPlayerDatas.size >= 2 && gPlayerDatas.size <= 4,
		"Unimplemented number of players for dogfight");
	for (int i = 0; i < (int)gPlayerDatas.size; i++)
	{
		const Vec2i pos = Vec2iNew(
			w / 4 + (i & 1) * w / 2,
			gPlayerDatas.size == 2 ? h / 2 : h / 4 + (i / 2) * h / 2);
		const PlayerData *p = CArrayGet(&gPlayerDatas, i);
		DisplayCharacterAndName(pos, &p->Char, p->name);
		ShowPlayerScore(pos, p->RoundsWon);
		if (!isTie && maxScore == p->RoundsWon)
		{
			FontStrMask(
				WINNER_TEXT,
				Vec2iNew(pos.x - FontStrW(WINNER_TEXT) / 2, pos.y + 30),
				colorGreen);
		}
	}
	if (isTie)
	{
		FontStrCenter(DRAW_TEXT);
	}
}
コード例 #8
0
ファイル: draw.c プロジェクト: cxong/cdogs-sdl
static void DrawSpawnerName(
	const TObject *obj, DrawBuffer *b, const struct vec2i offset)
{
	const char *name = obj->Class->u.PickupClass->Name;
	const struct vec2i textPos = svec2i(
		(int)obj->thing.Pos.x - b->xTop + offset.x - FontStrW(name) / 2,
		(int)obj->thing.Pos.y - b->yTop + offset.y);
	FontStr(name, textPos);
}
コード例 #9
0
ファイル: menu_utils.c プロジェクト: evktalo/cdogs-sdl
// Display a character and the player name above it, with the character
// centered around the target position
void DisplayCharacterAndName(Vec2i pos, Character *c, char *name)
{
	Vec2i namePos;
	// Move the point down a bit since the default character draw point is at
	// its feet
	pos.y += 8;
	namePos = Vec2iAdd(pos, Vec2iNew(-FontStrW(name) / 2, -30));
	DrawCharacterSimple(
		c, pos,
		DIRECTION_DOWN, STATE_IDLE, -1, GUNSTATE_READY, &c->table);
	FontStr(name, namePos);
}
コード例 #10
0
ファイル: draw.c プロジェクト: CliffsDover/cdogs-sdl
static void DrawObjectiveName(
	const TTileItem *ti, DrawBuffer *b, const Vec2i offset)
{
	const int objective = ObjectiveFromTileItem(ti->flags);
	const Objective *o =
		CArrayGet(&gMission.missionData->Objectives, objective);
	const char *typeName = ObjectiveTypeStr(o->Type);
	const Vec2i textPos = Vec2iNew(
		ti->x - b->xTop + offset.x - FontStrW(typeName) / 2,
		ti->y - b->yTop + offset.y);
	FontStr(typeName, textPos);
}
コード例 #11
0
ファイル: draw.c プロジェクト: cxong/cdogs-sdl
static void DrawObjectiveName(
	const Thing *ti, DrawBuffer *b, const struct vec2i offset)
{
	const int objective = ObjectiveFromThing(ti->flags);
	const Objective *o =
		CArrayGet(&gMission.missionData->Objectives, objective);
	const char *typeName = ObjectiveTypeStr(o->Type);
	const struct vec2i textPos = svec2i(
		(int)ti->Pos.x - b->xTop + offset.x - FontStrW(typeName) / 2,
		(int)ti->Pos.y - b->yTop + offset.y);
	FontStr(typeName, textPos);
}
コード例 #12
0
ファイル: hiscores.c プロジェクト: ChunHungLiu/cdogs-sdl
static int DisplayEntry(int x, int y, int idx, struct Entry *e, int hilite)
{
	char s[10];

#define INDEX_OFFSET     15
#define SCORE_OFFSET     40
#define MISSIONS_OFFSET  60
#define MISSION_OFFSET   80
#define NAME_OFFSET      85

	sprintf(s, "%d.", idx + 1);
	DisplayAt(x + INDEX_OFFSET - FontStrW(s), y, s, hilite);
	sprintf(s, "%d", e->score);
	DisplayAt(x + SCORE_OFFSET - FontStrW(s), y, s, hilite);
	sprintf(s, "%d", e->missions);
	DisplayAt(x + MISSIONS_OFFSET - FontStrW(s), y, s, hilite);
	sprintf(s, "(%d)", e->lastMission + 1);
	DisplayAt(x + MISSION_OFFSET - FontStrW(s), y, s, hilite);
	DisplayAt(x + NAME_OFFSET, y, e->name, hilite);

	return 1 + FontH();
}
コード例 #13
0
ファイル: draw.c プロジェクト: NSYXin/cdogs-sdl
static void DrawChatter(
    const TTileItem *ti, DrawBuffer *b, const Vec2i offset)
{
    const TActor *a = CArrayGet(&gActors, ti->id);
    // Draw character text
    if (strlen(a->Chatter) > 0)
    {
        const Vec2i textPos = Vec2iNew(
                                  a->tileItem.x - b->xTop + offset.x -
                                  FontStrW(a->Chatter) / 2,
                                  a->tileItem.y - b->yTop + offset.y - ACTOR_HEIGHT);
        FontStr(a->Chatter, textPos);
    }
}
コード例 #14
0
static void DrawObjectiveCounts(HUD *hud)
{
	int x = 5 + GAUGE_WIDTH;
	int y = hud->device->cachedConfig.Res.y - 5 - FontH();
	for (int i = 0; i < (int)gMission.missionData->Objectives.size; i++)
	{
		MissionObjective *mo = CArrayGet(&gMission.missionData->Objectives, i);
		const ObjectiveDef *o = CArrayGet(&gMission.Objectives, i);

		// Don't draw anything for optional objectives
		if (mo->Required == 0)
		{
			continue;
		}

		// Objective color dot
		Draw_Rect(x, y + 3, 2, 2, o->color);

		x += 5;
		char s[32];
		int itemsLeft = mo->Required - o->done;
		if (itemsLeft > 0)
		{
			if (!(mo->Flags & OBJECTIVE_UNKNOWNCOUNT))
			{
				sprintf(s, "%s: %d", ObjectiveTypeStr(mo->Type), itemsLeft);
			}
			else
			{
				sprintf(s, "%s: ?", ObjectiveTypeStr(mo->Type));
			}
		}
		else
		{
			strcpy(s, "Done");
		}
		FontStr(s, Vec2iNew(x, y));

		DrawNumUpdate(
			CArrayGet(&hud->objectiveUpdates, i), "%d", o->done,
			Vec2iNew(x + FontStrW(s) - 8, y), 0);

		x += 40;
	}
}
コード例 #15
0
ファイル: screens_end.c プロジェクト: cxong/cdogs-sdl
static void VictoryDraw(void *data)
{
	const VictoryData *vd = data;

	const int w = gGraphicsDevice.cachedConfig.Res.x;
	FontOpts opts = FontOptsNew();
	opts.HAlign = ALIGN_CENTER;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	int y = 30;

	// Congratulations text
#define CONGRATULATIONS "Congratulations, you have completed "
	FontStrOpt(CONGRATULATIONS, svec2i(0, y), opts);
	y += 15;
	opts.Mask = colorRed;
	FontStrOpt(vd->Campaign->Setting.Title, svec2i(0, y), opts);
	y += 15;

	// Final words
	struct vec2i pos = svec2i((w - FontStrW(vd->FinalWords)) / 2, y);
	pos = FontChMask('"', pos, colorDarker);
	pos = FontStrMask(vd->FinalWords, pos, colorPurple);
	FontChMask('"', pos, colorDarker);
}
コード例 #16
0
ファイル: menu_utils.c プロジェクト: evktalo/cdogs-sdl
void MenuDisplayPlayerControls(
	menu_t *menu, GraphicsDevice *g, Vec2i pos, Vec2i size, void *data)
{
	UNUSED(g);
	char s[256];
	MenuDisplayPlayerControlsData *d = data;
	Vec2i textPos = Vec2iNew(0, pos.y + size.y - FontH());
	int textWidth = 0;

	UNUSED(menu);

	switch (d->pData->inputDevice)
	{
	case INPUT_DEVICE_KEYBOARD:
		{
			input_keys_t *keys =
				&d->inputConfig->PlayerKeys[d->pData->deviceIndex].Keys;
			sprintf(s, "(%s, %s, %s, %s, %s and %s)",
				SDL_GetKeyName(keys->left),
				SDL_GetKeyName(keys->right),
				SDL_GetKeyName(keys->up),
				SDL_GetKeyName(keys->down),
				SDL_GetKeyName(keys->button1),
				SDL_GetKeyName(keys->button2));
			textWidth = FontStrW(s);
		}
		break;
	case INPUT_DEVICE_MOUSE:
		sprintf(s, "(mouse wheel to scroll, left and right click)");
		break;
	case INPUT_DEVICE_JOYSTICK:
		sprintf(s, "(%s)",
			InputDeviceName(d->pData->inputDevice, d->pData->deviceIndex));
		break;
	case INPUT_DEVICE_NET:
		sprintf(s, "(Network)");
		break;
	case INPUT_DEVICE_AI:
		sprintf(s, "(Computer)");
		break;
	default:
		assert(0 && "unknown device");
		break;
	}

	// If the text is too long, split the text with a newline
	textWidth = FontStrW(s);
	if (textWidth < 125)
	{
		textPos.x = pos.x - textWidth / 2;
		FontStr(s, textPos);
	}
	else
	{
		// find the first whitespace before half of the string, split there,
		// and print two lines
		char *secondLine;
		for (secondLine = &s[strlen(s) / 2]; secondLine > s; secondLine--)
		{
			if (isspace(*secondLine))
			{
				*secondLine = '\0';
				secondLine++;
				break;
			}
		}
		textWidth = FontStrW(s);
		textPos.x = pos.x - textWidth / 2;
		textPos.y -= FontH();
		FontStr(s, textPos);
		textWidth = FontStrW(secondLine);
		textPos.x = pos.x - textWidth / 2;
		textPos.y += FontH();
		FontStr(secondLine, textPos);
	}
}
コード例 #17
0
ファイル: briefing_screens.c プロジェクト: Wuzzy2/cdogs-sdl
static void VictoryDraw(void *data)
{
	// This will only draw once
	const CampaignOptions *c = data;

	GraphicsBlitBkg(&gGraphicsDevice);
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;
	FontOpts opts = FontOptsNew();
	opts.HAlign = ALIGN_CENTER;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	int y = 100;

	// Congratulations text
#define CONGRATULATIONS "Congratulations, you have completed "
	FontStrOpt(CONGRATULATIONS, Vec2iNew(0, y), opts);
	y += 15;
	opts.Mask = colorRed;
	FontStrOpt(c->Setting.Title, Vec2iNew(0, y), opts);

	// Display players
	switch (gPlayerDatas.size)
	{
	case 1:
		{
			const PlayerData *p = CArrayGet(&gPlayerDatas, 0);
			DisplayCharacterAndName(Vec2iNew(w / 4, h / 4), &p->Char, p->name);
		}
		break;
	case 2:
		{
			// side by side
			const PlayerData *p1 = CArrayGet(&gPlayerDatas, 0);
			DisplayCharacterAndName(
				Vec2iNew(w / 8, h / 4), &p1->Char, p1->name);
			const PlayerData *p2 = CArrayGet(&gPlayerDatas, 1);
			DisplayCharacterAndName(
				Vec2iNew(w / 8 + w / 2, h / 4), &p2->Char, p2->name);
		}
		break;
	case 3:	// fallthrough
	case 4:
		{
			// 2x2
			const PlayerData *p1 = CArrayGet(&gPlayerDatas, 0);
			DisplayCharacterAndName(
				Vec2iNew(w / 8, h / 8), &p1->Char, p1->name);
			const PlayerData *p2 = CArrayGet(&gPlayerDatas, 1);
			DisplayCharacterAndName(
				Vec2iNew(w / 8 + w / 2, h / 8), &p2->Char, p2->name);
			const PlayerData *p3 = CArrayGet(&gPlayerDatas, 2);
			DisplayCharacterAndName(
				Vec2iNew(w / 8, h / 8 + h / 4), &p3->Char, p3->name);
			if (gPlayerDatas.size == 4)
			{
				const PlayerData *p4 = CArrayGet(&gPlayerDatas, 3);
				DisplayCharacterAndName(
					Vec2iNew(w / 8 + w / 2, h / 8 + h / 4),
					&p4->Char, p4->name);
			}
		}
		break;
	default:
		CASSERT(false, "not implemented");
		break;
	}

	// Final words
	const char *finalWordsSingle[] = {
		"Ha, next time I'll use my good hand",
		"Over already? I was just warming up...",
		"There's just no good opposition to be found these days!",
		"Well, maybe I'll just do my monthly reload then",
		"Woof woof",
		"I'll just bury the bones in the back yard, he-he",
		"I just wish they'd let me try bare-handed",
		"Rambo? Who's Rambo?",
		"<in Austrian accent:> I'll be back",
		"Gee, my trigger finger is sore",
		"I need more practice. I think I missed a few shots at times"
	};
	const char *finalWordsMulti[] = {
		"United we stand, divided we conquer",
		"Nothing like good teamwork, is there?",
		"Which way is the camera?",
		"We eat bullets for breakfast and have grenades as dessert",
		"We're so cool we have to wear mittens",
	};
	const char *finalWords;
	if (gPlayerDatas.size == 1)
	{
		const int numWords = sizeof finalWordsSingle / sizeof(char *);
		finalWords = finalWordsSingle[rand() % numWords];
	}
	else
	{
		const int numWords = sizeof finalWordsMulti / sizeof(char *);
		finalWords = finalWordsMulti[rand() % numWords];
	}
	Vec2i pos = Vec2iNew((w - FontStrW(finalWords)) / 2, h / 2 + 20);
	pos = FontChMask('"', pos, colorDarker);
	pos = FontStrMask(finalWords, pos, colorPurple);
	FontChMask('"', pos, colorDarker);
}
コード例 #18
0
void HUDDraw(HUD *hud, const input_device_e pausingDevice)
{
	char s[50];
	int flags = 0;
	const int numPlayersAlive =
		GetNumPlayers(PLAYER_ALIVE_OR_DYING, false, false);
	const int numLocalPlayers = GetNumPlayers(PLAYER_ANY, false, true);
	const int numLocalPlayersAlive =
		GetNumPlayers(PLAYER_ALIVE_OR_DYING, false, true);

	Rect2i r;
	r.Size = Vec2iNew(
		hud->device->cachedConfig.Res.x,
		hud->device->cachedConfig.Res.y);
	if (numLocalPlayersAlive <= 1)
	{
		flags = 0;
	}
	else if (
		ConfigGetEnum(&gConfig, "Interface.Splitscreen") == SPLITSCREEN_NEVER)
	{
		flags |= HUDFLAGS_SHARE_SCREEN;
	}
	else if (numLocalPlayers == 2)
	{
		r.Size.x /= 2;
		flags |= HUDFLAGS_HALF_SCREEN;
	}
	else if (numLocalPlayers == 3 || numLocalPlayers == 4)
	{
		r.Size.x /= 2;
		r.Size.y /= 2;
		flags |= HUDFLAGS_QUARTER_SCREEN;
	}
	else
	{
		assert(0 && "not implemented");
	}

	int idx = 0;
	for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++)
	{
		const PlayerData *p = CArrayGet(&gPlayerDatas, i);
		if (!p->IsLocal)
		{
			idx--;
			continue;
		}
		int drawFlags = flags;
		r.Pos = Vec2iZero();
		if (idx & 1)
		{
			r.Pos.x = r.Size.x;
			drawFlags |= HUDFLAGS_PLACE_RIGHT;
		}
		if (idx >= 2)
		{
			r.Pos.y = r.Size.y;
			drawFlags |= HUDFLAGS_PLACE_BOTTOM;
		}
		TActor *player = NULL;
		if (IsPlayerAlive(p))
		{
			player = ActorGetByUID(p->ActorUID);
		}
		DrawPlayerStatus(hud, p, player, drawFlags, r);
		DrawScoreUpdate(&hud->scoreUpdates[idx], drawFlags);
		DrawHealthUpdate(&hud->healthUpdates[idx], drawFlags);
		DrawAmmoUpdate(&hud->ammoUpdates[idx], drawFlags);
	}
	// Only draw radar once if shared
	if (ConfigGetBool(&gConfig, "Interface.ShowHUDMap") &&
		(flags & HUDFLAGS_SHARE_SCREEN) &&
		IsAutoMapEnabled(gCampaign.Entry.Mode))
	{
		DrawSharedRadar(hud->device, RADAR_SCALE, hud->showExit);
	}

	if (numPlayersAlive == 0)
	{
		if (AreAllPlayersDeadAndNoLives())
		{
			if (!IsPVP(gCampaign.Entry.Mode))
			{
				FontStrCenter("Game Over!");
			}
			else
			{
				FontStrCenter("All Kill!");
			}
		}
	}
	else if (hud->mission->state == MISSION_STATE_PICKUP)
	{
		int timeLeft = gMission.pickupTime + PICKUP_LIMIT - gMission.time;
		sprintf(s, "Pickup in %d seconds\n",
			(timeLeft + (FPS_FRAMELIMIT - 1)) / FPS_FRAMELIMIT);
		FontStrCenter(s);
	}

	if (pausingDevice != INPUT_DEVICE_UNSET)
	{
		Vec2i pos = Vec2iScaleDiv(Vec2iMinus(
			gGraphicsDevice.cachedConfig.Res,
			FontStrSize("Foo\nPress foo or bar to unpause\nBaz")), 2);
		const int x = pos.x;
		FontStr("<Paused>", pos);

		pos.y += FontH();
		pos = FontStr("Press ", pos);
		color_t c = colorWhite;
		const char *buttonName =
			InputGetButtonNameColor(pausingDevice, 0, CMD_ESC, &c);
		pos = FontStrMask(buttonName, pos, c);
		FontStr(" again to quit", pos);

		pos.x = x;
		pos.y += FontH();
		pos = FontStr("Press ", pos);
		buttonName = InputGetButtonNameColor(
			pausingDevice, 0, CMD_BUTTON1, &c);
		pos = FontStrMask(buttonName, pos, c);
		pos = FontStr(" or ", pos);
		buttonName = InputGetButtonNameColor(
			pausingDevice, 0, CMD_BUTTON2, &c);
		pos = FontStrMask(buttonName, pos, c);
		FontStr(" to unpause", pos);
	}

	if (hud->messageTicks > 0 || hud->messageTicks == -1)
	{
		// Draw the message centered, and just below the automap
		Vec2i pos = Vec2iNew(
			(hud->device->cachedConfig.Res.x -
			FontStrW(hud->message)) / 2,
			AUTOMAP_SIZE + AUTOMAP_PADDING + AUTOMAP_PADDING);
		FontStrMask(hud->message, pos, colorCyan);
	}

	if (ConfigGetBool(&gConfig, "Interface.ShowFPS"))
	{
		FPSCounterDraw(&hud->fpsCounter);
	}
	if (ConfigGetBool(&gConfig, "Interface.ShowTime"))
	{
		WallClockDraw(&hud->clock);
	}

	DrawKeycards(hud);

	// Draw elapsed mission time as MM:SS
	int missionTimeSeconds = gMission.time / FPS_FRAMELIMIT;
	sprintf(s, "%d:%02d",
		missionTimeSeconds / 60, missionTimeSeconds % 60);

	FontOpts opts = FontOptsNew();
	opts.HAlign = ALIGN_CENTER;
	opts.Area = hud->device->cachedConfig.Res;
	opts.Pad.y = 5;
	FontStrOpt(s, Vec2iZero(), opts);

	if (HasObjectives(gCampaign.Entry.Mode))
	{
		DrawObjectiveCounts(hud);
	}
}
コード例 #19
0
static void DrawNumUpdate(
	const HUDNumUpdate *update,
	const char *formatText, int currentValue, Vec2i pos, int flags)
{
	if (update->Timer <= 0 || update->Amount == 0)
	{
		return;
	}
	color_t color = update->Amount > 0 ? colorGreen : colorRed;

	char s[50];
	if (!(flags & HUDFLAGS_PLACE_RIGHT))
	{
		// Find the right position to draw the update
		// Make sure the update is displayed lined up with the lowest digits
		// Find the position of where the normal text is displayed,
		// and move to its right
		sprintf(s, formatText, currentValue);
		pos.x += FontStrW(s);
		// Then find the size of the update, and move left
		sprintf(s, "%s%d", update->Amount > 0 ? "+" : "", update->Amount);
		pos.x -= FontStrW(s);
		// The final position should ensure the score update's lowest digit
		// lines up with the normal score's lowest digit
	}
	else
	{
		sprintf(s, "%s%d", update->Amount > 0 ? "+" : "", update->Amount);
	}

	// Now animate the score update based on its stage
	int timer = update->TimerMax - update->Timer;
	if (timer < NUM_UPDATE_POP_UP_DURATION_MS)
	{
		// update is still popping up
		// calculate height
		int popupHeight =
			timer * NUM_UPDATE_POP_UP_HEIGHT / NUM_UPDATE_POP_UP_DURATION_MS;
		pos.y -= popupHeight;
	}
	else if (timer <
		NUM_UPDATE_POP_UP_DURATION_MS + NUM_UPDATE_FALL_DOWN_DURATION_MS)
	{
		// update is falling down
		// calculate height
		timer -= NUM_UPDATE_POP_UP_DURATION_MS;
		timer = NUM_UPDATE_FALL_DOWN_DURATION_MS - timer;
		int popupHeight =
			timer * NUM_UPDATE_POP_UP_HEIGHT / NUM_UPDATE_FALL_DOWN_DURATION_MS;
		pos.y -= popupHeight;
	}
	else
	{
		// Change alpha so that the update fades away
		color.a = (Uint8)(update->Timer * 255 / update->TimerMax);
	}

	FontOpts opts = FontOptsNew();
	if (flags & HUDFLAGS_PLACE_RIGHT)
	{
		opts.HAlign = ALIGN_END;
	}
	if (flags & HUDFLAGS_PLACE_BOTTOM)
	{
		opts.VAlign = ALIGN_END;
		pos.y += BOTTOM_PADDING;
	}
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad = pos;
	opts.Mask = color;
	opts.Blend = true;
	FontStrOpt(s, Vec2iZero(), opts);
}
コード例 #20
0
ファイル: screens_end.c プロジェクト: cxong/cdogs-sdl
static void PlayerListCustomDraw(
	const menu_t *menu, GraphicsDevice *g, const struct vec2i pos, const struct vec2i size,
	const void *data)
{
	UNUSED(menu);
	UNUSED(g);
	// Draw players starting from the index
	// TODO: custom columns
	const PlayerList *pl = data;

	// First draw the headers
	const int xStart = pos.x + 80 + (size.x - 320) / 2;
	int x = xStart;
	int y = pos.y;
	FontStrMask("Player", svec2i(x, y), colorPurple);
	x += 100;
	FontStrMask("Score", svec2i(x, y), colorPurple);
	x += 32;
	FontStrMask("Kills", svec2i(x, y), colorPurple);
	y += FontH() * 2 + PLAYER_LIST_ROW_HEIGHT + 4;
	// Then draw the player list
	int maxScore = -1;
	for (int i = pl->scroll;
		i < MIN((int)pl->playerUIDs.size, pl->scroll + PlayerListMaxRows(pl));
		i++)
	{
		const int *playerUID = CArrayGet(&pl->playerUIDs, i);
		PlayerData *p = PlayerDataGetByUID(*playerUID);
		if (p == NULL)
		{
			continue;
		}
		if (maxScore < GetModeScore(p))
		{
			maxScore = GetModeScore(p);
		}

		x = xStart;
		// Highlight local players using different coloured text
		const color_t textColor = p->IsLocal ? colorPurple : colorWhite;

		// Draw the players offset on alternate rows
		DisplayCharacterAndName(
			svec2i(x + (i & 1) * 16, y + 4), &p->Char, DIRECTION_DOWN,
			p->name, textColor);

		// Draw score
		x += 100;
		char buf[256];
		sprintf(buf, "%d", p->Totals.Score);
		FontStrMask(buf, svec2i(x, y), textColor);

		// Draw kills
		x += 32;
		sprintf(buf, "%d", p->Totals.Kills);
		FontStrMask(buf, svec2i(x, y), textColor);

		// Draw winner/award text
		x += 32;
		if (pl->showWinners && GetModeScore(p) == maxScore)
		{
			FontStrMask("Winner!", svec2i(x, y), colorGreen);
		}
		else if (pl->showLastMan && p->Lives > 0 &&
			gCampaign.Entry.Mode == GAME_MODE_DEATHMATCH)
		{
			// Only show last man standing on deathmatch mode
			FontStrMask("Last man standing!", svec2i(x, y), colorGreen);
		}

		y += PLAYER_LIST_ROW_HEIGHT;
	}

	// Draw indicator arrows if there's enough to scroll
	if (pl->scroll > 0)
	{
		FontStr("^", svec2i(
			CENTER_X(pos, size, FontStrW("^")), pos.y + FontH()));
	}
	if (pl->scroll < PlayerListMaxScroll(pl))
	{
		FontStr("v", svec2i(
			CENTER_X(pos, size, FontStrW("v")), pos.y + size.y - FontH()));
	}

	// Finally draw any custom stuff
	if (pl->drawFunc)
	{
		pl->drawFunc(pl->data);
	}
}
コード例 #21
0
ファイル: menu.c プロジェクト: Wuzzy2/cdogs-sdl
static void MenuDisplaySubmenus(const MenuSystem *ms)
{
	int x = 0, yStart = 0;
	const menu_t *menu = ms->current;

	switch (menu->type)
	{
	// TODO: refactor the three menu types (normal, options, campaign) into one
	case MENU_TYPE_NORMAL:
	case MENU_TYPE_OPTIONS:
		{
			int iStart = 0;
			int iEnd = (int)menu->u.normal.subMenus.size;
			int numMenuLines = 0;
			int maxIEnd = (int)menu->u.normal.subMenus.size;
			if (menu->u.normal.maxItems > 0)
			{
				// Calculate first/last indices
				if (menu->u.normal.scroll != 0)
				{
					iStart = menu->u.normal.scroll;
				}
				maxIEnd = iStart + menu->u.normal.maxItems;
			}
			// Count the number of menu items that can fit
			// This is to account for multi-line items
			for (iEnd = iStart;
				iEnd < maxIEnd && iEnd < (int)menu->u.normal.subMenus.size;
				iEnd++)
			{
				const menu_t *subMenu =
					CArrayGet(&menu->u.normal.subMenus, iEnd);
				const int numLines = FontStrNumLines(subMenu->name);
				if (menu->u.normal.maxItems > 0 &&
					numMenuLines + numLines > menu->u.normal.maxItems)
				{
					break;
				}
				numMenuLines += numLines;
			}

			int maxWidth = 0;
			for (int i = 0; i < (int)menu->u.normal.subMenus.size; i++)
			{
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);
				const int width = FontStrW(subMenu->name);
				if (width > maxWidth)
				{
					maxWidth = width;
				}
			}
			// Limit max width if it is larger than the menu system size
			maxWidth = MIN(ms->size.x, maxWidth);
			const bool isCentered = menu->type == MENU_TYPE_NORMAL;
			switch (ms->align)
			{
			case MENU_ALIGN_CENTER:
				x = MS_CENTER_X(*ms, maxWidth);
				if (!isCentered)
				{
					x -= 20;
				}
				break;
			case MENU_ALIGN_LEFT:
				x = ms->pos.x;
				break;
			default:
				assert(0 && "unknown alignment");
				break;
			}

			yStart = MS_CENTER_Y(*ms, numMenuLines * FontH());
			if (menu->u.normal.maxItems > 0)
			{
				// Display scroll arrows
				if (menu->u.normal.scroll != 0)
				{
					DisplayMenuItem(
						Vec2iNew(
							MS_CENTER_X(*ms, FontW('^')),
							yStart - 2 - FontH()),
						"^",
						0, 0,
						colorBlack);
				}
				if (iEnd < (int)menu->u.normal.subMenus.size - 1)
				{
					DisplayMenuItem(
						Vec2iNew(
							MS_CENTER_X(*ms, FontW('v')),
							yStart + numMenuLines*FontH() + 2),
						"v",
						0, 0,
						colorBlack);
				}
			}
			const int xOptions = x + maxWidth + 10;

			// Display normal menu items
			Vec2i pos = Vec2iNew(x, yStart);
			for (int i = iStart; i < iEnd; i++)
			{
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);
				char *nameBuf;
				CMALLOC(nameBuf, strlen(subMenu->name) + 3);
				if (subMenu->type == MENU_TYPE_NORMAL &&
					subMenu->u.normal.isSubmenusAlt)
				{
					sprintf(nameBuf, "%s >", subMenu->name);
				}
				else
				{
					strcpy(nameBuf, subMenu->name);
				}

				switch (menu->u.normal.align)
				{
				case MENU_ALIGN_CENTER:
					pos.x = MS_CENTER_X(*ms, FontStrW(nameBuf));
					break;
				case MENU_ALIGN_LEFT:
					// Do nothing
					break;
				default:
					assert(0 && "unknown alignment");
					break;
				}

				const int yNext = DisplayMenuItem(
					pos,
					nameBuf,
					i == menu->u.normal.index,
					subMenu->isDisabled,
					subMenu->color).y + FontH();

				// display option value
				if (subMenu->type == MENU_TYPE_SET_OPTION_TOGGLE ||
					subMenu->type == MENU_TYPE_SET_OPTION_RANGE ||
					subMenu->type == MENU_TYPE_SET_OPTION_SEED ||
					subMenu->type == MENU_TYPE_SET_OPTION_UP_DOWN_VOID_FUNC_VOID ||
					subMenu->type == MENU_TYPE_SET_OPTION_RANGE_GET_SET)
				{
					const int optionInt = MenuOptionGetIntValue(subMenu);
					const Vec2i value_pos = Vec2iNew(xOptions, pos.y);
					switch (subMenu->u.option.displayStyle)
					{
					case MENU_OPTION_DISPLAY_STYLE_INT:
						{
							char buf[32];
							sprintf(buf, "%d", optionInt);
							FontStr(buf, value_pos);
						}
						break;
					case MENU_OPTION_DISPLAY_STYLE_YES_NO:
						FontStr(optionInt ? "Yes" : "No", value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_ON_OFF:
						FontStr(optionInt ? "On" : "Off", value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_STR_FUNC:
						FontStr(subMenu->u.option.uFunc.str(), value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_INT_TO_STR_FUNC:
						FontStr(
							subMenu->u.option.uFunc.intToStr(optionInt),
                            value_pos);
						break;
					default:
						break;
					}
				}

				pos.y = yNext;
			}
		}
		break;
	case MENU_TYPE_KEYS:
		{
			int xKeys;
			x = MS_CENTER_X(*ms, (FontW('a') * 10)) / 2;
			xKeys = x * 3;
			yStart = (gGraphicsDevice.cachedConfig.Res.y / 2) - (FontH() * 10);

			for (int i = 0; i < (int)menu->u.normal.subMenus.size; i++)
			{
				int y = yStart + i * FontH();
				int isSelected = i == menu->u.normal.index;
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);

				const char *name = subMenu->name;
				if (isSelected &&
					subMenu->type != MENU_TYPE_SET_OPTION_CHANGE_KEY)
				{
					FontStrMask(name, Vec2iNew(x, y), colorRed);
				}
				else
				{
					FontStr(name, Vec2iNew(x, y));
				}

				if (subMenu->type == MENU_TYPE_SET_OPTION_CHANGE_KEY)
				{
					const char *keyName;
					if (menu->u.normal.changeKeyMenu == subMenu)
					{
						keyName = "Press a key";
					}
					else if (subMenu->u.changeKey.code == KEY_CODE_MAP)
					{
						keyName = SDL_GetKeyName(gConfig.Input.PlayerKeys[0].Keys.map);
					}
					else
					{
						keyName = SDL_GetKeyName(InputGetKey(
							subMenu->u.changeKey.keys,
							subMenu->u.changeKey.code));
					}
					DisplayMenuItem(
						Vec2iNew(xKeys, y),
						keyName,
						isSelected,
						0,
						colorBlack);
				}
			}
		}
		break;
	default:
		// No submenus, don't display anything
		break;
	}
}