1 /*
2 *
3 * Copyright (c) 2002, 2003 Johannes Prix
4 * Copyright (c) 2004-2010 Arthur Huillet
5 *
6 * This file is part of Freedroid
7 *
8 * Freedroid is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Freedroid is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Freedroid; see the file COPYING. If not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 */
24
25 /**
26 * This file contains all the functions managing the character attributes
27 * and the character stats.
28 */
29
30 #define _character_c
31
32 #include "system.h"
33
34 #include "defs.h"
35 #include "struct.h"
36 #include "global.h"
37 #include "proto.h"
38
39 #define BASE_EXP_REQUIRED 500
40 #define BASE_HPMAX 20
41 #define HPMAX_GAIN_PER_LEVEL 5
42 #define HPMAX_GAIN_PER_PHY_POINT 2
43 #define Maxtemp_Gain_Per_CPU_Point 4
44
45 #define RECHARGE_SPEED_PERCENT_PER_DEX_POINT 0
46
47 //--------------------
48 // At first we state some geometry constants for where to insert
49 // which character stats in the character screen...
50 //
51
52 // common x-offsets for texts
53 #define LEFT_TXT_X 25
54 #define RIGHT_TXT_X 195
55
56 // x-offset for numbers in the "level / experience / next level" box
57 #define LEVEL_NR_X 105
58 // x-offset for numbers in the "health / temperature / stamina" box
59 #define HEALTH_NR_X 125
60 // x-offset for numbers in the "armor / attack / damage" box
61 #define ARMOR_NR_X 260
62 // x-offset for values in the skills box
63 #define SKILLS_VALUE_X 198
64
65 // y-offsets - left
66 // STR_X_Y - VIT_Y in defs.h
67 #define POINTS_Y 245
68 #define HEALTH_STAT_Y 289
69 #define TEMP_STAT_Y 308
70 #define STAMINA_STAT_Y 327
71
72 // y-offsets - right
73 #define TOHIT_Y 138
74 #define DAMAGE_Y 158
75 #define DAMRED_Y 178
76 #define MELEE_SKILL_Y 230
77 #define RANGED_SKILL_Y 268
78 #define SPELLCASTING_SKILL_Y 306
79
80 /**
81 * This function adds any bonuses that might be on the influencers things
82 * concerning ONLY PRIMARY STATS, NOT SECONDARY STATS!
83 */
AddInfluencerItemAttributeBonus(item * BonusItem)84 static void AddInfluencerItemAttributeBonus(item * BonusItem)
85 {
86 // In case of no item, the thing to do is pretty easy...
87 //
88 if (BonusItem->type == (-1))
89 return;
90
91 // Apply the bonuses to the stats of the character.
92 Me.strength += BonusItem->bonus_to_str + BonusItem->bonus_to_all_attributes;
93 Me.dexterity += BonusItem->bonus_to_dex + BonusItem->bonus_to_all_attributes;
94 Me.cooling += BonusItem->bonus_to_cooling + BonusItem->bonus_to_all_attributes;
95 Me.physique += BonusItem->bonus_to_physique + BonusItem->bonus_to_all_attributes;
96
97 }; // void AddInfluencerItemAttributeBonus( item* BonusItem )
98
99 /**
100 * This function adds any bonuses that might be on the influencers things
101 * concerning ONLY SECONDARY STATS, NOT PRIMARY STATS!
102 */
AddInfluencerItemSecondaryBonus(item * BonusItem)103 static void AddInfluencerItemSecondaryBonus(item * BonusItem)
104 {
105 // In case of no item, the thing to do is pretty easy...
106 //
107 if (BonusItem->type == (-1))
108 return;
109
110 // Apply the bonuses to the stats of the character.
111 Me.to_hit += BonusItem->bonus_to_attack;
112 Me.maxenergy += BonusItem->bonus_to_health_points;
113 Me.health_recovery_rate += BonusItem->bonus_to_health_recovery;
114 Me.cooling_rate += BonusItem->bonus_to_cooling_rate;
115
116 // Apply bonuses to the special abilities of the character.
117 Me.slowing_melee_targets += BonusItem->bonus_to_slow_enemy;
118 Me.paralyzing_melee_targets += BonusItem->bonus_to_paralyze_enemy;
119 Me.light_bonus_from_tux += BonusItem->bonus_to_light_radius;
120 Me.experience_factor += BonusItem->bonus_to_experience_gain / 100.0;
121 }
122
123 /**
124 * \brief Get the experience required for next level.
125 * \param level Current level.
126 */
get_experience_required(int lvl)127 unsigned int get_experience_required(int lvl)
128 {
129 if (lvl < 0)
130 return 0;
131 return BASE_EXP_REQUIRED * (lvl * lvl) + BASE_EXP_REQUIRED;
132 }
133
134 /**
135 * \brief Check if Tux has reached a new experience level.
136 */
check_for_new_experience_level_reached()137 static void check_for_new_experience_level_reached()
138 {
139 unsigned int exp_required = get_experience_required(Me.exp_level);
140
141 if (Me.Experience >= exp_required) {
142 Me.exp_level++;
143 Me.points_to_distribute += 5;
144
145 // When a droid reaches a new experience level, all health and
146 // force are restored to full this one time no longer. Gothic
147 // rulez more than Diablo rulez.
148 //
149 // Me .energy = Me .maxenergy ;
150 // Me .mana = Me .maxmana ;
151
152 // Also when a new level is reached, we will display a big message
153 // right over the combat window.
154 //
155 SetNewBigScreenMessage(_("Level Gained!"));
156 Takeover_Game_Won_Sound();
157 }
158 }; // void check_for_new_experience_level_reached ( )
159
160 /**
161 * Update all primary stats.
162 */
update_all_primary_stats()163 void update_all_primary_stats()
164 {
165 int i;
166
167 // Now we base PRIMARY stats
168 //
169 Me.strength = Me.base_strength;
170 Me.dexterity = Me.base_dexterity;
171 Me.cooling = Me.base_cooling;
172 Me.physique = Me.base_physique;
173
174 // Now we add all bonuses to the influencers PRIMARY stats
175 //
176 AddInfluencerItemAttributeBonus(&Me.armour_item);
177 AddInfluencerItemAttributeBonus(&Me.weapon_item);
178 AddInfluencerItemAttributeBonus(&Me.drive_item);
179 AddInfluencerItemAttributeBonus(&Me.shield_item);
180 AddInfluencerItemAttributeBonus(&Me.special_item);
181
182 // Maybe there is some boost from a potion or magic spell going on right
183 // now...
184 //
185 if (Me.dexterity_bonus_end_date > Me.current_game_date)
186 Me.dexterity += Me.current_dexterity_bonus;
187 if (Me.power_bonus_end_date > Me.current_game_date)
188 Me.strength += Me.current_power_bonus;
189
190 // Unequip items whose requirements aren't met anymore.
191 // This needs to be done last so that temporary bonuses, for example from
192 // strength and dexterity capsules, allow the player to keep items equipped.
193 item *equipment[5] = { &Me.armour_item, &Me.weapon_item, &Me.drive_item,
194 &Me.shield_item, &Me.special_item };
195 for (i = 0; i < 5; i++) {
196 if (equipment[i]->type == -1) {
197 continue;
198 }
199 if (!ItemUsageRequirementsMet(equipment[i], FALSE)) {
200 give_item(equipment[i]);
201 }
202 }
203
204 // Ensure the effective primary stats never drops below 1
205 if (Me.strength < 1)
206 Me.strength = 1;
207 if (Me.dexterity < 1)
208 Me.dexterity = 1;
209 if (Me.cooling < 1)
210 Me.cooling = 1;
211 if (Me.physique < 1)
212 Me.physique = 1;
213 }
214
215 /**
216 * This function computes secondary stats (i.e. chances for success or
217 * getting hit and the like) using ONLY THE PRIMARY STATS. Bonuses from
218 * current 'magic' modifiers from equipped items will be applied somewhere
219 * else.
220 */
update_secondary_stats_from_primary_stats()221 static void update_secondary_stats_from_primary_stats()
222 {
223 // The chance that this player character will score a hit on an enemy
224 //
225 Me.to_hit = 100 - 40 * exp(- 0.03 * Me.dexterity);
226
227 // How many life points can this character acquire currently
228 //
229 Me.maxenergy = BASE_HPMAX + (Me.exp_level) * HPMAX_GAIN_PER_LEVEL
230 + (Me.physique) * HPMAX_GAIN_PER_PHY_POINT;
231
232 // The maximum mana value computed from the primary stats
233 //
234 Me.max_temperature = (Me.cooling) * Maxtemp_Gain_Per_CPU_Point;
235
236 // How long can this character run until he must take a break and
237 // walk a bit
238 //
239 Me.max_running_power = (Me.strength) + (Me.dexterity) + (Me.physique) + Me.running_power_bonus;
240
241 // base regeneration speed set to 0.2 points per second
242 Me.health_recovery_rate = 0.2;
243 Me.cooling_rate = 1.0;
244 }; // void update_secondary_stats_from_primary_stats ( )
245
246 /**
247 * Now we compute the possible damage the player character can do.
248 * The damage value of course depends on the weapon type that the
249 * character is using. And depending on the weapon type (melee or
250 * ranged weapon) some additional attributes will also play a role.
251 */
update_damage_tux_can_do()252 static void update_damage_tux_can_do()
253 {
254 if (Me.weapon_item.type != (-1)) {
255 if (ItemMap[Me.weapon_item.type].weapon_is_melee != 0) {
256 // Damage modifier in case of MELEE WEAPON is computed:
257 // weapon's modifier * (100+strength)%
258 //
259 Me.base_damage = Me.weapon_item.damage * (Me.strength + 100.0) / 100.0;
260
261 Me.damage_modifier = Me.weapon_item.damage_modifier * (Me.strength + 100.0) / 100.0;
262
263 // Damage AND damage modifier a modified by additional melee weapon
264 // skill: A multiplier is applied!
265 //
266 Me.damage_modifier *= MeleeDamageMultiplierTable[Me.melee_weapon_skill];
267 Me.base_damage *= MeleeDamageMultiplierTable[Me.melee_weapon_skill];
268 } else {
269 // Damage modifier in case of RANGED WEAPON is computed:
270 // weapon's modifier * (100+dexterity)%
271 //
272 Me.base_damage = Me.weapon_item.damage * (Me.dexterity + 100.0) / 100.0;
273 Me.damage_modifier = Me.weapon_item.damage_modifier * (Me.dexterity + 100.0) / 100.0;
274
275 // Damage AND damage modifier a modified by additional ranged weapon
276 // skill: A multiplier is applied!
277 //
278 Me.damage_modifier *= RangedDamageMultiplierTable[Me.ranged_weapon_skill];
279 Me.base_damage *= RangedDamageMultiplierTable[Me.ranged_weapon_skill];
280 }
281 } else {
282 // In case of no weapon equipped at all, we initialize
283 // the damage values with some simple numbers. Currently
284 // strength and dexterity play NO ROLE in weaponless combat.
285 // Maybe that should be changed for something more suitable
286 // at some point...
287 //
288 Me.base_damage = 0;
289 Me.damage_modifier = 1;
290 }
291 }; // void update_damage_tux_can_do ( )
292
293 /**
294 * This function should re-compute all character stats according to the
295 * currently equipped items and currently distributed stats points.
296 */
UpdateAllCharacterStats()297 void UpdateAllCharacterStats()
298 {
299 // Maybe the influencer has reached a new experience level?
300 // Let's check this...
301 //
302 check_for_new_experience_level_reached();
303
304 // The primary status must be computed/updated first, because
305 // the secondary status (chances and the like) will depend on
306 // them...
307 //
308 update_all_primary_stats();
309
310 // At this point we know, that the primary stats of the influencer
311 // have been fully computed. So that means, that finally we can compute
312 // all base SECONDARY stats, that are dependent upon the influencer primary
313 // stats. Once we are done with that, the modifiers to the secondary
314 // stats can be applied as well.
315 //
316 update_secondary_stats_from_primary_stats();
317
318 // Now we compute the possible damage the player character can do.
319 // The damage value of course depends on the weapon type that the
320 // character is using. And depending on the weapon type (melee or
321 // ranged weapon) some additional attributes will also play a role.
322 //
323 update_damage_tux_can_do();
324
325 // Update tux armour class
326 //
327 update_player_armor_class();
328
329 // So at this point we can finally apply all the modifiers to the influencers
330 // SECONDARY stats due to 'magical' items and spells and the like
331 //
332 Me.slowing_melee_targets = 0;
333 Me.paralyzing_melee_targets = 0;
334 Me.light_bonus_from_tux = 0;
335 Me.experience_factor = 1.0;
336 AddInfluencerItemSecondaryBonus(&Me.armour_item);
337 AddInfluencerItemSecondaryBonus(&Me.weapon_item);
338 AddInfluencerItemSecondaryBonus(&Me.drive_item);
339 AddInfluencerItemSecondaryBonus(&Me.shield_item);
340 AddInfluencerItemSecondaryBonus(&Me.special_item);
341
342 // Add light bonus if necessary
343 if (Me.light_bonus_end_date > Me.current_game_date) {
344 // Fade out the bonus in the last second
345 float ratio = min(1.0, Me.light_bonus_end_date - Me.current_game_date);
346 Me.light_bonus_from_tux += 5 * ratio;
347 }
348
349 // Check player's health, temperature and stamina
350 if (Me.energy > Me.maxenergy)
351 Me.energy = Me.maxenergy;
352 if (Me.temperature < 0)
353 Me.temperature = 0;
354 if (Me.running_power > Me.max_running_power)
355 Me.running_power = Me.max_running_power;
356
357 }
358
359 /**
360 * Now we print out the current skill levels in hacking skill,
361 * spellcasting, melee combat, ranged weapon combat and repairing things
362 */
show_character_screen_skills()363 static void show_character_screen_skills()
364 {
365
366 // We add some security against skill values out of allowed
367 // bounds.
368 //
369 if ((Me.melee_weapon_skill < 0) || (Me.melee_weapon_skill >= NUMBER_OF_SKILL_LEVELS)) {
370 fprintf(stderr, "\nmelee_weapon_skill: %d.", Me.melee_weapon_skill);
371 error_message(__FUNCTION__, "\
372 Error: melee weapon skill seems out of bounds.", PLEASE_INFORM | IS_FATAL);
373 }
374 set_current_font(Messagestat_Font);
375 display_text(_("Melee"), RIGHT_TXT_X + CharacterRect.x, MELEE_SKILL_Y + CharacterRect.y, &CharacterRect, 1.0);
376 set_current_font(Messagevar_Font);
377 display_text(_(AllSkillTexts[Me.melee_weapon_skill]),
378 SKILLS_VALUE_X + CharacterRect.x, MELEE_SKILL_Y + 17 + CharacterRect.y, &CharacterRect, 1.0);
379
380 // We add some security against skill values out of allowed
381 // bounds.
382 //
383 if ((Me.ranged_weapon_skill < 0) || (Me.ranged_weapon_skill >= NUMBER_OF_SKILL_LEVELS)) {
384 fprintf(stderr, "\nranged_weapon_skill: %d.", Me.ranged_weapon_skill);
385 error_message(__FUNCTION__, "\
386 Error: ranged weapon skill seems out of bounds.", PLEASE_INFORM | IS_FATAL);
387 }
388 set_current_font(Messagestat_Font);
389 display_text(_("Ranged"), RIGHT_TXT_X + CharacterRect.x, RANGED_SKILL_Y + CharacterRect.y, &CharacterRect, 1.0);
390 set_current_font(Messagevar_Font);
391 display_text(_(AllSkillTexts[Me.ranged_weapon_skill]),
392 SKILLS_VALUE_X + CharacterRect.x, RANGED_SKILL_Y + 17 + CharacterRect.y, &CharacterRect, 1.0);
393
394 // We add some security against skill values out of allowed
395 // bounds.
396 //
397 if ((Me.spellcasting_skill < 0) || (Me.spellcasting_skill >= NUMBER_OF_SKILL_LEVELS)) {
398 fprintf(stderr, "\nProgramming_Skill: %d.", Me.spellcasting_skill);
399 error_message(__FUNCTION__, "\
400 Error: Programming_Skill skill seems out of bounds.", PLEASE_INFORM | IS_FATAL);
401 }
402 set_current_font(Messagestat_Font);
403 display_text(_("Programming"), RIGHT_TXT_X + CharacterRect.x, SPELLCASTING_SKILL_Y + CharacterRect.y, &CharacterRect, 1.0);
404 set_current_font(Messagevar_Font);
405 display_text(_(AllSkillTexts[Me.spellcasting_skill]),
406 SKILLS_VALUE_X + CharacterRect.x, SPELLCASTING_SKILL_Y + 17 + CharacterRect.y, &CharacterRect, 1.0);
407
408 }; // void show_character_screen_skills ( )
409
410 /**
411 * This function displays the character screen.
412 */
ShowCharacterScreen()413 void ShowCharacterScreen()
414 {
415 char CharText[1000];
416
417 DebugPrintf(2, "\n%s(): Function call confirmed.", __FUNCTION__);
418
419 // If the log is not set to visible right now, we do not need to
420 // do anything more, but to restore the usual user rectangle size
421 // back to normal and to return...
422 //
423 if (GameConfig.CharacterScreen_Visible == FALSE)
424 return;
425
426 set_current_font(Messagestat_Font);
427
428 // We define the right side of the user screen as the rectangle
429 // for our inventory screen.
430 //
431 CharacterRect.x = GameConfig.screen_width - CHARACTERRECT_W;
432 CharacterRect.y = 0;
433 CharacterRect.w = CHARACTERRECT_W;
434 CharacterRect.h = CHARACTERRECT_H;
435
436 blit_background("character.png");
437
438 set_current_font(Blue_Font);
439
440 set_current_font(Menu_Font);
441 display_text(Me.character_name, 20 + CharacterRect.x, 12 + CharacterRect.y, &CharacterRect, 1.0);
442
443 set_current_font(Messagestat_Font);
444 display_text(_("Level"), LEFT_TXT_X + CharacterRect.x, 73 + CharacterRect.y, &CharacterRect, 1.0);
445 set_current_font(Messagevar_Font);
446 sprintf(CharText, "%d", Me.exp_level);
447 display_text(CharText, LEVEL_NR_X + CharacterRect.x, 73 + CharacterRect.y, &CharacterRect, 1.0);
448
449 set_current_font(Messagestat_Font);
450 display_text(_("Experience"), LEFT_TXT_X + CharacterRect.x, 89 + CharacterRect.y, &CharacterRect, 1.0);
451 set_current_font(Messagevar_Font);
452 sprintf(CharText, "%u", Me.Experience);
453 display_text(CharText, LEVEL_NR_X + CharacterRect.x, 89 + CharacterRect.y, &CharacterRect, 1.0);
454
455 set_current_font(Messagestat_Font);
456 display_text(_("Next level"), LEFT_TXT_X + CharacterRect.x, 107 + CharacterRect.y, &CharacterRect, 1.0);
457 set_current_font(Messagevar_Font);
458 sprintf(CharText, "%u", get_experience_required(Me.exp_level));
459 display_text(CharText, LEVEL_NR_X + CharacterRect.x, 107 + CharacterRect.y, &CharacterRect, 1.0);
460
461 set_current_font(Messagestat_Font);
462 display_text(_("Circuits"), RIGHT_TXT_X + CharacterRect.x, 71 + CharacterRect.y, &CharacterRect, 1.0);
463 set_current_font(Messagevar_Font);
464 sprintf(CharText, "%6u", Me.Gold);
465 display_text(CharText, 240 + CharacterRect.x, 71 + CharacterRect.y, &CharacterRect, 1.0);
466
467 set_current_font(Messagestat_Font);
468 display_text(_("Strength"), LEFT_TXT_X + CharacterRect.x, STR_Y + CharacterRect.y, &CharacterRect, 1.0);
469 set_current_font(Messagevar_Font);
470 sprintf(CharText, "%d", Me.strength);
471 if (Me.strength != Me.base_strength)
472 sprintf(CharText + strlen(CharText), " (%+d)", Me.strength - Me.base_strength);
473 display_text(CharText, STR_X + CharacterRect.x, STR_Y + CharacterRect.y, &CharacterRect, 1.0);
474
475 set_current_font(Messagestat_Font);
476 display_text(_("Dexterity"), LEFT_TXT_X + CharacterRect.x, DEX_Y + CharacterRect.y, &CharacterRect, 1.0);
477 set_current_font(Messagevar_Font);
478 sprintf(CharText, "%d", Me.dexterity);
479 if (Me.dexterity != Me.base_dexterity)
480 sprintf(CharText + strlen(CharText), " (%+d)", Me.dexterity - Me.base_dexterity);
481 display_text(CharText, STR_X + CharacterRect.x, DEX_Y + CharacterRect.y, &CharacterRect, 1.0);
482
483 set_current_font(Messagestat_Font);
484 display_text(_("Physique"), LEFT_TXT_X + CharacterRect.x, VIT_Y + CharacterRect.y, &CharacterRect, 1.0);
485 set_current_font(Messagevar_Font);
486 sprintf(CharText, "%d", Me.physique);
487 if (Me.physique != Me.base_physique)
488 sprintf(CharText + strlen(CharText), " (%+d)", Me.physique - Me.base_physique);
489 display_text(CharText, STR_X + CharacterRect.x, VIT_Y + CharacterRect.y, &CharacterRect, 1.0);
490
491 set_current_font(Messagestat_Font);
492 display_text(_("Cooling"), LEFT_TXT_X + CharacterRect.x, MAG_Y + CharacterRect.y, &CharacterRect, 1.0);
493 set_current_font(Messagevar_Font);
494 sprintf(CharText, "%d", Me.cooling);
495 if (Me.cooling != Me.base_cooling)
496 sprintf(CharText + strlen(CharText), " (%+d)", Me.cooling - Me.base_cooling);
497 display_text(CharText, STR_X + CharacterRect.x, MAG_Y + CharacterRect.y, &CharacterRect, 1.0);
498
499 SDL_Rect tmprect = CharacterRect;
500 set_current_font(Messagestat_Font);
501 display_text(_("Training points"), LEFT_TXT_X + CharacterRect.x, POINTS_Y + CharacterRect.y, &tmprect, 1.0);
502 set_current_font(Messagevar_Font);
503 sprintf(CharText, "%d", Me.points_to_distribute);
504 display_text(CharText, 155 + CharacterRect.x, POINTS_Y + CharacterRect.y, &CharacterRect, 1.0);
505
506 set_current_font(Messagestat_Font);
507 display_text(_("Health"), LEFT_TXT_X + CharacterRect.x, HEALTH_STAT_Y + CharacterRect.y, &tmprect, 1.0);
508 set_current_font(Messagevar_Font);
509 sprintf(CharText, "%d/%d", (int)Me.energy, (int)Me.maxenergy);
510 display_text(CharText, HEALTH_NR_X + CharacterRect.x, HEALTH_STAT_Y + CharacterRect.y, &CharacterRect, 1.0);
511
512 set_current_font(Messagestat_Font);
513 display_text(_("Temperature"), LEFT_TXT_X + CharacterRect.x, TEMP_STAT_Y + CharacterRect.y, &tmprect, 1.0);
514 set_current_font(Messagevar_Font);
515 sprintf(CharText, "%d/%d", (int)Me.temperature, (int)Me.max_temperature);
516 display_text(CharText, HEALTH_NR_X + CharacterRect.x, TEMP_STAT_Y + CharacterRect.y, &CharacterRect, 1.0);
517
518 set_current_font(Messagestat_Font);
519 display_text(_("Stamina"), LEFT_TXT_X + CharacterRect.x, STAMINA_STAT_Y + CharacterRect.y, &tmprect, 1.0);
520 set_current_font(Messagevar_Font);
521 sprintf(CharText, "%d/%d", (int)Me.running_power, (int)Me.max_running_power);
522 display_text(CharText, HEALTH_NR_X + CharacterRect.x, STAMINA_STAT_Y + CharacterRect.y, &CharacterRect, 1.0);
523
524 set_current_font(Messagestat_Font);
525 display_text(_("Attack"), RIGHT_TXT_X + CharacterRect.x, TOHIT_Y + CharacterRect.y, &CharacterRect, 1.0);
526 set_current_font(Messagevar_Font);
527 sprintf(CharText, "%d%%", (int)Me.to_hit);
528 display_text(CharText, ARMOR_NR_X + CharacterRect.x, TOHIT_Y + CharacterRect.y, &CharacterRect, 1.0);
529
530 set_current_font(Messagestat_Font);
531 display_text(_("Damage"), RIGHT_TXT_X + CharacterRect.x, DAMAGE_Y + CharacterRect.y, &CharacterRect, 1.0);
532 set_current_font(Messagevar_Font);
533
534 // Display range of damage, or a single value if there is no range
535 if (Me.damage_modifier)
536 sprintf(CharText, "%d-%d", (int)Me.base_damage, (int)Me.base_damage + (int)Me.damage_modifier);
537 else
538 sprintf(CharText, "%d", (int)Me.base_damage);
539
540 display_text(CharText, ARMOR_NR_X + CharacterRect.x, DAMAGE_Y + CharacterRect.y, &CharacterRect, 1.0);
541
542 set_current_font(Messagestat_Font);
543 display_text(_("Armor"), RIGHT_TXT_X + CharacterRect.x, DAMRED_Y + CharacterRect.y, &CharacterRect, 1.0);
544 set_current_font(Messagevar_Font);
545 sprintf(CharText, "%d", (int)Me.armor_class);
546 display_text(CharText, ARMOR_NR_X + CharacterRect.x, DAMRED_Y + CharacterRect.y, &CharacterRect, 1.0);
547
548 // Now we print out the current skill levels in hacking skill,
549 // spellcasting, melee combat, ranged weapon combat and repairing things
550 //
551 show_character_screen_skills();
552 if (Me.points_to_distribute > 0) {
553 ShowGenericButtonFromList(MORE_STR_BUTTON);
554 ShowGenericButtonFromList(MORE_DEX_BUTTON);
555 ShowGenericButtonFromList(MORE_VIT_BUTTON);
556 ShowGenericButtonFromList(MORE_MAG_BUTTON);
557 }
558 }; //ShowCharacterScreen ( )
559
560 /**
561 * This function handles input for the character screen.
562 */
HandleCharacterScreen(void)563 void HandleCharacterScreen(void)
564 {
565
566 if (!GameConfig.CharacterScreen_Visible)
567 return;
568
569 if (Me.points_to_distribute > 0) {
570 if (MouseCursorIsOnButton(MORE_STR_BUTTON, GetMousePos_x(), GetMousePos_y()) && MouseLeftClicked()) {
571 Me.base_strength++;
572 Me.points_to_distribute--;
573 }
574 if (MouseCursorIsOnButton(MORE_DEX_BUTTON, GetMousePos_x(), GetMousePos_y()) && MouseLeftClicked()) {
575 Me.base_dexterity++;
576 Me.points_to_distribute--;
577 }
578 if (MouseCursorIsOnButton(MORE_MAG_BUTTON, GetMousePos_x(), GetMousePos_y()) && MouseLeftClicked()) {
579 Me.base_cooling++;
580 Me.points_to_distribute--;
581 }
582 if (MouseCursorIsOnButton(MORE_VIT_BUTTON, GetMousePos_x(), GetMousePos_y()) && MouseLeftClicked()) {
583 Me.base_physique++;
584 Me.points_to_distribute--;
585 }
586
587 }
588
589 }; // HandleCharacterScreen ( void )
590
591 #undef _character_c
592