static void DrawObjectiveInfo( const struct MissionOptions *mo, const int idx, const Vec2i pos) { const MissionObjective *mobj = CArrayGet(&mo->missionData->Objectives, idx); const ObjectiveDef *o = CArrayGet(&mo->Objectives, idx); const CharacterStore *store = &gCampaign.Setting.characters; switch (mobj->Type) { case OBJECTIVE_KILL: { const Character *cd = CArrayGet( &store->OtherChars, CharacterStoreGetSpecialId(store, 0)); const int i = cd->looks.face; TOffsetPic pic; pic.picIndex = cHeadPic[i][DIRECTION_DOWN][STATE_IDLE]; pic.dx = cHeadOffset[i][DIRECTION_DOWN].dx; pic.dy = cHeadOffset[i][DIRECTION_DOWN].dy; DrawTTPic( pos.x + pic.dx, pos.y + pic.dy, PicManagerGetOldPic(&gPicManager, pic.picIndex), &cd->table); } break; case OBJECTIVE_RESCUE: { const Character *cd = CArrayGet( &store->OtherChars, CharacterStoreGetPrisonerId(store, 0)); const int i = cd->looks.face; TOffsetPic pic; pic.picIndex = cHeadPic[i][DIRECTION_DOWN][STATE_IDLE]; pic.dx = cHeadOffset[i][DIRECTION_DOWN].dx; pic.dy = cHeadOffset[i][DIRECTION_DOWN].dy; DrawTTPic( pos.x + pic.dx, pos.y + pic.dy, PicManagerGetOldPic(&gPicManager, pic.picIndex), &cd->table); } break; case OBJECTIVE_COLLECT: { const Pic *p = o->pickupClass->Pic; Blit(&gGraphicsDevice, p, Vec2iAdd(pos, p->offset)); } break; case OBJECTIVE_DESTROY: { Vec2i picOffset; const Pic *p = MapObjectGetPic(IntMapObject(mobj->Index), &picOffset, false); Blit(&gGraphicsDevice, p, Vec2iAdd(pos, picOffset)); } break; case OBJECTIVE_INVESTIGATE: // Don't draw return; default: CASSERT(false, "Unknown objective type"); return; } }
void DrawActorHighlight( const ActorPics *pics, const Vec2i pos, const color_t color) { // Do not highlight dead, dying or transparent characters if (pics->IsDead || pics->IsTransparent) { return; } BlitPicHighlight( &gGraphicsDevice, pics->Head, Vec2iAdd(pos, pics->HeadOffset), color); if (pics->Body != NULL) { BlitPicHighlight( &gGraphicsDevice, pics->Body, Vec2iAdd(pos, pics->BodyOffset), color); } if (pics->Legs != NULL) { BlitPicHighlight( &gGraphicsDevice, pics->Legs, Vec2iAdd(pos, pics->LegsOffset), color); } if (pics->Gun != NULL) { BlitPicHighlight( &gGraphicsDevice, pics->Gun, Vec2iAdd(pos, pics->GunOffset), color); } }
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 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)); } }
// Check collision with a diamond shape // This means that the bounding box could be in collision, but the bounding // "radius" is not. The diamond is expressed with a single "radius" - that is, // the diamond is the same height and width. // This arrangement is used so that axis movement can slide off corners by // moving in a diagonal direction. // E.g. this is not a collision: // x // x x // x x // x x // x x // x x wwwww // x w // w // Where 'x' denotes the bounding diamond, and 'w' represents a wall corner. bool IsCollisionDiamond(const Map *map, const Vec2i pos, const Vec2i fullSize) { const Vec2i mapSize = Vec2iNew(map->Size.x * TILE_WIDTH, map->Size.y * TILE_HEIGHT); const Vec2i size = Vec2iScaleDiv(fullSize, 2); if (pos.x - size.x < 0 || pos.x + size.x >= mapSize.x || pos.y - size.y < 0 || pos.y + size.y >= mapSize.y) { return true; } // Only support wider-than-taller collision diamonds for now CASSERT(size.x >= size.y, "not implemented, taller than wider diamond"); const double gradient = (double)size.y / size.x; // Now we need to check in a diamond pattern that the boundary does not // collide // Top to right for (int i = 0; i < size.x; i++) { const int y = (int)Round((-size.x + i)* gradient); const Vec2i p = Vec2iAdd(pos, Vec2iNew(i, y)); if (HitWall(p.x, p.y)) { return true; } } // Right to bottom for (int i = 0; i < size.x; i++) { const int y = (int)Round(i * gradient); const Vec2i p = Vec2iAdd(pos, Vec2iNew(size.x - i, y)); if (HitWall(p.x, p.y)) { return true; } } // Bottom to left for (int i = 0; i < size.x; i++) { const int y = (int)Round((size.x - i) * gradient); const Vec2i p = Vec2iAdd(pos, Vec2iNew(-i, y)); if (HitWall(p.x, p.y)) { return true; } } // Left to top for (int i = 0; i < size.x; i++) { const int y = (int)Round(-i * gradient); const Vec2i p = Vec2iAdd(pos, Vec2iNew(-size.x + i, y)); if (HitWall(p.x, p.y)) { return true; } } return false; }
static void DrawMapItem( UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { UNUSED(g); const EditorBrush *brush = vData; DisplayMapItem( Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)), brush->u.MapObject); }
void DrawKey(UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { UNUSED(g); EditorBrushAndCampaign *data = vData; PicPaletted *keyPic = PicManagerGetOldPic( &gPicManager, cGeneralPics[gMission.keyPics[data->Brush.ItemIndex]].picIndex); pos = Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)); DrawTPic(pos.x, pos.y, keyPic); }
static void DrawPickupSpawner( UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { const IndexedEditorBrush *data = vData; const MapObject *mo = data->u.MapObject; DisplayMapItem( Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)), mo); const Pic *pic = mo->u.PickupClass->Pic; pos = Vec2iMinus(pos, Vec2iScaleDiv(pic->size, 2)); Blit(g, pic, Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2))); }
void UITooltipDraw(GraphicsDevice *device, Vec2i pos, const char *s) { Vec2i bgSize = FontStrSize(s); pos = Vec2iAdd(pos, Vec2iNew(10, 10)); // add offset DrawRectangle( device, Vec2iAdd(pos, Vec2iScale(Vec2iUnit(), -TOOLTIP_PADDING)), Vec2iAdd(bgSize, Vec2iScale(Vec2iUnit(), 2 * TOOLTIP_PADDING)), bgColor, 0); FontStr(s, pos); }
static void DrawCharacter( UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { UNUSED(g); EditorBrushAndCampaign *data = vData; CharacterStore *store = &data->Campaign->Setting.characters; Character *c = CArrayGet(&store->OtherChars, data->Brush.u.ItemIndex); DrawCharacterSimple( c, Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)), DIRECTION_DOWN, false, false); }
void UITooltipDraw(GraphicsDevice *device, Vec2i pos, const char *s) { Vec2i bgSize = TextGetSize(s); pos = Vec2iAdd(pos, Vec2iNew(10, 10)); // add offset DrawRectangle( device, Vec2iAdd(pos, Vec2iScale(Vec2iUnit(), -TOOLTIP_PADDING)), Vec2iAdd(bgSize, Vec2iScale(Vec2iUnit(), 2 * TOOLTIP_PADDING)), bgColor, 0); TextString(&gTextManager, s, device, pos); }
static void DrawWreck( UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { const IndexedEditorBrush *data = vData; const char **name = CArrayGet(&gMapObjects.Destructibles, data->u.ItemIndex); const MapObject *mo = StrMapObject(*name); pos = Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)); Vec2i offset; const Pic *pic = MapObjectGetPic(mo, &offset, true); Blit(g, pic, Vec2iAdd(pos, offset)); }
void DrawKey(UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { EditorBrushAndCampaign *data = vData; if (data->Brush.ItemIndex == -1) { // No key; don't draw return; } const Pic *pic = KeyPickupClass(gMission.keyStyle, data->Brush.ItemIndex)->Pic; pos = Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)); pos = Vec2iMinus(pos, Vec2iScaleDiv(pic->size, 2)); Blit(g, pic, pos); }
void DisplayCharacter( const Vec2i pos, const Character *c, const bool hilite, const bool showGun) { DrawCharacterSimple( c, pos, DIRECTION_DOWN, STATE_IDLE, -1, GUNSTATE_READY, &c->table); if (hilite) { FontCh('>', Vec2iAdd(pos, Vec2iNew(-8, -16))); if (showGun) { FontStr(c->Gun->name, Vec2iAdd(pos, Vec2iNew(-8, 8))); } } }
bool AreasCollide( const Vec2i pos1, const Vec2i pos2, const Vec2i size1, const Vec2i size2) { const Vec2i d = Vec2iNew(abs(pos1.x - pos2.x), abs(pos1.y - pos2.y)); const Vec2i r = Vec2iAdd(size1, size2); return d.x < r.x && d.y < r.y; }
TTileItem *GetItemOnTileInCollision( TTileItem *item, Vec2i pos, int mask, CollisionTeam team, int isDogfight) { Vec2i tv = Vec2iToTile(pos); Vec2i dv; if (!MapIsTileIn(&gMap, tv)) { return NULL; } // Check collisions with all other items on this tile, in all 8 directions for (dv.y = -1; dv.y <= 1; dv.y++) { for (dv.x = -1; dv.x <= 1; dv.x++) { CArray *tileThings = &MapGetTile(&gMap, Vec2iAdd(tv, dv))->things; for (int i = 0; i < (int)tileThings->size; i++) { TTileItem *ti = ThingIdGetTileItem(CArrayGet(tileThings, i)); // Don't collide if items are on the same team if (!CollisionIsOnSameTeam(ti, team, isDogfight)) { if (item != ti && (ti->flags & mask) && ItemsCollide(item, ti, pos)) { return ti; } } } } } return NULL; }
static void DrawObjectiveHighlight( TTileItem *ti, Tile *tile, DrawBuffer *b, Vec2i offset) { color_t color; if (ti->flags & TILEITEM_OBJECTIVE) { // Objective const int objective = ObjectiveFromTileItem(ti->flags); const Objective *o = CArrayGet(&gMission.missionData->Objectives, objective); if (o->Flags & OBJECTIVE_HIDDEN) { return; } if (!(o->Flags & OBJECTIVE_POSKNOWN) && (tile->flags & MAPTILE_OUT_OF_SIGHT)) { return; } color = o->color; } else if (ti->kind == KIND_PICKUP) { // Gun pickup const Pickup *p = CArrayGet(&gPickups, ti->id); if (!PickupIsManual(p)) { return; } color = colorDarker; } else { return; } const Vec2i pos = Vec2iNew( ti->x - b->xTop + offset.x, ti->y - b->yTop + offset.y); const int pulsePeriod = ConfigGetInt(&gConfig, "Game.FPS"); int alphaUnscaled = (gMission.time % pulsePeriod) * 255 / (pulsePeriod / 2); if (alphaUnscaled > 255) { alphaUnscaled = 255 * 2 - alphaUnscaled; } color.a = (Uint8)alphaUnscaled; if (ti->getPicFunc != NULL) { Vec2i picOffset; const Pic *pic = ti->getPicFunc(ti->id, &picOffset); BlitPicHighlight( &gGraphicsDevice, pic, Vec2iAdd(pos, picOffset), color); } else if (ti->kind == KIND_CHARACTER) { TActor *a = CArrayGet(&gActors, ti->id); ActorPics pics = GetCharacterPicsFromActor(a); DrawActorHighlight(&pics, pos, color); } }
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()))); } } }
static int FindWallRun( const Map *map, const Vec2i mid, const Vec2i d, const int len) { int run = 0; int next = 0; bool plus = false; // Find the wall run by starting from a midpoint and expanding outwards in // both directions, in a series 0, 1, -1, 2, -2... for (int i = 0; i < len; i++, run++) { // Check if this is a wall so we can add a door here // Also check if the two tiles aside are not walls // Note: we must look for runs if (plus) { next += i; } else { next -= i; } const Vec2i v = Vec2iAdd(mid, Vec2iScale(d, next)); plus = !plus; if (IMapGet(map, v) != MAP_WALL || IMapGet(map, Vec2iNew(v.x + d.y, v.y + d.x)) == MAP_WALL || IMapGet(map, Vec2iNew(v.x - d.y, v.y - d.x)) == MAP_WALL) { break; } } return run; }
void CollideAllItems( const TTileItem *item, const Vec2i pos, const int mask, const CollisionTeam team, const bool isPVP, CollideItemFunc func, void *data) { const Vec2i tv = Vec2iToTile(pos); Vec2i dv; // Check collisions with all other items on this tile, in all 8 directions for (dv.y = -1; dv.y <= 1; dv.y++) { for (dv.x = -1; dv.x <= 1; dv.x++) { const Vec2i dtv = Vec2iAdd(tv, dv); if (!MapIsTileIn(&gMap, dtv)) { continue; } CArray *tileThings = &MapGetTile(&gMap, dtv)->things; for (int i = 0; i < (int)tileThings->size; i++) { TTileItem *ti = ThingIdGetTileItem(CArrayGet(tileThings, i)); // Don't collide if items are on the same team if (!CollisionIsOnSameTeam(ti, team, isPVP)) { if (item != ti && (ti->flags & mask) && ItemsCollide(item, ti, pos)) { func(ti, data); } } } } } }
void WeaponFire( Weapon *w, const direction_e d, const Vec2i pos, const int flags, const int player, const int uid) { if (w->state != GUNSTATE_FIRING && w->state != GUNSTATE_RECOIL) { WeaponSetState(w, GUNSTATE_FIRING); } if (!w->Gun->CanShoot) { return; } const double radians = dir2radians[d]; const Vec2i muzzleOffset = GunGetMuzzleOffset(w->Gun, d); const Vec2i muzzlePosition = Vec2iAdd(pos, muzzleOffset); const bool playSound = w->soundLock <= 0; GunAddBullets( w->Gun, muzzlePosition, w->Gun->MuzzleHeight, radians, flags, player, uid, playSound); if (playSound) { w->soundLock = w->Gun->SoundLockLength; } // Brass shells // If we have a reload lead, defer the creation of shells until then if (w->Gun->Brass && w->Gun->ReloadLead == 0) { AddBrass(w->Gun, d, pos); } w->lock = w->Gun->Lock; }
int AIHunt(TActor *actor, Vec2i targetPos) { Vec2i fullPos = Vec2iAdd( actor->Pos, GunGetMuzzleOffset(actor->weapon.Gun, actor->direction)); const int dx = abs(targetPos.x - fullPos.x); const int dy = abs(targetPos.y - fullPos.y); int cmd = 0; if (2 * dx > dy) { if (fullPos.x < targetPos.x) cmd |= CMD_RIGHT; else if (fullPos.x > targetPos.x) cmd |= CMD_LEFT; } if (2 * dy > dx) { if (fullPos.y < targetPos.y) cmd |= CMD_DOWN; else if (fullPos.y > targetPos.y) cmd |= CMD_UP; } // If it's a coward, reverse directions... if (actor->flags & FLAGS_RUNS_AWAY) { cmd = AIReverseDirection(cmd); } return cmd; }
static void DrawLives( const GraphicsDevice *device, const PlayerData *player, const Vec2i pos, const FontAlign hAlign, const FontAlign vAlign) { const int xStep = hAlign == ALIGN_START ? 10 : -10; const Vec2i offset = Vec2iNew(5, 20); Vec2i drawPos = Vec2iAdd(pos, offset); if (hAlign == ALIGN_END) { const int w = device->cachedConfig.Res.x; drawPos.x = w - drawPos.x - offset.x; } if (vAlign == ALIGN_END) { const int h = device->cachedConfig.Res.y; drawPos.y = h - drawPos.y + offset.y + 5; } const TOffsetPic head = GetHeadPic( BODY_ARMED, DIRECTION_DOWN, player->Char.looks.Face, STATE_IDLE); for (int i = 0; i < player->Lives; i++) { BlitOld( drawPos.x + head.dx, drawPos.y + head.dy, PicManagerGetOldPic(&gPicManager, head.picIndex), &player->Char.table, BLIT_TRANSPARENT); drawPos.x += xStep; } }
void DrawLaserSight( const ActorPics *pics, const TActor *a, const Vec2i picPos) { // Don't draw if dead or transparent if (pics->IsDead || pics->IsTransparent) return; // Check config const LaserSight ls = ConfigGetEnum(&gConfig, "Game.LaserSight"); if (ls != LASER_SIGHT_ALL && !(ls == LASER_SIGHT_PLAYERS && a->PlayerUID >= 0)) { return; } // Draw weapon indicators const GunDescription *g = ActorGetGun(a)->Gun; Vec2i muzzlePos = Vec2iAdd( picPos, Vec2iFull2Real(GunGetMuzzleOffset(g, a->direction))); muzzlePos.y -= g->MuzzleHeight / Z_FACTOR; const double radians = dir2radians[a->direction] + g->AngleOffset; const int range = GunGetRange(g); color_t color = colorCyan; color.a = 64; const double spreadHalf = (g->Spread.Count - 1) * g->Spread.Width / 2 + g->Recoil / 2; if (spreadHalf > 0) { DrawLaserSightSingle(muzzlePos, radians - spreadHalf, range, color); DrawLaserSightSingle(muzzlePos, radians + spreadHalf, range, color); } else { DrawLaserSightSingle(muzzlePos, radians, range, color); } }
void DrawCharacterSimple( Character *c, const Vec2i pos, const direction_e d, const bool hilite, const bool showGun) { ActorPics pics; GetCharacterPics( &pics, c, d, STATE_IDLE, NULL, GUNSTATE_READY, false, NULL, NULL, 0); DrawActorPics(&pics, pos, d); if (hilite) { FontCh('>', Vec2iAdd(pos, Vec2iNew(-8, -16))); if (showGun) { FontStr(c->Gun->name, Vec2iAdd(pos, Vec2iNew(-8, 8))); } } }
static void DrawObjectiveHighlight( TTileItem *ti, Tile *tile, DrawBuffer *b, Vec2i offset) { if (!(ti->flags & TILEITEM_OBJECTIVE)) { return; } int objective = ObjectiveFromTileItem(ti->flags); MissionObjective *mo = CArrayGet(&gMission.missionData->Objectives, objective); if (mo->Flags & OBJECTIVE_HIDDEN) { return; } if (!(mo->Flags & OBJECTIVE_POSKNOWN) && (tile->flags & MAPTILE_OUT_OF_SIGHT)) { return; } Vec2i pos = Vec2iNew( ti->x - b->xTop + offset.x, ti->y - b->yTop + offset.y); struct Objective *o = CArrayGet(&gMission.Objectives, objective); color_t color = o->color; int pulsePeriod = FPS_FRAMELIMIT; int alphaUnscaled = (gMission.time % pulsePeriod) * 255 / (pulsePeriod / 2); if (alphaUnscaled > 255) { alphaUnscaled = 255 * 2 - alphaUnscaled; } color.a = (Uint8)alphaUnscaled; if (ti->getPicFunc != NULL) { Vec2i picOffset; const Pic *pic = ti->getPicFunc(ti->id, &picOffset); BlitPicHighlight( &gGraphicsDevice, pic, Vec2iAdd(pos, picOffset), color); } else if (ti->getActorPicsFunc != NULL) { ActorPics pics = ti->getActorPicsFunc(ti->id); // Do not highlight dead, dying or transparent characters if (!pics.IsDead && !pics.IsTransparent) { for (int i = 0; i < 3; i++) { if (PicIsNotNone(&pics.Pics[i])) { BlitPicHighlight( &gGraphicsDevice, &pics.Pics[i], pos, color); } } } } }
void EmitterStart( Emitter *em, const Vec2i fullPos, const int z, const Vec2i vel) { const Vec2i p = Vec2iAdd(fullPos, Vec2iReal2Full(em->offset)); // TODO: single event multiple particles GameEvent e = GameEventNew(GAME_EVENT_ADD_PARTICLE); e.u.AddParticle.FullPos = p; e.u.AddParticle.Z = z * Z_FACTOR; e.u.AddParticle.Class = em->p; const int speed = RAND_INT(em->minSpeed, em->maxSpeed); const Vec2i baseVel = Vec2iFromPolar(speed, RAND_DOUBLE(0, PI * 2)); e.u.AddParticle.Vel = Vec2iAdd(vel, baseVel); e.u.AddParticle.Angle = RAND_DOUBLE(0, PI * 2); e.u.AddParticle.DZ = RAND_INT(em->minDZ, em->maxDZ); e.u.AddParticle.Spin = RAND_DOUBLE(em->minRotation, em->maxRotation); GameEventsEnqueue(&gGameEvents, e); }
static void DrawLaserSightSingle( const Vec2i from, const double radians, const int range, const color_t color) { double x, y; GetVectorsForRadians(radians, &x, &y); const Vec2i to = Vec2iAdd( from, Vec2iNew((int)round(x * range), (int)round(y * range))); DrawLine(from, to, color); }
static void DrawObjective( UIObject *o, GraphicsDevice *g, Vec2i pos, void *vData) { UNUSED(g); EditorBrushAndCampaign *data = vData; Mission *m = CampaignGetCurrentMission(data->Campaign); const Objective *obj = CArrayGet(&m->Objectives, data->Brush.u.ItemIndex); CharacterStore *store = &data->Campaign->Setting.characters; pos = Vec2iAdd(Vec2iAdd(pos, o->Pos), Vec2iScaleDiv(o->Size, 2)); switch (obj->Type) { case OBJECTIVE_KILL: { Character *c = CArrayGet( &store->OtherChars, CharacterStoreGetSpecialId(store, data->Brush.Index2)); DrawCharacterSimple(c, pos, DIRECTION_DOWN, false, false); } break; case OBJECTIVE_RESCUE: { Character *c = CArrayGet( &store->OtherChars, CharacterStoreGetPrisonerId(store, data->Brush.Index2)); DrawCharacterSimple(c, pos, DIRECTION_DOWN, false, false); } break; case OBJECTIVE_COLLECT: { const Pic *p = obj->u.Pickup->Pic; pos = Vec2iMinus(pos, Vec2iScaleDiv(p->size, 2)); Blit(&gGraphicsDevice, p, pos); } break; case OBJECTIVE_DESTROY: DisplayMapItem(pos, obj->u.MapObject); break; default: assert(0 && "invalid objective type"); break; } }
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); }