diff --git a/config.cpp b/config.cpp index 1c2c83ba..3d3c28ef 100644 --- a/config.cpp +++ b/config.cpp @@ -997,11 +997,7 @@ EX string csnameid(int id) { if(id == 1) return XLAT("female"); if(id == 2) return XLAT("Prince"); if(id == 3) return XLAT("Princess"); - if(id == 4 || id == 5) return XLAT("cat"); - if(id == 6 || id == 7) return XLAT("dog"); - if(id == 8 || id == 9) return XLATN("Familiar"); - if(id == 10 || id == 11) return XLATN("spaceship"); - return XLAT("none"); + return XLAT(playershapes[id >> 1].name); } EX string csname(charstyle& cs) { @@ -3566,6 +3562,29 @@ EX void switchcolor(unsigned int& c, unsigned int* cs) { double cc_footphase; int lmousex, lmousey; +EX void pick_player_shape() { + cmode = sm::SIDE | sm::MAYDARK; + gamescreen(); + dialog::init(XLAT("Choose character")); + charstyle& cs = getcs(); + for(int i=0; i>1), 'a'+i); + dialog::add_action([i, &cs] { + if(i == pshPrincess) { + if(!princess::everSaved && !autocheat && !unlock_all) { + addMessage(XLAT("Save %the1 first!", moPrincess)); + return; + } + } + cs.charid = (cs.charid & 1) | (i << 1); + }); + } + dialog::addSelItem("variant", XLAT((cs.charid & 1) ? "female" : "male"), 'x'); + dialog::add_action([&cs] { cs.charid ^= 1; }); + dialog::addBack(); + dialog::display(); + } + EX void showCustomizeChar() { cc_footphase += hypot(mousex - lmousex, mousey - lmousey); @@ -3577,6 +3596,7 @@ EX void showCustomizeChar() { if(shmup::on || multi::players) multi::cpid = multi::cpid_edit % multi::players; charstyle& cs = getcs(); + auto id = ePlayershape(cs.charid >> 1); dialog::addSelItem(XLAT("character"), csname(cs), 'g'); dialog::addColorItem(XLAT("skin color"), cs.skincolor, 's'); @@ -3588,7 +3608,7 @@ EX void showCustomizeChar() { dialog::addColorItem(XLAT("bowstring color"), cs.bowcolor2, 'c'); } - if(cs.charid >= 1) dialog::addColorItem(XLAT("dress color"), cs.dresscolor, 'd'); + if(id != pshRogue) dialog::addColorItem(XLAT("dress color"), cs.dresscolor, 'd'); else dialog::addBreak(100); if(cs.charid == 3) dialog::addColorItem(XLAT("dress color II"), cs.dresscolor2, 'f'); else dialog::addBreak(100); @@ -3624,11 +3644,7 @@ EX void showCustomizeChar() { charstyle& cs = getcs(); bool cat = cs.charid >= 4; if(uni == 'a') { multi::cpid_edit++; multi::cpid_edit %= 60; } - else if(uni == 'g') { - cs.charid++; - if(cs.charid == 2 && !princess::everSaved && !autocheat) cs.charid = 4; - cs.charid %= 12; - } + else if(uni == 'g') pushScreen(pick_player_shape); else if(uni == 'p') vid.samegender = !vid.samegender; else if(uni == 's') switchcolor(cs.skincolor, cat ? haircolors : skincolors); else if(uni == 'h') switchcolor(cs.haircolor, haircolors); @@ -4471,10 +4487,19 @@ EX void set_char_by_name(charstyle& cs, const string& s) { cs.eyecolor = 0x500040FF; cs.swordcolor = 0x808080FF; } + else if(s == "felix") { + cs.charid = 12; + cs.skincolor = 0xD0D0D0FF; + cs.haircolor = 0xF0F0F0FF; + cs.dresscolor =0xF0F0F0FF; + cs.eyecolor = 0xFF0000FF; + cs.swordcolor = 0x808080FF; + } else { cs.charid = atoi(s.c_str()); - cs.lefthanded = cs.charid >= 10; - cs.charid %= 10; + cs.lefthanded = cs.charid >= 100; + cs.charid %= 100; + cs.charid %= (2 * pshGUARD); } } diff --git a/geometry.cpp b/geometry.cpp index 6827b7bc..a9bb2841 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -386,7 +386,9 @@ hpcshape hpcshape shChristmasLight, shSmallPike; - hpcshape shReserved[8]; + hpcshape shBunnyBody, shBunnyHead, shBunnyEar, shBunnyTail; + + hpcshape shReserved[16]; int orb_inner_ring; //< for shDisk* shapes, the number of vertices in the inner ring int res1, res2; diff --git a/graph.cpp b/graph.cpp index 72454f44..adfc843d 100644 --- a/graph.cpp +++ b/graph.cpp @@ -671,6 +671,13 @@ transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, doub // todo + auto who1 = who; + if(who == moPlayer) { + charstyle& cs = getcs(); + auto id = ePlayershape(cs.charid >> 1); + if(id == pshRatling) who1 = moRatling; + } + if(detaillevel >= 2 && GDIM == 2) { shiftmatrix VL = at_smart_lof(V, cgi.LEG1); queuepoly(VL * xpush(rightfoot*3/4), cgi.shHumanLeg, col); @@ -716,7 +723,7 @@ transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, doub queuepoly(Tleft, cgi.shSkeletalFoot, col); return spin(rightfoot * wobble); } - else if(isTroll(who) || who == moMonkey || who == moYeti || who == moRatling || who == moRatlingAvenger || who == moGoblin) { + else if(isTroll(who1) || among(who1, moMonkey, moYeti, moRatling, moRatlingAvenger, moGoblin)) { queuepoly(Tright, cgi.shYetiFoot, col); queuepoly(Tleft, cgi.shYetiFoot, col); } @@ -1331,21 +1338,261 @@ EX void drawTerraWarrior(const shiftmatrix& V, int t, int hp, double footphase) } #endif +#if HDR +struct playershape { + string name; + bool is_humanoid; + bool is_animal; + }; + +enum ePlayershape { pshRogue, pshPrincess, pshCat, pshDog, pshFamiliar, pshSpaceship, pshBunny, pshRatling, pshGUARD }; +#endif + +EX vector playershapes = { + {"Rogue", true, false}, + {"Princess", true, false}, + {"cat", false, true}, + {"dog", false, true}, + {"Familiar", false, true}, + {"spaceship", false, false}, + {"bunny", false, true}, + {"Ratling", true, false} + }; + +EX void drawPlayer_animal(eMonster m, cell *where, const shiftmatrix& V0, color_t col, double footphase, bool stop IS(false)) { + charstyle& cs = getcs(); + + auto id = ePlayershape(cs.charid >> 1); + + auto V = V0; + + if(id == pshBunny) { + auto z2 = WDIM == 3 ? 0 : GDIM == 3 ? -abs(sin(footphase * TAU)) * cgi.human_height/3 : geom3::lev_to_factor(abs(sin(footphase * TAU)) * cgi.human_height * 2); + auto V0 = V; + V = at_smart_lof(V0, z2); + } + + if(id == pshBunny) { + /* bunny */ + if(!mmspatial && !footphase) { + if(stop) return; + queuepoly(VALEGS, cgi.shCatLegs, fc(500, cs.dresscolor, 4)); + } + else { + ShadowV(V, cgi.shBunnyBody); + if(stop) return; + animallegs(VALEGS, moRunDog, fc(500, cs.dresscolor, 4), footphase); + } + queuepoly(VABODY, cgi.shBunnyTail, fc(0, cs.skincolor, 0)); + queuepoly(VABODY, cgi.shBunnyBody, fc(0, cs.skincolor, 0)); + queuepoly(VAHEAD, cgi.shBunnyHead, fc(150, cs.haircolor, 2)); + } + else if(id == pshFamiliar) { + /* famililar */ + if(!mmspatial && !footphase) { + if(stop) return; + queuepoly(VALEGS, cgi.shWolfLegs, fc(150, cs.dresscolor, 4)); + } + else { + ShadowV(V, cgi.shWolfBody); + if(stop) return; + animallegs(VALEGS, moWolf, fc(500, cs.dresscolor, 4), footphase); + } + queuepoly(VABODY, cgi.shWolfBody, fc(0, cs.skincolor, 0)); + queuepoly(VAHEAD, cgi.shFamiliarHead, fc(500, cs.haircolor, 2)); + } + else if(id == pshDog) { + /* dog */ + if(!mmspatial && !footphase) { + if(stop) return; + queuepoly(VABODY, cgi.shDogBody, fc(0, cs.skincolor, 0)); + } + else { + ShadowV(V, cgi.shDogTorso); + if(stop) return; + animallegs(VALEGS, moRunDog, fc(500, cs.dresscolor, 4), footphase); + queuepoly(VABODY, cgi.shDogTorso, fc(0, cs.skincolor, 0)); + } + queuepoly(VAHEAD, cgi.shDogHead, fc(150, cs.haircolor, 2)); + } + else if(id == pshCat) { + /* cat */ + if(!mmspatial && !footphase) { + if(stop) return; + queuepoly(VALEGS, cgi.shCatLegs, fc(500, cs.dresscolor, 4)); + } + else { + ShadowV(V, cgi.shCatBody); + if(stop) return; + animallegs(VALEGS, moRunDog, fc(500, cs.dresscolor, 4), footphase); + } + queuepoly(VABODY, cgi.shCatBody, fc(0, cs.skincolor, 0)); + queuepoly(VAHEAD, cgi.shCatHead, fc(150, cs.haircolor, 2)); + } + + if(!shmup::on || shmup::curtime >= shmup::getPlayer()->nextshot) { + color_t col = items[itOrbDiscord] ? watercolor(0) : fc(314, cs.eyecolor, 3); + if(among(id, pshCat, pshBunny)) { + queuepoly(VAHEAD * xpush(.04), cgi.shWolf1, col); + queuepoly(VAHEAD * xpush(.04), cgi.shWolf2, col); + } + if(id == pshDog) { + queuepoly(VAHEAD, cgi.shWolf1, col); + queuepoly(VAHEAD, cgi.shWolf2, col); + } + if(id == pshFamiliar) { + queuepoly(VAHEAD, cgi.shFamiliarEye, col); + queuepoly(VAHEAD * lmirror(), cgi.shFamiliarEye, col); + } + } + + if(id == pshBunny) { + queuepoly(VAHEAD, cgi.shBunnyEar, fc(150, cs.haircolor, 2)); + queuepoly(VAHEAD * MirrorY, cgi.shBunnyEar, fc(150, cs.haircolor, 2)); + } + + if(id == pshDog) { + color_t colnose = items[itOrbDiscord] ? watercolor(0) : fc(314, 0xFF, 3); + queuepoly(VAHEAD, cgi.shWolf3, colnose); + } + + #if CAP_COMPLEX2 + if(camelot::knighted) + queuepoly(VABODY, cgi.shKnightCloak, darkena(cloakcolor(camelot::knighted), 1, 0xFF)); + #endif + + if(tortoise::seek()) + tortoise::draw(VABODY, tortoise::seekbits, 4, 0); + } + +EX void drawPlayer_humanoid(eMonster m, cell *where, const shiftmatrix& V, color_t col, double footphase, bool stop IS(false)) { + charstyle& cs = getcs(); + auto id = ePlayershape(cs.charid >> 1); + + auto& body = (id == pshRatling) ? cgi.shYeti : (cs.charid&1) ? cgi.shFemaleBody : cgi.shPBody; + + ShadowV(V, body); + if(stop) return; + + const transmatrix VBS = otherbodyparts(V, fc(0, (id == pshRatling) ? cs.dresscolor : cs.skincolor, 0), items[itOrbFish] ? moWaterElemental : moPlayer, footphase); + + + queuepoly(VBODY * VBS, body, fc(0, cs.skincolor, 0)); + + if(cs.charid&1) + queuepoly(VBODY1 * VBS, cgi.shFemaleDress, fc(500, cs.dresscolor, 4)); + + if(cs.charid == 2) + queuepoly(VBODY2 * VBS, cgi.shPrinceDress, fc(400, cs.dresscolor, 5)); + if(cs.charid == 3) + queuepoly(VBODY2 * VBS, cgi.shPrincessDress, fc(400, cs.dresscolor2, 5)); + + if(items[itOrbSide3]) + queuepoly(VBODY * VBS, (cs.charid&1) ? cgi.shFerocityF : cgi.shFerocityM, fc(0, cs.skincolor, 0)); + + if(items[itOrbHorns]) { + queuepoly(VBODY * VBS, cgi.shBullHead, items[itOrbDiscord] ? watercolor(0) : 0xFF000030); + queuepoly(VBODY * VBS, cgi.shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); + queuepoly(VBODY * VBS * lmirror(), cgi.shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); + } + + if(items[itOrbSide1] && !shmup::on) + queuepoly(VBODY * VBS * spin(-15._deg), cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, fc(314, cs.swordcolor, 3)); // 3 not colored + + shiftmatrix VWPN = cs.lefthanded ? VBODY * VBS * lmirror() : VBODY * VBS; + + if(peace::on) ; + else if(racing::on) { +#if CAP_RACING + if(racing::trophy[multi::cpid]) + queuepoly(VWPN, cgi.shTrophy, racing::trophy[multi::cpid]); +#endif + } + else if(bow::crossbow_mode() && cs.charid < 4) { + queuepoly(VWPN, cgi.shCrossbow, fc(314, cs.bowcolor, 3)); + int ti = items[itCrossbow]; + if(shmup::on) { + ti = shmup::getPlayer()->nextshot - shmup::curtime; + if(ti <= 0) ti = 0; + else ti = 1 + ti / 500; + } + shiftmatrix VWPN1 = VWPN, VWPN2 = VWPN; + if(GDIM == 3) { ld h = cgi.human_height; VWPN1 = VWPN * lzpush(-h/60); VWPN2 = VWPN * lzpush(-h/30); } + if(ti <= 1) queuepoly(VWPN1, cgi.shCrossbowstringLoaded, fc(314, cs.bowcolor2, 3)); + else if(ti <= 2) queuepoly(VWPN1, cgi.shCrossbowstringSemiloaded, fc(314, cs.bowcolor2, 3)); + else queuepoly(VWPN1, cgi.shCrossbowstringUnloaded, fc(314, cs.bowcolor2, 3)); + if(ti == 0) queuepoly(VWPN2, cgi.shCrossbowBolt, fc(314, cs.swordcolor, 3)); + } + else if(items[itOrbThorns]) + queuepoly(VWPN, cgi.shHedgehogBladePlayer, items[itOrbDiscord] ? watercolor(0) : 0x00FF00FF); + else if(!shmup::on && items[itOrbDiscord]) + queuepoly(VWPN, cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, watercolor(0)); + else if(items[itRevolver]) + queuepoly(VWPN, cgi.shGunInHand, fc(314, cs.swordcolor, 3)); // 3 not colored + else if(items[itOrbSlaying]) { + queuepoly(VWPN, cgi.shFlailTrunk, items[itOrbDiscord] ? watercolor(0) : fc(314, cs.swordcolor, 3)); + queuepoly(VWPN, cgi.shHammerHead, items[itOrbDiscord] ? watercolor(50) : fc(314, cs.swordcolor, 3)); + } + else if(items[itCurseWeakness]) { + /* no weapon shown */ + } + else if(!shmup::on) + queuepoly(VWPN, cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, fc(314, cs.swordcolor, 3)); // 3 not colored + else if(shmup::curtime >= shmup::getPlayer()->nextshot) + queuepoly(VWPN, cgi.shPKnife, fc(314, cs.swordcolor, 3)); // 3 not colored + + if(items[itOrbBeauty]) { + if(cs.charid&1) + queuepoly(VHEAD1, cgi.shFlowerHair, darkena(iinf[itOrbBeauty].color, 0, 0xFF)); + else + queuepoly(VWPN, cgi.shFlowerHand, darkena(iinf[itOrbBeauty].color, 0, 0xFF)); + } + + if(where && where->land == laWildWest) { + queuepoly(VHEAD1, cgi.shWestHat1, darkena(cs.swordcolor, 1, 0XFF)); + queuepoly(VHEAD2, cgi.shWestHat2, darkena(cs.swordcolor, 0, 0XFF)); + } + + if(cheater && !autocheat) { + queuepoly(VHEAD1, (cs.charid&1) ? cgi.shGoatHead : cgi.shDemon, darkena(0xFFFF00, 0, 0xFF)); + // queuepoly(V, shHood, darkena(0xFF00, 1, 0xFF)); + } + else if(id == pshRatling) { + queuepoly(VHEAD, cgi.shRatHead, fc(500, cs.haircolor, 1)); + queuepoly(VHEAD, cgi.shWolf1, cs.eyecolor); + queuepoly(VHEAD, cgi.shWolf2, cs.eyecolor); + queuepoly(VHEAD, cgi.shWolf3, darkena(0x202020, 0, 0xFF)); + } + else { + queuepoly(VHEAD, cgi.shPFace, fc(500, cs.skincolor, 1)); + queuepoly(VHEAD1, (cs.charid&1) ? cgi.shFemaleHair : cgi.shPHead, fc(150, cs.haircolor, 2)); + } + + humanoid_eyes(V, cs.eyecolor, cs.skincolor); + + #if CAP_COMPLEX2 + if(camelot::knighted) + queuepoly(VBODY * VBS, id == pshRatling ? cgi.shRatCape1 : cgi.shKnightCloak, darkena(cloakcolor(camelot::knighted), 1, 0xFF)); + #endif + + if(tortoise::seek()) + tortoise::draw(VBODY * VBS * ypush(-cgi.crossf*.25), tortoise::seekbits, 4, 0); + } + EX void drawPlayer(eMonster m, cell *where, const shiftmatrix& V, color_t col, double footphase, bool stop IS(false)) { charstyle& cs = getcs(); - #if CAP_COMPLEX2 - auto& knighted = camelot::knighted; - #else - const bool knighted = false; - #endif if(GDIM == 3) { addradar(V, '@', cs.uicolor >> 8, 0xFF00FF00); } if(mapeditor::drawplayer && !mapeditor::drawUserShape(V, mapeditor::sgPlayer, cs.charid, cs.skincolor, where)) { + + auto id = ePlayershape(cs.charid >> 1); + if(playershapes[id].is_animal) drawPlayer_animal(m, where, V, col, footphase, stop); + else if(playershapes[id].is_humanoid) drawPlayer_humanoid(m, where, V, col, footphase, stop); - if(cs.charid >= 10) { + else if(cs.charid >= 10) { ShadowV(V, cgi.shSpaceship); queuepoly(VBODY, cgi.shSpaceshipBase, fc(150, cs.skincolor, 4)); queuepoly(VBODY, cgi.shSpaceshipCockpit, fc(150, cs.eyecolor, 4)); @@ -1354,186 +1601,6 @@ EX void drawPlayer(eMonster m, cell *where, const shiftmatrix& V, color_t col, d queuepoly(VBODY * lmirror(), cgi.shSpaceshipGun, fc(150, cs.dresscolor, 4)); queuepoly(VBODY * lmirror(), cgi.shSpaceshipEngine, fc(150, cs.haircolor, 4)); } - else if(cs.charid >= 8) { - /* famililar */ - if(!mmspatial && !footphase) { - if(stop) return; - queuepoly(VALEGS, cgi.shWolfLegs, fc(150, cs.dresscolor, 4)); - } - else { - ShadowV(V, cgi.shWolfBody); - if(stop) return; - animallegs(VALEGS, moWolf, fc(500, cs.dresscolor, 4), footphase); - } - queuepoly(VABODY, cgi.shWolfBody, fc(0, cs.skincolor, 0)); - queuepoly(VAHEAD, cgi.shFamiliarHead, fc(500, cs.haircolor, 2)); - if(!shmup::on || shmup::curtime >= shmup::getPlayer()->nextshot) { - color_t col = items[itOrbDiscord] ? watercolor(0) : fc(314, cs.eyecolor, 3); - queuepoly(VAHEAD, cgi.shFamiliarEye, col); - queuepoly(VAHEAD * lmirror(), cgi.shFamiliarEye, col); - } - - if(knighted) - queuepoly(VABODY, cgi.shKnightCloak, darkena(cloakcolor(knighted), 1, 0xFF)); - - if(tortoise::seek()) - tortoise::draw(VABODY, tortoise::seekbits, 4, 0); - } - else if(cs.charid >= 6) { - /* dog */ - if(!mmspatial && !footphase) { - if(stop) return; - queuepoly(VABODY, cgi.shDogBody, fc(0, cs.skincolor, 0)); - } - else { - ShadowV(V, cgi.shDogTorso); - if(stop) return; - animallegs(VALEGS, moRunDog, fc(500, cs.dresscolor, 4), footphase); - queuepoly(VABODY, cgi.shDogTorso, fc(0, cs.skincolor, 0)); - } - queuepoly(VAHEAD, cgi.shDogHead, fc(150, cs.haircolor, 2)); - - if(!shmup::on || shmup::curtime >= shmup::getPlayer()->nextshot) { - color_t col = items[itOrbDiscord] ? watercolor(0) : fc(314, cs.eyecolor, 3); - queuepoly(VAHEAD, cgi.shWolf1, col); - queuepoly(VAHEAD, cgi.shWolf2, col); - } - - color_t colnose = items[itOrbDiscord] ? watercolor(0) : fc(314, 0xFF, 3); - queuepoly(VAHEAD, cgi.shWolf3, colnose); - - if(knighted) - queuepoly(VABODY, cgi.shKnightCloak, darkena(cloakcolor(knighted), 1, 0xFF)); - - if(tortoise::seek()) - tortoise::draw(VABODY, tortoise::seekbits, 4, 0); - } - else if(cs.charid >= 4) { - /* cat */ - if(!mmspatial && !footphase) { - if(stop) return; - queuepoly(VALEGS, cgi.shCatLegs, fc(500, cs.dresscolor, 4)); - } - else { - ShadowV(V, cgi.shCatBody); - if(stop) return; - animallegs(VALEGS, moRunDog, fc(500, cs.dresscolor, 4), footphase); - } - queuepoly(VABODY, cgi.shCatBody, fc(0, cs.skincolor, 0)); - queuepoly(VAHEAD, cgi.shCatHead, fc(150, cs.haircolor, 2)); - if(!shmup::on || shmup::curtime >= shmup::getPlayer()->nextshot) { - color_t col = items[itOrbDiscord] ? watercolor(0) : fc(314, cs.eyecolor, 3); - queuepoly(VAHEAD * xpush(.04), cgi.shWolf1, col); - queuepoly(VAHEAD * xpush(.04), cgi.shWolf2, col); - } - - if(knighted) - queuepoly(VABODY, cgi.shKnightCloak, darkena(cloakcolor(knighted), 1, 0xFF)); - - if(tortoise::seek()) - tortoise::draw(VABODY, tortoise::seekbits, 4, 0); - } - else { - /* human */ - ShadowV(V, (cs.charid&1) ? cgi.shFemaleBody : cgi.shPBody); - if(stop) return; - - const transmatrix VBS = otherbodyparts(V, fc(0, cs.skincolor, 0), items[itOrbFish] ? moWaterElemental : moPlayer, footphase); - - - queuepoly(VBODY * VBS, (cs.charid&1) ? cgi.shFemaleBody : cgi.shPBody, fc(0, cs.skincolor, 0)); - - if(cs.charid&1) - queuepoly(VBODY1 * VBS, cgi.shFemaleDress, fc(500, cs.dresscolor, 4)); - - if(cs.charid == 2) - queuepoly(VBODY2 * VBS, cgi.shPrinceDress, fc(400, cs.dresscolor, 5)); - if(cs.charid == 3) - queuepoly(VBODY2 * VBS, cgi.shPrincessDress, fc(400, cs.dresscolor2, 5)); - - if(items[itOrbSide3]) - queuepoly(VBODY * VBS, (cs.charid&1) ? cgi.shFerocityF : cgi.shFerocityM, fc(0, cs.skincolor, 0)); - - if(items[itOrbHorns]) { - queuepoly(VBODY * VBS, cgi.shBullHead, items[itOrbDiscord] ? watercolor(0) : 0xFF000030); - queuepoly(VBODY * VBS, cgi.shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); - queuepoly(VBODY * VBS * lmirror(), cgi.shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); - } - - if(items[itOrbSide1] && !shmup::on) - queuepoly(VBODY * VBS * spin(-15._deg), cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, fc(314, cs.swordcolor, 3)); // 3 not colored - - shiftmatrix VWPN = cs.lefthanded ? VBODY * VBS * lmirror() : VBODY * VBS; - - if(peace::on) ; - else if(racing::on) { - #if CAP_RACING - if(racing::trophy[multi::cpid]) - queuepoly(VWPN, cgi.shTrophy, racing::trophy[multi::cpid]); - #endif - } - else if(bow::crossbow_mode() && cs.charid < 4) { - queuepoly(VWPN, cgi.shCrossbow, fc(314, cs.bowcolor, 3)); - int ti = items[itCrossbow]; - if(shmup::on) { - ti = shmup::getPlayer()->nextshot - shmup::curtime; - if(ti <= 0) ti = 0; - else ti = 1 + ti / 500; - } - shiftmatrix VWPN1 = VWPN, VWPN2 = VWPN; - if(GDIM == 3) { ld h = cgi.human_height; VWPN1 = VWPN * lzpush(-h/60); VWPN2 = VWPN * lzpush(-h/30); } - if(ti <= 1) queuepoly(VWPN1, cgi.shCrossbowstringLoaded, fc(314, cs.bowcolor2, 3)); - else if(ti <= 2) queuepoly(VWPN1, cgi.shCrossbowstringSemiloaded, fc(314, cs.bowcolor2, 3)); - else queuepoly(VWPN1, cgi.shCrossbowstringUnloaded, fc(314, cs.bowcolor2, 3)); - if(ti == 0) queuepoly(VWPN2, cgi.shCrossbowBolt, fc(314, cs.swordcolor, 3)); - } - else if(items[itOrbThorns]) - queuepoly(VWPN, cgi.shHedgehogBladePlayer, items[itOrbDiscord] ? watercolor(0) : 0x00FF00FF); - else if(!shmup::on && items[itOrbDiscord]) - queuepoly(VWPN, cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, watercolor(0)); - else if(items[itRevolver]) - queuepoly(VWPN, cgi.shGunInHand, fc(314, cs.swordcolor, 3)); // 3 not colored - else if(items[itOrbSlaying]) { - queuepoly(VWPN, cgi.shFlailTrunk, fc(314, cs.swordcolor, 3)); - queuepoly(VWPN, cgi.shHammerHead, fc(314, cs.swordcolor, 3)); - } - else if(items[itCurseWeakness]) { - /* no weapon shown */ - } - else if(!shmup::on) - queuepoly(VWPN, cs.charid >= 2 ? cgi.shSabre : cgi.shPSword, fc(314, cs.swordcolor, 3)); // 3 not colored - else if(shmup::curtime >= shmup::getPlayer()->nextshot) - queuepoly(VWPN, cgi.shPKnife, fc(314, cs.swordcolor, 3)); // 3 not colored - - if(items[itOrbBeauty]) { - if(cs.charid&1) - queuepoly(VHEAD1, cgi.shFlowerHair, darkena(iinf[itOrbBeauty].color, 0, 0xFF)); - else - queuepoly(VWPN, cgi.shFlowerHand, darkena(iinf[itOrbBeauty].color, 0, 0xFF)); - } - - if(where && where->land == laWildWest) { - queuepoly(VHEAD1, cgi.shWestHat1, darkena(cs.swordcolor, 1, 0XFF)); - queuepoly(VHEAD2, cgi.shWestHat2, darkena(cs.swordcolor, 0, 0XFF)); - } - - if(cheater && !autocheat) { - queuepoly(VHEAD1, (cs.charid&1) ? cgi.shGoatHead : cgi.shDemon, darkena(0xFFFF00, 0, 0xFF)); - // queuepoly(V, shHood, darkena(0xFF00, 1, 0xFF)); - } - else { - queuepoly(VHEAD, cgi.shPFace, fc(500, cs.skincolor, 1)); - queuepoly(VHEAD1, (cs.charid&1) ? cgi.shFemaleHair : cgi.shPHead, fc(150, cs.haircolor, 2)); - } - - humanoid_eyes(V, cs.eyecolor, cs.skincolor); - - if(knighted) - queuepoly(VBODY * VBS, cgi.shKnightCloak, darkena(cloakcolor(knighted), 1, 0xFF)); - - if(tortoise::seek()) - tortoise::draw(VBODY * VBS * ypush(-cgi.crossf*.25), tortoise::seekbits, 4, 0); - } } } @@ -1710,7 +1777,7 @@ EX bool drawMonsterType(eMonster m, cell *where, const shiftmatrix& V1, color_t return true; case moBullet: - if(getcs().charid >= 10) { + if(getcs().charid/2 == pshSpaceship) { ShadowV(V, cgi.shKnife); queuepoly(VBODY, cgi.shMissile, getcs().swordcolor); return true; @@ -1762,13 +1829,19 @@ EX bool drawMonsterType(eMonster m, cell *where, const shiftmatrix& V1, color_t bool evil = !isPrincess(m); int facecolor = evil ? 0xC0B090FF : 0xD0C080FF; - - ShadowV(V, girl ? cgi.shFemaleBody : cgi.shPBody); - const transmatrix VBS = otherbodyparts(V, facecolor, !evil && items[itOrbFish] && items[itOrbEmpathy] ? moWaterElemental : m, footphase); - queuepoly(VBODY * VBS, girl ? cgi.shFemaleBody : cgi.shPBody, facecolor); + + auto& cs = vid.cs; + auto id = ePlayershape(cs.charid >> 1); + + auto& body = id == pshRatling ? cgi.shYeti : girl ? cgi.shFemaleBody : cgi.shPBody; + bool wears_dress = among(id, pshRogue, pshRatling); + + ShadowV(V, body); + const transmatrix VBS = otherbodyparts(V, facecolor, !evil && items[itOrbFish] && items[itOrbEmpathy] ? moWaterElemental : id == pshRatling ? moYeti : m, footphase); + queuepoly(VBODY * VBS, body, facecolor); if(m == moPrincessArmed) - queuepoly(VBODY * VBS * lmirror(), vid.cs.charid < 2 ? cgi.shSabre : cgi.shPSword, 0xFFFFFFFF); + queuepoly(VBODY * VBS * lmirror(), id == pshRogue ? cgi.shSabre : cgi.shPSword, 0xFFFFFFFF); if((m == moFalsePrincess || m == moRoseBeauty) && where && where->cpdist == 1) queuepoly(VBODY * VBS, cgi.shPKnife, 0xFFFFFFFF); @@ -1780,18 +1853,20 @@ EX bool drawMonsterType(eMonster m, cell *where, const shiftmatrix& V1, color_t if(girl) { queuepoly(VBODY1 * VBS, cgi.shFemaleDress, evil ? 0xC000C0FF : 0x00C000FF); - if(vid.cs.charid < 2) + if(wears_dress) queuepoly(VBODY2 * VBS, cgi.shPrincessDress, (evil ? 0xC040C0C0 : 0x8080FFC0) | UNTRANS); } else { - if(vid.cs.charid < 2) + if(wears_dress) queuepoly(VBODY1 * VBS, cgi.shPrinceDress, evil ? 0x802080FF : 0x404040FF); } - + + auto& hair = id == pshRatling ? cgi.shRatHead : girl ? cgi.shFemaleHair : cgi.shPHead; + if(m == moRoseLady) { // queuepoly(V, girl ? cgi.shGoatHead : cgi.shDemon, 0x800000FF); // make her hair a bit darker to stand out in 3D - queuepoly(VHEAD1, girl ? cgi.shFemaleHair : cgi.shPHead, evil ? 0x500050FF : GDIM == 3 ? 0x666A64FF : 0x332A22FF); + queuepoly(VHEAD1, hair, evil ? 0x500050FF : GDIM == 3 ? 0x666A64FF : 0x332A22FF); } else if(m == moRoseBeauty) { if(girl) { @@ -1805,10 +1880,14 @@ EX bool drawMonsterType(eMonster m, cell *where, const shiftmatrix& V1, color_t } } else { - queuepoly(VHEAD1, girl ? cgi.shFemaleHair : cgi.shPHead, - evil ? 0xC00000FF : 0x332A22FF); + queuepoly(VHEAD1, hair, evil ? 0xC00000FF : 0x332A22FF); } - queuepoly(VHEAD, cgi.shPFace, facecolor); + if(&hair == &cgi.shRatHead) { + queuepoly(VHEAD, cgi.shWolf1, 0x008000FF); + queuepoly(VHEAD, cgi.shWolf2, 0x008000FF); + queuepoly(VHEAD, cgi.shWolf3, darkena(0x202020, 0, 0xFF)); + } + else queuepoly(VHEAD, cgi.shPFace, facecolor); humanoid_eyes(V, evil ? 0x0000C0FF : 0x00C000FF, facecolor); return true; } @@ -6267,7 +6346,7 @@ EX void animateAttack(const movei& m, int layer) { } EX void animateCorrectAttack(const movei& m, int layer, eMonster who) { - if(among(who, moPlayer, moMimic, moIllusion, moShadow) && getcs().charid >= 10) { + if(among(who, moPlayer, moMimic, moIllusion, moShadow) && (getcs().charid/2) == pshSpaceship) { animate_item_throw(m.s, m.t, itNone, moBullet); return; } @@ -6275,7 +6354,7 @@ EX void animateCorrectAttack(const movei& m, int layer, eMonster who) { } EX void animateHug(const movei& m, int layer) { - animateAttackOrHug(m, layer, 3, 0.5, -0.0713828 * cgi.scalefactor); + animateAttackOrHug(m, layer, 3, 0.5, ((getcs().charid/2) == pshRatling ? -0.15 : -0.0713828) * cgi.scalefactor); } vector > animstack; diff --git a/polygons.cpp b/polygons.cpp index cb064267..0abc50aa 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -1586,6 +1586,12 @@ void geometry_information::prepare_shapes() { bshape(shBugAntenna, PPR::MONSTER_BODY, scalefactor, 307); bshape(shCatBody, PPR::MONSTER_BODY, scalefactor, 139); bshape(shCatLegs, PPR::MONSTER_LEG, scalefactor, 140); + + bshape(shBunnyBody, PPR::MONSTER_BODY, scalefactor, 434); + bshape(shBunnyHead, PPR::MONSTER_HEAD, scalefactor, 436); + bshape(shBunnyEar, PPR::MONSTER_HEAD, scalefactor, 437); + bshape(shBunnyTail, PPR::MONSTER_BODY, scalefactor, 438); + bshape(shFamiliarHead, PPR::MONSTER_HEAD, scalefactor, 141); bshape(shFamiliarEye, PPR::MONSTER_EYE1, scalefactor, 142); bshape(shCatHead, PPR::MONSTER_HEAD, scalefactor, 143); @@ -2560,6 +2566,18 @@ NEWSHAPE, 432, 1, 1, -0.0498532, 0.0220752, -0.0675516, 0.0261371, -0.0684933, // shSpaceship NEWSHAPE, 433, 1, 1, 0.0699706, 0, 0.0509304, 0.019032, 0.0056909, 0.023788, 0.0318813, 0.0309258, 0.0330715, 0.0368693, 0.00331668, 0.0380512, -0.0630665, 0.0699568, -0.0619577, 0.041535, -0.0678691, 0.0415233, -0.0678946, 0.0261072, -0.0572505, 0.0237463, -0.0572505, -0.0237463, -0.0678946, -0.0261072, -0.0678691, -0.0415233, -0.0619577, -0.041535, -0.0630665, -0.0699568, 0.00331668, -0.0380512, 0.0330715, -0.0368693, 0.0318813, -0.0309258, 0.0056909, -0.023788, 0.0509304, -0.019032, +// shBunnyBody +NEWSHAPE, 434, 1, 2, -0.182836, 0.00134439, -0.166475, 0.00939776, -0.184217, 0.0174805, -0.166723, 0.024617, -0.17245, 0.042553, -0.157684, 0.035786, -0.164538, 0.051488, -0.14867, 0.046949, -0.155517, 0.061536, -0.140794, 0.054753, -0.141981, 0.068196, -0.125033, 0.058051, -0.125087, 0.071478, -0.112675, 0.059126, -0.113871, 0.078147, -0.099238, 0.065787, -0.09929, 0.080325, -0.089161, 0.065756, -0.086969, 0.080279, -0.080217, 0.066848, -0.07356, 0.083591, -0.06347, 0.067924, -0.055703, 0.086897, -0.048978, 0.070128, -0.045663, 0.085757, -0.036721, 0.067879, -0.028944, 0.082379, -0.024473, 0.063406, -0.016698, 0.085718, -0.012236, 0.066743, -0.001113, 0.080128, 0.005561, 0.062283, 0.014465, 0.073436, 0.017795, 0.058945, 0.026707, 0.073445, 0.030032, 0.057839, 0.042293, 0.070117, 0.044501, 0.055626, 0.053427, 0.064557, 0.054515, 0.046727, 0.072375, 0.056786, 0.070112, 0.038951, 0.082394, 0.040084, 0.070104, 0.03227, 0.077909, 0.026712, 0.075671, 0.020031, 0.089069, 0.014474, 0.075666, 0.011127, 0.085713, 0.005566, 0.077896, -0.001113, + +// shBunnyHead +NEWSHAPE, 436, 1, 2, 0.073175, 0, 0.058843, 0.007699, 0.07428, 0.010454, 0.062705, 0.019251, 0.077045, 0.019811, 0.068229, 0.032464, 0.084236, 0.031933, 0.077073, 0.043491, 0.091431, 0.037454, 0.098645, 0.047394, 0.108865, 0.0406363, 0.121029, 0.0547394, 0.125041, 0.0426847, 0.141797, 0.0512883, 0.136185, 0.0422124, 0.157048, 0.0488258, 0.147348, 0.0397287, 0.167717, 0.041514, 0.160393, 0.029313, 0.171614, 0.030448, 0.164858, 0.020469, 0.171594, 0.021588, 0.174963, 0.020486, 0.178894, 0.017169, 0.181703, 0.013295, 0.183949, 0.005541, + +// shBunnyEar +NEWSHAPE, 437, 1, 1, 0.0826431, 0.0110191, 0.0685843, 0.0150185, 0.0575504, 0.0140123, 0.0535413, 0.0150116, 0.0425239, 0.0210118, 0.0325139, 0.0255109, 0.0210093, 0.0365162, 0.0205116, 0.0430244, 0.0190131, 0.0490339, 0.040542, 0.0500518, 0.0766509, 0.0450888, 0.0871982, 0.0390888, 0.0992563, 0.0230596, 0.101266, 0.0175461, 0.0856591, 0.0110205, + +// shBunnyTail +NEWSHAPE, 438, 1, 2, -0.146275, -0.00452397, -0.135622, -0.0105484, -0.149835, -0.0100561, -0.145778, -0.0180966, -0.158996, -0.0100631, -0.159013, -0.0231475, -0.164607, -0.013088, -0.187654, -0.0257267, -0.184047, -0.0176483, -0.195877, -0.0267564, -0.195345, -0.0186764, -0.205659, -0.0242546, -0.203064, -0.0161643, -0.21598, -0.0187149, -0.20873, -0.00960259, -0.221145, -0.0101211, -0.21441, -0.00455116, -0.224251, -0.000506209, + NEWSHAPE, NEWSHAPE };