# player_face.h

Go to the documentation of this file.

    00001 /* $Id: player_face.h 11800 2008-01-09 21:05:03Z rubidium $ */
    00002
    00005 #ifndef PLAYER_FACE_H
    00006 #define PLAYER_FACE_H
    00007
    00008 #include "core/random_func.hpp"
    00009 #include "core/bitmath_func.hpp"
    00010
    00012 enum GenderEthnicity {
    00013   GENDER_FEMALE    = 0,
    00014   ETHNICITY_BLACK  = 1,
    00015
    00016   GE_WM = 0,
    00017   GE_WF = 1 << GENDER_FEMALE,
    00018   GE_BM = 1 << ETHNICITY_BLACK,
    00019   GE_BF = 1 << ETHNICITY_BLACK | 1 << GENDER_FEMALE,
    00020   GE_END,
    00021 };
    00022 DECLARE_ENUM_AS_BIT_SET(GenderEthnicity);
    00023
    00025 enum PlayerFaceVariable {
    00026   PFV_GENDER,
    00027   PFV_ETHNICITY,
    00028   PFV_GEN_ETHN,
    00029   PFV_HAS_MOUSTACHE,
    00030   PFV_HAS_TIE_EARRING,
    00031   PFV_HAS_GLASSES,
    00032   PFV_EYE_COLOUR,
    00033   PFV_CHEEKS,
    00034   PFV_CHIN,
    00035   PFV_EYEBROWS,
    00036   PFV_MOUSTACHE,
    00037   PFV_LIPS,
    00038   PFV_NOSE,
    00039   PFV_HAIR,
    00040   PFV_JACKET,
    00041   PFV_COLLAR,
    00042   PFV_TIE_EARRING,
    00043   PFV_GLASSES,
    00044   PFV_END
    00045 };
    00046 DECLARE_POSTFIX_INCREMENT(PlayerFaceVariable);
    00047
    00049 struct PlayerFaceBitsInfo {
    00050   byte     offset;
    00051   byte     length;
    00052   byte     valid_values[GE_END];
    00053   SpriteID first_sprite[GE_END];
    00054 };
    00055
    00057 static const PlayerFaceBitsInfo _pf_info[] = {
    00058   /* Index                   off len   WM  WF  BM  BF         WM     WF     BM     BF */
    00059   /* PFV_GENDER          */ {  0, 1, {  2,  2,  2,  2 }, {     0,     0,     0,     0 } },
    00060   /* PFV_ETHNICITY       */ {  1, 2, {  2,  2,  2,  2 }, {     0,     0,     0,     0 } },
    00061   /* PFV_GEN_ETHN        */ {  0, 3, {  4,  4,  4,  4 }, {     0,     0,     0,     0 } },
    00062   /* PFV_HAS_MOUSTACHE   */ {  3, 1, {  2,  0,  2,  0 }, {     0,     0,     0,     0 } },
    00063   /* PFV_HAS_TIE_EARRING */ {  3, 1, {  0,  2,  0,  2 }, {     0,     0,     0,     0 } },
    00064   /* PFV_HAS_GLASSES     */ {  4, 1, {  2,  2,  2,  2 }, {     0,     0,     0,     0 } },
    00065   /* PFV_EYE_COLOUR      */ {  5, 2, {  3,  3,  1,  1 }, {     0,     0,     0,     0 } },
    00066   /* PFV_CHEEKS          */ {  0, 0, {  1,  1,  1,  1 }, { 0x325, 0x326, 0x390, 0x3B0 } },
    00067   /* PFV_CHIN            */ {  7, 2, {  4,  1,  2,  2 }, { 0x327, 0x327, 0x391, 0x3B1 } },
    00068   /* PFV_EYEBROWS        */ {  9, 4, { 12, 16, 11, 16 }, { 0x32B, 0x337, 0x39A, 0x3B8 } },
    00069   /* PFV_MOUSTACHE       */ { 13, 2, {  3,  0,  3,  0 }, { 0x367,     0, 0x397,     0 } },
    00070   /* PFV_LIPS            */ { 13, 4, { 12, 10,  9,  9 }, { 0x35B, 0x351, 0x3A5, 0x3C8 } },
    00071   /* PFV_NOSE            */ { 17, 3, {  8,  4,  4,  5 }, { 0x349, 0x34C, 0x393, 0x3B3 } },
    00072   /* PFV_HAIR            */ { 20, 4, {  9,  5,  5,  4 }, { 0x382, 0x38B, 0x3D4, 0x3D9 } },
    00073   /* PFV_JACKET          */ { 24, 2, {  3,  3,  3,  3 }, { 0x36B, 0x378, 0x36B, 0x378 } },
    00074   /* PFV_COLLAR          */ { 26, 2, {  4,  4,  4,  4 }, { 0x36E, 0x37B, 0x36E, 0x37B } },
    00075   /* PFV_TIE_EARRING     */ { 28, 3, {  6,  3,  6,  3 }, { 0x372, 0x37F, 0x372, 0x3D1 } },
    00076   /* PFV_GLASSES         */ { 31, 1, {  2,  2,  2,  2 }, { 0x347, 0x347, 0x3AE, 0x3AE } }
    00077 };
    00078 assert_compile(lengthof(_pf_info) == PFV_END);
    00079
    00088 static inline uint GetPlayerFaceBits(PlayerFace pf, PlayerFaceVariable pfv, GenderEthnicity ge)
    00089 {
    00090   assert(_pf_info[pfv].valid_values[ge] != 0);
    00091
    00092   return GB(pf, _pf_info[pfv].offset, _pf_info[pfv].length);
    00093 }
    00094
    00103 static inline void SetPlayerFaceBits(PlayerFace &pf, PlayerFaceVariable pfv, GenderEthnicity ge, uint val)
    00104 {
    00105   assert(val < _pf_info[pfv].valid_values[ge]);
    00106
    00107   SB(pf, _pf_info[pfv].offset, _pf_info[pfv].length, val);
    00108 }
    00109
    00122 static inline void IncreasePlayerFaceBits(PlayerFace &pf, PlayerFaceVariable pfv, GenderEthnicity ge, int8 amount)
    00123 {
    00124   int8 val = GetPlayerFaceBits(pf, pfv, ge) + amount; // the new value for the pfv
    00125
    00126   /* scales the new value to the correct scope */
    00127   if (val >= _pf_info[pfv].valid_values[ge]) {
    00128     val = 0;
    00129   } else if (val < 0) {
    00130     val = _pf_info[pfv].valid_values[ge] - 1;
    00131   }
    00132
    00133   SetPlayerFaceBits(pf, pfv, ge, val); // save the new value
    00134 }
    00135
    00143 static inline bool ArePlayerFaceBitsValid(PlayerFace pf, PlayerFaceVariable pfv, GenderEthnicity ge)
    00144 {
    00145   return GB(pf, _pf_info[pfv].offset, _pf_info[pfv].length) < _pf_info[pfv].valid_values[ge];
    00146 }
    00147
    00156 static inline uint ScalePlayerFaceValue(PlayerFaceVariable pfv, GenderEthnicity ge, uint val)
    00157 {
    00158   assert(val < (1U << _pf_info[pfv].length));
    00159
    00160   return (val * _pf_info[pfv].valid_values[ge]) >> _pf_info[pfv].length;
    00161 }
    00162
    00168 static inline void ScaleAllPlayerFaceBits(PlayerFace &pf)
    00169 {
    00170   IncreasePlayerFaceBits(pf, PFV_ETHNICITY, GE_WM, 0); // scales the ethnicity
    00171
    00172   GenderEthnicity ge = (GenderEthnicity)GB(pf, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // gender & ethnicity of the face
    00173
    00174   /* Is a male face with moustache. Need to reduce CPU load in the loop. */
    00175   bool is_moust_male = !HasBit(ge, GENDER_FEMALE) && GetPlayerFaceBits(pf, PFV_HAS_MOUSTACHE, ge) != 0;
    00176
    00177   for (PlayerFaceVariable pfv = PFV_EYE_COLOUR; pfv < PFV_END; pfv++) { // scales all other variables
    00178
    00179     /* The moustache variable will be scaled only if it is a male face with has a moustache */
    00180     if (pfv != PFV_MOUSTACHE || is_moust_male) {
    00181       IncreasePlayerFaceBits(pf, pfv, ge, 0);
    00182     }
    00183   }
    00184 }
    00185
    00197 static inline void RandomPlayerFaceBits(PlayerFace &pf, GenderEthnicity ge, bool adv)
    00198 {
    00199   pf = InteractiveRandom(); // random all player face bits
    00200
    00201   /* scale ge: 0 == GE_WM, 1 == GE_WF, 2 == GE_BM, 3 == GE_BF (and maybe in future: ...) */
    00202   ge = (GenderEthnicity)((uint)ge % GE_END);
    00203
    00204   /* set the gender (and ethnicity) for the new player face */
    00205   if (adv) {
    00206     SetPlayerFaceBits(pf, PFV_GEN_ETHN, ge, ge);
    00207   } else {
    00208     SetPlayerFaceBits(pf, PFV_GENDER, ge, HasBit(ge, GENDER_FEMALE));
    00209   }
    00210
    00211   /* scales all player face bits to the correct scope */
    00212   ScaleAllPlayerFaceBits(pf);
    00213 }
    00214
    00223 static inline SpriteID GetPlayerFaceSprite(PlayerFace pf, PlayerFaceVariable pfv, GenderEthnicity ge)
    00224 {
    00225   assert(_pf_info[pfv].valid_values[ge] != 0);
    00226
    00227   return _pf_info[pfv].first_sprite[ge] + GB(pf, _pf_info[pfv].offset, _pf_info[pfv].length);
    00228 }
    00229
    00230 void DrawPlayerFace(PlayerFace face, int color, int x, int y);
    00231 PlayerFace ConvertFromOldPlayerFace(uint32 face);
    00232 bool IsValidPlayerFace(PlayerFace pf);
    00233 void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget);
    00234
    00235 #endif /* PLAYER_FACE_H */