fallout2-ce/src/trait.cc

315 lines
7.3 KiB
C++
Raw Normal View History

2022-05-19 01:51:26 -07:00
#include "trait.h"
2022-09-15 02:38:23 -07:00
#include <stdio.h>
2022-05-19 01:51:26 -07:00
#include "game.h"
2022-06-18 09:06:37 -07:00
#include "message.h"
2022-05-19 01:51:26 -07:00
#include "object.h"
2022-05-28 02:34:49 -07:00
#include "platform_compat.h"
2022-05-19 01:51:26 -07:00
#include "skill.h"
#include "stat.h"
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-06-18 09:06:37 -07:00
// Provides metadata about traits.
typedef struct TraitDescription {
// The name of trait.
char* name;
// The description of trait.
//
// The description is only used in character editor to inform player about
// effects of this trait.
char* description;
// Identifier of art in [intrface.lst].
int frmId;
} TraitDescription;
2022-05-19 01:51:26 -07:00
// 0x66BE38
2022-06-18 09:06:37 -07:00
static MessageList gTraitsMessageList;
2022-05-19 01:51:26 -07:00
// List of selected traits.
//
// 0x66BE40
2022-06-18 09:06:37 -07:00
static int gSelectedTraits[TRAITS_MAX_SELECTED_COUNT];
2022-05-19 01:51:26 -07:00
// 0x51DB84
2022-06-18 09:06:37 -07:00
static TraitDescription gTraitDescriptions[TRAIT_COUNT] = {
2022-05-19 01:51:26 -07:00
{ NULL, NULL, 55 },
{ NULL, NULL, 56 },
{ NULL, NULL, 57 },
{ NULL, NULL, 58 },
{ NULL, NULL, 59 },
{ NULL, NULL, 60 },
{ NULL, NULL, 61 },
{ NULL, NULL, 62 },
{ NULL, NULL, 63 },
{ NULL, NULL, 64 },
{ NULL, NULL, 65 },
{ NULL, NULL, 66 },
{ NULL, NULL, 67 },
{ NULL, NULL, 94 },
{ NULL, NULL, 69 },
{ NULL, NULL, 70 },
};
// 0x4B39F0
int traitsInit()
{
if (!messageListInit(&gTraitsMessageList)) {
return -1;
}
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-12-08 12:05:50 -08:00
snprintf(path, sizeof(path), "%s%s", asc_5186C8, "trait.msg");
2022-05-19 01:51:26 -07:00
if (!messageListLoad(&gTraitsMessageList, path)) {
return -1;
}
for (int trait = 0; trait < TRAIT_COUNT; trait++) {
MessageListItem messageListItem;
messageListItem.num = 100 + trait;
if (messageListGetItem(&gTraitsMessageList, &messageListItem)) {
gTraitDescriptions[trait].name = messageListItem.text;
}
messageListItem.num = 200 + trait;
if (messageListGetItem(&gTraitsMessageList, &messageListItem)) {
gTraitDescriptions[trait].description = messageListItem.text;
}
}
// NOTE: Uninline.
traitsReset();
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_TRAIT, &gTraitsMessageList);
2022-05-19 01:51:26 -07:00
return true;
}
// 0x4B3ADC
void traitsReset()
{
for (int index = 0; index < TRAITS_MAX_SELECTED_COUNT; index++) {
gSelectedTraits[index] = -1;
}
}
// 0x4B3AF8
void traitsExit()
{
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_TRAIT, nullptr);
2022-05-19 01:51:26 -07:00
messageListFree(&gTraitsMessageList);
}
// Loads trait system state from save game.
//
// 0x4B3B08
int traitsLoad(File* stream)
{
return fileReadInt32List(stream, gSelectedTraits, TRAITS_MAX_SELECTED_COUNT);
}
// Saves trait system state to save game.
//
// 0x4B3B28
int traitsSave(File* stream)
{
return fileWriteInt32List(stream, gSelectedTraits, TRAITS_MAX_SELECTED_COUNT);
}
// Sets selected traits.
//
// 0x4B3B48
void traitsSetSelected(int trait1, int trait2)
{
gSelectedTraits[0] = trait1;
gSelectedTraits[1] = trait2;
}
// Returns selected traits.
//
// 0x4B3B54
void traitsGetSelected(int* trait1, int* trait2)
{
*trait1 = gSelectedTraits[0];
*trait2 = gSelectedTraits[1];
}
// Returns a name of the specified trait, or `NULL` if the specified trait is
// out of range.
//
// 0x4B3B68
char* traitGetName(int trait)
{
return trait >= 0 && trait < TRAIT_COUNT ? gTraitDescriptions[trait].name : NULL;
}
// Returns a description of the specified trait, or `NULL` if the specified
// trait is out of range.
//
// 0x4B3B88
char* traitGetDescription(int trait)
{
return trait >= 0 && trait < TRAIT_COUNT ? gTraitDescriptions[trait].description : NULL;
}
// Return an art ID of the specified trait, or `0` if the specified trait is
// out of range.
//
// 0x4B3BA8
int traitGetFrmId(int trait)
{
return trait >= 0 && trait < TRAIT_COUNT ? gTraitDescriptions[trait].frmId : 0;
}
// Returns `true` if the specified trait is selected.
//
// 0x4B3BC8
bool traitIsSelected(int trait)
{
return gSelectedTraits[0] == trait || gSelectedTraits[1] == trait;
}
// Returns stat modifier depending on selected traits.
//
// 0x4B3C7C
int traitGetStatModifier(int stat)
{
int modifier = 0;
switch (stat) {
case STAT_STRENGTH:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
if (traitIsSelected(TRAIT_BRUISER)) {
modifier += 2;
}
break;
case STAT_PERCEPTION:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
break;
case STAT_ENDURANCE:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
break;
case STAT_CHARISMA:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
break;
case STAT_INTELLIGENCE:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
break;
case STAT_AGILITY:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
if (traitIsSelected(TRAIT_SMALL_FRAME)) {
modifier += 1;
}
break;
case STAT_LUCK:
if (traitIsSelected(TRAIT_GIFTED)) {
modifier += 1;
}
break;
case STAT_MAXIMUM_ACTION_POINTS:
if (traitIsSelected(TRAIT_BRUISER)) {
modifier -= 2;
}
break;
case STAT_ARMOR_CLASS:
if (traitIsSelected(TRAIT_KAMIKAZE)) {
modifier -= critterGetBaseStat(gDude, STAT_ARMOR_CLASS);
}
break;
case STAT_MELEE_DAMAGE:
if (traitIsSelected(TRAIT_HEAVY_HANDED)) {
modifier += 4;
}
break;
case STAT_CARRY_WEIGHT:
if (traitIsSelected(TRAIT_SMALL_FRAME)) {
modifier -= 10 * critterGetBaseStat(gDude, STAT_STRENGTH);
}
break;
case STAT_SEQUENCE:
if (traitIsSelected(TRAIT_KAMIKAZE)) {
modifier += 5;
}
break;
case STAT_HEALING_RATE:
if (traitIsSelected(TRAIT_FAST_METABOLISM)) {
modifier += 2;
}
break;
case STAT_CRITICAL_CHANCE:
if (traitIsSelected(TRAIT_FINESSE)) {
modifier += 10;
}
break;
case STAT_BETTER_CRITICALS:
if (traitIsSelected(TRAIT_HEAVY_HANDED)) {
modifier -= 30;
}
break;
case STAT_RADIATION_RESISTANCE:
if (traitIsSelected(TRAIT_FAST_METABOLISM)) {
2023-02-12 12:12:36 -08:00
modifier -= critterGetBaseStat(gDude, STAT_RADIATION_RESISTANCE);
2022-05-19 01:51:26 -07:00
}
break;
case STAT_POISON_RESISTANCE:
if (traitIsSelected(TRAIT_FAST_METABOLISM)) {
2023-02-12 12:12:36 -08:00
modifier -= critterGetBaseStat(gDude, STAT_POISON_RESISTANCE);
2022-05-19 01:51:26 -07:00
}
break;
}
return modifier;
}
// Returns skill modifier depending on selected traits.
//
// 0x4B40FC
int traitGetSkillModifier(int skill)
{
int modifier = 0;
if (traitIsSelected(TRAIT_GIFTED)) {
modifier -= 10;
}
if (traitIsSelected(TRAIT_GOOD_NATURED)) {
switch (skill) {
case SKILL_SMALL_GUNS:
case SKILL_BIG_GUNS:
case SKILL_ENERGY_WEAPONS:
case SKILL_UNARMED:
case SKILL_MELEE_WEAPONS:
case SKILL_THROWING:
modifier -= 10;
break;
case SKILL_FIRST_AID:
case SKILL_DOCTOR:
case SKILL_SPEECH:
case SKILL_BARTER:
modifier += 15;
break;
}
}
return modifier;
}
2022-09-23 05:43:44 -07:00
} // namespace fallout