// Hyperbolic Rogue -- item graphics file // Copyright (C) 2011-2025 Zeno Rogue, see 'hyper.cpp' for details #include "hyper.h" namespace hr { EX shiftmatrix face_the_player(const shiftmatrix V) { if(GDIM == 2) return V; if(mproduct) return bobbing ? orthogonal_move(V, cos(ptick(750)) * cgi.plevel / 16) : V; if(mhybrid) return bobbing ? V * zpush(cos(ptick(750)) * cgi.plevel / 16) : V; transmatrix dummy; /* used only in prod anyways */ if(embedded_plane && !cgi.emb->is_same_in_same()) return V; if(nonisotropic) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0)); #if CAP_VR if(vrhr::enabled) { shiftpoint h = tC0(V); hyperpoint uh = unshift(h); return shiftless(cspin90(1, 2) * rspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270()); } #endif return rgpushxto0(tC0(V)); } EX hpcshape& orbshape(eOrbshape s) { if(vid.orbmode == 0) return cgi.shRing; switch(s) { case osLove: return cgi.shLoveRing; case osRanged: return cgi.shTargetRing; case osOffensive: return cgi.shSawRing; case osDirectional: return vid.orbmode == 2 ? cgi.shSawRing : cgi.shSpearRing; case osFriend: return cgi.shPeaceRing; case osUtility: return cgi.shGearRing; case osPowerUtility: return cgi.shPowerGearRing; case osWarping: return cgi.shHeptaRing; case osFrog: return cgi.shFrogRing; case osProtective: return cgi.shProtectiveRing; case osTerraform: return cgi.shTerraRing; case osMovement: return cgi.shMoveRing; default: return cgi.shRing; } } EX void queue_ring(const shiftmatrix& V, hpcshape& sh, color_t col, PPR p) { queuepolyat(V, sh, col, p).outline = 0; auto& p1 = queuepolyat(V, sh, col, p); p1.cnt = cgi.orb_inner_ring; p1.color = 0; auto& p2 = queuepolyat(V, sh, col, p); p2.color = 0; p2.offset += cgi.orb_inner_ring; p2.cnt -= cgi.orb_inner_ring + 1; } EX color_t orb_auxiliary_color(eItem it) { if(it == itOrbFire) return firecolor(200); if(it == itOrbWater) return 0x000060; if(it == itOrbFriend || it == itOrbDiscord) return 0xC0C0C0; if(it == itOrbFrog) return 0xFF0000; if(it == itOrbImpact) return 0xFF0000; if(it == itOrbPhasing) return 0xFF0000; if(it == itOrbDash) return 0xFF0000; if(it == itOrbFreedom) return 0xC0FF00; if(it == itOrbPlague) return 0x409040; if(it == itOrbChaos) return 0xFF00FF; if(it == itOrbAir) return 0xFFFFFF; if(it == itOrbUndeath) return minf[moFriendlyGhost].color; if(it == itOrbRecall) return 0x101010; if(it == itOrbLife) return 0x90B090; if(it == itOrbSlaying) return 0xFF0000; if(it == itOrbSide1) return 0x307080; if(it == itOrbDigging) return 0x606060; if(it == itOrbEnergy) return 0xFFFF80; return iinf[it].color; } EX color_t orb_inner_color(eItem it) { if(it == itOrbWater) return 0x0070C0; if(it == itOrbEnergy) return 0x8B4513; // if(it == itOrbDash) return 0xFF0000; if(it == itOrbSide1) return 0x00FF00; // if(it == itOrbPhasing) return 0xFF0000; if(it == itOrbDigging) return 0x00FF00; if(it == itOrbLife) return 0x306000; return iinf[it].color; } EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int pticks, bool hidden) { if(!it) return false; char xch = iinf[it].glyph; #if MAXMDIM >= 4 if(c && GDIM == 3) addradar(V, xch, icol, kind_outline(it)); #endif if(WDIM == 3 && c == centerover && in_perspective() && hdist0(tC0(V)) < cgi.orbsize * 0.25) return false; if(!mmitem || !CAP_SHAPES) { draw_ascii_or_zh(V, iinf[it].glyph, iinf[it].name, icol, 1, 0.5); return true; } #if CAP_SHAPES auto sinptick = [c, pticks] (int period) { return c ? sintick(period) : sin(animation_factor * vid.ispeed * pticks / period);}; auto spinptick = [c, pticks] (int period, ld phase) { return c ? spintick(period, phase) : spin((animation_factor * vid.ispeed * pticks) / period + phase * TAU); }; int ct6 = c ? ctof(c) : 1; hpcshape *xsh = (it == itPirate || it == itKraken) ? &cgi.shPirateX : (it == itBuggy || it == itBuggy2) ? &cgi.shPirateX : it == itHolyGrail ? &cgi.shGrail : isElementalShard(it) ? &cgi.shElementalShard : (it == itBombEgg || it == itTrollEgg || it == itCursed) ? &cgi.shEgg : (it == itFrog || it == itWhirlpool) ? &cgi.shDisk : it == itHunting ? &cgi.shTriangle : (it == itDodeca || it == itDice) ? &cgi.shDodeca : xch == '*' ? &cgi.shGem[ct6] : xch == '(' ? &cgi.shKnife : it == itShard ? &cgi.shMFloor.b[0] : it == itTreat ? &cgi.shTreat : it == itSlime ? &cgi.shEgg : xch == '%' ? &cgi.shDaisy : xch == '$' ? &cgi.shStar : xch == ';' ? &cgi.shTriangle : xch == '!' ? &cgi.shTriangle : it == itBone ? &cgi.shNecro : it == itStatue ? &cgi.shStatue : among(it, itIvory, itEclectic) ? &cgi.shFigurine : xch == '?' ? &cgi.shBookCover : it == itKey ? &cgi.shKey : it == itRevolver ? &cgi.shGun : NULL; if(c && doHighlight()) poly_outline = kind_outline(it); shiftmatrix Vit = V; if(embedded_plane && c && it != itBabyTortoise) Vit = orthogonal_move_fol(V, cgi.STUFF); if(c && mproduct) Vit = orthogonal_move(Vit, sin(ptick(750)) * cgi.plevel / 4); else if(c && sl2 && !embedded_plane) Vit = Vit * zpush(sin(ptick(750)) * cgi.plevel / 4); else if(GDIM == 3 && c && it != itBabyTortoise) Vit = face_the_player(Vit); // V * cspin(0, 2, ptick(618, 0)); #if CAP_SHAPES if(mapeditor::drawUserShape(Vit, mapeditor::sgItem, it, darkena(icol, 0, 0xFF), c)) return true; #endif if(c && history::includeHistory && history::infindhistory.count(c)) poly_outline = OUTLINE_DEAD; else if(it == itSavedPrincess) { drawMonsterType(moPrincess, c, V, icol, 0, icol); return true; } else if(it == itStrongWind) { queuepoly(Vit * spinptick(750, 0), cgi.shFan, darkena(icol, 0, 255)); } else if(it == itFatigue) { queuepoly(Vit * spinptick(750, 0), cgi.shFan, darkena(icol, 0, 255)); } else if(it == itWarning) { queuepoly(Vit * spinptick(750, 0), cgi.shTriangle, darkena(icol, 0, 255)); } else if(it == itCrossbow) { queuepoly(Vit, cgi.shCrossbowIcon, getcs().bowcolor); queuepoly(Vit, cgi.shCrossbowstringIcon, getcs().bowcolor2); } else if(it == itBabyTortoise) { int bits = c ? tortoise::babymap[c] : tortoise::last; int over = c && c->monst == moTortoise; tortoise::draw(Vit * spinptick(5000, 0) * ypush(cgi.crossf*.15), bits, over ? 4 : 2, 0); // queuepoly(Vit, cgi.shHeptaMarker, darkena(tortoise::getMatchColor(bits), 0, 0xC0)); } else if(it == itCompass) { shiftmatrix V2; #if CAP_CRYSTAL if(cryst) { if(crystal::compass_probability <= 0) return true; if(cwt.at->land == laCamelot && celldistAltRelative(cwt.at) < 0) crystal::used_compass_inside = true; V2 = V * spin(crystal::compass_angle() + M_PI); } else #endif if(1) { shiftpoint P1; if(mark_compass(c, P1)) { V2 = V * lrspintox(inverse_shift(V, P1)); } else V2 = V; } if(GDIM == 3) { queue_ring(Vit, cgi.shRing, 0xFFFFFFFF, PPR::ITEM); if(WDIM == 2) V2 = orthogonal_move_fol(V2, cgi.STUFF); V2 = V2 * cspin(1, 2, M_PI * sintick(100) / 39); queuepoly(V2, cgi.shCompass3, 0xFF0000FF); queuepoly(V2 * lpispin(), cgi.shCompass3, 0x000000FF); } else { if(c) V2 = V2 * spin(M_PI * sintick(100) / 30); color_t hider = hidden ? 0xFFFFFF20 : 0xFFFFFFFF; queuepoly(V2, cgi.shCompass1, 0xFF8080FF & hider); queuepoly(V2, cgi.shCompass2, 0xFFFFFFFF & hider); queuepoly(V2, cgi.shCompass3, 0xFF0000FF & hider); queuepoly(V2 * lpispin(), cgi.shCompass3, 0x000000FF & hider); } xsh = NULL; } else if(it == itPalace) { #if MAXMDIM >= 4 if(GDIM == 3 && WDIM == 2) { ld h = cgi.human_height; dynamicval qfi2(qfi, qfi); shiftmatrix V2 = V * spin(pticks * vid.ispeed / 1500.); /* divisors should be higher than in plate renderer */ qfi.fshape = &cgi.shMFloor2; draw_shapevec(c, V2 * lzpush(-h/30), qfi.fshape->levels[SIDE::FLOOR], 0xFFD500FF, PPR::WALL); qfi.fshape = &cgi.shMFloor3; draw_shapevec(c, V2 * lzpush(-h/25), qfi.fshape->levels[SIDE::FLOOR], darkena(icol, 0, 0xFF), PPR::WALL); qfi.fshape = &cgi.shMFloor4; draw_shapevec(c, V2 * lzpush(-h/20), qfi.fshape->levels[SIDE::FLOOR], 0xFFD500FF, PPR::WALL); } else if(WDIM == 3 && c) { ld h = cgi.human_height; shiftmatrix V2 = Vit * spin(pticks * vid.ispeed / 1500.); draw_floorshape(c, V2 * lzpush(h/100), cgi.shMFloor3, 0xFFD500FF); draw_floorshape(c, V2 * lzpush(h/50), cgi.shMFloor4, darkena(icol, 0, 0xFF)); queuepoly(V2, cgi.shGem[ct6], 0xFFD500FF); } else if(WDIM == 3 && !c) { queuepoly(Vit, cgi.shGem[ct6], 0xFFD500FF); } else #endif { color_t hider = hidden ? 0xFFFFFF20 : 0xFFFFFFFF; shiftmatrix V2 = Vit * spin(pticks * vid.ispeed / 1500.); draw_floorshape(c, V2, cgi.shMFloor3, 0xFFD500FF & hider); draw_floorshape(c, V2, cgi.shMFloor4, darkena(icol, 0, 0xFF) & hider); queuepoly(V2, cgi.shGem[ct6], 0xFFD500FF & hider); } xsh = NULL; } else if(it == itRose) { for(int u=0; u<4; u++) queuepoly(Vit * spinptick(1500, 0) * spin(30._deg * u), cgi.shRoseItem, darkena(icol, 0, hidden ? 0x30 : 0xA0)); } else if(it == itBarrow && c) { for(int i = 0; i