mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9a5aeff9a | ||
|
|
bf55a6fbb1 | ||
|
|
9764e2911d | ||
|
|
5d5bb78087 |
@@ -16,7 +16,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| Skills | get/set_critter_skill_points<br>get/set_available_skill_points<br>set_skill_max<br>set_critter_skill_mod<br>set_base_skill_mod<br>mod_skill_points_per_level | not implemented | - |
|
||||
| Graphics | graphics_funcs_available<br>force_graphics_refresh<br>get_screen_width<br>get_screen_height<br>set_palette | implemented: only get_screen_width, get_screen_height | - |
|
||||
| Shaders | load_shader<br>free_shader<br>activate_shader<br>deactivate_shader<br>set/get_shader_* | đźš« | likely will not implement direct compatibility
|
||||
| Perks and traits | set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | not implemented | - |
|
||||
| Perks and traits | get_perk_owed<br>set_perk_owed<br>set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | implemented: only get_perk_owed, set_perk_owed | - |
|
||||
| Virtual file system | fs_create<br>fs_copy<br>fs_find<br>fs_read/write_*<br>fs_delete<br>fs_size<br>fs_pos<br>fs_seek<br>fs_resize | đźš« | Open an issue if you have a use case for these |
|
||||
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
|
||||
| Maps and encounters | in_world_map<br>force_encounter<br>force_encounter_with_flags<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
|
||||
|
||||
+152
-32
@@ -37,6 +37,7 @@
|
||||
#include "platform_compat.h"
|
||||
#include "proto.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
@@ -144,6 +145,11 @@ enum {
|
||||
EDITOR_BUTTONS_COUNT = EDITOR_FIRST_TRAIT + TRAIT_COUNT,
|
||||
};
|
||||
|
||||
static constexpr int kMaxPerkOwed = 250;
|
||||
// nb. this is number of perks, not total perk ranks. This only prevents level ups from granting more perks.
|
||||
static constexpr int kMaxSelectablePerks = 37;
|
||||
static constexpr int kPrimaryStatDescriptionWidth = 100;
|
||||
|
||||
enum {
|
||||
EDITOR_GRAPHIC_BIG_NUMBERS,
|
||||
EDITOR_GRAPHIC_AGE_MASK,
|
||||
@@ -282,6 +288,8 @@ static int perkDialogDrawTraits(int a1);
|
||||
static int perkDialogOptionCompare(const void* a1, const void* a2);
|
||||
static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description);
|
||||
static void _pop_perks();
|
||||
static int characterEditorGetLevelsPerPerk();
|
||||
static void characterEditorGrantPerkAtLevel(int level);
|
||||
static int _is_supper_bonus();
|
||||
static int characterEditorFolderViewInit();
|
||||
static void characterEditorFolderViewScroll(int direction);
|
||||
@@ -769,7 +777,7 @@ static int gCharacterEditorTaggedSkillCount;
|
||||
static int gCharacterEditorTempTaggedSkills[NUM_TAGGED_SKILLS];
|
||||
|
||||
// 0x570A28
|
||||
static char gCharacterEditorHasFreePerkBackup;
|
||||
static unsigned char gCharacterEditorHasFreePerkBackup;
|
||||
|
||||
// 0x570A29
|
||||
static unsigned char gCharacterEditorHasFreePerk;
|
||||
@@ -2474,7 +2482,7 @@ static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousV
|
||||
|
||||
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], flags, value, previousValue, gCharacterEditorWindow);
|
||||
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, kPrimaryStatDescriptionWidth, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
|
||||
messageListItemId = critterGetStat(gDude, stat) + 199;
|
||||
if (messageListItemId > 210) {
|
||||
@@ -2486,7 +2494,7 @@ static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousV
|
||||
} else {
|
||||
value = critterGetStat(gDude, stat);
|
||||
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], 0, value, 0, gCharacterEditorWindow);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, kPrimaryStatDescriptionWidth, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
||||
|
||||
value = critterGetStat(gDude, stat);
|
||||
if (value > 10) {
|
||||
@@ -5668,11 +5676,117 @@ int characterEditorLoad(File* stream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int characterEditorGetPerkOwed()
|
||||
{
|
||||
return gCharacterEditorHasFreePerk;
|
||||
}
|
||||
|
||||
void characterEditorSetPerkOwed(int value)
|
||||
{
|
||||
unsigned int maskedValue = static_cast<unsigned int>(value) & 0xFF;
|
||||
if (maskedValue <= kMaxPerkOwed) {
|
||||
gCharacterEditorHasFreePerk = maskedValue;
|
||||
}
|
||||
}
|
||||
|
||||
// External interface: called when level up occurs
|
||||
void characterEditorHandleLevelUp(int level)
|
||||
{
|
||||
characterEditorGrantPerkAtLevel(level);
|
||||
}
|
||||
|
||||
// compute the character level that the next perk selection should use
|
||||
int characterEditorGetPerkSelectionLevel()
|
||||
{
|
||||
int currentLevel = pcGetStat(PC_STAT_LEVEL);
|
||||
if (settings.gameplay.perk_carryover != PERK_CARRY_OVER_MODE_ON) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
int owed = characterEditorGetPerkOwed();
|
||||
if (owed <= 1) {
|
||||
// If a single perk is owed, use the current level. This prevents odd effects in
|
||||
// saves where perks have been skipped and is a general safe fallback.
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
int levelsPerPerk = characterEditorGetLevelsPerPerk();
|
||||
|
||||
// This therefore uses the number of perk thresholds strictly before the
|
||||
// current level, then compares that against the total perk ranks already
|
||||
// spent. In the common non-scripted case:
|
||||
// - level 6 with 0 spent perks yields one deferred threshold (level 3)
|
||||
// - after spending one perk, there is no older backlog left, so the next
|
||||
// owed perk uses level 6 requirements
|
||||
// - level 9 with 2 spent perks has no older backlog, so owed perks are
|
||||
// immediately spendable at level 9
|
||||
int previousThresholdsReached = (currentLevel - 1) / levelsPerPerk;
|
||||
int spentPerks = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
spentPerks += perkGetRank(gDude, perk);
|
||||
}
|
||||
|
||||
// This is a heuristic for the 99.9% case where perk ranks come from normal
|
||||
// perk picks. If enough perk ranks have already been spent to cover all
|
||||
// earlier thresholds, there is no deferred backlog to force in order.
|
||||
if (spentPerks >= previousThresholdsReached) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
// The next deferred pick corresponds to the earliest previously missed
|
||||
// threshold after the already-spent perk ranks.
|
||||
int thresholdIndex = spentPerks + 1;
|
||||
int selectionLevel = std::max(3, thresholdIndex * levelsPerPerk);
|
||||
if (selectionLevel <= 0 || selectionLevel > currentLevel) {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
return selectionLevel;
|
||||
}
|
||||
|
||||
// 0x43C20C
|
||||
void characterEditorReset()
|
||||
{
|
||||
gCharacterEditorRemainingCharacterPoints = 5;
|
||||
gCharacterEditorLastLevel = 1;
|
||||
characterEditorSetPerkOwed(0);
|
||||
}
|
||||
|
||||
static int characterEditorGetLevelsPerPerk()
|
||||
{
|
||||
int progression = 3;
|
||||
if (traitIsSelected(TRAIT_SKILLED)) {
|
||||
progression += 1;
|
||||
}
|
||||
|
||||
return progression;
|
||||
}
|
||||
|
||||
static void characterEditorGrantPerkAtLevel(int level)
|
||||
{
|
||||
if (level <= 0 || level % characterEditorGetLevelsPerPerk() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int selectedPerksCount = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
if (perkGetRank(gDude, perk) != 0) {
|
||||
selectedPerksCount += 1;
|
||||
if (selectedPerksCount >= kMaxSelectablePerks) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (settings.gameplay.perk_carryover) {
|
||||
case PERK_CARRY_OVER_MODE_OFF:
|
||||
characterEditorSetPerkOwed(1);
|
||||
break;
|
||||
case PERK_CARRY_OVER_MODE_ON:
|
||||
case PERK_CARRY_OVER_MODE_SFALL:
|
||||
characterEditorSetPerkOwed(characterEditorGetPerkOwed() + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// level up if needed
|
||||
@@ -5682,6 +5796,13 @@ static int characterEditorUpdateLevel()
|
||||
{
|
||||
int level = pcGetStat(PC_STAT_LEVEL);
|
||||
if (level != gCharacterEditorLastLevel && level <= PC_LEVEL_MAX) {
|
||||
// Runtime level-up now grants perks immediately. However, older saves
|
||||
// may still have last_level behind the real level with no owed perks
|
||||
// recorded, because perk grants used to be deferred until the next
|
||||
// character screen visit. Replay perk grants only for that legacy
|
||||
// catch-up case.
|
||||
bool shouldReplayPerkGrants = characterEditorGetPerkOwed() == 0;
|
||||
|
||||
for (int nextLevel = gCharacterEditorLastLevel + 1; nextLevel <= level; nextLevel++) {
|
||||
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
||||
sp += 5;
|
||||
@@ -5700,30 +5821,13 @@ static int characterEditorUpdateLevel()
|
||||
|
||||
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp);
|
||||
|
||||
int selectedPerksCount = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
if (perkGetRank(gDude, perk) != 0) {
|
||||
selectedPerksCount += 1;
|
||||
if (selectedPerksCount >= 37) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedPerksCount < 37) {
|
||||
int progression = 3;
|
||||
if (traitIsSelected(TRAIT_SKILLED)) {
|
||||
progression += 1;
|
||||
}
|
||||
|
||||
if (nextLevel % progression == 0) {
|
||||
gCharacterEditorHasFreePerk = 1;
|
||||
}
|
||||
if (shouldReplayPerkGrants) {
|
||||
characterEditorGrantPerkAtLevel(nextLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gCharacterEditorHasFreePerk != 0) {
|
||||
while (characterEditorGetPerkOwed() != 0) {
|
||||
characterEditorWindowSelectedFolder = 0;
|
||||
characterEditorDrawFolders();
|
||||
windowRefresh(gCharacterEditorWindow);
|
||||
@@ -5732,11 +5836,15 @@ static int characterEditorUpdateLevel()
|
||||
if (rc == -1) {
|
||||
debugPrint("\n *** Error running perks dialog! ***\n");
|
||||
return -1;
|
||||
} else if (rc == 0) {
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
characterEditorDrawFolders();
|
||||
} else if (rc == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
characterEditorDrawFolders();
|
||||
gCharacterEditorHasFreePerk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5785,6 +5893,10 @@ static int perkDialogShow()
|
||||
gPerkDialogCardFrmId = -1;
|
||||
gPerkDialogCardTitle[0] = '\0';
|
||||
gPerkDialogCardDrawn = false;
|
||||
int previousPerkRanks[PERK_COUNT];
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
previousPerkRanks[perk] = perkGetRank(gDude, perk);
|
||||
}
|
||||
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 86, 0, 0, 0);
|
||||
if (!_perkDialogBackgroundFrmImage.lock(backgroundFid)) {
|
||||
@@ -5910,6 +6022,12 @@ static int perkDialogShow()
|
||||
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 186 + 171, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
||||
|
||||
int count = perkDialogDrawPerks();
|
||||
if (count == 0) {
|
||||
debugPrint("*** No perks available for current owed slot! ***");
|
||||
_perkDialogBackgroundFrmImage.unlock();
|
||||
windowDestroy(gPerkDialogWindow);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Original code is slightly different, but does the same thing.
|
||||
int perk = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value;
|
||||
@@ -5931,7 +6049,8 @@ static int perkDialogShow()
|
||||
int rc = perkDialogHandleInput(count, perkDialogRefreshPerks);
|
||||
|
||||
if (rc == 1) {
|
||||
if (perkAdd(gDude, gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value) == -1) {
|
||||
int selectionLevel = characterEditorGetPerkSelectionLevel();
|
||||
if (perkAddAtLevel(gDude, gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value, selectionLevel) == -1) {
|
||||
debugPrint("\n*** Unable to add perk! ***\n");
|
||||
rc = 2;
|
||||
}
|
||||
@@ -5940,19 +6059,20 @@ static int perkDialogShow()
|
||||
rc &= 1;
|
||||
|
||||
if (rc != 0) {
|
||||
if (perkGetRank(gDude, PERK_TAG) != 0 && gCharacterEditorPerksBackup[PERK_TAG] == 0) {
|
||||
characterEditorSetPerkOwed(characterEditorGetPerkOwed() - 1);
|
||||
if (perkGetRank(gDude, PERK_TAG) != 0 && previousPerkRanks[PERK_TAG] == 0) {
|
||||
if (!perkDialogHandleTagPerk()) {
|
||||
perkRemove(gDude, PERK_TAG);
|
||||
}
|
||||
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && gCharacterEditorPerksBackup[PERK_MUTATE] == 0) {
|
||||
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && previousPerkRanks[PERK_MUTATE] == 0) {
|
||||
if (!perkDialogHandleMutatePerk()) {
|
||||
perkRemove(gDude, PERK_MUTATE);
|
||||
}
|
||||
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != gCharacterEditorPerksBackup[PERK_LIFEGIVER]) {
|
||||
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != previousPerkRanks[PERK_LIFEGIVER]) {
|
||||
int maxHp = critterGetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
||||
critterSetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS, maxHp + 4);
|
||||
critterAdjustHitPoints(gDude, 4);
|
||||
} else if (perkGetRank(gDude, PERK_EDUCATED) != gCharacterEditorPerksBackup[PERK_EDUCATED]) {
|
||||
} else if (perkGetRank(gDude, PERK_EDUCATED) != previousPerkRanks[PERK_EDUCATED]) {
|
||||
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
||||
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp + 2);
|
||||
}
|
||||
@@ -6266,7 +6386,7 @@ static int perkDialogDrawPerks()
|
||||
fontSetCurrent(101);
|
||||
|
||||
int perks[PERK_COUNT];
|
||||
int count = perkGetAvailablePerks(gDude, perks);
|
||||
int count = perkGetAvailablePerks(gDude, characterEditorGetPerkSelectionLevel(), perks);
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,16 @@ namespace fallout {
|
||||
|
||||
extern int gCharacterEditorRemainingCharacterPoints;
|
||||
|
||||
enum PerkCarryOverMode {
|
||||
// Unspent perks are lost on level up (vanilla)
|
||||
PERK_CARRY_OVER_MODE_OFF = 0,
|
||||
// Unspent perks are preserved on level up, but you still spend unspent perks at the appropriate levels.
|
||||
// E.g. if you reach level 9 and have never spent any perks, you first choose from the level 3 perks, then 6, then 9. (CE)
|
||||
PERK_CARRY_OVER_MODE_ON = 1,
|
||||
// Unspent perks are preserved on level up, and you can choose to spend them on perks for the current level.
|
||||
PERK_CARRY_OVER_MODE_SFALL = 2,
|
||||
};
|
||||
|
||||
int characterEditorShow(bool isCreationMode);
|
||||
void characterEditorInit();
|
||||
bool _isdoschar(int ch);
|
||||
@@ -14,6 +24,10 @@ char* _strmfe(char* dest, const char* name, const char* ext);
|
||||
int characterEditorSave(File* stream);
|
||||
int characterEditorLoad(File* stream);
|
||||
void characterEditorReset();
|
||||
int characterEditorGetPerkOwed();
|
||||
void characterEditorSetPerkOwed(int value);
|
||||
void characterEditorHandleLevelUp(int level);
|
||||
int characterEditorGetPerkSelectionLevel();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace fallout {
|
||||
#define GAME_CONFIG_SYSTEM_KEY "system"
|
||||
#define GAME_CONFIG_SCREEN_KEY "screen"
|
||||
#define GAME_CONFIG_UI_KEY "ui"
|
||||
#define GAME_CONFIG_GAMEPLAY_KEY "gameplay"
|
||||
#define GAME_CONFIG_PREFERENCES_KEY "preferences"
|
||||
#define GAME_CONFIG_SOUND_KEY "sound"
|
||||
#define GAME_CONFIG_MAPPER_KEY "mapper"
|
||||
@@ -86,6 +87,7 @@ namespace fallout {
|
||||
#define GAME_CONFIG_SORT_SCRIPT_LIST_KEY "sort_script_list"
|
||||
#define GAME_CONFIG_PLAYER_SPEEDUP_KEY "player_speedup"
|
||||
#define GAME_CONFIG_UI_ANIM_SPEED_KEY "ui_anim_speed"
|
||||
#define GAME_CONFIG_PERK_CARRYOVER_KEY "perk_carryover"
|
||||
|
||||
#define GAME_CONFIG_RESOLUTION_X_KEY "resolution_x"
|
||||
#define GAME_CONFIG_RESOLUTION_Y_KEY "resolution_y"
|
||||
|
||||
+11
-6
@@ -49,7 +49,7 @@ typedef struct PerkRankData {
|
||||
} PerkRankData;
|
||||
|
||||
static PerkRankData* perkGetRankData(Object* critter);
|
||||
static bool perkCanAdd(Object* critter, int perk);
|
||||
static bool perkCanAddAtLevel(Object* critter, int perk, int level);
|
||||
static void perkResetRanks();
|
||||
|
||||
// 0x519DCC
|
||||
@@ -299,7 +299,7 @@ static PerkRankData* perkGetRankData(Object* critter)
|
||||
}
|
||||
|
||||
// 0x49680C
|
||||
static bool perkCanAdd(Object* critter, int perk)
|
||||
static bool perkCanAddAtLevel(Object* critter, int perk, int level)
|
||||
{
|
||||
if (!perkIsValid(perk)) {
|
||||
return false;
|
||||
@@ -317,7 +317,7 @@ static bool perkCanAdd(Object* critter, int perk)
|
||||
}
|
||||
|
||||
if (critter == gDude) {
|
||||
if (pcGetStat(PC_STAT_LEVEL) < perkDescription->minLevel) {
|
||||
if (level < perkDescription->minLevel) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -432,12 +432,17 @@ static void perkResetRanks()
|
||||
|
||||
// 0x496A5C
|
||||
int perkAdd(Object* critter, int perk)
|
||||
{
|
||||
return perkAddAtLevel(critter, perk, pcGetStat(PC_STAT_LEVEL));
|
||||
}
|
||||
|
||||
int perkAddAtLevel(Object* critter, int perk, int level)
|
||||
{
|
||||
if (!perkIsValid(perk)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!perkCanAdd(critter, perk)) {
|
||||
if (!perkCanAddAtLevel(critter, perk, level)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -498,11 +503,11 @@ int perkRemove(Object* critter, int perk)
|
||||
// Returns perks available to pick.
|
||||
//
|
||||
// 0x496B44
|
||||
int perkGetAvailablePerks(Object* critter, int* perks)
|
||||
int perkGetAvailablePerks(Object* critter, int level, int* perks)
|
||||
{
|
||||
int count = 0;
|
||||
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
||||
if (perkCanAdd(critter, perk)) {
|
||||
if (perkCanAddAtLevel(critter, perk, level)) {
|
||||
perks[count] = perk;
|
||||
count++;
|
||||
}
|
||||
|
||||
+2
-1
@@ -13,9 +13,10 @@ void perksExit();
|
||||
int perksLoad(File* stream);
|
||||
int perksSave(File* stream);
|
||||
int perkAdd(Object* critter, int perk);
|
||||
int perkAddAtLevel(Object* critter, int perk, int level);
|
||||
int perkAddForce(Object* critter, int perk);
|
||||
int perkRemove(Object* critter, int perk);
|
||||
int perkGetAvailablePerks(Object* critter, int* perks);
|
||||
int perkGetAvailablePerks(Object* critter, int level, int* perks);
|
||||
int perkGetRank(Object* critter, int perk);
|
||||
char* perkGetName(int perk);
|
||||
char* perkGetDescription(int perk);
|
||||
|
||||
@@ -135,6 +135,8 @@ static struct SfallOpcodeInfo opcodeInfoArray[] = {
|
||||
{ 0x189, "set_perk_name" },
|
||||
{ 0x18a, "set_perk_desc" },
|
||||
{ 0x18b, "set_pipboy_available" },
|
||||
{ 0x18e, "get_perk_owed" },
|
||||
{ 0x18f, "set_perk_owed" },
|
||||
{ 0x190, "get_perk_available" },
|
||||
{ 0x192, "set_critter_current_ap" },
|
||||
{ 0x195, "set_weapon_knockback" },
|
||||
@@ -288,4 +290,4 @@ static struct SfallOpcodeInfo opcodeInfoArray[] = {
|
||||
{ 0x281, "sfall_func8" }
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -74,6 +74,10 @@ static void settingsFromConfig()
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_SPLASH_SCREEN_SIZE_KEY, settings.ui.splash_screen_size, 0, 2);
|
||||
settingsRead(GAME_CONFIG_UI_KEY, GAME_CONFIG_IGNORE_MAP_EDGES_KEY, settings.ui.ignore_map_edges);
|
||||
|
||||
int perkCarryOver = settings.gameplay.perk_carryover;
|
||||
settingsRead(GAME_CONFIG_GAMEPLAY_KEY, GAME_CONFIG_PERK_CARRYOVER_KEY, perkCarryOver, 0, 2);
|
||||
settings.gameplay.perk_carryover = static_cast<PerkCarryOverMode>(perkCarryOver);
|
||||
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, settings.preferences.game_difficulty);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, settings.preferences.combat_difficulty);
|
||||
settingsRead(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, settings.preferences.violence_level);
|
||||
@@ -163,6 +167,8 @@ static void settingsToConfig()
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_SPLASH_SCREEN_SIZE_KEY, settings.ui.splash_screen_size);
|
||||
settingsWrite(GAME_CONFIG_UI_KEY, GAME_CONFIG_IGNORE_MAP_EDGES_KEY, settings.ui.ignore_map_edges);
|
||||
|
||||
settingsWrite(GAME_CONFIG_GAMEPLAY_KEY, GAME_CONFIG_PERK_CARRYOVER_KEY, static_cast<int>(settings.gameplay.perk_carryover));
|
||||
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_GAME_DIFFICULTY_KEY, settings.preferences.game_difficulty);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_DIFFICULTY_KEY, settings.preferences.combat_difficulty);
|
||||
settingsWrite(GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, settings.preferences.violence_level);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "character_editor.h"
|
||||
#include "game_config.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -52,6 +53,10 @@ struct UISettings {
|
||||
bool ignore_map_edges = false;
|
||||
};
|
||||
|
||||
struct GameplaySettings {
|
||||
PerkCarryOverMode perk_carryover = PERK_CARRY_OVER_MODE_ON;
|
||||
};
|
||||
|
||||
struct PreferencesSettings {
|
||||
int game_difficulty = GAME_DIFFICULTY_NORMAL;
|
||||
int combat_difficulty = COMBAT_DIFFICULTY_NORMAL;
|
||||
@@ -126,6 +131,7 @@ struct Settings {
|
||||
SystemSettings system;
|
||||
ScreenSettings screen;
|
||||
UISettings ui;
|
||||
GameplaySettings gameplay;
|
||||
PreferencesSettings preferences;
|
||||
SoundSettings sound;
|
||||
DebugSettings debug;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
#include "combat.h"
|
||||
#include "critter.h"
|
||||
@@ -219,6 +220,17 @@ static void op_set_global_script_repeat(Program* program)
|
||||
sfall_gl_scr_set_repeat(program, frames);
|
||||
}
|
||||
|
||||
static void op_get_perk_owed(Program* program)
|
||||
{
|
||||
programStackPushInteger(program, characterEditorGetPerkOwed());
|
||||
}
|
||||
|
||||
static void op_set_perk_owed(Program* program)
|
||||
{
|
||||
int value = programStackPopInteger(program);
|
||||
characterEditorSetPerkOwed(value);
|
||||
}
|
||||
|
||||
// key_pressed
|
||||
static void op_key_pressed(Program* program)
|
||||
{
|
||||
@@ -1663,7 +1675,9 @@ void sfallOpcodesInit()
|
||||
// 0x818d - void mod_kill_counter(int critterType, int amount)
|
||||
|
||||
// 0x818e - int get_perk_owed()
|
||||
interpreterRegisterOpcode(0x818E, op_get_perk_owed);
|
||||
// 0x818f - void set_perk_owed(int value)
|
||||
interpreterRegisterOpcode(0x818F, op_set_perk_owed);
|
||||
// 0x8190 - int get_perk_available(int perk)
|
||||
|
||||
// 0x8191 - int get_critter_current_ap(object critter)
|
||||
|
||||
+10
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
#include "combat.h"
|
||||
#include "critter.h"
|
||||
#include "display_monitor.h"
|
||||
@@ -755,6 +756,8 @@ int pcAddExperienceWithOptions(int xp, bool doParty, int* xpGained)
|
||||
}
|
||||
|
||||
if (pcSetStat(PC_STAT_LEVEL, gPcStatValues[PC_STAT_LEVEL] + 1) == 0) {
|
||||
characterEditorHandleLevelUp(gPcStatValues[PC_STAT_LEVEL]);
|
||||
|
||||
int maxHpBefore = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
||||
|
||||
// You have gone up a level.
|
||||
@@ -815,6 +818,13 @@ int pcSetExperience(int xp)
|
||||
int newLevel = level - 1;
|
||||
|
||||
pcSetStat(PC_STAT_LEVEL, newLevel);
|
||||
|
||||
if (newLevel > oldLevel) {
|
||||
for (int levelToGrant = oldLevel + 1; levelToGrant <= newLevel; levelToGrant++) {
|
||||
characterEditorHandleLevelUp(levelToGrant);
|
||||
}
|
||||
}
|
||||
|
||||
dudeDisableState(DUDE_STATE_LEVEL_UP_AVAILABLE);
|
||||
|
||||
// NOTE: Uninline.
|
||||
|
||||
Reference in New Issue
Block a user