Esempio n. 1
0
static int DisplayPage(
	const char *title, int idx, struct Entry *e,
	int highlights[MAX_LOCAL_PLAYERS])
{
	int x = 80;
	int y = 5 + FontH();

	FontStr(title, Vec2iNew(5, 5));
	while (idx < MAX_ENTRY && e[idx].score > 0 && x < 300)
	{
		bool isHighlighted = false;
		for (int i = 0; i < MAX_LOCAL_PLAYERS; i++)
		{
			if (idx == highlights[i])
			{
				isHighlighted = true;
				break;
			}
		}
		y += DisplayEntry(x, y, idx, &e[idx], isHighlighted);
		if (y > 198 - FontH())
		{
			y = 20;
			x += 100;
		}
		idx++;
	}
	return idx;
}
Esempio n. 2
0
static void DrawNameMenu(
	menu_t *menu, GraphicsDevice *g, Vec2i pos, Vec2i size, void *data)
{
	PlayerSelectMenuData *d = data;

#define ENTRY_COLS	8
#define	ENTRY_SPACING	7

	int x = pos.x;
	int y = CENTER_Y(
		pos, size, FontH() * ((strlen(letters) - 1) / ENTRY_COLS));

	UNUSED(menu);
	UNUSED(g);

	int i;
	for (i = 0; i < (int)strlen(letters); i++)
	{
		Vec2i menuPos = Vec2iNew(
			x + (i % ENTRY_COLS) * ENTRY_SPACING,
			y + (i / ENTRY_COLS) * FontH());
		FontChMask(
			letters[i], menuPos,
			i == d->nameMenuSelection ? colorRed : colorWhite);
	}

	DisplayMenuItem(
		Vec2iNew(
			x + (i % ENTRY_COLS) * ENTRY_SPACING,
			y + (i / ENTRY_COLS) * FontH()),
		"(End)", i == d->nameMenuSelection, 0, colorBlack);
}
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;
}
Esempio n. 4
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, &gConfig.Graphics);

	int c = GetKey(&gEventHandlers);
	return (c == 'Y' || c == 'y');
}
Esempio n. 5
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, 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;
}
Esempio n. 6
0
static void DisplayEquippedWeapons(
	const menu_t *menu, GraphicsDevice *g,
	const Vec2i pos, const Vec2i size, const void *data)
{
	UNUSED(g);
	const WeaponMenuData *d = data;
	Vec2i weaponsPos;
	Vec2i maxTextSize = FontStrSize("LongestWeaponName");
	UNUSED(menu);
	Vec2i dPos = pos;
	dPos.x -= size.x;	// move to left half of screen
	weaponsPos = Vec2iNew(
		dPos.x + size.x * 3 / 4 - maxTextSize.x / 2,
		CENTER_Y(dPos, size, 0) + 14);
	const PlayerData *p = PlayerDataGetByUID(d->display.PlayerUID);
	if (p->weaponCount == 0)
	{
		FontStr("None selected...", weaponsPos);
	}
	else
	{
		for (int i = 0; i < p->weaponCount; i++)
		{
			FontStr(
				p->weapons[i]->name,
				Vec2iAdd(weaponsPos, Vec2iNew(0, i * FontH())));
		}
	}
}
Esempio n. 7
0
bool ScreenMissionBriefing(const struct MissionOptions *m)
{
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;
	const int y = h / 4;
	MissionBriefingData mData;
	memset(&mData, 0, sizeof mData);
	mData.IsOK = true;

	// Title
	CMALLOC(mData.Title, strlen(m->missionData->Title) + 32);
	sprintf(mData.Title, "Mission %d: %s",
		m->index + 1, m->missionData->Title);
	mData.TitleOpts = FontOptsNew();
	mData.TitleOpts.HAlign = ALIGN_CENTER;
	mData.TitleOpts.Area = gGraphicsDevice.cachedConfig.Res;
	mData.TitleOpts.Pad.y = y - 25;

	// Password
	if (m->index > 0)
	{
		sprintf(
			mData.Password, "Password: %s", gAutosave.LastMission.Password);
		mData.PasswordOpts = FontOptsNew();
		mData.PasswordOpts.HAlign = ALIGN_CENTER;
		mData.PasswordOpts.Area = gGraphicsDevice.cachedConfig.Res;
		mData.PasswordOpts.Pad.y = y - 15;
	}

	// Split the description, and prepare it for typewriter effect
	mData.TypewriterCount = 0;
	// allow some slack for newlines
	CMALLOC(mData.Description, strlen(m->missionData->Description) * 2 + 1);
	CCALLOC(mData.TypewriterBuf, strlen(m->missionData->Description) * 2 + 1);
	// Pad about 1/6th of the screen width total (1/12th left and right)
	FontSplitLines(m->missionData->Description, mData.Description, w * 5 / 6);
	mData.DescriptionPos = Vec2iNew(w / 12, y);

	// Objectives
	mData.ObjectiveDescPos =
		Vec2iNew(w / 6, y + FontStrH(mData.Description) + h / 10);
	mData.ObjectiveInfoPos =
		Vec2iNew(w - (w / 6), mData.ObjectiveDescPos.y + FontH());
	mData.ObjectiveHeight = h / 12;
	mData.MissionOptions = m;

	GameLoopData gData = GameLoopDataNew(
		&mData, MissionBriefingUpdate,
		&mData, MissionBriefingDraw);
	GameLoop(&gData);
	if (mData.IsOK)
	{
		SoundPlay(&gSoundDevice, StrSound("mg"));
	}

	CFREE(mData.Title);
	CFREE(mData.Description);
	CFREE(mData.TypewriterBuf);
	return mData.IsOK;
}
UIObject *CreateAddItemObjs(
	Vec2i pos, EditorBrush *brush, CampaignOptions *co)
{
	const int th = FontH();
	UIObject *o2;
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());

	UIObject *o = UIObjectCreate(
		UITYPE_LABEL, 0, Vec2iZero(), Vec2iNew(65, th));
	o->Data = brush;

	pos = Vec2iZero();
	o2 = UIObjectCopy(o);
	o2->Label = "Player start";
	o2->ChangeFunc = BrushSetBrushTypeSetPlayerStart;
	o2->Pos = pos;
	CSTRDUP(o2->Tooltip, "Location where players start");
	o2->OnFocusFunc = ActivateBrush;
	o2->OnUnfocusFunc = DeactivateBrush;
	o2->Data = brush;
	UIObjectAddChild(c, o2);
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->Label = "Map item >";
	o2->Pos = pos;
	UIObjectAddChild(o2, CreateAddMapItemObjs(
		o2->Size, AddMapItemBrushObjFunc, brush, sizeof(IndexedEditorBrush),
		true));
	UIObjectAddChild(c, o2);
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->Label = "Pickup spawner >";
	o2->Pos = pos;
	UIObjectAddChild(o2, CreateAddPickupSpawnerObjs(
		o2->Size, AddPickupSpawnerBrushObjFunc, brush,
		sizeof(IndexedEditorBrush)));
	UIObjectAddChild(c, o2);
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->Label = "Character >";
	o2->Pos = pos;
	UIObjectAddChild(o2, CreateAddCharacterObjs(o2->Size, brush, co));
	UIObjectAddChild(c, o2);
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->Label = "Objective >";
	o2->Pos = pos;
	UIObjectAddChild(o2, CreateAddObjectiveObjs(o2->Size, brush, co));
	UIObjectAddChild(c, o2);
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->Label = "Key >";
	o2->Pos = pos;
	UIObjectAddChild(o2, CreateAddKeyObjs(o2->Size, brush));
	UIObjectAddChild(c, o2);

	UIObjectDestroy(o);
	return c;
}
Esempio n. 9
0
static void DrawHealthUpdate(const HUDNumUpdate *u, const int flags)
{
	const PlayerData *p = PlayerDataGetByUID(u->u.PlayerUID);
	if (!IsPlayerAlive(p)) return;
	const int rowHeight = 1 + FontH();
	const int y = 5 + rowHeight * 2;
	const TActor *a = ActorGetByUID(p->ActorUID);
	DrawNumUpdate(u, "%d", a->health, Vec2iNew(5, y), flags);
}
Esempio n. 10
0
void WallClockDraw(WallClock *wc)
{
	char s[50];
	sprintf(s, "%02d:%02d", wc->hours, wc->minutes);

	FontOpts opts = FontOptsNew();
	opts.VAlign = ALIGN_END;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad = Vec2iNew(10, 5 + FontH());
	FontStrOpt(s, Vec2iZero(), opts);
}
Esempio n. 11
0
static void DrawWeaponStatus(
	HUD *hud, const TActor *actor, Vec2i pos,
	const FontAlign hAlign, const FontAlign vAlign)
{
	const Weapon *weapon = ActorGetGun(actor);

	// Draw gun icon, and allocate padding to draw the gun icon
	const GunDescription *g = ActorGetGun(actor)->Gun;
	const Vec2i iconPos = Vec2iAligned(
		Vec2iNew(pos.x - 2, pos.y - 2),
		g->Icon->size, hAlign, vAlign, gGraphicsDevice.cachedConfig.Res);
	Blit(&gGraphicsDevice, g->Icon, iconPos);

	// don't draw gauge if not reloading
	if (weapon->lock > 0)
	{
		const Vec2i gaugePos = Vec2iAdd(pos, Vec2iNew(-1 + GUN_ICON_PAD, -1));
		const Vec2i size = Vec2iNew(GAUGE_WIDTH - GUN_ICON_PAD, FontH() + 2);
		const color_t barColor = { 0, 0, 255, 255 };
		const int maxLock = weapon->Gun->Lock;
		int innerWidth;
		color_t backColor = { 128, 128, 128, 255 };
		if (maxLock == 0)
		{
			innerWidth = 0;
		}
		else
		{
			innerWidth = MAX(1, size.x * (maxLock - weapon->lock) / maxLock);
		}
		DrawGauge(
			hud->device, gaugePos, size, innerWidth, barColor, backColor,
			hAlign, vAlign);
	}
	FontOpts opts = FontOptsNew();
	opts.HAlign = hAlign;
	opts.VAlign = vAlign;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad = Vec2iNew(pos.x + GUN_ICON_PAD, pos.y);
	char buf[128];
	if (ConfigGetBool(&gConfig, "Game.Ammo") && weapon->Gun->AmmoId >= 0)
	{
		// Include ammo counter
		sprintf(buf, "%s %d/%d",
			weapon->Gun->name,
			ActorGunGetAmmo(actor, weapon),
			AmmoGetById(&gAmmo, weapon->Gun->AmmoId)->Max);
	}
	else
	{
		strcpy(buf, weapon->Gun->name);
	}
	FontStrOpt(buf, Vec2iZero(), opts);
}
Esempio n. 12
0
static void DrawScoreUpdate(const HUDNumUpdate *u, const int flags)
{
	if (!IsScoreNeeded(gCampaign.Entry.Mode))
	{
		return;
	}
	const PlayerData *p = PlayerDataGetByUID(u->u.PlayerUID);
	if (!IsPlayerAlive(p)) return;
	const int rowHeight = 1 + FontH();
	const int y = 5 + rowHeight;
	DrawNumUpdate(u, "Score: %d", p->score, Vec2iNew(5, y), flags);
}
Esempio n. 13
0
static void DrawAmmoUpdate(const HUDNumUpdate *u, const int flags)
{
	const PlayerData *p = PlayerDataGetByUID(u->u.PlayerUID);
	if (!IsPlayerAlive(p)) return;
	const int rowHeight = 1 + FontH();
	const int y = 5 + rowHeight * 4 + LIVES_ROW_EXTRA_Y;
	const TActor *a = ActorGetByUID(p->ActorUID);
	const Weapon *w = ActorGetGun(a);
	char gunNameBuf[256];
	sprintf(gunNameBuf, "%s %%d", w->Gun->name);
	const int ammo = ActorGunGetAmmo(a, w);
	DrawNumUpdate(u, gunNameBuf, ammo, Vec2iNew(5 + GUN_ICON_PAD, y), flags);
}
Esempio n. 14
0
static void DisplayGunIcon(
	const menu_t *menu, GraphicsDevice *g, const Vec2i pos, const Vec2i size,
	const void *data)
{
	UNUSED(data);
	if (menu->u.normal.index >= (int)gMission.Weapons.size)
	{
		return;
	}
	// Display a gun icon next to the currently selected weapon
	const GunDescription **gun =
		CArrayGet(&gMission.Weapons, menu->u.normal.index);
	const int menuItems = MIN(
		menu->u.normal.maxItems, (int)menu->u.normal.subMenus.size);
	const int textScroll =
		-menuItems * FontH() / 2 +
		(menu->u.normal.index - menu->u.normal.scroll) * FontH();
	const Vec2i iconPos = Vec2iNew(
		pos.x - (*gun)->Icon->size.x - 4,
		pos.y + size.y / 2 + textScroll + (FontH() - (*gun)->Icon->size.y) / 2);
	Blit(g, (*gun)->Icon, iconPos);
}
Esempio n. 15
0
UIObject *CreateCampaignSeedObj(const struct vec2i pos, CampaignOptions *co)
{
	const int th = FontH();
	UIObject *o = UIObjectCreate(
		UITYPE_LABEL, 0, svec2i_zero(), svec2i(50, th));
	o->ChangesData = true;
	o->u.LabelFunc = CampaignGetSeedStr;
	o->Data = co;
	o->ChangeFunc = CampaignChangeSeed;
	CSTRDUP(o->Tooltip, "Preview with different random seed");
	o->Pos = pos;
	return o;
}
Esempio n. 16
0
void FPSCounterDraw(FPSCounter *counter)
{
	char s[50];
	counter->framesDrawn++;
	sprintf(s, "FPS: %d", counter->fps);

	FontOpts opts = FontOptsNew();
	opts.HAlign = ALIGN_END;
	opts.VAlign = ALIGN_END;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad = Vec2iNew(10, 5 + FontH());
	FontStrOpt(s, Vec2iZero(), opts);
}
Esempio n. 17
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;
	}
}
Esempio n. 18
0
UIObject *CreateAddMapItemObjs(
	const struct vec2i pos, bool (*objFunc)(UIObject *, MapObject *, void *),
	void *data, const size_t dataSize, const bool expandDown)
{
	CreateAddMapItemObjsImplData d;
	d.ObjFunc = objFunc;
	d.Data = data;
	d.DataSize = dataSize;
	d.GridItemSize = svec2i(TILE_WIDTH + 4, TILE_HEIGHT * 2 + 4);
	d.GridSize = svec2i(8, 6);
	if (expandDown)
	{
		d.PageOffset = svec2i(-5, 5);
	}
	else
	{
		d.PageOffset =
			svec2i(-5, -d.GridItemSize.y * d.GridSize.y - FontH() - 5);
	}
	return CreateAddMapItemObjsImpl(pos, d);
}
Esempio n. 19
0
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();
}
Esempio n. 20
0
static void DrawHealth(
	GraphicsDevice *device, const TActor *actor, const Vec2i pos,
	const FontAlign hAlign, const FontAlign vAlign)
{
	char s[50];
	Vec2i gaugePos = Vec2iAdd(pos, Vec2iNew(-1, -1));
	Vec2i size = Vec2iNew(GAUGE_WIDTH, FontH() + 2);
	HSV hsv = { 0.0, 1.0, 1.0 };
	color_t barColor;
	int health = actor->health;
	const int maxHealth = ActorGetCharacter(actor)->maxHealth;
	int innerWidth;
	color_t backColor = { 50, 0, 0, 255 };
	innerWidth = MAX(1, size.x * health / maxHealth);
	if (actor->poisoned)
	{
		hsv.h = 120.0;
		hsv.v = 0.5;
	}
	else
	{
		double maxHealthHue = 50.0;
		double minHealthHue = 0.0;
		hsv.h =
			((maxHealthHue - minHealthHue) * health / maxHealth + minHealthHue);
	}
	barColor = ColorTint(colorWhite, hsv);
	DrawGauge(
		device, gaugePos, size, innerWidth, barColor, backColor,
		hAlign, vAlign);
	sprintf(s, "%d", health);

	FontOpts opts = FontOptsNew();
	opts.HAlign = hAlign;
	opts.VAlign = vAlign;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad = pos;
	FontStrOpt(s, Vec2iZero(), opts);
}
Esempio n. 21
0
static void CreateAddMapItemSubObjs(UIObject *c, void *vData)
{
	const CreateAddMapItemObjsImplData *data = vData;
	const int pageSize = data->GridSize.x * data->GridSize.y;
	// Check if we need to recreate the objs
	// TODO: this is a very heavyweight way to do it
	int count = 0;
	bool allChildrenSame = true;
	for (int i = 0; i < MapObjectsCount(&gMapObjects); i++)
	{
		MapObject *mo = IndexMapObject(i);
		UIObject *o2 =
			UIObjectCreate(UITYPE_CUSTOM, 0, svec2i_zero(), data->GridItemSize);
		o2->IsDynamicData = true;
		CCALLOC(o2->Data, data->DataSize);
		if (!data->ObjFunc(o2, mo, data->Data))
		{
			UIObjectDestroy(o2);
			continue;
		}
		const int pageIdx = count / pageSize;
		if (pageIdx >= (int)c->Children.size)
		{
			allChildrenSame = false;
			break;
		}
		const UIObject **op = CArrayGet(&c->Children, pageIdx);
		const UIObject **octx = CArrayGet(&(*op)->Children, 0);
		const int idx = count % pageSize;
		if (idx >= (int)(*octx)->Children.size)
		{
			allChildrenSame = false;
			break;
		}
		const UIObject **oc = CArrayGet(&(*octx)->Children, idx);
		if (memcmp(o2->Data, (*oc)->Data, data->DataSize) != 0)
		{
			allChildrenSame = false;
			UIObjectDestroy(o2);
			break;
		}
		count++;
		UIObjectDestroy(o2);
	}
	int cCount = CountAddMapItemSubObjs(c);
	if (cCount == count && allChildrenSame)
	{
		return;
	}

	// Recreate the child UI objects
	c->Highlighted = NULL;
	UIObject **objs = c->Children.data;
	for (int i = 0; i < (int)c->Children.size; i++, objs++)
	{
		UIObjectDestroy(*objs);
	}
	CArrayClear(&c->Children);

	// Create pagination
	int pageNum = 1;
	UIObject *pageLabel = NULL;
	UIObject *page = NULL;
	UIObject *o =
		UIObjectCreate(UITYPE_CUSTOM, 0, svec2i_zero(), data->GridItemSize);
	o->ChangesData = true;
	const struct vec2i gridStart = svec2i_zero();
	struct vec2i pos = svec2i_zero();
	count = 0;
	for (int i = 0; i < MapObjectsCount(&gMapObjects); i++)
	{
		// Only add normal map objects
		MapObject *mo = IndexMapObject(i);
		UIObject *o2 = UIObjectCopy(o);
		o2->IsDynamicData = true;
		CCALLOC(o2->Data, data->DataSize);
		if (!data->ObjFunc(o2, mo, data->Data))
		{
			UIObjectDestroy(o2);
			continue;
		}
		o2->Pos = pos;
		if (count == 0)
		{
			pageLabel = UIObjectCreate(
				UITYPE_LABEL, 0,
				svec2i((pageNum - 1) * 10, 0), svec2i(10, FontH()));
			char buf[32];
			sprintf(buf, "%d", pageNum);
			UIObjectSetDynamicLabel(pageLabel, buf);
			page = UIObjectCreate(
				UITYPE_CONTEXT_MENU, 0,
				svec2i_add(data->PageOffset, pageLabel->Size), svec2i_zero());
			UIObjectAddChild(pageLabel, page);
			pageNum++;
		}
		UIObjectAddChild(page, o2);
		pos.x += o->Size.x;
		if (((count + 1) % data->GridSize.x) == 0)
		{
			pos.x = gridStart.x;
			pos.y += o->Size.y;
		}
		count++;
		if (count == pageSize)
		{
			count = 0;
			pos = gridStart;
			UIObjectAddChild(c, pageLabel);
		}
	}
	if (pageLabel != NULL)
	{
		UIObjectAddChild(c, pageLabel);
	}

	UIObjectDestroy(o);
}
Esempio n. 22
0
UIObject *CreateCaveMapObjs(struct vec2i pos, CampaignOptions *co)
{
	const int th = FontH();
	UIObject *c = UIObjectCreate(UITYPE_NONE, 0, svec2i_zero(), svec2i_zero());
	UIObject *o = UIObjectCreate(
		UITYPE_LABEL, 0, svec2i_zero(), svec2i(50, th));
	const int x = pos.x;
	o->ChangesData = true;
	// Check whether the map type matches, and set visibility
	c->CheckVisible = MissionCheckTypeFunc;
	c->Data = co;


	UIObject *o2 = CreateCampaignSeedObj(pos, co);
	UIObjectAddChild(c, o2);

	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetFillPercentStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeFillPercent;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRepeatStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRepeat;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);

	pos.x = x;
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetR1Str;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeR1;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetR2Str;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeR2;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetCorridorWidthStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeCorridorWidth;
	o2->Pos = pos;
	o2->Size.x = 60;
	UIObjectAddChild(c, o2);

	pos.x = x;
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomCountStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomCount;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomMinStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomMin;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomMaxStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomMax;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, svec2i(60, th));
	o2->ChangesData = true;
	o2->u.CustomDrawFunc = MissionDrawRoomsOverlap;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomsOverlap;
	UIObjectAddChild(c, o2);

	pos.x = x;
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomWallCountStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomWallCount;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomWallLenStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomWallLen;
	o2->Pos = pos;
	o2->Size.x = 60;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetRoomWallPadStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeRoomWallPad;
	o2->Pos = pos;
	o2->Size.x = 60;
	UIObjectAddChild(c, o2);

	pos.x = x;
	pos.y += th;
	o2 = UIObjectCopy(o);
	o2->u.LabelFunc = MissionGetSquareCountStr;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeSquareCount;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);
	pos.x += o2->Size.x;
	o2 = UIObjectCreate(UITYPE_CUSTOM, 0, pos, o->Size);
	o2->u.CustomDrawFunc = MissionDrawDoorEnabled;
	o2->Data = co;
	o2->ChangeFunc = MissionChangeDoorEnabled;
	o2->ChangesData = true;
	o2->Pos = pos;
	UIObjectAddChild(c, o2);

	UIObjectDestroy(o);
	return c;
}
Esempio n. 23
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);
	}
}
Esempio n. 24
0
// Draw player's score, health etc.
static void DrawPlayerStatus(
	HUD *hud, const PlayerData *data, const TActor *p,
	const int flags, const Rect2i r)
{
	if (p != NULL)
	{
		DrawObjectiveCompass(
			hud->device, Vec2iFull2Real(p->Pos), r, hud->showExit);
	}

	Vec2i pos = Vec2iNew(5, 5);

	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;
	FontStrOpt(data->name, Vec2iZero(), opts);

	const int rowHeight = 1 + FontH();
	pos.y += rowHeight;
	char s[50];
	if (IsScoreNeeded(gCampaign.Entry.Mode))
	{
		if (ConfigGetBool(&gConfig, "Game.Ammo"))
		{
			// Display money instead of ammo
			sprintf(s, "Cash: $%d", data->score);
		}
		else
		{
			sprintf(s, "Score: %d", data->score);
		}
	}
	else
	{
		s[0] = 0;
	}
	if (p)
	{
		// Score/money
		opts.Pad = pos;
		FontStrOpt(s, Vec2iZero(), opts);

		// Health
		pos.y += rowHeight;
		DrawHealth(hud->device, p, pos, opts.HAlign, opts.VAlign);

		// Lives
		pos.y += rowHeight;
		DrawLives(hud->device, data, pos, opts.HAlign, opts.VAlign);

		// Weapon
		pos.y += rowHeight + LIVES_ROW_EXTRA_Y;
		DrawWeaponStatus(hud, p, pos, opts.HAlign, opts.VAlign);
	}
	else
	{
		opts.Pad = pos;
		FontStrOpt(s, Vec2iZero(), opts);
	}

	if (ConfigGetBool(&gConfig, "Interface.ShowHUDMap") &&
		!(flags & HUDFLAGS_SHARE_SCREEN) &&
		IsAutoMapEnabled(gCampaign.Entry.Mode))
	{
		DrawRadar(hud->device, p, RADAR_SCALE, flags, hud->showExit);
	}
}
Esempio n. 25
0
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);
	}
}
Esempio n. 26
0
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;
	}
}
Esempio n. 27
0
static void MissionSummaryDraw(void *data)
{
	// This will only draw once
	const struct MissionOptions *m = data;

	GraphicsBlitBkg(&gGraphicsDevice);
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;

	// Display password
	if (strlen(gAutosave.LastMission.Password) > 0)
	{
		char s[64];
		sprintf(s, "Last password: %s", gAutosave.LastMission.Password);
		FontOpts opts = FontOptsNew();
		opts.HAlign = ALIGN_CENTER;
		opts.VAlign = ALIGN_END;
		opts.Area = gGraphicsDevice.cachedConfig.Res;
		opts.Pad.y = opts.Area.y / 12;
		FontStrOpt(s, Vec2iZero(), opts);
	}

	// Display objectives and bonuses
	Vec2i pos = Vec2iNew(w / 6, h / 2 + h / 10);
	int idx = 1;
	for (int i = 0; i < (int)m->missionData->Objectives.size; i++)
	{
		const struct Objective *o = CArrayGet(&m->Objectives, i);
		const MissionObjective *mo = CArrayGet(&m->missionData->Objectives, i);

		// Do not mention optional objectives with none completed
		if (o->done == 0 && mo->Required == 0)
		{
			continue;
		}

		// Objective icon
		DrawObjectiveInfo(m, i, Vec2iAdd(pos, Vec2iNew(-26, FontH())));

		// Objective completion text
		char s[100];
		sprintf(s, "Objective %d: %d of %d, %d required",
			idx, o->done, mo->Count, mo->Required);
		FontOpts opts = FontOptsNew();
		opts.Area = gGraphicsDevice.cachedConfig.Res;
		opts.Pad = pos;
		if (mo->Required == 0)
		{
			// Show optional objectives in purple
			opts.Mask = colorPurple;
		}
		FontStrOpt(s, Vec2iZero(), opts);

		// Objective status text
		opts = FontOptsNew();
		opts.HAlign = ALIGN_END;
		opts.Area = gGraphicsDevice.cachedConfig.Res;
		opts.Pad = pos;
		if (o->done < mo->Required)
		{
			opts.Mask = colorRed;
			FontStrOpt("Failed", Vec2iZero(), opts);
		}
		else if (
			o->done == mo->Count && o->done > mo->Required && AreAnySurvived())
		{
			opts.Mask = colorGreen;
			char buf[16];
			sprintf(buf, "Perfect: %d", PERFECT_BONUS);
			FontStrOpt(buf, Vec2iZero(), opts);
		}
		else if (mo->Required > 0)
		{
			FontStrOpt("Done", Vec2iZero(), opts);
		}
		else
		{
			FontStrOpt("Bonus!", Vec2iZero(), opts);
		}

		pos.y += 15;
		idx++;
	}

	// Draw other bonuses
	if (AreAnySurvived())
	{
		char s[64];

		sprintf(s, "Access bonus: %d", GetAccessBonus(m));
		FontStr(s, pos);

		pos.y += FontH() + 1;
		int seconds;
		const int timeBonus = GetTimeBonus(m, &seconds);
		sprintf(s, "Time bonus: %d secs x 25 = %d", seconds, timeBonus);
		FontStr(s, pos);
	}

	// Draw per-player summaries
	Vec2i size;
	switch (gPlayerDatas.size)
	{
	case 1:
		size = Vec2iNew(w, h / 2);
		DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0));
		break;
	case 2:
		// side by side
		size = Vec2iNew(w / 2, h / 2);
		DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0));
		DrawPlayerSummary(
			Vec2iNew(w / 2, 0), size, CArrayGet(&gPlayerDatas, 1));
		break;
	case 3:	// fallthrough
	case 4:
		// 2x2
		size = Vec2iNew(w / 2, h / 4);
		DrawPlayerSummary(Vec2iZero(), size, CArrayGet(&gPlayerDatas, 0));
		DrawPlayerSummary(
			Vec2iNew(w / 2, 0), size, CArrayGet(&gPlayerDatas, 1));
		DrawPlayerSummary(
			Vec2iNew(0, h / 4), size, CArrayGet(&gPlayerDatas, 2));
		if (gPlayerDatas.size == 4)
		{
			DrawPlayerSummary(
				Vec2iNew(w / 2, h / 4), size, CArrayGet(&gPlayerDatas, 3));
		}
		break;
	default:
		CASSERT(false, "not implemented");
		break;
	}
}
Esempio n. 28
0
static void MissionSummaryDraw(
	const menu_t *menu, GraphicsDevice *g,
	const Vec2i p, const Vec2i size, const void *data)
{
	UNUSED(menu);
	UNUSED(p);
	UNUSED(size);
	const struct MissionOptions *m = data;

	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;

	// Display password
	if (strlen(gAutosave.LastMission.Password) > 0)
	{
		char s[64];
		sprintf(s, "Last password: %s", gAutosave.LastMission.Password);
		FontOpts opts = FontOptsNew();
		opts.HAlign = ALIGN_CENTER;
		opts.VAlign = ALIGN_END;
		opts.Area = g->cachedConfig.Res;
		opts.Pad.y = opts.Area.y / 12;
		FontStrOpt(s, Vec2iZero(), opts);
	}

	// Display objectives and bonuses
	Vec2i pos = Vec2iNew(w / 6, h / 2 + h / 10);
	int idx = 1;
	CA_FOREACH(const Objective, o, m->missionData->Objectives)
		// Do not mention optional objectives with none completed
		if (o->done == 0 && !ObjectiveIsRequired(o))
		{
			continue;
		}

		// Objective icon
		DrawObjectiveInfo(o, Vec2iAdd(pos, Vec2iNew(-26, FontH())));

		// Objective completion text
		char s[100];
		sprintf(s, "Objective %d: %d of %d, %d required",
			idx, o->done, o->Count, o->Required);
		FontOpts opts = FontOptsNew();
		opts.Area = gGraphicsDevice.cachedConfig.Res;
		opts.Pad = pos;
		if (!ObjectiveIsRequired(o))
		{
			// Show optional objectives in purple
			opts.Mask = colorPurple;
		}
		FontStrOpt(s, Vec2iZero(), opts);

		// Objective status text
		opts = FontOptsNew();
		opts.HAlign = ALIGN_END;
		opts.Area = gGraphicsDevice.cachedConfig.Res;
		opts.Pad = pos;
		if (!ObjectiveIsComplete(o))
		{
			opts.Mask = colorRed;
			FontStrOpt("Failed", Vec2iZero(), opts);
		}
		else if (ObjectiveIsPerfect(o) && AreAnySurvived())
		{
			opts.Mask = colorGreen;
			char buf[16];
			sprintf(buf, "Perfect: %d", PERFECT_BONUS);
			FontStrOpt(buf, Vec2iZero(), opts);
		}
		else if (ObjectiveIsRequired(o))
		{
			FontStrOpt("Done", Vec2iZero(), opts);
		}
		else
		{
			FontStrOpt("Bonus!", Vec2iZero(), opts);
		}

		pos.y += 15;
		idx++;
	CA_FOREACH_END()

	// Draw other bonuses
	if (AreAnySurvived())
	{
		char s[64];

		sprintf(s, "Access bonus: %d", GetAccessBonus(m));
		FontStr(s, pos);

		pos.y += FontH() + 1;
		int seconds;
		const int timeBonus = GetTimeBonus(m, &seconds);
		sprintf(s, "Time bonus: %d secs x 25 = %d", seconds, timeBonus);
		FontStr(s, pos);
	}

	// Draw per-player summaries
	PlayerData *pds[MAX_LOCAL_PLAYERS];
	idx = 0;
	CA_FOREACH(PlayerData, pd, gPlayerDatas)
		if (!pd->IsLocal)
		{
			continue;
		}
		pds[idx] = pd;
		idx++;
	CA_FOREACH_END()
	Vec2i playerSize;
	switch (idx)
	{
	case 1:
		playerSize = Vec2iNew(w, h / 2);
		DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]);
		break;
	case 2:
		// side by side
		playerSize = Vec2iNew(w / 2, h / 2);
		DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]);
		DrawPlayerSummary(Vec2iNew(w / 2, 0), playerSize, pds[1]);
		break;
	case 3:	// fallthrough
	case 4:
		// 2x2
		playerSize = Vec2iNew(w / 2, h / 4);
		DrawPlayerSummary(Vec2iZero(), playerSize, pds[0]);
		DrawPlayerSummary(Vec2iNew(w / 2, 0), playerSize, pds[1]);
		DrawPlayerSummary(Vec2iNew(0, h / 4), playerSize, pds[2]);
		if (idx == 4)
		{
			DrawPlayerSummary(Vec2iNew(w / 2, h / 4), playerSize, pds[3]);
		}
		break;
	default:
		CASSERT(false, "not implemented");
		break;
	}
}
Esempio n. 29
0
// Display compact player summary, with player on left half and score summaries
// on right half
static void DrawPlayerSummary(
	const Vec2i pos, const Vec2i size, const PlayerData *data)
{
	char s[50];
	const int totalTextHeight = FontH() * 7;
	// display text on right half
	Vec2i textPos = Vec2iNew(
		pos.x + size.x / 2, CENTER_Y(pos, size, totalTextHeight));

	DisplayCharacterAndName(
		Vec2iAdd(pos, Vec2iNew(size.x / 4, size.y / 2)),
		&data->Char, data->name);

	if (data->survived)
	{
		FontStr("Completed mission", textPos);
	}
	else
	{
		FontStrMask("Failed mission", textPos, colorRed);
	}

	textPos.y += 2 * FontH();
	sprintf(s, "Score: %d", data->score);
	FontStr(s, textPos);
	textPos.y += FontH();
	sprintf(s, "Total: %d", data->totalScore);
	FontStr(s, textPos);
	textPos.y += FontH();
	sprintf(s, "Missions: %d", data->missions + (data->survived ? 1 : 0));
	FontStr(s, textPos);
	textPos.y += FontH();

	// Display bonuses if the player has survived
	if (data->survived)
	{
		const int healthBonus = GetHealthBonus(data);
		if (healthBonus != 0)
		{
			sprintf(s, "Health bonus: %d", healthBonus);
		}
		const int resurrectionFee = GetResurrectionFee(data);
		if (resurrectionFee != 0)
		{
			sprintf(s, "Resurrection fee: %d", resurrectionFee);
		}
		if (healthBonus != 0 || resurrectionFee != 0)
		{
			FontStr(s, textPos);
			textPos.y += FontH();
		}

		const int butcherPenalty = GetButcherPenalty(data);
		if (butcherPenalty != 0)
		{
			sprintf(s, "Butcher penalty: %d", butcherPenalty);
		}
		const int ninjaBonus = GetNinjaBonus(data);
		if (ninjaBonus != 0)
		{
			sprintf(s, "Ninja bonus: %d", ninjaBonus);
		}
		const int friendlyBonus = GetFriendlyBonus(data);
		if (friendlyBonus != 0)
		{
			sprintf(s, "Friendly bonus: %d", friendlyBonus);
		}
		if (butcherPenalty != 0 || ninjaBonus != 0 || friendlyBonus != 0)
		{
			FontStr(s, textPos);
		}
	}
}
Esempio n. 30
0
bool ScreenMissionSummary(
	CampaignOptions *c, struct MissionOptions *m, const bool completed)
{
	if (completed)
	{
		// Save password
		MissionSave ms;
		MissionSaveInit(&ms);
		ms.Campaign = c->Entry;
		// Don't make password for next level if there is none
		int passwordIndex = m->index + 1;
		if (passwordIndex == c->Entry.NumMissions)
		{
			passwordIndex--;
		}
		strcpy(ms.Password, MakePassword(passwordIndex, 0));
		ms.MissionsCompleted = m->index + 1;
		AutosaveAddMission(&gAutosave, &ms);
		AutosaveSave(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE));
	}

	// Calculate bonus scores
	// Bonuses only apply if at least one player has lived
	if (AreAnySurvived())
	{
		int bonus = 0;
		// Objective bonuses
		CA_FOREACH(const Objective, o, m->missionData->Objectives)
			if (ObjectiveIsPerfect(o))
			{
				bonus += PERFECT_BONUS;
			}
		CA_FOREACH_END()
		bonus += GetAccessBonus(m);
		bonus += GetTimeBonus(m, NULL);

		CA_FOREACH(PlayerData, p, gPlayerDatas)
			ApplyBonuses(p, bonus);
		CA_FOREACH_END()
	}
	MenuSystem ms;
	const int h = FontH() * 10;
	MenuSystemInit(
		&ms, &gEventHandlers, &gGraphicsDevice,
		Vec2iNew(0, gGraphicsDevice.cachedConfig.Res.y - h),
		Vec2iNew(gGraphicsDevice.cachedConfig.Res.x, h));
	ms.current = ms.root = MenuCreateNormal("", "", MENU_TYPE_NORMAL, 0);
	// Use return code 0 for whether to continue the game
	if (completed)
	{
		MenuAddSubmenu(ms.root, MenuCreateReturn("Continue", 0));
	}
	else
	{
		MenuAddSubmenu(ms.root, MenuCreateReturn("Replay mission", 0));
		MenuAddSubmenu(ms.root, MenuCreateReturn("Back to menu", 1));
	}
	ms.allowAborts = true;
	MenuAddExitType(&ms, MENU_TYPE_RETURN);
	MenuSystemAddCustomDisplay(&ms, MissionSummaryDraw, m);
	MenuLoop(&ms);
	return ms.current->u.returnCode == 0;
}