3 * Summary: Region system implementations
5 * Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
18 #include "tiledef-player.h"
19 #include "tilepick-p.h"
20 #include "transform.h"
22 dolls_data::dolls_data()
24 parts
= new tileidx_t
[TILEP_PART_MAX
];
25 memset(parts
, 0, TILEP_PART_MAX
* sizeof(int));
28 dolls_data::dolls_data(const dolls_data
& _orig
)
30 parts
= new tileidx_t
[TILEP_PART_MAX
];
31 memcpy(parts
, _orig
.parts
, TILEP_PART_MAX
* sizeof(int));
34 const dolls_data
& dolls_data::operator=(const dolls_data
& other
)
36 memcpy(parts
, other
.parts
, TILEP_PART_MAX
* sizeof(int));
40 dolls_data::~dolls_data()
46 dolls_data player_doll
;
48 bool save_doll_data(int mode
, int num
, const dolls_data
* dolls
)
50 // Save mode, num, and all dolls into dolls.txt.
51 std::string dollsTxtString
= datafile_path("dolls.txt", false, true);
53 struct stat stFileInfo
;
54 stat(dollsTxtString
.c_str(), &stFileInfo
);
56 // Write into the current directory instead if we didn't find the file
57 // or don't have write permissions.
58 const char *dollsTxt
= (dollsTxtString
.c_str()[0] == 0
59 || !(stFileInfo
.st_mode
& S_IWUSR
)) ? "dolls.txt"
60 : dollsTxtString
.c_str();
63 if ((fp
= fopen(dollsTxt
, "w+")) != NULL
)
65 fprintf(fp
, "MODE=%s\n",
66 (mode
== TILEP_MODE_EQUIP
) ? "EQUIP" :
67 (mode
== TILEP_MODE_LOADING
) ? "LOADING"
70 fprintf(fp
, "NUM=%02d\n", num
== -1 ? 0 : num
);
72 // Print some explanatory comments. May contain no spaces!
73 fprintf(fp
, "#Legend:\n");
74 fprintf(fp
, "#***:equipment/123:index/000:none\n");
75 fprintf(fp
, "#Shadow/Base/Cloak/Boots/Legs/Body/Gloves/Weapon/Shield/Hair/Beard/Helmet/Halo/Enchant/DrcHead/DrcWing\n");
76 fprintf(fp
, "#Sh:Bse:Clk:Bts:Leg:Bdy:Glv:Wpn:Shd:Hai:Brd:Hlm:Hal:Enc:Drc:Wng\n");
78 for (unsigned int i
= 0; i
< NUM_MAX_DOLLS
; ++i
)
80 tilep_print_parts(fbuf
, dolls
[i
]);
81 fprintf(fp
, "%s", fbuf
);
91 bool load_doll_data(const char *fn
, dolls_data
*dolls
, int max
,
92 tile_doll_mode
*mode
, int *cur
)
97 std::string dollsTxtString
= datafile_path(fn
, false, true);
99 struct stat stFileInfo
;
100 stat(dollsTxtString
.c_str(), &stFileInfo
);
102 // Try to read from the current directory instead if we didn't find the
103 // file or don't have reading permissions.
104 const char *dollsTxt
= (dollsTxtString
.c_str()[0] == 0
105 || !(stFileInfo
.st_mode
& S_IRUSR
)) ? "dolls.txt"
106 : dollsTxtString
.c_str();
109 if ((fp
= fopen(dollsTxt
, "r")) == NULL
)
111 // File doesn't exist. By default, use equipment settings.
112 *mode
= TILEP_MODE_EQUIP
;
117 memset(fbuf
, 0, sizeof(fbuf
));
118 // Read mode from file.
119 if (fscanf(fp
, "%1023s", fbuf
) != EOF
)
121 if (strcmp(fbuf
, "MODE=DEFAULT") == 0)
122 *mode
= TILEP_MODE_DEFAULT
;
123 else if (strcmp(fbuf
, "MODE=EQUIP") == 0)
124 *mode
= TILEP_MODE_EQUIP
; // Nothing else to be done.
126 // Read current doll from file.
127 if (fscanf(fp
, "%1023s", fbuf
) != EOF
)
129 if (strncmp(fbuf
, "NUM=", 4) == 0)
131 sscanf(fbuf
, "NUM=%d", cur
);
132 if (*cur
< 0 || *cur
>= NUM_MAX_DOLLS
)
139 // Load only one doll, either the one defined by NUM or
140 // use the default/equipment setting.
141 if (*mode
!= TILEP_MODE_LOADING
)
143 if (*mode
== TILEP_MODE_DEFAULT
)
144 tilep_job_default(you
.char_class
, &dolls
[0]);
146 // If we don't need to load a doll, return now.
152 while (fscanf(fp
, "%1023s", fbuf
) != EOF
)
154 if (fbuf
[0] == '#') // Skip comment lines.
159 tilep_scan_parts(fbuf
, dolls
[0], you
.species
,
160 you
.experience_level
);
165 else // Load up to max dolls from file.
167 for (int count
= 0; count
< max
&& fscanf(fp
, "%1023s", fbuf
) != EOF
;)
169 if (fbuf
[0] == '#') // Skip comment lines.
172 tilep_scan_parts(fbuf
, dolls
[count
++], you
.species
,
173 you
.experience_level
);
182 void init_player_doll()
184 dolls_data dolls
[NUM_MAX_DOLLS
];
186 for (int i
= 0; i
< NUM_MAX_DOLLS
; i
++)
187 for (int j
= 0; j
< TILEP_PART_MAX
; j
++)
188 dolls
[i
].parts
[j
] = TILEP_SHOW_EQUIP
;
190 tile_doll_mode mode
= TILEP_MODE_LOADING
;
192 load_doll_data("dolls.txt", dolls
, NUM_MAX_DOLLS
, &mode
, &cur
);
194 if (mode
== TILEP_MODE_LOADING
)
196 player_doll
= dolls
[cur
];
197 tilep_race_default(you
.species
, you
.experience_level
, &player_doll
);
201 for (int i
= 0; i
< TILEP_PART_MAX
; i
++)
202 player_doll
.parts
[i
] = TILEP_SHOW_EQUIP
;
203 tilep_race_default(you
.species
, you
.experience_level
, &player_doll
);
205 if (mode
== TILEP_MODE_EQUIP
)
208 tilep_job_default(you
.char_class
, &player_doll
);
211 static int _get_random_doll_part(int p
)
213 ASSERT(p
>= 0 && p
<= TILEP_PART_MAX
);
214 return (tile_player_part_start
[p
]
215 + random2(tile_player_part_count
[p
]));
218 static void _fill_doll_part(dolls_data
&doll
, int p
)
220 ASSERT(p
>= 0 && p
<= TILEP_PART_MAX
);
221 doll
.parts
[p
] = _get_random_doll_part(p
);
224 void create_random_doll(dolls_data
&rdoll
)
226 // All dolls roll for these.
227 _fill_doll_part(rdoll
, TILEP_PART_BODY
);
228 _fill_doll_part(rdoll
, TILEP_PART_HAND1
);
229 _fill_doll_part(rdoll
, TILEP_PART_LEG
);
230 _fill_doll_part(rdoll
, TILEP_PART_BOOTS
);
231 _fill_doll_part(rdoll
, TILEP_PART_HAIR
);
233 // The following are only rolled with 50% chance.
235 _fill_doll_part(rdoll
, TILEP_PART_CLOAK
);
237 _fill_doll_part(rdoll
, TILEP_PART_ARM
);
239 _fill_doll_part(rdoll
, TILEP_PART_HAND2
);
241 _fill_doll_part(rdoll
, TILEP_PART_HELM
);
243 if (one_chance_in(4))
244 _fill_doll_part(rdoll
, TILEP_PART_BEARD
);
247 // Deterministically pick a pair of trousers for this character to use
248 // for SHOW_EQUIP, as there's no corresponding item slot for this.
249 static tileidx_t
_random_trousers()
251 int offset
= static_cast<int>(you
.species
) * 9887
252 + static_cast<int>(you
.char_class
) * 8719;
253 const char *name
= you
.your_name
.c_str();
254 for (int i
= 0; i
< 8 && *name
; ++i
, ++name
)
255 offset
+= name
[i
] * 4643;
257 const int range
= TILEP_LEG_LAST_NORM
- TILEP_LEG_FIRST_NORM
+ 1;
258 return (TILEP_LEG_FIRST_NORM
+ offset
% range
);
261 void fill_doll_equipment(dolls_data
&result
)
264 if (result
.parts
[TILEP_PART_BASE
] == TILEP_SHOW_EQUIP
)
266 tilep_race_default(you
.species
, you
.experience_level
, &result
);
270 if (result
.parts
[TILEP_PART_HAND1
] == TILEP_SHOW_EQUIP
)
272 const int item
= you
.equip
[EQ_WEAPON
];
273 if (you
.form
== TRAN_BLADE_HANDS
)
274 result
.parts
[TILEP_PART_HAND1
] = TILEP_HAND1_BLADEHAND
;
276 result
.parts
[TILEP_PART_HAND1
] = 0;
278 result
.parts
[TILEP_PART_HAND1
] = tilep_equ_weapon(you
.inv
[item
]);
281 if (result
.parts
[TILEP_PART_HAND2
] == TILEP_SHOW_EQUIP
)
283 const int item
= you
.equip
[EQ_SHIELD
];
284 if (you
.form
== TRAN_BLADE_HANDS
)
285 result
.parts
[TILEP_PART_HAND2
] = TILEP_HAND2_BLADEHAND
;
287 result
.parts
[TILEP_PART_HAND2
] = 0;
289 result
.parts
[TILEP_PART_HAND2
] = tilep_equ_shield(you
.inv
[item
]);
292 if (result
.parts
[TILEP_PART_BODY
] == TILEP_SHOW_EQUIP
)
294 const int item
= you
.equip
[EQ_BODY_ARMOUR
];
296 result
.parts
[TILEP_PART_BODY
] = 0;
298 result
.parts
[TILEP_PART_BODY
] = tilep_equ_armour(you
.inv
[item
]);
301 if (result
.parts
[TILEP_PART_CLOAK
] == TILEP_SHOW_EQUIP
)
303 const int item
= you
.equip
[EQ_CLOAK
];
305 result
.parts
[TILEP_PART_CLOAK
] = 0;
307 result
.parts
[TILEP_PART_CLOAK
] = tilep_equ_cloak(you
.inv
[item
]);
310 if (result
.parts
[TILEP_PART_HELM
] == TILEP_SHOW_EQUIP
)
312 const int item
= you
.equip
[EQ_HELMET
];
315 result
.parts
[TILEP_PART_HELM
] = tilep_equ_helm(you
.inv
[item
]);
317 else if (player_mutation_level(MUT_HORNS
) > 0)
319 switch (player_mutation_level(MUT_HORNS
))
322 result
.parts
[TILEP_PART_HELM
] = TILEP_HELM_HORNS1
;
325 result
.parts
[TILEP_PART_HELM
] = TILEP_HELM_HORNS2
;
328 result
.parts
[TILEP_PART_HELM
] = TILEP_HELM_HORNS3
;
334 result
.parts
[TILEP_PART_HELM
] = 0;
338 if (result
.parts
[TILEP_PART_LEG
] == TILEP_SHOW_EQUIP
)
340 result
.parts
[TILEP_PART_LEG
] = _random_trousers();
343 if (result
.parts
[TILEP_PART_BOOTS
] == TILEP_SHOW_EQUIP
)
345 const int item
= you
.equip
[EQ_BOOTS
];
347 result
.parts
[TILEP_PART_BOOTS
] = tilep_equ_boots(you
.inv
[item
]);
348 else if (player_mutation_level(MUT_HOOVES
) >= 3)
349 result
.parts
[TILEP_PART_BOOTS
] = TILEP_BOOTS_HOOVES
;
351 result
.parts
[TILEP_PART_BOOTS
] = 0;
354 if (result
.parts
[TILEP_PART_ARM
] == TILEP_SHOW_EQUIP
)
356 const int item
= you
.equip
[EQ_GLOVES
];
358 result
.parts
[TILEP_PART_ARM
] = tilep_equ_gloves(you
.inv
[item
]);
359 else if (you
.has_claws(false) >= 3)
360 result
.parts
[TILEP_PART_ARM
] = TILEP_ARM_CLAWS
;
362 result
.parts
[TILEP_PART_ARM
] = 0;
365 if (result
.parts
[TILEP_PART_HALO
] == TILEP_SHOW_EQUIP
)
367 const bool halo
= you
.haloed();
368 result
.parts
[TILEP_PART_HALO
] = halo
? TILEP_HALO_TSO
: 0;
371 if (result
.parts
[TILEP_PART_ENCH
] == TILEP_SHOW_EQUIP
)
373 result
.parts
[TILEP_PART_ENCH
] =
374 (you
.duration
[DUR_LIQUID_FLAMES
] ? TILEP_ENCH_STICKY_FLAME
: 0);
376 // Draconian head/wings.
377 if (player_genus(GENPC_DRACONIAN
))
382 tilep_draconian_init(you
.species
, you
.experience_level
,
383 &base
, &head
, &wing
);
385 if (result
.parts
[TILEP_PART_DRCHEAD
] == TILEP_SHOW_EQUIP
)
386 result
.parts
[TILEP_PART_DRCHEAD
] = head
;
387 if (result
.parts
[TILEP_PART_DRCWING
] == TILEP_SHOW_EQUIP
)
388 result
.parts
[TILEP_PART_DRCWING
] = wing
;
391 if (result
.parts
[TILEP_PART_SHADOW
] == TILEP_SHOW_EQUIP
)
392 result
.parts
[TILEP_PART_SHADOW
] = TILEP_SHADOW_SHADOW
;
394 // Various other slots.
395 for (int i
= 0; i
< TILEP_PART_MAX
; i
++)
396 if (result
.parts
[i
] == TILEP_SHOW_EQUIP
)
400 // Writes equipment information into per-character doll file.
401 void save_doll_file(writer
&dollf
)
403 dolls_data result
= player_doll
;
404 fill_doll_equipment(result
);
408 tilep_print_parts(fbuf
, result
);
409 dollf
.write(fbuf
, strlen(fbuf
));
411 if (you
.attribute
[ATTR_HELD
] > 0)
412 dollf
.write("net\n", 4);
415 void pack_doll_buf(SubmergedTileBuffer
& buf
, const dolls_data
&doll
, int x
, int y
, bool submerged
, bool ghost
)
417 // Ordered from back to front.
418 int p_order
[TILEP_PART_MAX
] =
440 int flags
[TILEP_PART_MAX
];
441 tilep_calc_flags(doll
, flags
);
443 // For skirts, boots go under the leg armour. For pants, they go over.
444 if (doll
.parts
[TILEP_PART_LEG
] < TILEP_LEG_SKIRT_OFS
)
446 p_order
[7] = TILEP_PART_BOOTS
;
447 p_order
[6] = TILEP_PART_LEG
;
450 // Special case bardings from being cut off.
451 const bool is_naga
= is_player_tile(doll
.parts
[TILEP_PART_BASE
],
454 if (doll
.parts
[TILEP_PART_BOOTS
] >= TILEP_BOOTS_NAGA_BARDING
455 && doll
.parts
[TILEP_PART_BOOTS
] <= TILEP_BOOTS_NAGA_BARDING_RED
)
457 flags
[TILEP_PART_BOOTS
] = is_naga
? TILEP_FLAG_NORMAL
: TILEP_FLAG_HIDE
;
460 const bool is_cent
= is_player_tile(doll
.parts
[TILEP_PART_BASE
],
463 if (doll
.parts
[TILEP_PART_BOOTS
] >= TILEP_BOOTS_CENTAUR_BARDING
464 && doll
.parts
[TILEP_PART_BOOTS
] <= TILEP_BOOTS_CENTAUR_BARDING_RED
)
466 flags
[TILEP_PART_BOOTS
] = is_cent
? TILEP_FLAG_NORMAL
: TILEP_FLAG_HIDE
;
469 // A higher index here means that the part should be drawn on top.
470 // This is drawn in reverse order because this could be a ghost
471 // or being drawn in water, in which case we want the top-most part
472 // to blend with the background underneath and not with the parts
473 // underneath. Parts drawn afterwards will not obscure parts drawn
474 // previously, because "i" is passed as the depth below.
475 for (int i
= TILEP_PART_MAX
- 1; i
>= 0; --i
)
479 if (!doll
.parts
[p
] || flags
[p
] == TILEP_FLAG_HIDE
)
482 if (p
== TILEP_PART_SHADOW
&& (submerged
|| ghost
))
487 if (flags
[p
] == TILEP_FLAG_CUT_CENTAUR
488 || flags
[p
] == TILEP_FLAG_CUT_NAGA
)
493 buf
.add(doll
.parts
[p
], x
, y
, i
, submerged
, ghost
, 0, 0, ymax
);