static UIObject *CreateAddKeyObjs(Vec2i pos, EditorBrush *brush) { UIObject *o2; UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero()); UIObject *o = UIObjectCreate( UITYPE_CUSTOM, 0, Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4)); o->ChangeFunc = BrushSetBrushTypeAddKey; o->u.CustomDrawFunc = DrawKey; o->OnFocusFunc = ActivateIndexedEditorBrush; o->OnUnfocusFunc = DeactivateIndexedEditorBrush; pos = Vec2iZero(); int width = 4; for (int i = 0; i < KEY_COUNT; i++) { o2 = UIObjectCopy(o); o2->IsDynamicData = 1; CMALLOC(o2->Data, sizeof(IndexedEditorBrush)); ((IndexedEditorBrush *)o2->Data)->Brush = brush; ((IndexedEditorBrush *)o2->Data)->u.ItemIndex = i; o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o->Size.x; if (((i + 1) % width) == 0) { pos.x = 0; pos.y += o->Size.y; } } UIObjectDestroy(o); return c; }
static void MissionBriefingDraw(void *data) { const MissionBriefingData *mData = data; GraphicsClear(&gGraphicsDevice); // Mission title FontStrOpt(mData->Title, Vec2iZero(), mData->TitleOpts); // Display password FontStrOpt(mData->Password, Vec2iZero(), mData->PasswordOpts); // Display description with typewriter effect FontStr(mData->TypewriterBuf, mData->DescriptionPos); // Display objectives CA_FOREACH( const Objective, o, mData->MissionOptions->missionData->Objectives) // Do not brief optional objectives if (o->Required == 0) { continue; } Vec2i offset = Vec2iNew(0, _ca_index * mData->ObjectiveHeight); FontStr(o->Description, Vec2iAdd(mData->ObjectiveDescPos, offset)); // Draw the icons slightly offset so that tall icons don't overlap each // other offset.x = -16 * (_ca_index & 1); DrawObjectiveInfo(o, Vec2iAdd(mData->ObjectiveInfoPos, offset)); CA_FOREACH_END() }
static UIObject *CreateSetKeyObjs(Vec2i pos, EditorBrush *brush) { UIObject *o2; UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero()); UIObject *o = UIObjectCreate( UITYPE_CUSTOM, 0, Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4)); o->ChangeFunc = BrushSetBrushTypeSetKey; o->u.CustomDrawFunc = DrawKey; o->OnFocusFunc = ActivateIndexedEditorBrush; o->OnUnfocusFunc = DeactivateIndexedEditorBrush; pos = Vec2iZero(); for (int i = -1; i < KEY_COUNT; i++) { o2 = UIObjectCopy(o); o2->IsDynamicData = 1; CMALLOC(o2->Data, sizeof(IndexedEditorBrush)); ((IndexedEditorBrush *)o2->Data)->Brush = brush; ((IndexedEditorBrush *)o2->Data)->ItemIndex = i; o2->Pos = pos; if (i == -1) { // -1 means no key CSTRDUP(o2->Tooltip, "no key"); } UIObjectAddChild(c, o2); pos.x += o->Size.x; } UIObjectDestroy(o); return c; }
static void MissionBriefingDraw(void *data) { const MissionBriefingData *mData = data; GraphicsBlitBkg(&gGraphicsDevice); // Mission title FontStrOpt(mData->Title, Vec2iZero(), mData->TitleOpts); // Display password FontStrOpt(mData->Password, Vec2iZero(), mData->PasswordOpts); // Display description with typewriter effect FontStr(mData->TypewriterBuf, mData->DescriptionPos); // Display objectives for (int i = 0; i < (int)mData->MissionOptions->missionData->Objectives.size; i++) { const MissionObjective *o = CArrayGet(&mData->MissionOptions->missionData->Objectives, i); // Do not brief optional objectives if (o->Required == 0) { continue; } const Vec2i yInc = Vec2iNew(0, i * mData->ObjectiveHeight); FontStr(o->Description, Vec2iAdd(mData->ObjectiveDescPos, yInc)); DrawObjectiveInfo( mData->MissionOptions, i, Vec2iAdd(mData->ObjectiveInfoPos, yInc)); } }
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; }
bool RunGame(const CampaignOptions *co, struct MissionOptions *m, Map *map) { // Clear the background DrawRectangle( &gGraphicsDevice, Vec2iZero(), gGraphicsDevice.cachedConfig.Res, colorBlack, 0); SDL_UpdateTexture( gGraphicsDevice.bkg, NULL, gGraphicsDevice.buf, gGraphicsDevice.cachedConfig.Res.x * sizeof(Uint32)); MapLoad(map, m, co); // Seed random if PVP mode (otherwise players will always spawn in same // position) if (IsPVP(co->Entry.Mode)) { srand((unsigned int)time(NULL)); } if (!co->IsClient) { MapLoadDynamic(map, m, &co->Setting.characters); // For PVP modes, mark all map as explored if (IsPVP(co->Entry.Mode)) { MapMarkAllAsVisited(map); } // Reset players for the mission CA_FOREACH(const PlayerData, p, gPlayerDatas) // Only reset for local players; for remote ones wait for the // client ready message if (!p->IsLocal) continue; GameEvent e = GameEventNew(GAME_EVENT_PLAYER_DATA); e.u.PlayerData = PlayerDataMissionReset(p); GameEventsEnqueue(&gGameEvents, e); CA_FOREACH_END() // Process the events to force add the players HandleGameEvents(&gGameEvents, NULL, NULL, NULL); // Note: place players first, // as bad guys are placed away from players Vec2i firstPos = Vec2iZero(); CA_FOREACH(const PlayerData, p, gPlayerDatas) if (!p->Ready) continue; firstPos = PlacePlayer(&gMap, p, firstPos, true); CA_FOREACH_END() if (!IsPVP(co->Entry.Mode)) { InitializeBadGuys(); CreateEnemies(); } }
void PicTrim(Pic *pic, const bool xTrim, const bool yTrim) { // Scan all pixels looking for the min/max of x and y Vec2i min = pic->size; Vec2i max = Vec2iZero(); for (Vec2i pos = Vec2iZero(); pos.y < pic->size.y; pos.y++) { for (pos.x = 0; pos.x < pic->size.x; pos.x++) { const Uint32 pixel = *(pic->Data + pos.x + pos.y * pic->size.x); if (PixelToColor(&gGraphicsDevice, pixel).a > 0) { min.x = MIN(min.x, pos.x); min.y = MIN(min.y, pos.y); max.x = MAX(max.x, pos.x); max.y = MAX(max.y, pos.y); } } } // If no opaque pixels found, don't trim Vec2i newSize = pic->size; Vec2i offset = Vec2iZero(); if (min.x < max.x && min.y < max.y) { if (xTrim) { newSize.x = max.x - min.x + 1; offset.x = min.x; } if (yTrim) { newSize.y = max.y - min.y + 1; offset.y = min.y; } } // Trim by copying pixels Uint32 *newData; CMALLOC(newData, newSize.x * newSize.y * sizeof *newData); for (Vec2i pos = Vec2iZero(); pos.y < newSize.y; pos.y++) { for (pos.x = 0; pos.x < newSize.x; pos.x++) { Uint32 *target = newData + pos.x + pos.y * newSize.x; const int srcIdx = pos.x + offset.x + (pos.y + offset.y) * pic->size.x; *target = *(pic->Data + srcIdx); } } // Replace the old data CFREE(pic->Data); pic->Data = newData; pic->size = newSize; pic->offset = Vec2iZero(); }
void ShowControls(void) { FontOpts opts = FontOptsNew(); opts.HAlign = ALIGN_CENTER; opts.VAlign = ALIGN_END; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad.y = 10; #ifdef __GCWZERO__ FontStrOpt( "(use joystick or D pad + START + SELECT)", Vec2iZero(), opts); #else FontStrOpt( "(use joystick 1 or arrow keys + Enter/Backspace)", Vec2iZero(), opts); #endif }
static void CreateAddCharacterSubObjs(UIObject *c, void *vData) { EditorBrushAndCampaign *data = vData; CharacterStore *store = &data->Campaign->Setting.characters; if (c->Children.size == store->OtherChars.size) { 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); } CArrayTerminate(&c->Children); CArrayInit(&c->Children, sizeof c); UIObject *o = UIObjectCreate( UITYPE_CUSTOM, 0, Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT * 2 + 4)); o->ChangeFunc = BrushSetBrushTypeAddCharacter; o->u.CustomDrawFunc = DrawCharacter; o->OnFocusFunc = ActivateEditorBrushAndCampaignBrush; o->OnUnfocusFunc = DeactivateEditorBrushAndCampaignBrush; Vec2i pos = Vec2iZero(); int width = 8; for (int i = 0; i < (int)store->OtherChars.size; i++) { UIObject *o2 = UIObjectCopy(o); Character *ch = CArrayGet(&store->OtherChars, i); CSTRDUP(o2->Tooltip, ch->Gun->name); o2->IsDynamicData = 1; CMALLOC(o2->Data, sizeof(EditorBrushAndCampaign)); ((EditorBrushAndCampaign *)o2->Data)->Brush.Brush = data->Brush.Brush; ((EditorBrushAndCampaign *)o2->Data)->Campaign = data->Campaign; ((EditorBrushAndCampaign *)o2->Data)->Brush.u.ItemIndex = i; o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o->Size.x; if (((i + 1) % width) == 0) { pos.x = 0; pos.y += o->Size.y; } } UIObjectDestroy(o); }
static void CampaignIntroDraw(void *data) { // This will only draw once const CampaignSetting *c = data; GraphicsBlitBkg(&gGraphicsDevice); const int w = gGraphicsDevice.cachedConfig.Res.x; const int h = gGraphicsDevice.cachedConfig.Res.y; const int y = h / 4; // Display title + author char *buf; CMALLOC(buf, strlen(c->Title) + strlen(c->Author) + 16); sprintf(buf, "%s by %s", c->Title, c->Author); FontOpts opts = FontOptsNew(); opts.HAlign = ALIGN_CENTER; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad.y = y - 25; FontStrOpt(buf, Vec2iZero(), opts); CFREE(buf); // Display campaign description // allow some slack for newlines if (strlen(c->Description) > 0) { CMALLOC(buf, strlen(c->Description) * 2); // Pad about 1/6th of the screen width total (1/12th left and right) FontSplitLines(c->Description, buf, w * 5 / 6); FontStr(buf, Vec2iNew(w / 12, y)); CFREE(buf); } }
static void DrawEditorTiles(DrawBuffer *b, Vec2i offset) { Vec2i pos; Tile *tile = &b->tiles[0][0]; pos.y = b->dy + offset.y; for (int y = 0; y < Y_TILES; y++, pos.y += TILE_HEIGHT) { pos.x = b->dx + offset.x; for (int x = 0; x < b->Size.x; x++, tile++, pos.x += TILE_WIDTH) { if (gMission.missionData->Type == MAPTYPE_STATIC) { Vec2i start = gMission.missionData->u.Static.Start; if (!Vec2iEqual(start, Vec2iZero()) && Vec2iEqual(start, Vec2iNew(x + b->xStart, y + b->yStart))) { // mission start BlitMasked( &gGraphicsDevice, PicManagerGetPic(&gPicManager, "editor/start"), pos, colorWhite, 1); } } } tile += X_TILES - b->Size.x; } }
static void MakeBackground(GraphicsDevice *g, int buildTables) { if (buildTables) { // Automatically pan camera to middle of screen Mission *m = gMission.missionData; Vec2i focusTile = Vec2iScaleDiv(m->Size, 2); // Better yet, if the map has a known start position, focus on that if (m->Type == MAPTYPE_STATIC && !Vec2iEqual(m->u.Static.Start, Vec2iZero())) { focusTile = m->u.Static.Start; } camera = Vec2iCenterOfTile(focusTile); } // Clear background first for (int i = 0; i < GraphicsGetScreenSize(&g->cachedConfig); i++) { g->buf[i] = PixelFromColor(g, colorBlack); } GrafxDrawExtra extra; extra.guideImage = brush.GuideImageSurface; extra.guideImageAlpha = brush.GuideImageAlpha; DrawBufferTerminate(&sDrawBuffer); DrawBufferInit(&sDrawBuffer, Vec2iNew(X_TILES, Y_TILES), &gGraphicsDevice); GrafxMakeBackground( g, &sDrawBuffer, &gCampaign, &gMission, &gMap, tintNone, 1, buildTables, camera, &extra); }
static Vec2i GenerateQuickPlayMapSize(QuickPlayQuantity size) { const int minMapDim = 16; const int maxMapDim = 64; // Map sizes based on total dimensions (width + height) // Small: 32 - 64 // Medium: 64 - 96 // Large: 96 - 128 // Restrictions: at least 16, at most 64 per side switch (size) { case QUICKPLAY_QUANTITY_ANY: return GenerateRandomPairPartitionWithRestrictions( 32 + (rand() % (128 - 32 + 1)), minMapDim, maxMapDim); case QUICKPLAY_QUANTITY_SMALL: return GenerateRandomPairPartitionWithRestrictions( 32 + (rand() % (64 - 32 + 1)), minMapDim, maxMapDim); case QUICKPLAY_QUANTITY_MEDIUM: return GenerateRandomPairPartitionWithRestrictions( 64 + (rand() % (96 - 64 + 1)), minMapDim, maxMapDim); case QUICKPLAY_QUANTITY_LARGE: return GenerateRandomPairPartitionWithRestrictions( 96 + (rand() % (128 - 96 + 1)), minMapDim, maxMapDim); default: assert(0 && "invalid quick play map size config"); return Vec2iZero(); } }
void PicLoad( Pic *p, const Vec2i size, const Vec2i offset, const SDL_Surface *image, const SDL_Surface *s) { p->size = size; p->offset = Vec2iZero(); CMALLOC(p->Data, size.x * size.y * sizeof *((Pic *)0)->Data); // Manually copy the pixels and replace the alpha component, // since our gfx device format has no alpha int srcI = offset.y*image->w + offset.x; for (int i = 0; i < size.x * size.y; i++, srcI++) { const Uint32 alpha = ((Uint32 *)image->pixels)[srcI] >> image->format->Ashift; // If completely transparent, replace rgb with black (0) too // This is because transparency blitting checks entire pixel if (alpha == 0) { p->Data[i] = 0; } else { const Uint32 pixel = ((Uint32 *)s->pixels)[srcI]; const Uint32 rgbMask = s->format->Rmask | s->format->Gmask | s->format->Bmask; p->Data[i] = (pixel & rgbMask) | (alpha << gGraphicsDevice.Ashift); } if ((i + 1) % size.x == 0) { srcI += image->w - size.x; } } }
void PicLoad( Pic *p, const Vec2i size, const Vec2i offset, const SDL_Surface *image) { p->size = size; p->offset = Vec2iZero(); p->Data = malloc(size.x * size.y * sizeof *((Pic *)0)->Data); // Manually copy the pixels and replace the alpha component, // since our gfx device format has no alpha int srcI = offset.y*image->w + offset.x; for (int i = 0; i < size.x * size.y; i++, srcI++) { const Uint32 pixel = ((Uint32 *)image->pixels)[srcI]; SDL_Color c; SDL_GetRGBA(pixel, image->format, &c.r, &c.g, &c.b, &c.a); // If completely transparent, replace rgb with black (0) too // This is because transparency blitting checks entire pixel if (c.a == 0) { p->Data[i] = 0; } else { p->Data[i] = WHITE; } if ((i + 1) % size.x == 0) { srcI += image->w - size.x; } } }
bool NumPlayersSelection( GameMode mode, GraphicsDevice *graphics, EventHandlers *handlers) { MenuSystem ms; MenuSystemInit( &ms, handlers, graphics, Vec2iZero(), graphics->cachedConfig.Res); ms.allowAborts = true; ms.root = ms.current = MenuCreateNormal( "", "Select number of players", MENU_TYPE_NORMAL, 0); for (int i = 0; i < MAX_LOCAL_PLAYERS; i++) { char buf[2]; if (IsMultiplayer(mode) && i == 0) { // At least two players for dogfights continue; } sprintf(buf, "%d", i + 1); MenuAddSubmenu(ms.current, MenuCreateReturn(buf, i + 1)); } MenuAddExitType(&ms, MENU_TYPE_RETURN); MenuLoop(&ms); const bool ok = !ms.hasAbort; if (ok) { const int numPlayers = ms.current->u.returnCode; for (int i = 0; i < (int)gPlayerDatas.size; i++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); CASSERT(!p->IsLocal, "unexpected local player"); } if (NetClientIsConnected(&gNetClient)) { // Tell the server that we want to add new players NetMsgNewPlayers np; np.ClientId = gNetClient.ClientId; np.NumPlayers = numPlayers; NetClientSendMsg(&gNetClient, MSG_NEW_PLAYERS, &np); } else { // We are the server, just add the players for (int i = 0; i < numPlayers; i++) { PlayerData *p = PlayerDataAdd(&gPlayerDatas); PlayerDataSetLocalDefaults(p, i); p->inputDevice = INPUT_DEVICE_UNSET; } } } MenuSystemTerminate(&ms); return ok; }
int NumPlayersSelection( int *numPlayers, campaign_mode_e mode, GraphicsDevice *graphics, InputDevices *input) { MenuSystem ms; int i; int res = 0; MenuSystemInit( &ms, input, graphics, Vec2iZero(), Vec2iNew( graphics->cachedConfig.ResolutionWidth, graphics->cachedConfig.ResolutionHeight)); ms.root = ms.current = MenuCreateNormal( "", "Select number of players", MENU_TYPE_NORMAL, 0); for (i = 0; i < MAX_PLAYERS; i++) { if (mode == CAMPAIGN_MODE_DOGFIGHT && i == 0) { // At least two players for dogfights continue; } char buf[2]; sprintf(buf, "%d", i + 1); MenuAddSubmenu(ms.current, MenuCreateReturn(buf, i + 1)); } MenuAddExitType(&ms, MENU_TYPE_RETURN); for (;;) { int cmd; InputPoll(&gInputDevices, SDL_GetTicks()); if (KeyIsPressed(&gInputDevices.keyboard, SDLK_ESCAPE)) { res = 0; break; // hack to allow exit } cmd = GetMenuCmd(gPlayerDatas); MenuProcessCmd(&ms, cmd); if (MenuIsExit(&ms)) { *numPlayers = ms.current->u.returnCode; res = 1; break; } GraphicsBlitBkg(graphics); MenuDisplay(&ms); BlitFlip(graphics, &gConfig.Graphics); SDL_Delay(10); } MenuSystemTerminate(&ms); return res; }
void UIButtonSetPic(UIObject *o, Pic *pic) { assert(o->Type == UITYPE_BUTTON && "invalid UI type"); o->u.Button.Pic = pic; if (Vec2iEqual(o->Size, Vec2iZero())) { o->Size = o->u.Button.Pic->size; } }
void CameraInit(Camera *camera) { memset(camera, 0, sizeof *camera); DrawBufferInit( &camera->Buffer, Vec2iNew(X_TILES, Y_TILES), &gGraphicsDevice); camera->lastPosition = Vec2iZero(); HUDInit(&camera->HUD, &gGraphicsDevice, &gMission); camera->shake = ScreenShakeZero(); }
// TODO: reimplement in camera Vec2i GetPlayerCenter( GraphicsDevice *device, const Camera *camera, const PlayerData *pData, const int playerIdx) { if (pData->ActorUID < 0) { // Player is dead return Vec2iZero(); } Vec2i center = Vec2iZero(); int w = device->cachedConfig.Res.x; int h = device->cachedConfig.Res.y; if (GetNumPlayers(PLAYER_ALIVE_OR_DYING, true, true) == 1 || GetNumPlayers(PLAYER_ALIVE_OR_DYING, false , true) == 1 || CameraIsSingleScreen()) { const Vec2i pCenter = camera->lastPosition; const Vec2i screenCenter = Vec2iNew(w / 2, device->cachedConfig.Res.y / 2); const TActor *actor = ActorGetByUID(pData->ActorUID); const Vec2i p = Vec2iNew(actor->tileItem.x, actor->tileItem.y); center = Vec2iAdd(Vec2iMinus(p, pCenter), screenCenter); } else { const int numLocalPlayers = GetNumPlayers(PLAYER_ANY, false, true); if (numLocalPlayers == 2) { center.x = playerIdx == 0 ? w / 4 : w * 3 / 4; center.y = h / 2; } else if (numLocalPlayers >= 3 && numLocalPlayers <= 4) { center.x = (playerIdx & 1) ? w * 3 / 4 : w / 4; center.y = (playerIdx >= 2) ? h * 3 / 4 : h / 4; } else { CASSERT(false, "invalid number of players"); } } return center; }
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); }
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); }
Vec2i GetWallBounceFullPos( const Vec2i startFull, const Vec2i newFull, Vec2i *velFull) { CASSERT(velFull != NULL, "need velocity for wall bouncing"); Vec2i newReal = Vec2iFull2Real(newFull); if (!ShootWall(newReal.x, newReal.y)) { return newFull; } Vec2i startRealPos = Vec2iFull2Real(startFull); Vec2i bounceFull = startFull; if (!ShootWall(startRealPos.x, newReal.y)) { bounceFull.y = newFull.y; velFull->x *= -1; } else if (!ShootWall(newReal.x, startRealPos.y)) { bounceFull.x = newFull.x; velFull->y *= -1; } else { *velFull = Vec2iScale(*velFull, -1); // Keep bouncing back if it's inside a wall // However, do not bounce more than half a tile's size if (!Vec2iIsZero(*velFull)) { Vec2i bounceReal = newReal; const int maxBounces = MAX( velFull->x / 256 / TILE_WIDTH, velFull->y / 256 / TILE_HEIGHT); for (int i = 0; i < maxBounces && MapIsRealPosIn(&gMap, bounceReal) && ShootWall(bounceReal.x, bounceReal.y); i++) { bounceFull = Vec2iAdd(bounceFull, *velFull); bounceReal = Vec2iFull2Real(bounceFull); } // If still colliding wall or outside map, // can't recover from this point; zero velocity and return if (!MapIsRealPosIn(&gMap, bounceReal) || ShootWall(bounceReal.x, bounceReal.y)) { *velFull = Vec2iZero(); return startFull; } } } return bounceFull; }
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); }
static UIObject *CreateAddCharacterObjs( Vec2i pos, EditorBrush *brush, CampaignOptions *co) { UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero()); // Need to update UI objects dynamically as new characters can be // added and removed c->OnFocusFunc = CreateAddCharacterSubObjs; c->IsDynamicData = 1; CMALLOC(c->Data, sizeof(EditorBrushAndCampaign)); ((EditorBrushAndCampaign *)c->Data)->Brush.Brush = brush; ((EditorBrushAndCampaign *)c->Data)->Campaign = co; return c; }
static void AddAndPlacePlayers(void) { Vec2i firstPos = Vec2iZero(); for (int i = 0; i < (int)gPlayerDatas.size; i++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); if (!p->IsUsed) { continue; } firstPos = PlacePlayer(&gMap, p, firstPos, true); } }
static UIObject *CreateAddWreckObjs(Vec2i pos, EditorBrush *brush) { UIObject *o2; UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero()); UIObject *o = UIObjectCreate( UITYPE_CUSTOM, 0, Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4)); o->ChangeFunc = BrushSetBrushTypeAddWreck; o->u.CustomDrawFunc = DrawWreck; o->OnFocusFunc = ActivateIndexedEditorBrush; o->OnUnfocusFunc = DeactivateIndexedEditorBrush; pos = Vec2iZero(); const int width = 8; for (int i = 0; i < (int)gMapObjects.Destructibles.size; i++) { o2 = UIObjectCopy(o); o2->IsDynamicData = 1; CMALLOC(o2->Data, sizeof(IndexedEditorBrush)); ((IndexedEditorBrush *)o2->Data)->Brush = brush; ((IndexedEditorBrush *)o2->Data)->u.ItemIndex = i; o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o->Size.x; if (((i + 1) % width) == 0) { pos.x = 0; pos.y += o->Size.y; } const char **name = CArrayGet(&gMapObjects.Destructibles, i); const MapObject *mo = StrMapObject(*name); CSTRDUP(o2->Tooltip, mo->Name); } UIObjectDestroy(o); return c; }
static void PlayerSelectionDraw(void *data) { const PlayerSelectionData *pData = data; GraphicsBlitBkg(&gGraphicsDevice); const int w = gGraphicsDevice.cachedConfig.Res.x; const int h = gGraphicsDevice.cachedConfig.Res.y; int idx = 0; for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); if (!p->IsLocal) { idx--; continue; } if (p->inputDevice != INPUT_DEVICE_UNSET) { MenuDisplay(&pData->menus[idx].ms); } else { Vec2i center = Vec2iZero(); const char *prompt = "Press Fire to join..."; const Vec2i offset = Vec2iScaleDiv(FontStrSize(prompt), -2); switch (GetNumPlayers(false, false, true)) { case 1: // Center of screen center = Vec2iNew(w / 2, h / 2); break; case 2: // Side by side center = Vec2iNew(idx * w / 2 + w / 4, h / 2); break; case 3: case 4: // Four corners center = Vec2iNew( (idx & 1) * w / 2 + w / 4, (idx / 2) * h / 2 + h / 4); break; default: CASSERT(false, "not implemented"); break; } FontStr(prompt, Vec2iAdd(center, offset)); } } }
void MissionStaticLayout(Mission *m, Vec2i oldSize) { assert(m->Type == MAPTYPE_STATIC && "invalid map type"); // re-layout the static map after a resize // The mission contains the new size; the old dimensions are oldSize // Simply try to "paint" the old tiles to the new mission Vec2i v; CArray oldTiles; CArrayInit(&oldTiles, m->u.Static.Tiles.elemSize); CArrayCopy(&oldTiles, &m->u.Static.Tiles); // Clear the tiles first CArrayTerminate(&m->u.Static.Tiles); CArrayInit(&m->u.Static.Tiles, oldTiles.elemSize); for (v.y = 0; v.y < m->Size.y; v.y++) { for (v.x = 0; v.x < m->Size.x; v.x++) { unsigned short tile = MAP_FLOOR; CArrayPushBack(&m->u.Static.Tiles, &tile); } } // Paint the old tiles back for (v.y = 0; v.y < m->Size.y; v.y++) { for (v.x = 0; v.x < m->Size.x; v.x++) { if (v.x >= oldSize.x || v.y >= oldSize.y) { MissionTrySetTile(m, v, MAP_NOTHING); } else { int idx = v.y * oldSize.x + v.x; unsigned short *tile = CArrayGet(&oldTiles, idx); MissionTrySetTile(m, v, *tile); } } } CArrayTerminate(&oldTiles); if (m->u.Static.Start.x >= m->Size.x || m->u.Static.Start.y >= m->Size.y) { m->u.Static.Start = Vec2iZero(); } }
void PicFromPicPaletted(GraphicsDevice *g, Pic *pic, PicPaletted *picP) { pic->size = Vec2iNew(picP->w, picP->h); pic->offset = Vec2iZero(); CMALLOC(pic->Data, pic->size.x * pic->size.y * sizeof *pic->Data); for (int i = 0; i < pic->size.x * pic->size.y; i++) { unsigned char palette = *(picP->data + i); pic->Data[i] = PixelFromColor(g, PaletteToColor(palette)); // Special case: if the palette colour is 0, it's transparent if (palette == 0) { pic->Data[i] = 0; } } }