const Pic *GetObjectPic(const int id, Vec2i *offset) { const TObject *obj = CArrayGet(&gObjs, id); Pic *pic = NULL; // Try to get new pic if available if (obj->picName && obj->picName[0] != '\0') { pic = PicManagerGetPic(&gPicManager, obj->picName); } // Use new pic offset if old one unavailable const TOffsetPic *ofpic = obj->pic; if (!ofpic) { // If new one also unavailable, bail if (pic == NULL) { return NULL; } *offset = Vec2iScaleDiv(pic->size, -2); } else if (pic == NULL) { // Default old pic pic = PicManagerGetFromOld(&gPicManager, ofpic->picIndex); *offset = pic->offset; } if (ofpic != NULL) { *offset = Vec2iNew(ofpic->dx, ofpic->dy); } return pic; }
static void LoadGunSpawners(CArray *classes, const CArray *guns) { for (int i = 0; i < (int)guns->size; i++) { const GunDescription *g = CArrayGet(guns, i); if (!g->IsRealGun) { continue; } MapObject m; memset(&m, 0, sizeof m); char buf[256]; sprintf(buf, "%s spawner", g->name); CSTRDUP(m.Name, buf); m.Normal.Pic = PicManagerGetPic(&gPicManager, "spawn_pad"); m.Normal.Offset = Vec2iNew( -m.Normal.Pic->size.x / 2, TILE_HEIGHT / 2 - m.Normal.Pic->size.y); m.Size = Vec2iNew(TILE_WIDTH, TILE_HEIGHT); m.Health = 0; m.Type = MAP_OBJECT_TYPE_PICKUP_SPAWNER; sprintf(buf, "gun_%s", g->name); m.u.PickupClass = StrPickupClass(buf); CArrayPushBack(classes, &m); } }
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; } }
void LoadPic(const Pic **value, json_t *node, const char *name) { if (json_find_first_label(node, name)) { char *tmp = GetString(node, name); *value = PicManagerGetPic(&gPicManager, tmp); CFREE(tmp); } }
static void LoadAmmo(Ammo *a, json_t *node) { a->Name = GetString(node, "Name"); char *tmp; tmp = GetString(node, "Pic"); a->Pic = PicManagerGetPic(&gPicManager, tmp); CFREE(tmp); a->Sound = GetString(node, "Sound"); LoadInt(&a->Amount, node, "Amount"); LoadInt(&a->Max, node, "Max"); }
static void LoadOldPic( PicManager *pm, const char *name, const TOffsetPic *pic) { // Don't use old pics if new ones are available if (PicManagerGetPic(pm, name) != NULL) { return; } NamedPic p; CSTRDUP(p.name, name); const Pic *original = PicManagerGetFromOld(pm, pic->picIndex); PicCopy(&p.pic, original); CArrayPushBack(&pm->pics, &p); }
void LoadPic( const Pic **value, json_t *node, const char *name, const char *oldPicName) { if (json_find_first_label(node, name)) { char *tmp = GetString(node, name); *value = PicManagerGetPic(&gPicManager, tmp); CFREE(tmp); } if ((*value == NULL || ConfigGetBool(&gConfig, "Graphics.OriginalPics")) && json_find_first_label(node, oldPicName)) { int oldPic; LoadInt(&oldPic, node, oldPicName); *value = PicManagerGetFromOld(&gPicManager, oldPic); } }
static void SetupSpawner( MapObject *m, const char *spawnerName, const char *pickupClassName) { memset(m, 0, sizeof *m); CSTRDUP(m->Name, spawnerName); m->Pic.Type = PICTYPE_NORMAL; m->Pic.u.Pic = PicManagerGetPic(&gPicManager, "spawn_pad"); m->Pic.UseMask = true; m->Pic.u1.Mask = colorWhite; const Vec2i size = CPicGetSize(&m->Pic); m->Offset = Vec2iNew(-size.x / 2, TILE_HEIGHT / 2 - size.y); m->Size = TILE_SIZE; m->Health = 0; m->DrawLast = true; m->Type = MAP_OBJECT_TYPE_PICKUP_SPAWNER; m->u.PickupClass = StrPickupClass(pickupClassName); }
static void LoadAmmoSpawners(CArray *classes, const CArray *ammo) { for (int i = 0; i < (int)ammo->size; i++) { const Ammo *a = CArrayGet(ammo, i); MapObject m; memset(&m, 0, sizeof m); char buf[256]; sprintf(buf, "%s spawner", a->Name); CSTRDUP(m.Name, buf); m.Normal.Pic = PicManagerGetPic(&gPicManager, "spawn_pad"); m.Normal.Offset = Vec2iNew( -m.Normal.Pic->size.x / 2, TILE_HEIGHT / 2 - m.Normal.Pic->size.y); m.Size = Vec2iNew(TILE_WIDTH, TILE_HEIGHT); m.Health = 0; m.Type = MAP_OBJECT_TYPE_PICKUP_SPAWNER; sprintf(buf, "ammo_%s", a->Name); m.u.PickupClass = StrPickupClass(buf); CArrayPushBack(classes, &m); } }
Pic *PicManagerGet(PicManager *pm, const char *name, const int oldIdx) { Pic *pic; if (!name || name[0] == '\0' || gConfig.Graphics.OriginalPics) { goto defaultPic; } pic = PicManagerGetPic(pm, name); if (!pic) { goto defaultPic; } return pic; defaultPic: pic = PicManagerGetFromOld(pm, oldIdx); CASSERT(pic != NULL, "Cannot find pic"); if (pic == NULL) { pic = PicManagerGetFromOld(pm, PIC_UZIBULLET); } return pic; }
static void DrawCompassArrow( GraphicsDevice *g, Rect2i r, Vec2i pos, Vec2i playerPos, color_t mask, const char *label) { Vec2i compassV = Vec2iMinus(pos, playerPos); // Don't draw if objective is on screen if (abs(pos.x - playerPos.x) < r.Size.x / 2 && abs(pos.y - playerPos.y) < r.Size.y / 2) { return; } Vec2i textPos = Vec2iZero(); // Find which edge of screen is the best bool hasDrawn = false; if (compassV.x != 0) { double sx = r.Size.x / 2.0 / compassV.x; int yInt = (int)floor(fabs(sx) * compassV.y + 0.5); if (yInt >= -r.Size.y / 2 && yInt <= r.Size.y / 2) { // Intercepts either left or right side hasDrawn = true; if (compassV.x > 0) { // right edge textPos = Vec2iNew( r.Pos.x + r.Size.x, r.Pos.y + r.Size.y / 2 + yInt); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_right"); Vec2i drawPos = Vec2iNew( textPos.x - p->size.x, textPos.y - p->size.y / 2); BlitMasked(g, p, drawPos, mask, true); } else if (compassV.x < 0) { // left edge textPos = Vec2iNew(r.Pos.x, r.Pos.y + r.Size.y / 2 + yInt); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_left"); Vec2i drawPos = Vec2iNew(textPos.x, textPos.y - p->size.y / 2); BlitMasked(g, p, drawPos, mask, true); } } } if (!hasDrawn && compassV.y != 0) { double sy = r.Size.y / 2.0 / compassV.y; int xInt = (int)floor(fabs(sy) * compassV.x + 0.5); if (xInt >= -r.Size.x / 2 && xInt <= r.Size.x / 2) { // Intercepts either top or bottom side if (compassV.y > 0) { // bottom edge textPos = Vec2iNew( r.Pos.x + r.Size.x / 2 + xInt, r.Pos.y + r.Size.y); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_down"); Vec2i drawPos = Vec2iNew( textPos.x - p->size.x / 2, textPos.y - p->size.y); BlitMasked(g, p, drawPos, mask, true); } else if (compassV.y < 0) { // top edge textPos = Vec2iNew(r.Pos.x + r.Size.x / 2 + xInt, r.Pos.y); const Pic *p = PicManagerGetPic(&gPicManager, "arrow_up"); Vec2i drawPos = Vec2iNew(textPos.x - p->size.x / 2, textPos.y); BlitMasked(g, p, drawPos, mask, true); } } } if (label && strlen(label) > 0) { Vec2i textSize = FontStrSize(label); // Center the text around the target position textPos.x -= textSize.x / 2; textPos.y -= textSize.y / 2; // Make sure the text is inside the screen int padding = 8; textPos.x = MAX(textPos.x, r.Pos.x + padding); textPos.x = MIN(textPos.x, r.Pos.x + r.Size.x - textSize.x - padding); textPos.y = MAX(textPos.y, r.Pos.y + padding); textPos.y = MIN(textPos.y, r.Pos.y + r.Size.y - textSize.y - padding); FontStrMask(label, textPos, mask); } }
UIObject *CreateStaticMapObjs( Vec2i pos, CampaignOptions *co, EditorBrush *brush) { int x = pos.x; const int th = FontH(); UIObject *c = UIObjectCreate(UITYPE_NONE, 0, Vec2iZero(), Vec2iZero()); UIObject *o2; // Check whether the map type matches, and set visibility c->CheckVisible = MissionCheckTypeStatic; c->Data = co; UIObject *o = UIObjectCreate(UITYPE_BUTTON, 0, Vec2iZero(), Vec2iZero()); o->Data = brush; o->OnFocusFunc = ActivateBrush; o->OnUnfocusFunc = DeactivateBrush; o->ChangesData = false; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/pencil")); o2->u.Button.IsDownFunc = BrushIsBrushTypePoint; o2->ChangeFunc = BrushSetBrushTypePoint; CSTRDUP(o2->Tooltip, "Point"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/line")); o2->u.Button.IsDownFunc = BrushIsBrushTypeLine; o2->ChangeFunc = BrushSetBrushTypeLine; CSTRDUP(o2->Tooltip, "Line"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/box")); o2->u.Button.IsDownFunc = BrushIsBrushTypeBox; o2->ChangeFunc = BrushSetBrushTypeBox; CSTRDUP(o2->Tooltip, "Box"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/box_filled")); o2->u.Button.IsDownFunc = BrushIsBrushTypeBoxFilled; o2->ChangeFunc = BrushSetBrushTypeBoxFilled; CSTRDUP(o2->Tooltip, "Box filled"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/room")); o2->u.Button.IsDownFunc = BrushIsBrushTypeRoom; o2->ChangeFunc = BrushSetBrushTypeRoom; CSTRDUP(o2->Tooltip, "Room"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/select")); o2->u.Button.IsDownFunc = BrushIsBrushTypeSelect; o2->ChangeFunc = BrushSetBrushTypeSelect; CSTRDUP(o2->Tooltip, "Select and move"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/bucket")); o2->u.Button.IsDownFunc = BrushIsBrushTypeFill; o2->ChangeFunc = BrushSetBrushTypeFill; o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/add")); o2->u.Button.IsDownFunc = BrushIsBrushTypeAddItem; CSTRDUP(o2->Tooltip, "Add items\nRight click to remove"); o2->Pos = pos; o2->OnFocusFunc = NULL; o2->OnUnfocusFunc = NULL; UIObjectAddChild(o2, CreateAddItemObjs(o2->Size, brush, co)); UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/set_key")); o2->u.Button.IsDownFunc = BrushIsBrushTypeSetKey; CSTRDUP(o2->Tooltip, "Set key required for door"); o2->Pos = pos; o2->OnFocusFunc = NULL; o2->OnUnfocusFunc = NULL; UIObjectAddChild(o2, CreateSetKeyObjs(o2->Size, brush)); UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); UIButtonSetPic(o2, PicManagerGetPic(&gPicManager, "editor/set_exit")); o2->u.Button.IsDownFunc = BrushIsBrushTypeSetExit; o2->ChangeFunc = BrushSetBrushTypeSetExit; CSTRDUP(o2->Tooltip, "Set exit area (box drag)"); o2->Pos = pos; UIObjectAddChild(c, o2); UIObjectDestroy(o); o = UIObjectCreate( UITYPE_LABEL, 0, Vec2iZero(), Vec2iNew(60, th)); pos.x = x; pos.y += o2->Size.y; o2 = UIObjectCopy(o); o2->u.LabelFunc = BrushGetMainTypeStr; o2->Data = brush; o2->ChangeFunc = BrushChangeMainType; o2->OnFocusFunc = ActivateBrush; o2->OnUnfocusFunc = DeactivateBrush; CSTRDUP(o2->Tooltip, "Left click to paint the map with this tile type"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x += o2->Size.x; o2 = UIObjectCopy(o); o2->u.LabelFunc = BrushGetSecondaryTypeStr; o2->Data = brush; o2->ChangeFunc = BrushChangeSecondaryType; o2->OnFocusFunc = ActivateBrush; o2->OnUnfocusFunc = DeactivateBrush; CSTRDUP(o2->Tooltip, "Right click to paint the map with this tile type"); o2->Pos = pos; UIObjectAddChild(c, o2); pos.x = x; pos.y += th; o2 = UIObjectCopy(o); o2->u.LabelFunc = BrushGetSizeStr; o2->Data = brush; o2->ChangeFunc = BrushChangeSize; o2->OnFocusFunc = ActivateBrush; o2->OnUnfocusFunc = DeactivateBrush; o2->Pos = pos; UIObjectAddChild(c, o2); UIObjectDestroy(o); o = UIObjectCreate(UITYPE_TEXTBOX, 0, Vec2iZero(), Vec2iNew(100, th)); pos.x = x; pos.y += th; o2 = UIObjectCopy(o); o2->u.Textbox.TextLinkFunc = BrushGetGuideImageStr; o2->u.Textbox.MaxLen = sizeof((EditorBrush *)0)->GuideImage - 1; o2->Data = brush; o2->ChangesData = 0; o2->ChangeFunc = BrushLoadGuideImage; CSTRDUP(o2->u.Textbox.Hint, "(Tracing guide image)"); o2->Pos = pos; UIObjectAddChild(c, o2); UIObjectDestroy(o); o = UIObjectCreate(UITYPE_LABEL, 0, Vec2iZero(), Vec2iNew(100, th)); pos.x = x; pos.y += th; o2 = UIObjectCopy(o); o2->u.LabelFunc = BrushGetGuideImageAlphaStr; o2->Data = brush; o2->ChangeFunc = BrushChangeGuideImageAlpha; o2->Pos = pos; UIObjectAddChild(c, o2); UIObjectDestroy(o); return c; }
static void LoadBullet( BulletClass *b, json_t *node, const BulletClass *defaultBullet) { memset(b, 0, sizeof *b); if (defaultBullet != NULL) { memcpy(b, defaultBullet, sizeof *b); if (defaultBullet->HitSound.Object != NULL) { CSTRDUP(b->HitSound.Object, defaultBullet->HitSound.Object); } if (defaultBullet->HitSound.Flesh != NULL) { CSTRDUP(b->HitSound.Flesh, defaultBullet->HitSound.Flesh); } if (defaultBullet->HitSound.Wall != NULL) { CSTRDUP(b->HitSound.Wall, defaultBullet->HitSound.Wall); } // TODO: enable default bullet guns? memset(&b->Falling.DropGuns, 0, sizeof b->Falling.DropGuns); memset(&b->OutOfRangeGuns, 0, sizeof b->OutOfRangeGuns); memset(&b->HitGuns, 0, sizeof b->HitGuns); memset(&b->ProximityGuns, 0, sizeof b->ProximityGuns); } char *tmp; LoadStr(&b->Name, node, "Name"); if (json_find_first_label(node, "Pic")) { json_t *pic = json_find_first_label(node, "Pic")->child; tmp = GetString(pic, "Type"); b->CPic.Type = StrPicType(tmp); CFREE(tmp); bool picLoaded = false; switch (b->CPic.Type) { case PICTYPE_NORMAL: tmp = GetString(pic, "Pic"); b->CPic.u.Pic = PicManagerGetPic(&gPicManager, tmp); CFREE(tmp); picLoaded = b->CPic.u.Pic != NULL; break; case PICTYPE_DIRECTIONAL: tmp = GetString(pic, "Sprites"); b->CPic.u.Sprites = &PicManagerGetSprites(&gPicManager, tmp)->pics; CFREE(tmp); picLoaded = b->CPic.u.Sprites != NULL; break; case PICTYPE_ANIMATED: // fallthrough case PICTYPE_ANIMATED_RANDOM: tmp = GetString(pic, "Sprites"); b->CPic.u.Animated.Sprites = &PicManagerGetSprites(&gPicManager, tmp)->pics; CFREE(tmp); LoadInt(&b->CPic.u.Animated.Count, pic, "Count"); LoadInt(&b->CPic.u.Animated.TicksPerFrame, pic, "TicksPerFrame"); // Set safe default ticks per frame 1; // if 0 then this leads to infinite loop when animating b->CPic.u.Animated.TicksPerFrame = MAX( b->CPic.u.Animated.TicksPerFrame, 1); picLoaded = b->CPic.u.Animated.Sprites != NULL; break; default: CASSERT(false, "unknown pic type"); break; } b->CPic.UseMask = true; b->CPic.u1.Mask = colorWhite; if (json_find_first_label(pic, "Mask")) { tmp = GetString(pic, "Mask"); b->CPic.u1.Mask = StrColor(tmp); CFREE(tmp); } else if (json_find_first_label(pic, "Tint")) { b->CPic.UseMask = false; json_t *tint = json_find_first_label(pic, "Tint")->child->child; b->CPic.u1.Tint.h = atof(tint->text); tint = tint->next; b->CPic.u1.Tint.s = atof(tint->text); tint = tint->next; b->CPic.u1.Tint.v = atof(tint->text); } if ((json_find_first_label(pic, "OldPic") && ConfigGetBool(&gConfig, "Graphics.OriginalPics")) || !picLoaded) { int oldPic = PIC_UZIBULLET; LoadInt(&oldPic, pic, "OldPic"); b->CPic.Type = PICTYPE_NORMAL; b->CPic.u.Pic = PicManagerGetFromOld(&gPicManager, oldPic); } } LoadVec2i(&b->ShadowSize, node, "ShadowSize"); LoadInt(&b->Delay, node, "Delay"); if (json_find_first_label(node, "Speed")) { LoadInt(&b->SpeedLow, node, "Speed"); b->SpeedHigh = b->SpeedLow; } if (json_find_first_label(node, "SpeedLow")) { LoadInt(&b->SpeedLow, node, "SpeedLow"); } if (json_find_first_label(node, "SpeedHigh")) { LoadInt(&b->SpeedHigh, node, "SpeedHigh"); } b->SpeedLow = MIN(b->SpeedLow, b->SpeedHigh); b->SpeedHigh = MAX(b->SpeedLow, b->SpeedHigh); LoadBool(&b->SpeedScale, node, "SpeedScale"); LoadInt(&b->Friction, node, "Friction"); if (json_find_first_label(node, "Range")) { LoadInt(&b->RangeLow, node, "Range"); b->RangeHigh = b->RangeLow; } if (json_find_first_label(node, "RangeLow")) { LoadInt(&b->RangeLow, node, "RangeLow"); } if (json_find_first_label(node, "RangeHigh")) { LoadInt(&b->RangeHigh, node, "RangeHigh"); } b->RangeLow = MIN(b->RangeLow, b->RangeHigh); b->RangeHigh = MAX(b->RangeLow, b->RangeHigh); LoadInt(&b->Power, node, "Power"); LoadVec2i(&b->Size, node, "Size"); if (json_find_first_label(node, "Special")) { tmp = GetString(node, "Special"); b->Special = StrSpecialDamage(tmp); CFREE(tmp); } LoadBool(&b->HurtAlways, node, "HurtAlways"); LoadBool(&b->Persists, node, "Persists"); if (json_find_first_label(node, "Spark")) { tmp = GetString(node, "Spark"); b->Spark = StrParticleClass(&gParticleClasses, tmp); CFREE(tmp); } if (json_find_first_label(node, "HitSounds")) { json_t *hitSounds = json_find_first_label(node, "HitSounds")->child; CFREE(b->HitSound.Object); b->HitSound.Object = NULL; LoadStr(&b->HitSound.Object, hitSounds, "Object"); CFREE(b->HitSound.Flesh); b->HitSound.Flesh = NULL; LoadStr(&b->HitSound.Flesh, hitSounds, "Flesh"); CFREE(b->HitSound.Wall); b->HitSound.Wall = NULL; LoadStr(&b->HitSound.Wall, hitSounds, "Wall"); } LoadBool(&b->WallBounces, node, "WallBounces"); LoadBool(&b->HitsObjects, node, "HitsObjects"); if (json_find_first_label(node, "Falling")) { json_t *falling = json_find_first_label(node, "Falling")->child; LoadInt(&b->Falling.GravityFactor, falling, "GravityFactor"); LoadBool(&b->Falling.FallsDown, falling, "FallsDown"); LoadBool(&b->Falling.DestroyOnDrop, falling, "DestroyOnDrop"); LoadBool(&b->Falling.Bounces, falling, "Bounces"); } LoadInt(&b->SeekFactor, node, "SeekFactor"); LoadBool(&b->Erratic, node, "Erratic"); b->node = node; }