2026/05/20 Update

Background system cleanup.
This commit is contained in:
Jaysyn904
2026-05-20 10:03:40 -04:00
parent dc174e1aaa
commit 0fc4ec3324
62 changed files with 10754 additions and 255 deletions

View File

@@ -0,0 +1,305 @@
{
"__data_type": "DLG ",
"DelayEntry": {
"type": "dword",
"value": 0
},
"DelayReply": {
"type": "dword",
"value": 0
},
"EndConverAbort": {
"type": "resref",
"value": "nw_walk_wp"
},
"EndConversation": {
"type": "resref",
"value": "nw_walk_wp"
},
"EntryList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"ActionParams": {
"type": "list",
"value": []
},
"Animation": {
"type": "dword",
"value": 0
},
"AnimLoop": {
"type": "byte",
"value": 1
},
"Comment": {
"type": "cexostring",
"value": ""
},
"Delay": {
"type": "dword",
"value": 4294967295
},
"Quest": {
"type": "cexostring",
"value": ""
},
"RepliesList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"Active": {
"type": "resref",
"value": ""
},
"ConditionParams": {
"type": "list",
"value": []
},
"Index": {
"type": "dword",
"value": 0
},
"IsChild": {
"type": "byte",
"value": 0
}
}
]
},
"Script": {
"type": "resref",
"value": ""
},
"Sound": {
"type": "resref",
"value": ""
},
"Speaker": {
"type": "cexostring",
"value": ""
},
"Text": {
"type": "cexolocstring",
"value": {
"0": "Welcome to Spellplague: The Rebirth. We hope you enjoy your stay. The world's lore takes place in 1480, when Mystra's just returned and the Shadow Plague is coming into effect. You will now choose background feats that define your character! These have societal and mechanical effects so choose what best fits your character."
}
}
},
{
"__struct_id": 1,
"ActionParams": {
"type": "list",
"value": []
},
"Animation": {
"type": "dword",
"value": 0
},
"AnimLoop": {
"type": "byte",
"value": 1
},
"Comment": {
"type": "cexostring",
"value": ""
},
"Delay": {
"type": "dword",
"value": 4294967295
},
"Quest": {
"type": "cexostring",
"value": ""
},
"RepliesList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"Active": {
"type": "resref",
"value": ""
},
"ConditionParams": {
"type": "list",
"value": []
},
"Index": {
"type": "dword",
"value": 1
},
"IsChild": {
"type": "byte",
"value": 0
}
}
]
},
"Script": {
"type": "resref",
"value": ""
},
"Sound": {
"type": "resref",
"value": ""
},
"Speaker": {
"type": "cexostring",
"value": ""
},
"Text": {
"type": "cexolocstring",
"value": {
"0": "The Selection process is as follows:\n1. Subrace/Ethnicity, 2. Class Standing, 3. Background, 4. Deity, 5. Language, 6. Proficiencies, 7 Final Touches.\n\nIf for any reason you accidentally exit out of this conversation, pull the lever next to you to continue your progress from the selection point you left off at."
}
}
}
]
},
"NumWords": {
"type": "dword",
"value": 106
},
"PreventZoomIn": {
"type": "byte",
"value": 0
},
"ReplyList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"ActionParams": {
"type": "list",
"value": []
},
"Animation": {
"type": "dword",
"value": 0
},
"AnimLoop": {
"type": "byte",
"value": 1
},
"Comment": {
"type": "cexostring",
"value": ""
},
"Delay": {
"type": "dword",
"value": 4294967295
},
"EntriesList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"Active": {
"type": "resref",
"value": ""
},
"ConditionParams": {
"type": "list",
"value": []
},
"Index": {
"type": "dword",
"value": 1
},
"IsChild": {
"type": "byte",
"value": 0
}
}
]
},
"Quest": {
"type": "cexostring",
"value": ""
},
"Script": {
"type": "resref",
"value": ""
},
"Sound": {
"type": "resref",
"value": ""
},
"Text": {
"type": "cexolocstring",
"value": {
"0": "Next."
}
}
},
{
"__struct_id": 1,
"ActionParams": {
"type": "list",
"value": []
},
"Animation": {
"type": "dword",
"value": 0
},
"AnimLoop": {
"type": "byte",
"value": 1
},
"Comment": {
"type": "cexostring",
"value": ""
},
"Delay": {
"type": "dword",
"value": 4294967295
},
"EntriesList": {
"type": "list",
"value": []
},
"Quest": {
"type": "cexostring",
"value": ""
},
"Script": {
"type": "resref",
"value": "cv_background"
},
"Sound": {
"type": "resref",
"value": ""
},
"Text": {
"type": "cexolocstring",
"value": {
"0": "Understood."
}
}
}
]
},
"StartingList": {
"type": "list",
"value": [
{
"__struct_id": 0,
"Active": {
"type": "resref",
"value": ""
},
"ConditionParams": {
"type": "list",
"value": []
},
"Index": {
"type": "dword",
"value": 0
}
}
]
}
}

View File

@@ -1,11 +1,8 @@
// bg_age_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
const int STAGE_LIST = 0;
const int STAGE_CONFIRM = 1;
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
@@ -20,124 +17,247 @@ object EnsurePlayerDataObject(object oPC)
return oItem;
}
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_age_cv main() entered");
const int STAGE_LIST = 0;
const int STAGE_CONFIRM = 1;
object oItem = EnsurePlayerDataObject(oPC);
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
// Required guard: abort if nValue is 0
if (nValue == 0) return;
if (nValue == DYNCONV_SETUP_STAGE)
{
if (!GetIsStageSetUp(nStage, oPC))
{
if (nStage == STAGE_LIST)
{
SetHeader("Now for the finishing touches. If you would like to apply an age modifier to your character, you may do so. Aging affects are as follows:\n" +
"Young Age/Opt Out: No effects\n" +
"Middle Age: -1 STR, -1 DEX, -1 CON, +1 INT, +1 WIS, +1 CHA\n" +
"Old Age: -2 STR, -2 DEX, -2 CON, +2 INT, +2 WIS, +2 CHA\n" +
"Venerable Age: -3 STR, -3 DEX, -3 CON, +3 INT, +3 WIS, +3 CHA");
// Store descriptive text for each age choice
SetLocalString(oPC, "age_text_0", "You are in the prime of your youth, with physical abilities at their peak and mental faculties still developing. This represents a character starting their adventuring career in their late teens or early twenties, with no modifiers to abilities.");
SetLocalString(oPC, "age_text_1", "You have reached middle age, where the physical toll of years begins to show, but experience and wisdom have sharpened your mind. Your body has begun to slow (-1 STR, -1 DEX, -1 CON) while your mental faculties have matured (+1 INT, +1 WIS, +1 CHA).");
SetLocalString(oPC, "age_text_2", "The weight of many decades rests upon you. Physical decline is more pronounced (-2 STR, -2 DEX, -2 CON) but your accumulated knowledge and insight have grown significantly (+2 INT, +2 WIS, +2 CHA). You are a veteran of life's trials.");
SetLocalString(oPC, "age_text_3", "You have lived a very long life, and your body shows the full extent of your years (-3 STR, -3 DEX, -3 CON). However, your mind is a repository of vast knowledge and profound wisdom (+3 INT, +3 WIS, +3 CHA). You are truly an elder whose experience spans generations.");
AddChoice("Young Age / Opt Out", 0, oPC);
AddChoice("Middle Age", 1, oPC);
AddChoice("Old Age", 2, oPC);
AddChoice("Venerable Age", 3, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
else if (nStage == STAGE_CONFIRM)
{
int nSelected = GetLocalInt(oPC, "age_selected");
string sAgeText = GetLocalString(oPC, "age_text_" + IntToString(nSelected));
string sPrompt = sAgeText + "\n\nAre you sure you want to apply this age modifier?";
SetHeader(sPrompt);
AddChoice("Yes", nSelected, oPC);
AddChoice("No", -1, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
}
SetupTokens();
}
else
{
int nChoice = GetChoice(oPC);
if (nStage == STAGE_LIST)
{
SetLocalInt(oPC, "age_selected", nChoice);
SetStage(STAGE_CONFIRM, oPC);
}
else if (nStage == STAGE_CONFIRM)
{
if (nChoice >= 0)
{
string sGrant;
switch (nChoice)
{
default:
case 0:
{// youthful
//sGrant = "te_bg_a_n";
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_YOUTHFUL);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_YOUTHFUL);
break;
}
case 1:
{// middle-aged
//sGrant = "te_bg_a_m";
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_MIDDLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_MIDDLE);
break;
}
case 2:
{
//sGrant = "te_bg_a_o";
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_OLD);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_OLD);
break;
}
case 3:
{
//sGrant = "te_bg_a_v"; break;
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_VENERABLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_VENERABLE);
}
}
//if (sGrant != "") ExecuteScript(sGrant, oPC);
// Conversation ends naturally
}
else
{
SetStage(STAGE_LIST, oPC);
}
}
SetStage(nStage, oPC);
}
void main()
{
object oPC = GetPCSpeaker();
object oItem = EnsurePlayerDataObject(oPC);
//SendMessageToPC(oPC, "DEBUG: bg_age_cv main() entered");
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
// Required guard: abort if nValue is 0
if (nValue == 0) return;
if (nValue == DYNCONV_SETUP_STAGE)
{
if (!GetIsStageSetUp(nStage, oPC))
{
if (nStage == STAGE_LIST)
{
SetHeader("Now for the finishing touches. If you would like to apply an age modifier to your character, you may do so. Aging affects are as follows:\n" +
"Young Age/Opt Out: No effects\n" +
"Middle Age: -1 STR, -1 DEX, -1 CON, +1 INT, +1 WIS, +1 CHA\n" +
"Old Age: -2 STR, -2 DEX, -2 CON, +2 INT, +2 WIS, +2 CHA\n" +
"Venerable Age: -3 STR, -3 DEX, -3 CON, +3 INT, +3 WIS, +3 CHA");
// Store descriptive text for each age choice
SetLocalString(oPC, "age_text_0", "You are in the prime of your youth, with physical abilities at their peak and mental faculties still developing. This represents a character starting their adventuring career in their late teens or early twenties, with no modifiers to abilities.");
SetLocalString(oPC, "age_text_1", "You have reached middle age, where the physical toll of years begins to show, but experience and wisdom have sharpened your mind. Your body has begun to slow (-1 STR, -1 DEX, -1 CON) while your mental faculties have matured (+1 INT, +1 WIS, +1 CHA).");
SetLocalString(oPC, "age_text_2", "The weight of many decades rests upon you. Physical decline is more pronounced (-2 STR, -2 DEX, -2 CON) but your accumulated knowledge and insight have grown significantly (+2 INT, +2 WIS, +2 CHA). You are a veteran of life's trials.");
SetLocalString(oPC, "age_text_3", "You have lived a very long life, and your body shows the full extent of your years (-3 STR, -3 DEX, -3 CON). However, your mind is a repository of vast knowledge and profound wisdom (+3 INT, +3 WIS, +3 CHA). You are truly an elder whose experience spans generations.");
AddChoice("Young Age / Opt Out", 0, oPC);
AddChoice("Middle Age", 1, oPC);
AddChoice("Old Age", 2, oPC);
AddChoice("Venerable Age", 3, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
else if (nStage == STAGE_CONFIRM)
{
int nSelected = GetLocalInt(oPC, "age_selected");
string sAgeText = GetLocalString(oPC, "age_text_" + IntToString(nSelected));
string sPrompt = sAgeText + "\n\nAre you sure you want to apply this age modifier?";
SetHeader(sPrompt);
AddChoice("Yes", nSelected, oPC);
AddChoice("No", -1, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
}
SetupTokens();
}
else
{
int nChoice = GetChoice(oPC);
if (nStage == STAGE_LIST)
{
SetLocalInt(oPC, "cs_selected", nChoice);
nStage = STAGE_CONFIRM; // update local nStage
}
else if (nStage == STAGE_CONFIRM)
{
if (nChoice >= 0)
{
string sGrant;
switch (nChoice)
{
default:
case 0:
{// youthful
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_YOUTHFUL);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_YOUTHFUL);
break;
}
case 1:
{// middle-aged
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_MIDDLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_MIDDLE);
break;
}
case 2:
{
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_OLD);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_OLD);
break;
}
case 3:
{
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_VENERABLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_VENERABLE);
break;
}
}
ClearCurrentStage(oPC);
SetPersistantLocalInt(oPC, "CC6_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 7);
SetLocalInt(oItem, "CC6_DONE", 1);
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
//SendMessageToPC(oPC, "DEBUG: firing bg_disfig_cv");
DelayCommand(0.1f, StartDynamicConversation("bg_disfig_cv", oPC));
}
else
{
SetStage(STAGE_LIST, oPC);
}
}
SetStage(nStage, oPC);
}
}
/*
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_age_cv main() entered");
object oItem = EnsurePlayerDataObject(oPC);
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
// Required guard: abort if nValue is 0
if (nValue == 0) return;
if (nValue == DYNCONV_SETUP_STAGE)
{
if (!GetIsStageSetUp(nStage, oPC))
{
if (nStage == STAGE_LIST)
{
SetHeader("Now for the finishing touches. If you would like to apply an age modifier to your character, you may do so. Aging affects are as follows:\n" +
"Young Age/Opt Out: No effects\n" +
"Middle Age: -1 STR, -1 DEX, -1 CON, +1 INT, +1 WIS, +1 CHA\n" +
"Old Age: -2 STR, -2 DEX, -2 CON, +2 INT, +2 WIS, +2 CHA\n" +
"Venerable Age: -3 STR, -3 DEX, -3 CON, +3 INT, +3 WIS, +3 CHA");
// Store descriptive text for each age choice
SetLocalString(oPC, "age_text_0", "You are in the prime of your youth, with physical abilities at their peak and mental faculties still developing. This represents a character starting their adventuring career in their late teens or early twenties, with no modifiers to abilities.");
SetLocalString(oPC, "age_text_1", "You have reached middle age, where the physical toll of years begins to show, but experience and wisdom have sharpened your mind. Your body has begun to slow (-1 STR, -1 DEX, -1 CON) while your mental faculties have matured (+1 INT, +1 WIS, +1 CHA).");
SetLocalString(oPC, "age_text_2", "The weight of many decades rests upon you. Physical decline is more pronounced (-2 STR, -2 DEX, -2 CON) but your accumulated knowledge and insight have grown significantly (+2 INT, +2 WIS, +2 CHA). You are a veteran of life's trials.");
SetLocalString(oPC, "age_text_3", "You have lived a very long life, and your body shows the full extent of your years (-3 STR, -3 DEX, -3 CON). However, your mind is a repository of vast knowledge and profound wisdom (+3 INT, +3 WIS, +3 CHA). You are truly an elder whose experience spans generations.");
AddChoice("Young Age / Opt Out", 0, oPC);
AddChoice("Middle Age", 1, oPC);
AddChoice("Old Age", 2, oPC);
AddChoice("Venerable Age", 3, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
else if (nStage == STAGE_CONFIRM)
{
int nSelected = GetLocalInt(oPC, "age_selected");
string sAgeText = GetLocalString(oPC, "age_text_" + IntToString(nSelected));
string sPrompt = sAgeText + "\n\nAre you sure you want to apply this age modifier?";
SetHeader(sPrompt);
AddChoice("Yes", nSelected, oPC);
AddChoice("No", -1, oPC);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
}
SetupTokens();
}
else
{
int nChoice = GetChoice(oPC);
if (nStage == STAGE_LIST)
{
SetLocalInt(oPC, "age_selected", nChoice);
SetStage(STAGE_CONFIRM, oPC);
}
else if (nStage == STAGE_CONFIRM)
{
if (nChoice >= 0)
{
string sGrant;
switch (nChoice)
{
default:
case 0:
{// youthful
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_YOUTHFUL);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_YOUTHFUL);
break;
}
case 1:
{// middle-aged
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_MIDDLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_MIDDLE);
break;
}
case 2:
{
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_OLD);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_OLD);
break;
}
case 3:
{
SetLocalInt(oItem, "BG_Select",7);
SetPersistantLocalInt(oPC, "BG_Select", 7);
SetLocalInt(oItem, "CC6", AGE_CATEGORY_VENERABLE);
SetPersistantLocalInt(oPC, "CC6", AGE_CATEGORY_VENERABLE);
break;
}
}
// Chain to disfigurement conversation
SetPersistantLocalInt(oPC, "CC6_DONE", 1);
SetLocalInt(oItem, "CC6_DONE", 1);
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
SendMessageToPC(oPC, "DEBUG: firing bg_disfig_cv");
DelayCommand(0.1f, StartDynamicConversation("bg_disfig_cv", oPC));
}
else
{
SetStage(STAGE_LIST, oPC);
}
}
SetStage(nStage, oPC);
}
}
*/
/* void main() {
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_age_cv main() entered");

290
src/nss/bg_apply.nss Normal file
View File

@@ -0,0 +1,290 @@
// LordValinar's Scripts - Background Application (12/18/2023)
// =============================================================================
/*
The final process, to take all of the saved settings from character
creation and apply them here. (This was to prevent exploits)
*/
// =============================================================================
#include "nwnx_creature"
#include "te_afflic_func"
#include "lv_inc"
#include "bg_inc_p_locals"
void main()
{
object oPC = OBJECT_SELF; // from ExecuteScript()
object oItem = GetItemPossessedBy(oPC, "PC_Data_Object");
int nSubrace = GetLocalInt(oItem, "CC0"); /**/ DeleteLocalInt(oItem, "CC0");
int nClass = GetLocalInt(oItem, "CC1"); /**/ DeleteLocalInt(oItem, "CC1");
int nBackground = GetLocalInt(oItem, "CC2"); /**/ DeleteLocalInt(oItem, "CC2");
int nDeity = GetLocalInt(oItem, "CC3"); /**/ DeleteLocalInt(oItem, "CC3");
int nAge = GetLocalInt(oItem, "CC6"); /**/ DeleteLocalInt(oItem, "CC6");
int bDisfigured = GetLocalInt(oItem, "CC7"); /**/ DeleteLocalInt(oItem, "CC7");
// Stats
int iCL = GetHitDice(oPC);
int iSTR = GetAbilityScore(oPC, ABILITY_STRENGTH, TRUE);
int iDEX = GetAbilityScore(oPC, ABILITY_DEXTERITY, TRUE);
int iCON = GetAbilityScore(oPC, ABILITY_CONSTITUTION, TRUE);
int iINT = GetAbilityScore(oPC, ABILITY_INTELLIGENCE, TRUE);
int iWIS = GetAbilityScore(oPC, ABILITY_WISDOM, TRUE);
int iCHA = GetAbilityScore(oPC, ABILITY_CHARISMA, TRUE);
// Skills
int iHide = GetSkillRank(SKILL_HIDE, oPC, TRUE);
int iBluff = GetSkillRank(SKILL_BLUFF, oPC, TRUE);
int iSpot = GetSkillRank(SKILL_SPOT, oPC, TRUE);
int iListen = GetSkillRank(SKILL_LISTEN, oPC, TRUE);
int iLore = GetSkillRank(SKILL_LORE, oPC, TRUE);
int iMoveSil = GetSkillRank(SKILL_MOVE_SILENTLY, oPC, TRUE);
int iSpellCraft = GetSkillRank(SKILL_SPELLCRAFT, oPC, TRUE);
// Effects
effect eSpellResist = EffectSpellResistanceIncrease(11+iCL);
// Step 0: Subrace/Ethnicity
if (nSubrace > 0) NWNX_Creature_AddFeatByLevel(oPC, nSubrace, 1);
switch (nSubrace)
{
case ETHNICITY_TETHYRIAN: case ETHNICITY_CALISHITE: {
SetLocalInt(oItem, "23", 1); // Language: Alzhedo
} break;
case ETHNICITY_CHONDATHAN: {
SetLocalInt(oItem, "53", 1); // Language: Chondathan
} break;
case ETHNICITY_DAMARAN: {
SetLocalInt(oItem, "56", 1); // Language: Damaran
} break;
case 1445: { // Talfirian
SetLocalInt(oItem, "38", 1); // Language: Talfiric
} break;
case ETHNICITY_ILLUSKAN: {
SetLocalInt(oItem, "22", 1); // Language: Illuskan
} break;
case 1447: { // Imaskari
SetLocalInt(oItem, "46", 1); // Language: Undercommon
} break;
case ETHNICITY_MULAN: {
SetLocalInt(oItem, "27", 1); // Language: Mulanese
} break;
case ETHNICITY_RASHEMI: {
SetLocalInt(oItem, "30", 1); // Langauge: Rashemi
} break;
case BACKGROUND_TIEFLING: {
SetLocalInt(oItem, "iPCSubrace", 11);
SetLocalInt(oItem, "PC_ECL", 1);
SetSubRace(oPC, "Tiefling");
NWNX_Creature_AddFeatByLevel(oPC,228,1); // Darkvision
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA -2);
NWNX_Creature_SetSkillRank(oPC, SKILL_BLUFF, iBluff +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_HIDE, iHide+2);
} break;
case BACKGROUND_NAT_LYCAN: {
SetLocalInt(oItem, "PC_ECL", 2);
if (GetRacialType(oPC) == RACIAL_TYPE_ELF) {
SetSubRace(oPC, "Lythari");
} else {
SetSubRace(oPC, "Natural Lycanthrope");
}
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS + 2);
} break;
case BACKGROUND_AASIMAR: {
SetLocalInt(oItem, "iPCSubrace", 10);
SetLocalInt(oItem, "PC_ECL",1);
SetSubRace(oPC, "Aasimar");
NWNX_Creature_AddFeatByLevel(oPC,228,1); // Darkvision
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_SPOT, iSpot +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_LISTEN, iListen+2);
} break;
case BACKGROUND_GOLD_DWARF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Gold Dwarf");
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA +4);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX -2);
} break;
case BACKGROUND_GREY_DWARF: {
SetLocalInt(oItem, "PC_ECL", 2);
SetSubRace(oPC, "Grey Dwarf");
NWNX_Creature_SetSkillRank(oPC, SKILL_MOVE_SILENTLY, iMoveSil +4);
AddSubraceEffect(oPC, EffectImmunity(IMMUNITY_TYPE_POISON));
AddSubraceEffect(oPC, EffectImmunity(IMMUNITY_TYPE_PARALYSIS));
SetLocalInt(oItem, "64", 1); // Language: Duergar
SetLocalInt(oItem, "46", 1); // Language: Undercommon
} break;
case BACKGROUND_SHIELD_DWARF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Shield Dwarf");
} break;
case BACKGROUND_COPPER_ELF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Copper Elf");
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_STRENGTH, iSTR +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT -2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA -2);
} break;
case BACKGROUND_DARK_ELF: {
SetLocalInt(oItem, "PC_ECL", 2);
SetSubRace(oPC, "Dark Elf");
NWNX_Creature_AddFeatByLevel(oPC, 228, 1); // Darkvision
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA +2);
AddSubraceEffect(oPC, eSpellResist);
SetLocalInt(oItem, "81", 1); // Language: Drow
SetLocalInt(oItem, "46", 1); // Language: Undercommon
SetLocalInt(oItem, "13", 1); // Language: Drow Sign
} break;
case 1458: { // BACKGROUND_ELF_FEYRI
SetLocalInt(oItem, "PC_ECL", 3);
SetSubRace(oPC, "Fey'ri");
NWNX_Creature_AddFeatByLevel(oPC, 228, 1); // Darkvision
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON -2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_BLUFF, iBluff +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_HIDE, iHide +2);
} break;
case BACKGROUND_GREEN_ELF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Green Elf");
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON +4);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT -2);
} break;
case BACKGROUND_GOLD_ELF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Gold Elf");
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX -2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT +2);
} break;
case BACKGROUND_SILVER_ELF: {
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Silver Elf");
} break;
case 1452: { // BACKGROUND_GNOME_DEEP
SetLocalInt(oItem, "PC_ECL", 2);
SetSubRace(oPC, "Deep Gnome");
NWNX_Creature_AddFeatByLevel(oPC,nSubrace,1);
NWNX_Creature_AddFeatByLevel(oPC,228,1); // Darkvision
NWNX_Creature_AddFeatByLevel(oPC,227,1); // Stonecunning
AddSubraceEffect(oPC, eSpellResist);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON -4);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS +2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA -4);
NWNX_Creature_SetSkillRank(oPC, SKILL_HIDE, iHide +2);
SetLocalInt(oItem,"46",1); // Language: Undercommon
} break;
case 1453: { // BACKGROUND_GNOME_FOREST
SetLocalInt(oItem, "PC_ECL", 1);
SetSubRace(oPC, "Forest Gnome");
NWNX_Creature_SetSkillRank(oPC, SKILL_HIDE, iHide + 4);
SetLocalInt(oItem, "8", 1); // Language: Animals
} break;
case 1454: { // BACKGROUND_GNOME_ROCK
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Rock Gnome");
} break;
case 1455: { // BACKGROUND_HALFLING_GHOSTWISE
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Ghostwise Halfling");
} break;
case 1456: { // BACKGROUND_HALFLING_LIGHTFOOT
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Lightfoot Halfling");
} break;
case 1457: { // BACKGROUND_HALFLING_STRONGHEART
SetLocalInt(oItem, "PC_ECL", 0);
SetSubRace(oPC, "Strongheart Halfling");
} break;
}
// Step 1: Class Adjustments
if (nClass > 0) NWNX_Creature_AddFeatByLevel(oPC, nClass, 1);
// Step 2: Background Adjustments
if (nBackground > 0) NWNX_Creature_AddFeatByLevel(oPC, nBackground, 1);
switch (nBackground)
{
case BACKGROUND_CALISHITE_TRAINED:
SetLocalInt(oItem, "23", 1); // Language: Alzhedo
break;
case BACKGROUND_CIRCLE_BORN:
SetLocalInt(oItem, "8", 1); // Language: Animals
break;
case BACKGROUND_OCCULTIST: {
NWNX_Creature_AddFeatByLevel(oPC, PROFICIENCY_ASTROLOGY, 1);
NWNX_Creature_SetSkillRank(oPC, SKILL_LORE, iLore +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_SPELLCRAFT, iSpellCraft +2);
} break;
case BACKGROUND_TALFIRIAN:
SetLocalInt(oItem, "38", 1); // Language: Talfirian
break;
}
// Step 4: Deity Adjustments
if (nDeity > 0) NWNX_Creature_AddFeat(oPC, nDeity);
// Step 5: Languages
string sArr = GetLocalString(oItem, "ARR_LANGUAGES");
int i; for (i = 0; i < ArrayLength(sArr); i++)
{
string lang = ArrayParse(sArr, i);
SetLocalInt(oItem, lang, 1);
}
DeleteLocalString(oItem, "ARR_LANGUAGES");
// Step 6: Proficiencies
sArr = GetLocalString(oItem, "ARR_PROF");
for (i = 0; i < ArrayLength(sArr); i++)
{
int nFeat = StringToInt(ArrayParse(sArr, i));
if (nFeat > 0) NWNX_Creature_AddFeatByLevel(oPC, nFeat, 1);
if (nFeat == PROFICIENCY_ASTROLOGY)
{
NWNX_Creature_SetSkillRank(oPC, SKILL_LORE, iLore +2);
NWNX_Creature_SetSkillRank(oPC, SKILL_SPELLCRAFT, iSpellCraft +2);
}
}
DeleteLocalString(oItem, "ARR_PROF");
// Step 7: Age Settings
switch (nAge)
{
case 1: // Middle-Aged
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_STRENGTH, iSTR-1);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON-1);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX-1);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT+1);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA+1);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS+1);
break;
case 2: // Old-Age
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_STRENGTH, iSTR-2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON-2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX-2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT+2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA+2);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS+2);
break;
case 3: // Venerable
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_STRENGTH, iSTR-3);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CONSTITUTION, iCON-3);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_DEXTERITY, iDEX-3);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_INTELLIGENCE, iINT+3);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_CHARISMA, iCHA+3);
NWNX_Creature_SetRawAbilityScore(oPC, ABILITY_WISDOM, iWIS+3);
break;
}
// Step 8: One-Armed?
if (bDisfigured)
{
NWNX_Creature_AddFeatByLevel(oPC, 2000, 1);//One-Armed
//Set Arm to be nonexistent. I set the non-models to be all model number 200.
SetCreatureBodyPart(CREATURE_PART_LEFT_BICEP, 200, oPC);
SetCreatureBodyPart(CREATURE_PART_LEFT_FOREARM, 200, oPC);
SetCreatureBodyPart(CREATURE_PART_LEFT_HAND, 200, oPC);
}
}

View File

@@ -8,8 +8,8 @@
#include "nwnx_creature"
#include "te_afflic_func"
#include "lv_inc"
#include "inc_persist_loca"
#include "te_lang"
#include "bg_inc_p_locals"
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
@@ -28,7 +28,7 @@ void ApplyProficiencies(object oPC)
{
object oItem = EnsurePlayerDataObject(oPC);
if (!GetIsObjectValid(oItem)) {
SendMessageToPC(oPC, "DEBUG: Invalid player data object");
//SendMessageToPC(oPC, "DEBUG: Invalid player data object");
return;
}
@@ -49,7 +49,7 @@ void ApplyProficiencies(object oPC)
if (nProficiencyFeat > 0)
{
SendMessageToPC(oPC, "DEBUG: Applying feat " + IntToString(nProficiencyFeat) + " from slot " + sSlot);
//SendMessageToPC(oPC, "DEBUG: Applying feat " + IntToString(nProficiencyFeat) + " from slot " + sSlot);
NWNX_Creature_AddFeatByLevel(oPC, nProficiencyFeat, 1);
nFound++;
@@ -63,7 +63,7 @@ void ApplyProficiencies(object oPC)
i++;
}
SendMessageToPC(oPC, "DEBUG: Applied " + IntToString(nFound) + " proficiencies");
//SendMessageToPC(oPC, "DEBUG: Applied " + IntToString(nFound) + " proficiencies");
}
/* void ApplyProficiencies(object oPC)
@@ -103,6 +103,7 @@ void ApplyProficiencies(object oPC)
}
}
*/
void ApplyBonusLanguages(object oPC)
{
object oItem = GetItemPossessedBy(oPC, "PC_Data_Object");
@@ -162,7 +163,8 @@ void main()
int iSpellCraft = GetSkillRank(SKILL_SPELLCRAFT, oPC, TRUE);
// Effects
effect eSpellResist = EffectSpellResistanceIncrease(11+iCL);
//SendMessageToPC(oPC, "DEBUG: bg_apply_cv main() entered");
// Step 0: Subrace/Ethnicity (some of this might be redundant now)
if (nSubrace > 0) NWNX_Creature_AddFeatByLevel(oPC, nSubrace, 1);
@@ -202,7 +204,7 @@ void main()
NWNX_Creature_AddFeatByLevel(oPC, FEAT_LANGUAGE_TALFIRIC, 1);
//:: For legacy DMFI
SetLocalInt(oItem, IntToString(LangFeatToLangID(FEAT_LANGUAGE_DAMARAN)), 1);
SetLocalInt(oItem, IntToString(LangFeatToLangID(FEAT_LANGUAGE_TALFIRIC)), 1);
}
break;
case ETHNICITY_ILLUSKAN:
@@ -565,7 +567,7 @@ void main()
if (nDeity > 0) NWNX_Creature_AddFeat(oPC, nDeity);
// Step 5: Languages
ApplyBonusLanguages(oPC);
DelayCommand(0.0f, ApplyBonusLanguages(oPC));
/* string sArr = GetLocalString(oItem, "ARR_LANGUAGES");
int i; for (i = 0; i < ArrayLength(sArr); i++)
@@ -576,7 +578,7 @@ void main()
DeleteLocalString(oItem, "ARR_LANGUAGES"); */
// Step 6: Proficiencies
ApplyProficiencies(oPC);
DelayCommand(0.0f, ApplyProficiencies(oPC));
/* sArr = GetLocalString(oItem, "ARR_PROF");
for (i = 0; i < ArrayLength(sArr); i++)

View File

@@ -0,0 +1,3 @@
void main()
{
}

View File

@@ -1,7 +1,7 @@
// bg_background_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
@@ -24,7 +24,8 @@ object EnsurePlayerDataObject(object oPC)
WriteTimestampedLogEntry("Language data object recreated");
}
return oItem;
}
}
int _CanBeAffluent(object oPC = OBJECT_SELF)
{
@@ -491,7 +492,7 @@ void main()
{
object oPC = GetPCSpeaker();
object oItem = EnsurePlayerDataObject(oPC);
SendMessageToPC(oPC, "DEBUG: bg_background_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_background_cv main() entered");
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
@@ -595,7 +596,7 @@ void main()
// 13 Eldreth Veluuthra
if (nRacial == RACIAL_TYPE_ELF)
{
AddChoice(" Eldreth Veluuthra", 13, oPC);
AddChoice("Eldreth Veluuthra", 13, oPC);
SetLocalString(oPC, "bg_dyn_text_13",
"You believe that elves are the superior race, and that they have a right as well as a duty to reclaim the Wealdath forest. You are angered or disgusted by the very existence of half elves and will strive to drive these abominations out of the unspoiled woods that remain..\n\nDoes this describe you?");
}
@@ -869,7 +870,8 @@ void main()
}
else if(nValue == DYNCONV_EXITED)
{
DelayCommand(0.1f, StartDynamicConversation("bg_deity_cv", oPC));
SetPersistantLocalInt(oPC, "Background_Stage", 3);
DelayCommand(0.1f, StartDynamicConversation("bg_deity_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else if(nValue == DYNCONV_ABORTED)
{

View File

@@ -1,5 +1,5 @@
// bg_deity_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "bg_inc_p_locals"
#include "inc_alignment"
#include "te_afflic_func"
@@ -42,7 +42,7 @@ object EnsurePlayerDataObject(object oPC)
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_deity_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_deity_cv main() entered");
int nRacialType = GetRacialType(oPC);
int nAlignment = GetCreaturesAlignment(oPC);
@@ -1317,8 +1317,9 @@ void main()
}
}
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
SetPersistantLocalInt(oPC, "CC3_DONE", 1);
DelayCommand(0.1f, StartDynamicConversation("bg_language_cv", oPC));
SetPersistantLocalInt(oPC, "CC3_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 4);
DelayCommand(0.1f, StartDynamicConversation("bg_language_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else
{ // No

View File

@@ -1,22 +1,43 @@
// bg_disfig_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "bg_inc_p_locals"
const int STAGE_LIST = 0;
const int STAGE_CONFIRM = 1;
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
{
object oItem = GetItemPossessedBy(oPC, "PC_Data_Object");
if (!GetIsObjectValid(oItem))
{
oItem = CreateItemOnObject("pc_data_object", oPC);
SendMessageToPC(oPC, "Language data object recreated");
WriteTimestampedLogEntry("Language data object recreated");
}
return oItem;
}
void main() {
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_disfig_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_disfig_cv main() entered");
object oItem = EnsurePlayerDataObject(oPC);
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
// Required guard: abort if nValue is 0
if (nValue == 0) return;
if (nValue == DYNCONV_SETUP_STAGE) {
if (!GetIsStageSetUp(nStage, oPC)) {
if (nStage == STAGE_LIST) {
if (nValue == DYNCONV_SETUP_STAGE)
{
if (!GetIsStageSetUp(nStage, oPC))
{
if (nStage == STAGE_LIST)
{
SetHeader(
"Some players wish to have intentional disfigurements such as lost limbs or lingering injuries. " +
"These are rare among those who still wish to adventure, but not unique. Many keep these as " +
@@ -31,13 +52,14 @@ void main() {
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
else if (nStage == STAGE_CONFIRM) {
else if (nStage == STAGE_CONFIRM)
{
int nSelected = GetLocalInt(oPC, "disfig_selected");
string sPrompt = (nSelected == 1)
? "You lost an arm. At some point, you lost one. Maybe it was a woodcutting accident, " +
"maybe it was a punishment for theft. In any case, you're down an appendage.\n\n" +
"You can't use your left arm. This means one-handed weapons only, no two handers. " +
"No left hand rings.\n\nAre you sure?"
"You can't use your left arm. This means one-handed weapons only, no shields, " +
"no left hand rings.\n\nAre you sure?"
: "Are you sure you want to continue without a disfigurement?";
SetHeader(sPrompt);
AddChoice("Yes!", nSelected, oPC);
@@ -48,19 +70,40 @@ void main() {
SetupTokens();
}
}
else {
else if (nValue == DYNCONV_EXITED)
{
SetPersistantLocalInt(oPC, "Background_Stage", 8);
DelayCommand(0.1f, ExecuteScript("bg_apply_cv", oPC));
}
else
{
int nChoice = GetChoice(oPC);
if (nStage == STAGE_LIST) {
if (nStage == STAGE_LIST)
{
SetLocalInt(oPC, "disfig_selected", nChoice);
SetStage(STAGE_CONFIRM, oPC);
}
else if (nStage == STAGE_CONFIRM) {
if (nChoice >= 0) {
string sGrant = (nChoice == 1) ? "bg_give_noarm" : "bg_give_nodisfig";
ExecuteScript(sGrant, oPC);
else if (nStage == STAGE_CONFIRM)
{
if (nChoice >= 0)
{
//string sGrant = (nChoice == 1) ? "bg_give_noarm" : "bg_give_nodisfig";
//ExecuteScript(sGrant, oPC);
// Chain to next step, e.g., final touches
// StartDynamicConversation("bg_final_cv", oPC);
} else {
if (nChoice == 1)
{
SetLocalInt(oItem,"CC7",1); // One-Armed
SetPersistantLocalInt(oPC,"CC7",1); // One-Armed
SetLocalInt(oItem,"BG_Select",8);
}
else
{
SetLocalInt(oItem,"BG_Select",8);
}
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
}
else
{
SetStage(STAGE_LIST, oPC);
}
}

568
src/nss/bg_inc_array.nss Normal file
View File

@@ -0,0 +1,568 @@
//::///////////////////////////////////////////////
//:: Array simulation include
//:: bg_inc_array
//:://////////////////////////////////////////////
/** @file
Array simulation include
This file defines a set of functions for creating
and manipulating arrays, which are implemented as
local variables on some holder object.
Notes:
* Arrays are dynamic and may be increased in size by just _set_'ing a new
element
* There are no restrictions on what is in the array (can have multiple
types in the same array)
* Arrays start at index 0
////////////////////////////////////////////////////////////////////////////////
// (c) Mr. Figglesworth 2002
// This code is licensed under beerware. You are allowed to freely use it
// and modify it in any way. Your only two obligations are: (1) at your option,
// to buy the author a beer if you ever meet him; and (2) include the
// copyright notice and license in any redistribution of this code or
// alterations of it.
//
// Full credit for how the array gets implemented goes to the guy who wrote
// the article and posted it on the NWNVault (I couldn't find your article
// to give you credit :( ). And, of course, to bioware. Great job!
////////////////////////////////////////////////////////////////////////////////
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
/**
* Creates a new array on the given storage object. If an
* array with the same name already exists, the function
* errors.
*
* @param store The object to use as holder for the array
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully created,
* one of SDL_ERROR_* on error.
*/
int array_create(object store, string name);
/**
* Deletes an array, erasing all it's entries.
*
* @param store The object which holds the array to delete
* @param name The name of the array
* @return SDL_SUCCESS if the array was successfully deleted,
* one of SDL_ERROR_* on error
*/
int array_delete(object store, string name);
/**
* Stores a string in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the string at
* @param entry The string to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_string(object store, string name, int i, string entry);
/**
* Stores an integer in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the integer at
* @param entry The integer to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_int(object store, string name, int i, int entry);
/**
* Stores a float in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the float at
* @param entry The float to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_float(object store, string name, int i, float entry);
/**
* Stores an object in an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to store the object at
* @param entry The object to store
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
*/
int array_set_object(object store, string name, int i, object entry);
/**
* Gets a string from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the string from
* @return The value contained at the index on success,
* "" on error
*/
string array_get_string(object store, string name, int i);
/**
* Gets an integer from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the integer from
* @return The value contained at the index on success,
* 0 on error
*/
int array_get_int(object store, string name, int i);
/**
* Gets a float from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the float from
* @return The value contained at the index on success,
* 0.0f on error
*/
float array_get_float(object store, string name, int i);
/**
* Gets an object from an array.
*
* @param store The object holding the array
* @param name The name of the array
* @param i The index to retrieve the object from
* @return The value contained at the index on success,
* OBJECT_INVALID on error
*/
object array_get_object(object store, string name, int i);
/**
* Removes all entries in the array with indexes greater than or equal to
* the new size and sets the array size to be equal to the new size.
*
* @param store The object holding the array
* @param name The name of the array
* @param size_new The new number of entries in the array
* @return SDL_SUCCESS on successful resize, SDL_ERROR_* on
* error
*/
int array_shrink(object store, string name, int size_new);
/**
* Gets the current size of the array. This is one greater
* than the index of highest indexed element the array
* has contained since the last array_shrink or the new size
* specified by the last array_shrink, whichever is greater.
*
* @param store The object holding the array
* @param name The name of the array
* @return The size of the array, or -1 if the specified
* array does not exist.
*/
int array_get_size(object store, string name);
/**
* Checks whether the given array exists.
*
* @param store The object holding the array
* @param name The name of the array
* @return TRUE if the array exists, FALSE otherwise.
*/
int array_exists(object store, string name);
/* These need to be rewritten and made less bug-prone before being taken into use.
Preferrably not necessarily have it be fucking massive square matrix, but instead
store a separate length for each x row.
int array_2d_create(object store, string name);
int array_2d_delete(object store, string name);
int array_2d_set_string(object store, string name, int i, int j, string entry);
int array_2d_set_int(object store, string name, int i, int j, int entry);
int array_2d_set_float(object store, string name, int i, int j, float entry);
int array_2d_set_object(object store, string name, int i, int j, object entry);
// returns "" or 0 on error
string array_2d_get_string(object store, string name, int i, int j);
int array_2d_get_int(object store, string name, int i, int j);
float array_2d_get_float(object store, string name, int i, int j);
object array_2d_get_object(object store, string name, int i, int j);
// changes memory usage of array (deletes x[ > size_new])
int array_2d_shrink(object store, string name, int size_new, int axis);
// gets current maximum size of array
int array_2d_get_size(object store, string name, int axis);
int array_2d_exists(object store, string name);
*/
/////////////////////////////////////
// Error Returns
/////////////////////////////////////
const int SDL_SUCCESS = 1;
const int SDL_ERROR = 1000;
const int SDL_ERROR_ALREADY_EXISTS = 1001;
const int SDL_ERROR_DOES_NOT_EXIST = 1002;
const int SDL_ERROR_OUT_OF_BOUNDS = 1003;
const int SDL_ERROR_NO_ZERO_SIZE = 1004; // Not used - Ornedan 2006.09.15
const int SDL_ERROR_NOT_VALID_OBJECT = 1005;
const int SDL_ERROR_INVALID_PARAMETER = 1006;
/////////////////////////////////////
// Implementation
/////////////////////////////////////
int array_create(object store, string name)
{
// error checking
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
else if(array_exists(store, name))
return SDL_ERROR_ALREADY_EXISTS;
else
{
// Initialize the size (always one greater than the actual size)
SetLocalInt(store,name,1);
return SDL_SUCCESS;
}
}
void array_delete_loop(object store, string name, int nMin, int nMax)
{
int i = nMin;
while(i < nMin + 250 && i < nMax)
{
DeleteLocalString(store, name+"_"+IntToString(i));
// just in case, delete possible object names
DeleteLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
i++;
}
// delay continuation to avoid TMI
if(i < nMax)
DelayCommand(0.0, array_delete_loop(store, name, i, nMax));
}
int array_delete(object store, string name)
{
// error checking
int size=GetLocalInt(store,name);
if (size==0)
return SDL_ERROR_DOES_NOT_EXIST;
array_delete_loop(store, name, 0, size+5);
DeleteLocalInt(store,name);
return SDL_SUCCESS;
}
int array_set_string(object store, string name, int i, string entry)
{
int size = GetLocalInt(store,name);
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
if(i < 0)
return SDL_ERROR_OUT_OF_BOUNDS;
SetLocalString(store,name+"_"+IntToString(i),entry);
// save size if we've enlarged it
if(i+2>size)
SetLocalInt(store,name,i+2);
return SDL_SUCCESS;
}
int array_set_int(object store, string name, int i, int entry)
{
return array_set_string(store,name,i,IntToString(entry));
}
int array_set_float(object store, string name, int i, float entry)
{
return array_set_string(store,name,i,FloatToString(entry));
}
int array_set_object(object store, string name, int i, object entry)
{
int results = array_set_string(store, name, i, "OBJECT");
if (results == SDL_SUCCESS)
SetLocalObject(store, name + "_" + IntToString(i) + "_OBJECT", entry);
return results;
}
string array_get_string(object store, string name, int i)
{
// error checking
int size=GetLocalInt(store,name);
if (size==0 || i>size || i < 0)
return "";
return GetLocalString(store,name+"_"+IntToString(i));
}
int array_get_int(object store, string name, int i)
{
return StringToInt(array_get_string(store,name,i));
}
float array_get_float(object store, string name, int i)
{
return StringToFloat(array_get_string(store,name,i));
}
object array_get_object(object store, string name, int i)
{
if(array_get_string(store, name, i) == "OBJECT")
return GetLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
else
return OBJECT_INVALID;
}
int array_shrink(object store, string name, int size_new)
{
// Get the current size value
int size = GetLocalInt(store, name);
// Error check - non-existent array
if(size == 0)
return SDL_ERROR_DOES_NOT_EXIST;
// If the new number of elements is equal to or greater than the current number of elements, autosuccess
if((size - 1) <= size_new)
return SDL_SUCCESS;
// Delete entries that are outside the new array bounds
int i;
for(i = size_new; i < size; i++)
{
DeleteLocalString(store, name+"_"+IntToString(i));
// just in case, delete possible object names
DeleteLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
}
// Store the new size, with the +1 existence marker
SetLocalInt(store, name, size_new + 1);
return SDL_SUCCESS;
}
int array_get_size(object store, string name)
{
return GetLocalInt(store, name) - 1;
}
int array_exists(object store, string name)
{
// If the size and presence indicator local is non-zero, the array exists. Normalize it's value to TRUE / FALSE and return
return GetLocalInt(store, name) != 0;
}
/*
int array_2d_create(object store, string name)
{
// error checking
if(!GetIsObjectValid(store))
return SDL_ERROR_NOT_VALID_OBJECT;
else if(GetLocalInt(store,name))
return SDL_ERROR_ALREADY_EXISTS;
else
{
// Initialize the size (always one greater than the actual size)
SetLocalInt(store,name+"_A",1);
SetLocalInt(store,name+"_B",1);
return SDL_SUCCESS;
}
}
int array_2d_delete(object store, string name)
{
// error checking
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
int i;
int j;
for (i=0; i<sizeA+5; i++)
{
for (j=0;j<sizeB+5; j++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
DeleteLocalInt(store,name+"_A");
DeleteLocalInt(store,name+"_B");
return SDL_SUCCESS;
}
int array_2d_set_string(object store, string name, int i, int j, string entry)
{
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
SetLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j),entry);
// save size if we've enlarged it
if (i+2>sizeA)
SetLocalInt(store,name+"_A",i+2);
if (j+2>sizeB)
SetLocalInt(store,name+"_B",j+2);
return SDL_SUCCESS;
}
int array_2d_set_int(object store, string name, int i, int j, int entry)
{
return array_2d_set_string(store,name,i,j,IntToString(entry));
}
int array_2d_set_float(object store, string name, int i, int j, float entry)
{
return array_2d_set_string(store,name,i,j,FloatToString(entry));
}
int array_2d_set_object(object store, string name, int i, int j, object entry)
{
// object is a little more complicated.
// we want to create an object as a local variable too
if (!GetIsObjectValid(entry))
return SDL_ERROR_NOT_VALID_OBJECT;
int results=array_2d_set_string(store,name,i,j,"OBJECT");
if (results==SDL_SUCCESS)
SetLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT",entry);
return results;
}
string array_2d_get_string(object store, string name, int i, int j)
{
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0 || i>sizeA)
return "";
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0 || j>sizeB)
return "";
return GetLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
}
int array_2d_get_int(object store, string name, int i, int j)
{
return StringToInt(array_2d_get_string(store,name,i,j));
}
float array_2d_get_float(object store, string name, int i, int j)
{
return StringToFloat(array_2d_get_string(store,name,i,j));
}
object array_2d_get_object(object store, string name, int i, int j)
{
return GetLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
int array_2d_shrink(object store, string name, int size_new, int axis)
{
// error checking
int sizeA=GetLocalInt(store,name+"_A");
if (sizeA==0)
return SDL_ERROR_DOES_NOT_EXIST;
int sizeB=GetLocalInt(store,name+"_B");
if (sizeB==0)
return SDL_ERROR_DOES_NOT_EXIST;
if (axis == 1 &&
(sizeA==size_new || sizeA<size_new))
return SDL_SUCCESS;
if (axis == 2 &&
(sizeB==size_new || sizeB<size_new))
return SDL_SUCCESS;
int i; int j;
if(axis==1)
{
for (i=size_new; i<sizeA; i++)
{
for(j=0;j<sizeB+5;j++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
SetLocalInt(store,name+"_A",size_new+1);
return SDL_SUCCESS;
}
else if(axis==2)
{
for (j=size_new; j<sizeB; j++)
{
for(i=0;i<sizeA+5;i++)
{
DeleteLocalString(store,name+"_"+IntToString(i)+"_"+IntToString(j));
// just in case, delete possible object names
DeleteLocalObject(store,name+"_"+IntToString(i)+"_"+IntToString(j)+"_OBJECT");
}
}
SetLocalInt(store,name+"_B",size_new+1);
return SDL_SUCCESS;
}
else
return SDL_ERROR_DOES_NOT_EXIST;
}
int array_2d_get_size(object store, string name, int axis)
{
if(axis==1)
return GetLocalInt(store,name+"_A")-1;
else if(axis==2)
return GetLocalInt(store,name+"_B")-1;
else
return 0;
}
int array_2d_exists(object store, string name)
{
if (GetLocalInt(store,name+"_A")==0||GetLocalInt(store,name+"_B")==0)
return FALSE;
else
return TRUE;
}
*/
// Test main
//void main(){}

217
src/nss/bg_inc_debug.nss Normal file
View File

@@ -0,0 +1,217 @@
//:://////////////////////////////////////////////
//:: Debug include
//:: bg_inc_debug
//:://////////////////////////////////////////////
/** @file
This file contains a debug printing function, the
purpose of which is to be leavable in place in code,
so that debug printing can be centrally turned off
by commenting out the contents of the function.
Also, an assertion function and related function for
killing script execution.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Globals */
//////////////////////////////////////////////////
/**
* Prefix all your debug calls with an if(DEBUG) so that they get stripped away
* during compilation as dead code when this is turned off.
*/
const int DEBUG = FALSE;
//int DEBUG = FALSE;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* May print the given string, depending on whether debug printing is needed.
*
* Calls to this function should be guarded by an "if(DEBUG)" clause in order
* to be disableable.
*
* @param sString The string to print
*/
void DoDebug(string sString, object oAdditionalRecipient = OBJECT_INVALID);
/**
* Kills script execution using the Die() function if the given assertion
* is false. If a message has been given, also prints it using DoDebug().
* An assertion is something that should always be true if the program
* is functioning correctly. An assertion being false indicates a fatal error.
*
* The format of the string printed when an assertion fails is:
* "Assertion failed: sAssertion\nsMessage; At sScriptName: sFunction"
*
* Calls to this function should be guarded by an "if(DEBUG)" clause in order
* to be disableable.
*
* Example use:
*
* if(DEBUG) Assert(1 == 1, "1 == 1", "Oh noes! Arithmetic processing is b0rked.", "fooscript", "Baz()");
*
* @param bAssertion The result of some evaluation that should always be true.
* @param sAssertion A string containing the statement evalueated for bAssertion.
* @param sMessage The message to print if bAssertion is FALSE. Will be
* prefixed with "Assertion failed: " when printed.
* If left to default (empty), the message printed will simply
* be "Assertion failed!".
* @param sFileName Name of the script file where the call to this function occurs.
* @param sFunction Name of the function where the call to this function occurs.
*/
void Assert(int bAssertion, string sAssertion, string sMessage = "", string sFileName = "", string sFunction = "");
/**
* Kills the execution of the current script by forcing a Too Many Instructions
* error.
* Not recommended for use outside of debugging purposes. Scripts should be able
* to handle expectable error conditions gracefully.
*/
void Die();
/**
* Converts data about a given object into a string of the following format:
* "'GetName' - 'GetTag' - 'GetResRef' - ObjectToString"
*
* @param o Object to convert into a string
* @return A string containing identifying data about o
*/
string DebugObject2Str(object o);
/**
* Converts the given location into a string representation.
*
* @param loc Location to convert into a string
* @return A string representation of loc
*/
string DebugLocation2Str(location loc);
/**
* Converts the given itemproperty into a string representation.
*
* @param iprop Itemproperty to convert into a string
* @return A string representation of iprop
*/
string DebugIProp2Str(itemproperty iprop);
/**
* Converts a boolean to a string. Quick debug version.
* @see BooleanToString to use the tlkified one
*
* @param bool The boolean value to convert. 0 is considered false
* and everything else is true.
*/
string DebugBool2String(int bool);
/**
* Converts the given effect into a string representation.
*
* @param eEffect effect to convert into a string
* @return A string representation of effect
*/
string DebugEffect2String(effect eEffect);
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void DoDebug(string sString, object oAdditionalRecipient = OBJECT_INVALID)
{
SendMessageToPC(GetFirstPC(), "<c<>j<EFBFBD>>" + sString + "</c>");
if(oAdditionalRecipient != OBJECT_INVALID)
SendMessageToPC(oAdditionalRecipient, "<c<>j<EFBFBD>>" + sString + "</c>");
WriteTimestampedLogEntry(sString);
}
void Assert(int bAssertion, string sAssertion, string sMessage = "", string sFileName = "", string sFunction = "")
{
if(bAssertion == FALSE)
{
//SpawnScriptDebugger();
string sErr = "Assertion failed: " + sAssertion;
if(sMessage != "" || sFileName != "" || sFunction != "")
{
sErr += "\n";
if(sMessage != "")
sErr += sMessage;
if(sFileName != "" || sFunction != "")
{
if(sMessage != "")
sErr += "\n";
sErr += "At " + sFileName;
if(sFileName != "" && sFunction != "")
sErr += ": ";
sErr += sFunction;
}
}
DoDebug(sErr);
Die();
}
}
void Die()
{
while(TRUE) {;}
}
string DebugObject2Str(object o)
{
return o == OBJECT_INVALID ?
"OBJECT_INVALID" : // Special case
"'" + GetName(o) + "' - '" + GetTag(o) + "' - '" + GetResRef(o) + "' - " + ObjectToString(o);
}
string DebugLocation2Str(location loc)
{
object oArea = GetAreaFromLocation(loc);
vector vPos = GetPositionFromLocation(loc);
string sX, sY, sZ, sF;
// 3 decimal places and no leading whitespace
sX = FloatToString(vPos.x,0,3);
sY = FloatToString(vPos.y,0,3);
sZ = FloatToString(vPos.z,0,3);
sF = FloatToString(GetFacingFromLocation(loc),0,3);
return "Area: Name = '" + GetName(oArea) + "', Tag = '" + GetTag(oArea) + "'; Position: (" + sX + ", " + sY + ", " + sZ + ",); Facing: " + sF;
}
string DebugIProp2Str(itemproperty iprop)
{
return "Type: " + IntToString(GetItemPropertyType(iprop)) + "; "
+ "Subtype: " + IntToString(GetItemPropertySubType(iprop)) + "; "
+ "Duration type: " + (GetItemPropertyDurationType(iprop) == DURATION_TYPE_INSTANT ? "DURATION_TYPE_INSTANT" :
GetItemPropertyDurationType(iprop) == DURATION_TYPE_TEMPORARY ? "DURATION_TYPE_TEMPORARY" :
GetItemPropertyDurationType(iprop) == DURATION_TYPE_PERMANENT ? "DURATION_TYPE_PERMANENT" :
IntToString(GetItemPropertyDurationType(iprop))) + "; "
+ "Param1: " + IntToString(GetItemPropertyParam1(iprop)) + "; "
+ "Param1 value: " + IntToString(GetItemPropertyParam1Value(iprop)) + "; "
+ "Cost table: " + IntToString(GetItemPropertyCostTable(iprop)) + "; "
+ "Cost table value: " + IntToString(GetItemPropertyCostTableValue(iprop));
}
string DebugBool2String(int bool)
{
return bool ? "True" : "False";
}
string DebugEffect2String(effect eEffect)
{
return "Effect; Type = " + IntToString(GetEffectType(eEffect))
+ ", SpellID: " + IntToString(GetEffectSpellId(eEffect))
+ ", Subtype: " + IntToString(GetEffectSubType(eEffect))
+ ", Duration: " + IntToString(GetEffectDurationType(eEffect))
+ ", Creator: " + GetName(GetEffectCreator(eEffect));
}

729
src/nss/bg_inc_dynconv.nss Normal file
View File

@@ -0,0 +1,729 @@
//:://////////////////////////////////////////////
//:: Dynamic Conversation System include
//:: bg_inc_dynconv
//:://////////////////////////////////////////////
/** @file
@author Primogenitor
@date 2005.09.23 - Rebuilt the system - Ornedan
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//PRC8 Token pre-fix = 161838
//////////////////////////////////////////////////
/* Constant definitions */
//////////////////////////////////////////////////
const int DYNCONV_EXITED = -2;
const int DYNCONV_ABORTED = -3;
const int DYNCONV_SETUP_STAGE = -1;
const int DYNCONV_TOKEN_HEADER = 16183899;
const int DYNCONV_TOKEN_REPLY_0 = 161838100;
const int DYNCONV_TOKEN_REPLY_1 = 161838101;
const int DYNCONV_TOKEN_REPLY_2 = 161838102;
const int DYNCONV_TOKEN_REPLY_3 = 161838103;
const int DYNCONV_TOKEN_REPLY_4 = 161838104;
const int DYNCONV_TOKEN_REPLY_5 = 161838105;
const int DYNCONV_TOKEN_REPLY_6 = 161838106;
const int DYNCONV_TOKEN_REPLY_7 = 161838107;
const int DYNCONV_TOKEN_REPLY_8 = 161838108;
const int DYNCONV_TOKEN_REPLY_9 = 161838109;
const int DYNCONV_TOKEN_EXIT = 161838110;
const int DYNCONV_TOKEN_WAIT = 161838111;
const int DYNCONV_TOKEN_NEXT = 161838112;
const int DYNCONV_TOKEN_PREV = 161838113;
const int DYNCONV_MIN_TOKEN = 16183899;
const int DYNCONV_MAX_TOKEN = 161838113;
const int DYNCONV_STRREF_PLEASE_WAIT = 16824202; // "Please wait"
const int DYNCONV_STRREF_PREVIOUS = 16824203; // "Previous"
const int DYNCONV_STRREF_NEXT = 16824204; // "Next"
const int DYNCONV_STRREF_ABORT_CONVO = 16824212; // "Abort"
const int DYNCONV_STRREF_EXIT_CONVO = 78; // "Exit"
const string DYNCONV_SCRIPT = "DynConv_Script";
const string DYNCONV_VARIABLE = "DynConv_Var";
const string DYNCONV_STAGE = "DynConv_Stage";
const string DYNCONV_TOKEN_BASE = "DynConv_TOKEN";
const string DYNCONV_CHOICEOFFSET = "ChoiceOffset";
/**
* Exiting the conversation is not allowed. The exit
* choice is not shown
*/
const int DYNCONV_EXIT_NOT_ALLOWED = 0;
/**
* Exiting the conversation is allowed and it is
* forced to exit due to no nodes being shown.
*/
const int DYNCONV_EXIT_FORCE_EXIT = -1;
/**
* Exiting the conversation is allowed and the exit
* choice is shown.
*/
const int DYNCONV_EXIT_ALLOWED_SHOW_CHOICE = 1;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Sets the header token and reply tokens for the PC to values stored
* via SetHeader and AddChoice, respectively.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetupTokens(object oPC = OBJECT_INVALID);
/**
* Builds the local variable name for a token.
*
* @param nTokenID One of the DYNCONV_TOKEN_* constants
*/
string GetTokenIDString(int nTokenID);
/**
* Sets the dynamic conversation header. ie, the "NPC"'s reply.
*
* @param sText The text to set the header to
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeader(string sText, object oPC = OBJECT_INVALID);
/**
* A wrapper for SetHeader() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID);
/**
* Add a reply choice to be displayed. The replies are displayed in
* the same order as they are added.
*
* @param sText The text of the choice
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID);
/**
* A wrapper for AddChoice() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID);
/**
* Sets the custom token at nTokenID to be the given string and stores
* the value in a local variable on OBJECT_SELF.
* Used by the dyynamic onversation system to track token assignment.
*
* @param nTokenID The custom token number to store the string in
* @param sString The string to store
* @param oPC The PC whose conversation this token belongs to
*/
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF);
/**
* Sets the default values for the Exit, Wait, Next and Previous
* tokens. The values will be as follows, or their translated
* equivalents should a non-english TLK be used.
*
* Exit = "Exit"
* Wait = "Please wait"
* Next = "Next"
* Previous = "Previous"
*/
void SetDefaultTokens();
/**
* Changes the conversation stage. If the new stage given is
* the same as the current, nothing happens. Otherwise
* the stage is changed and the choices stored for the old
* stage are deleted.
*
* @param nNewStage The stage to enter
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetStage(int nNewStage, object oPC = OBJECT_INVALID);
/**
* Gets the current stage of the conversation.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The current stage of the conversation, as previously
* set via SetStage() or 0 if no calls to SetStage()
* have been done yet.
*/
int GetStage(object oPC = OBJECT_INVALID);
/**
* Gets the value of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The value of the choice the PC made, as set
* by a call to AddChoice().
*/
int GetChoice(object oPC = OBJECT_INVALID);
/**
* Gets the text of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The text of the choice the PC made, as set
* by a call to AddChoice().
*/
string GetChoiceText(object oPC = OBJECT_INVALID);
/**
* Starts a dynamic conversation. Results are unspecified if called while
* already inside a dynamic conversation.
*
* @param sConversationScript The script to use for controlling the conversation.
* @param oPC The PC that is to be doing the responding in the conversation.
* @param bAllowExit One of the DYNCONV_EXIT_* constants.
* @param bAllowAbort If TRUE, the PC is allowed to aborts the conversation by moving / doing
* some other action or being involved in combat. This can be changed later
* on using AllowAbort()
* @param bForceStart If TRUE, the PC's actions are cleared, so the conversation starts immediately
* and cannot be avoided by the PC cancelling the action while it is in the queue.
* @param oConverseWith The object to speak the "NPC" side of the conversation. Usually, this is also
* the PC, which will be used when this parameter is left to it's default value.
* NOTE: If this parameter is given a value other than OBJECT_INVALID, no validity
* testing is performed upon that object. The function caller needs to make sure
* the object exists.
*/
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID);
/**
* Starts using another dynamic conversation script while inside a
* dynamic conversation. Should only be called from a dynamic conversation
* script.
* The current conversation's script and allow exit/abort variables are
* saved. When the conversation entered via this call exits, the system
* returns to the current conversation, with stage being the one specified
* in the call to this function.
* NOTE: Any stage setup markers are not stored for the return.
*
* @param sConversationToEnter The conversation script to use in the branch
* @param nStageToReturnTo The value of stage variable upong return
* from the branch.
* @param bAllowExit The branch's initial exit allowance state. See
* StartDynamicConversation() for more details.
* @param bAllowAbort The branch's initial abort allowance state. See
* StartDynamicConversation() for more details.
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int bAllowExit = TRUE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID);
/**
* Marks the current dynconvo as exitable via the exit conversation
* choice.
*
* @param nNewValue One of the DYNCONV_EXIT_* constants
* @param bChangeExitTokenText If this is TRUE, then changes the text on
* DYNCONV_TOKEN_EXIT to "Exit"
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID);
/**
* Marks the conversation as abortable, meaning that the player is
* allowed to leave the conversation via means other than the
* exit conversation choice.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void AllowAbort(object oPC = OBJECT_INVALID);
/**
* Checks whether the given stage is marked as already set up.
*
* @param nStage The stage to check
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks a stage as being set up. This means that when
* the conversation script is called to set up the
* stage, nothing is done and old values are used instead.
* This is useful for scrolling lists, as CPU is not
* wasted on rebuilding the exact same list.
*
* @param nStage The stage to set marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks the stage as not set up. This is used to undo
* the effects of MarkStageSetUp() when there is
* need to rerun the stage's builder.
* An example of such situation would be returning to
* a stage from another.
*
* @param nStage The stage to unset marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Clears the current stage's choices and marks it not set up.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void ClearCurrentStage(object oPC = OBJECT_INVALID);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "bg_inc_array"
#include "bg_inc_debug"
//////////////////////////////////////////////////
/* Internal function prototypes */
//////////////////////////////////////////////////
void _DynConvInternal_ExitedConvo(object oPC, int bAbort);
void _DynConvInternal_RunScript(object oPC, int nDynConvVar);
void _DynConvInternal_PreScript(object oPC);
void _DynConvInternal_PostScript(object oPC);
object _DynConvInternal_ResolvePC(object oPC);
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
void SetupTokens(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Set header
SetCustomToken(DYNCONV_TOKEN_HEADER, GetLocalString(oPC, "DynConv_HeaderText"));
// Set reply tokens. Assumes that the tokens used are a continuous block.
int nOffset = GetLocalInt(oPC, DYNCONV_CHOICEOFFSET);
int i;
for (i = 0; i < 10; i++)
{
SetToken(DYNCONV_TOKEN_REPLY_0 + i, array_get_string(oPC, "ChoiceTokens", nOffset + i), oPC);
}
}
void SetHeader(string sText, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
SetLocalString(oPC, "DynConv_HeaderText", sText);
}
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID)
{
SetHeader(GetStringByStrRef(nStrRef), oPC);
}
string GetTokenIDString(int nTokenID)
{
return DYNCONV_TOKEN_BASE + IntToString(nTokenID);
}
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "ChoiceTokens"))
array_create(oPC, "ChoiceTokens");
if(!array_exists(oPC, "ChoiceValues"))
array_create(oPC, "ChoiceValues");
array_set_string(oPC, "ChoiceTokens", array_get_size(oPC, "ChoiceTokens"), sText);
array_set_int (oPC, "ChoiceValues", array_get_size(oPC, "ChoiceValues"), nValue);
}
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID)
{
AddChoice(GetStringByStrRef(nStrRef), nValue, oPC);
}
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF)
{
// Set the token
SetCustomToken(nTokenID, sString);
// Set a marker on the PC for the reply conditional scripts to check
SetLocalString(oPC, GetTokenIDString(nTokenID), sString);
}
string GetToken(int nTokenID, object oPC = OBJECT_SELF)
{
// Set a marker on the PC for the reply conditional scripts to check
return GetLocalString(oPC, GetTokenIDString(nTokenID));
}
void SetDefaultTokens()
{
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
SetCustomToken(DYNCONV_TOKEN_WAIT, GetStringByStrRef(DYNCONV_STRREF_PLEASE_WAIT));
SetCustomToken(DYNCONV_TOKEN_NEXT, GetStringByStrRef(DYNCONV_STRREF_NEXT));
SetCustomToken(DYNCONV_TOKEN_PREV, GetStringByStrRef(DYNCONV_STRREF_PREVIOUS));
}
void _DynConvInternal_ExitedConvo(object oPC, int bAbort)
{
// Restart convo if not allowed to leave yet
if(bAbort && !GetLocalInt(oPC, "DynConv_AllowAbort")) // Allowed to abort?
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Conversation aborted, restarting.");
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
// Allowed to exit? Technically, the only way this branch should ever be run is by there not being any response choices available
else if(!bAbort &&
(GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): ERROR: Conversation exited via exit node while exiting not allowed!\n"
+ "DYNCONV_SCRIPT = '" + GetLocalString(oPC, DYNCONV_SCRIPT) + "'\n"
);
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
else{
// Run the conversation script's exit handler
SetLocalInt(oPC, DYNCONV_VARIABLE, bAbort ? DYNCONV_ABORTED : DYNCONV_EXITED);
ExecuteScript(GetLocalString(oPC, DYNCONV_SCRIPT), OBJECT_SELF);
// If there are entries remaining in the stack, pop the previous conversation
if(GetLocalInt(oPC, "DynConv_Stack"))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Exited a branch");
// Clean up after the previous conversation
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
// Pop the data from the stack
int nStack = GetLocalInt(oPC, "DynConv_Stack");
int nStage = GetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
int nAllowExit = GetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
int nAllowAbort = GetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
string sScript = GetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
// Delete the stack level
DeleteLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
DeleteLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
if(nStack - 1 > 0) SetLocalInt(oPC, "DynConv_Stack", nStack - 1);
else DeleteLocalInt(oPC, "DynConv_Stack");
// Store the date in the conversation variables
SetLocalInt(oPC, DYNCONV_STAGE, nStage);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", nAllowAbort);
SetLocalString(oPC, DYNCONV_SCRIPT, sScript);
// Restart the conversation
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
}
// Fully exited the conversation. Clean up
else
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Fully exited conversation");
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, "DynConv_AllowExit");
DeleteLocalInt(oPC, "DynConv_AllowAbort");
DeleteLocalInt(oPC, DYNCONV_VARIABLE);
DeleteLocalInt(oPC, DYNCONV_STAGE);
DeleteLocalString(oPC, DYNCONV_SCRIPT);
DeleteLocalString(oPC, "DynConv_HeaderText");
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_HEADER));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_0));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_1));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_2));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_3));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_4));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_5));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_6));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_7));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_8));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_REPLY_9));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_EXIT));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_WAIT));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_NEXT));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_TOKEN_PREV));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_MIN_TOKEN));
DeleteLocalString(oPC, GetTokenIDString(DYNCONV_MAX_TOKEN));
//int i;
//for(i = DYNCONV_MIN_TOKEN; i <= DYNCONV_MAX_TOKEN; i++)
//DeleteLocalString(oPC, GetTokenIDString(i));
}
}
}
void _DynConvInternal_RunScript(object oPC, int nDynConvVar)
{
if(!GetLocalInt(oPC, "DynConv_RestartMarker"))
{
_DynConvInternal_PreScript(oPC);
string sScript = GetLocalString(oPC, DYNCONV_SCRIPT);
SetLocalInt(oPC, DYNCONV_VARIABLE, nDynConvVar);
ExecuteScript(sScript, OBJECT_SELF);
_DynConvInternal_PostScript(oPC);
}
else
{
SetupTokens(oPC);
DeleteLocalInt(oPC, "DynConv_RestartMarker");
}
}
void _DynConvInternal_PreScript(object oPC)
{
// Create the choice arrays
array_create(oPC, "ChoiceTokens");
array_create(oPC, "ChoiceValues");
}
void _DynConvInternal_PostScript(object oPC)
{
// If debugging is active, check that the conversations have at least one response node
// when exiting is off
if(DEBUG)
{
if(GetLocalInt(oPC, DYNCONV_VARIABLE) == DYNCONV_SETUP_STAGE &&
GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED &&
array_get_size(oPC, "ChoiceTokens") == 0
)
{
DoDebug("Dynconvo ERROR: No response tokens set up and exiting not allowed!");
}
}
}
object _DynConvInternal_ResolvePC(object oPC)
{
return oPC == OBJECT_INVALID ? GetPCSpeaker() : oPC; // If no valid PC reference was passed, get it via GetPCSpeaker
}
void SetStage(int nNewStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// No need to act if the stage wasn't changed
if(nNewStage != GetStage(oPC))
{
SetLocalInt(oPC, DYNCONV_STAGE, nNewStage);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
}
}
int GetStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return GetLocalInt(oPC, DYNCONV_STAGE);
}
int GetChoice(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_int(oPC, "ChoiceValues", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
string GetChoiceText(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_string(oPC, "ChoiceTokens", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID)
{
if(IsInConversation(oPC))
{
if(DEBUG) DoDebug("StartDynamicConversation(): Aborting--already in conversation");
return;
}
if(DEBUG) DoDebug("StartDynamicConversation(): Starting new dynamic conversation, parameters:\n"
+ "sConversationScript = '" + sConversationScript + "'\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "bForceStart = " + DebugBool2String(bForceStart) + "\n"
+ "oConverseWith = " + DebugObject2Str(oConverseWith) + "\n"
);
// By default, the PC converses with itself
oConverseWith = oConverseWith == OBJECT_INVALID ? oPC : oConverseWith;
if(DEBUG) if(!GetIsObjectValid(oConverseWith)) DoDebug("StartDynamicConversation(): ERROR: oConverseWith is not valid!");
// Store the exit control variables
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
// Initiate conversation
if(bForceStart) AssignCommand(oPC, ClearAllActions(TRUE));
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationScript);
AssignCommand(oPC, ActionStartConversation(oConverseWith, "dyncov_base", TRUE, FALSE));
}
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("BranchDynamicConversation(): Entering another dynamic conversation, parameters:\n"
+ "sConversationToEnter = '" + sConversationToEnter + "'\n"
+ "nStageToReturnTo = " + IntToString(nStageToReturnTo) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n "
);
oPC = _DynConvInternal_ResolvePC(oPC);
// Get current stack level
int nStack = GetLocalInt(oPC, "DynConv_Stack") + 1;
// Push the return data onto the stack
SetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack), nStageToReturnTo);
SetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowExit"));
SetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowAbort"));
SetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack),
GetLocalString(oPC, DYNCONV_SCRIPT));
SetLocalInt(oPC, "DynConv_Stack", nStack);
// Clean the current conversation data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, DYNCONV_STAGE);
// Set the new conversation as active
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationToEnter);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
}
/// @todo Rename to SetExitable
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("AllowExit():\n"
+ "nNewValue = " + (nNewValue == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nNewValue == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nNewValue == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nNewValue)
) + "\n"
+ "bChangeExitTokenText = " + DebugBool2String(bChangeExitTokenText) + "\n"
+ "oPC = " + DebugObject2Str(_DynConvInternal_ResolvePC(oPC)) + "\n"
);
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowExit", nNewValue);
if(bChangeExitTokenText)
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
}
/// @todo Replace with SetAbortable(int bAllow, object oPC = OBJECT_INVALID)
void AllowAbort(object oPC = OBJECT_INVALID)
{
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowAbort", TRUE);
}
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return FALSE;
return array_get_int(oPC, "StagesSetup", nStage);
}
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
array_create(oPC, "StagesSetup");
array_set_int(oPC, "StagesSetup", nStage, TRUE);
}
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return;
array_set_int(oPC, "StagesSetup", nStage, FALSE);
}
void ClearCurrentStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
MarkStageNotSetUp(GetStage(oPC), oPC);
}

436
src/nss/bg_inc_p_locals.nss Normal file
View File

@@ -0,0 +1,436 @@
//::///////////////////////////////////////////////
//:: Persistant local variables include
//:: bg_inc_p_locals
//:://////////////////////////////////////////////
/** @file
A set of functions for storing local variables
on a token item stored in the creature's skin.
Since local variables on items within containers
are not stripped during serialization, these
variables persist across module changes and
server resets.
These functions work on NPCs in addition to PCs,
but the persitence is mostly useless for them,
since NPCs are usually not serialized in a way
that would remove normal locals from them, if
they are serialized at all.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Adapted by ebonfowl to fix the Beamdog local variable bug
//:: Functions all still intuitively work the same way
//:: Only difference is the variables all run through SQL rather than via the hide token
//:: Dedicated to Edgar, the real Ebonfowl
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets the token item inside the given creature's hide, on which the persistant
* variables are stored on.
* If a token does not exist already, one is created.
* WARNING: If called on a non-creature object, returns the object itself.
*
* @param oPC The creature whose storage token to get
* @param bAMS - TRUE will return special token for alternate magic system buckup info
* @return The creature's storage token
*
* GetNSBToken - special token for New Spellbook System information
*/
//object GetHideToken(object oPC, int bAMS = FALSE);
/**
* Set a local string variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param sValue The value to set the string local to
*/
void SetPersistantLocalString(object oPC, string sName, string sValue);
/**
* Set a local integer variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the integer local to
*/
void SetPersistantLocalInt(object oPC, string sName, int nValue);
/**
* Set a local float variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the float local to
*/
void SetPersistantLocalFloat(object oPC, string sName, float fValue);
/**
* Set a local location variable on the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalObject(). Location also contains an
* object reference, though it will only break across changes to the module,
* not across server resets.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the location local to
*/
void SetPersistantLocalLocation(object oPC, string sName, location lValue);
/**
* Set a local object variable on the creature's storage token.
*
* CAUTION! Object references are likely (and in some cases, certain) to break
* when transferring across modules or upon server reset. This means that
* persistantly stored local objects may not refer to the same object after such
* a change, if they refer to a valid object at all.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @param nValue The value to set the object local to
*/
void SetPersistantLocalObject(object oPC, string sName, object oValue);
/**
* Get a local string variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The string local specified. On error, returns ""
*/
string GetPersistantLocalString(object oPC, string sName);
/**
* Get a local integer variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The integer local specified. On error, returns 0
*/
int GetPersistantLocalInt(object oPC, string sName);
/**
* Get a local float variable from the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The float local specified. On error, returns 0.0
*/
float GetPersistantLocalFloat(object oPC, string sName);
/**
* Get a local location variable from the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalLocation()
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The location local specified. Return value on error is unknown
*/
location GetPersistantLocalLocation(object oPC, string sName);
/**
* Get a local object variable from the creature's storage token.
*
* CAUTION! See note in SetPersistantLocalObject()
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
* @return The object local specified. On error, returns OBJECT_INVALID
*/
object GetPersistantLocalObject(object oPC, string sName);
/**
* Delete a local string variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalString(object oPC, string sName);
/**
* Delete a local integer variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalInt(object oPC, string sName);
/**
* Delete a local float variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalFloat(object oPC, string sName);
/**
* Delete a local location variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalLocation(object oPC, string sName);
/**
* Delete a local object variable on the creature's storage token.
*
* @param oPC The creature whose local variables to manipulate
* @param sName The name of the local variable to manipulate
*/
void DeletePersistantLocalObject(object oPC, string sName);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "bg_inc_skin"
// SQL include
#include "inc_persistsql"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
object GetHideToken(object oPC, int bAMS = FALSE)
{
string sCache = bAMS ? "PRC_AMSTokenCache" : "PRC_HideTokenCache";
string sTag = bAMS ? "AMS_Token" : "HideToken";
// Creatureness check - non-creatures don't get persistent storage from here
if(!(GetObjectType(oPC) == OBJECT_TYPE_CREATURE))
return oPC; // Just return a reference to the object itself
object oHide = GetPCSkin(oPC);
object oToken = GetLocalObject(oPC, sCache);
if(!GetIsObjectValid(oToken))
{
object oTest = GetFirstItemInInventory(oHide);
while(GetIsObjectValid(oTest))
{
if(GetTag(oTest) == sTag)
{
oToken = oTest;
break;//exit while loop
}
oTest = GetNextItemInInventory(oHide);
}
if(!GetIsObjectValid(oToken))
{
oToken = GetItemPossessedBy(oPC, sTag);
// Move the token to hide's inventory
if(GetIsObjectValid(oToken))
AssignCommand(oHide, ActionTakeItem(oToken, oPC)); // Does this work? - Ornedan
else
{
//oToken = CreateItemOnObject("hidetoken", oPC);
//AssignCommand(oHide, ActionTakeItem(oToken, oPC));
oToken = CreateItemOnObject("hidetoken", oHide, 1, sTag);
}
}
AssignCommand(oToken, SetIsDestroyable(FALSE));
// Cache the token so that there needn't be multiple loops over an inventory
SetLocalObject(oPC, sCache, oToken);
//- If the cache reference is found to break under any conditions, uncomment this.
//looks like logging off then back on without the server rebooting breaks it
//I guess because the token gets a new ID, but the local still points to the old one
//Ive changed it to delete the local in OnClientEnter. Primogenitor
//DelayCommand(1.0f, DeleteLocalObject(oPC, "PRC_HideTokenCache"));
}
return oToken;
}
void SetPersistantLocalString(object oPC, string sName, string sValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetString(oPC, sName, sValue);
}
else
{
SetLocalString(oPC, sName, sValue);
}
}
/* void SetPersistantLocalString(object oPC, string sName, string sValue)
{
if(GetIsPC(oPC))
{
SQLocalsPlayer_SetString(oPC, sName, sValue);
}
else
{
SetLocalString(oPC, sName, sValue);
}
} */
void SetPersistantLocalInt(object oPC, string sName, int nValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetInt(oPC, sName, nValue);
}
else
{
SetLocalInt(oPC, sName, nValue);
}
}
void SetPersistantLocalFloat(object oPC, string sName, float fValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetFloat(oPC, sName, fValue);
}
else
{
SetLocalFloat(oPC, sName, fValue);
}
}
void SetPersistantLocalLocation(object oPC, string sName, location lValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetLocation(oPC, sName, lValue);
}
else
{
SetLocalLocation(oPC, sName, lValue);
}
}
void SetPersistantLocalObject(object oPC, string sName, object oValue)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_SetObject(oPC, sName, oValue);
}
else
{
SetLocalObject(oPC, sName, oValue);
}
}
string GetPersistantLocalString(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetString(oPC, sName);
}
return GetLocalString(oPC, sName);
}
int GetPersistantLocalInt(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetInt(oPC, sName);
}
return GetLocalInt(oPC, sName);
}
float GetPersistantLocalFloat(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetFloat(oPC, sName);
}
return GetLocalFloat(oPC, sName);
}
location GetPersistantLocalLocation(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
return SQLocalsPlayer_GetLocation(oPC, sName);
}
return GetLocalLocation(oPC, sName);
}
object GetPersistantLocalObject(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
// Additional check since the OID returned may be invalid, but not actually OBJECT_INVALID
object oReturn = SQLocalsPlayer_GetObject(oPC, sName);
if(GetIsObjectValid(oReturn)) return oReturn;
return OBJECT_INVALID;
}
return GetLocalObject(oPC, sName);
}
void DeletePersistantLocalString(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteString(oPC, sName);
}
else
{
DeleteLocalString(oPC, sName);
}
}
void DeletePersistantLocalInt(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteInt(oPC, sName);
}
else
{
DeleteLocalInt(oPC, sName);
}
}
void DeletePersistantLocalFloat(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteFloat(oPC, sName);
}
else
{
DeleteLocalFloat(oPC, sName);
}
}
void DeletePersistantLocalLocation(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteLocation(oPC, sName);
}
else
{
DeleteLocalLocation(oPC, sName);
}
}
void DeletePersistantLocalObject(object oPC, string sName)
{
if(GetIsPC(oPC) == TRUE && GetMaster(oPC) == OBJECT_INVALID && !GetIsDMPossessed(oPC))
{
SQLocalsPlayer_DeleteObject(oPC, sName);
}
else
{
DeleteLocalObject(oPC, sName);
}
}
// Test main
// void main() {}

139
src/nss/bg_inc_skin.nss Normal file
View File

@@ -0,0 +1,139 @@
//::///////////////////////////////////////////////
//:: skin include
//:: prc_inc_skin
//::///////////////////////////////////////////////
/** @file
This include contains GetPCSkin(). If only using
this function please include this directly and not via
the entire spell engine :p
Is included by bg_inc_p_locals for persistent
local variables
*/
//:://////////////////////////////////////////////
//:: Created By: fluffyamoeba
//:: Created On: 2008-4-23
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Sets up the pcskin object on oPC.
* If it already exists, simply return it. Otherwise, create and equip it.
*
* @param oPC The creature whose skin object to look for.
* @return Either the skin found or the skin created.
*/
object GetPCSkin(object oPC);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "bg_inc_debug"
//////////////////////////////////////////////////
/* private functions */
//////////////////////////////////////////////////
// to duplicate ForceEquip() from inc_utility
void _ForceEquipSkin(object oPC, object oSkin, int nThCall = 0)
{
// Make sure that the object we are attempting equipping is the latest one to be ForceEquipped into this slot
if(GetIsObjectValid(GetLocalObject(oPC, "ForceEquipToSlot_17"))
&& GetLocalObject(oPC, "ForceEquipToSlot_17") != oSkin)
return;
// Fail on non-commandable NPCs after ~1min
if(!GetIsPC(oPC) && !GetCommandable(oPC) && nThCall > 60)
{
WriteTimestampedLogEntry("ForceEquip() failed on non-commandable NPC: " + DebugObject2Str(oPC) + " for item: " + DebugObject2Str(oSkin));
return;
}
float fDelay;
// Check if the equipping has already happened
if(GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC) != oSkin)
{
// Test and increment the control counter
if(nThCall++ == 0)
{
// First, try to do the equipping non-intrusively and give the target a reasonable amount of time to do it
AssignCommand(oPC, ActionEquipItem(oSkin, INVENTORY_SLOT_CARMOUR));
fDelay = 1.0f;
// Store the item to be equipped in a local variable to prevent contest between two different calls to ForceEquip
SetLocalObject(oPC, "ForceEquipToSlot_17", oSkin);
}
else
{
// Nuke the target's action queue. This should result in "immediate" equipping of the item
if(GetIsPC(oPC) || nThCall > 5) // Skip nuking NPC action queue at first, since that can cause problems. 5 = magic number here. May need adjustment
{
if(!GetIsObjectValid(oSkin))
{
oSkin = GetPCSkin(oPC);
return;
}
else
{
AssignCommand(oPC, ClearAllActions());
AssignCommand(oPC, ActionEquipItem(oSkin, INVENTORY_SLOT_CARMOUR));
}
}
// Use a lenghtening delay in order to attempt handling lag and possible other interference. From 0.1s to 1s
fDelay = (nThCall < 10 ? nThCall : 10) / 10.0f; // yes this is the same as PRCMin(nThCall, 10)
}
// Loop
DelayCommand(fDelay, _ForceEquipSkin(oPC, oSkin, nThCall));
}
// It has, so clean up
else
DeleteLocalObject(oPC, "ForceEquipToSlot_17");
}
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
object GetPCSkin(object oPC)
{
// According to a bug report, this is being called on non-creature objects. This should catch the culprit
if(DEBUG) Assert(GetObjectType(oPC) == OBJECT_TYPE_CREATURE, "GetObjectType(oPC) == OBJECT_TYPE_CREATURE", "GetPRCSkin() called on non-creature object: " + DebugObject2Str(oPC), "prc_inc_skin", "object GetPCSkin(object oPC)");
object oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC);
if(!GetIsObjectValid(oSkin))
{
//oSkin = GetLocalObject(oPC, "PRCSkinCache");
//if(!GetIsObjectValid(oSkin))
{
//Added this check to prevent creation of extra skins on module entry
oSkin = GetItemPossessedBy(oPC, "base_prc_skin");
if(GetIsObjectValid(oSkin))
{
_ForceEquipSkin(oPC, oSkin, INVENTORY_SLOT_CARMOUR);
//AssignCommand(oPC, ActionEquipItem(oSkin, INVENTORY_SLOT_CARMOUR));
}
else
{
oSkin = CreateItemOnObject("base_prc_skin", oPC);
_ForceEquipSkin(oPC, oSkin, INVENTORY_SLOT_CARMOUR);
//AssignCommand(oPC, ActionEquipItem(oSkin, INVENTORY_SLOT_CARMOUR));
// The skin should not be droppable
SetDroppableFlag(oSkin, FALSE);
// other scripts should not be able to destroy the skin
AssignCommand(oSkin, SetIsDestroyable(FALSE));
}
// Cache the skin reference for further lookups during the same script
//SetLocalObject(oPC, "PRCSkinCache", oSkin);
//DelayCommand(0.0f, DeleteLocalObject(oPC, "PRCSkinCache"));
}
}
return oSkin;
}

View File

@@ -1,8 +1,9 @@
// bg_language_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
#include "te_lang"
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
@@ -88,15 +89,14 @@ int GetNextLanguageSlot(object oPC)
{
string sSlot = "LANGUAGE_" + (nSlot < 10 ? "0" : "") + IntToString(nSlot);
SetLocalInt(oItem, sSlot, nLanguageFeat);
SetPersistantLocalInt(oPC, sSlot, nLanguageFeat);
SetPersistantLocalInt(oPC, sSlot, nLanguageFeat);
}
// mark as selected for the conversation list
SetLocalInt(oPC, IntToString(nLanguageFeat), TRUE);
}
// Count automatic racial and class languages using slot-searching pattern
// Count automatic racial and class languages using slot-searching pattern
int GetAutomaticLanguageCount(object oPC)
{
int nAutomaticLanguages = 0;
@@ -348,7 +348,7 @@ void main() {
// Grant automatic languages before starting conversation
GrantDefaultLanguages(oPC);
SendMessageToPC(oPC, "DEBUG: bg_language_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_language_cv main() entered");
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
@@ -369,7 +369,8 @@ void main() {
if (nValue == DYNCONV_SETUP_STAGE) {
if (!GetIsStageSetUp(nStage, oPC)) {
if (nStage == STAGE_LIST) {
if (nStage == STAGE_LIST)
{
// Initialize language count if not set
if (!GetLocalInt(oPC, "LANGUAGE_COUNT")) {
SetLocalInt(oPC, "LANGUAGE_COUNT", 0);
@@ -458,7 +459,7 @@ void main() {
AddChoice("Lantanese", 24, oPC);
}
if (nRemaining > 0 && !KnowsLanguage(oPC, FEAT_LANGUAGE_MAZTILAN)) {
AddChoice("Mulanese", 25, oPC);
AddChoice("Maztilan", 25, oPC);
}
if (nRemaining > 0 && !KnowsLanguage(oPC, FEAT_LANGUAGE_MULANESE)) {
AddChoice("Mulanese", 26, oPC);
@@ -488,11 +489,19 @@ void main() {
AddChoice("Undercommon", 34, oPC);
}
// Show Done option if at least one language selected
if (nLangCount > 0) {
/* // Show Done option if at least one language selected
if (nLangCount > 0)
{
AddChoice("Done - I have selected enough languages", 99, oPC);
SetLocalString(oPC, "lang_dyn_text_99", "Finish language selection and continue to the next step.");
}
} */
// Show Done option if at least one language selected OR no picks remaining
if (nLangCount > 0 || nRemaining == 0)
{
AddChoice("Done - I have selected enough languages", 99, oPC);
SetLocalString(oPC, "lang_dyn_text_99", "Finish language selection and continue to the next step.");
}
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
@@ -513,7 +522,14 @@ void main() {
}
}
SetupTokens();
} else {
}
else if (nValue == DYNCONV_EXITED)
{
SetPersistantLocalInt(oPC, "Background_Stage", 5);
DelayCommand(0.1f, StartDynamicConversation("bg_profs_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else
{
// Handle PC responses
int nChoice = GetChoice(oPC);
@@ -522,8 +538,11 @@ void main() {
if (nChoice == 99)
{
// Done - finalize and proceed to next step
SetPersistantLocalInt(oPC, "CC4_DONE", 1);
DelayCommand(0.1f, StartDynamicConversation("bg_profs_cv", oPC));
SetPersistantLocalInt(oPC, "CC4_DONE", 1);
SetLocalInt(oItem, "CC4_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 5);
DelayCommand(0.1f, StartDynamicConversation("bg_profs_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
}
else if (nChoice >= 1 && nChoice <= 34)
{
@@ -644,8 +663,10 @@ void main() {
SetStage(STAGE_CONFIRM, oPC);
}
}
else if (nStage == STAGE_CONFIRM) {
if (nChoice == CHOICE_CONFIRM_YES) {
else if (nStage == STAGE_CONFIRM)
{
if (nChoice == CHOICE_CONFIRM_YES)
{
// Confirm selection - grant language
string sLangVar = GetLocalString(oPC, "TEMP_LANG_VAR");
int nLanguageFeat = GetLocalInt(oPC, "TEMP_LANG_FEAT");
@@ -670,10 +691,12 @@ void main() {
int nIntMod = GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
if (nIntMod <= 0) nIntMod = 0;
if (nCount >= nIntMod) {
if (nCount >= nIntMod)
{
SetPersistantLocalInt(oPC, "CC4_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 5);
DelayCommand(0.1f, StartDynamicConversation("bg_profs_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
DelayCommand(0.1f, StartDynamicConversation("bg_profs_cv", oPC));
}
else
{

View File

@@ -1,7 +1,7 @@
// bg_proficiency_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
// Ensure the PC Data Object exists; create if missing
@@ -264,7 +264,7 @@ const int CHOICE_CONFIRM_NO = 101;
void main() {
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_prof_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_prof_cv main() entered");
object oItem = EnsurePlayerDataObject(oPC);
@@ -398,7 +398,14 @@ void main() {
}
}
SetupTokens();
} else {
}
else if (nValue == DYNCONV_EXITED)
{
SetPersistantLocalInt(oPC, "Background_Stage", 6);
DelayCommand(0.1f, StartDynamicConversation("bg_age_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else
{
// Handle PC responses
int nChoice = GetChoice(oPC);
@@ -406,8 +413,10 @@ void main() {
{
if (nChoice == 21)
{
// Done - finalize and proceed to next step
ExecuteScript("prof_give_nomore", oPC);
// Done - finalize and proceed to next step
SetPersistantLocalInt(oPC, "CC5_DONE", 1);
SetLocalInt(oItem, "CC5_DONE", 1);
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
}
else if (nChoice >= 1 && nChoice <= 20)
{
@@ -618,14 +627,15 @@ void main() {
{
// Auto-finish
SetLocalInt(oItem,"BG_Select",6);
ActionStartConversation(oPC,"bg_final",TRUE);
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
//DelayCommand(0.1f, StartDynamicConversation("bg_age_cv", oPC));
}
else
{
// Return to list, force refresh
MarkStageNotSetUp(STAGE_CONFIRM, oPC);
MarkStageNotSetUp(STAGE_LIST, oPC);
nStage = STAGE_LIST; // Add this line
nStage = STAGE_LIST;
}
}
else if (nChoice == CHOICE_CONFIRM_NO)

View File

@@ -1,7 +1,7 @@
// bg_soclass_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
const int STAGE_LIST = 0;
@@ -48,7 +48,7 @@ object EnsurePlayerDataObject(object oPC)
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_soclass_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_soclass_cv main() entered");
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
@@ -132,8 +132,9 @@ void main()
}
}
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
SetPersistantLocalInt(oPC, "CC1_DONE", 1);
DelayCommand(0.1f, StartDynamicConversation("bg_background_cv", oPC));
SetPersistantLocalInt(oPC, "CC1_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 2);
DelayCommand(0.1f, StartDynamicConversation("bg_background_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else
{ // No

View File

@@ -1,10 +1,9 @@
// bg_subrace_cv.nss
#include "inc_dynconv"
#include "bg_inc_dynconv"
#include "x2_inc_switches"
#include "inc_persist_loca"
#include "bg_inc_p_locals"
#include "te_afflic_func"
const int STAGE_LIST = 0;
const int STAGE_CONFIRM = 1;
@@ -28,7 +27,7 @@ object EnsurePlayerDataObject(object oPC)
void main()
{
object oPC = GetPCSpeaker();
SendMessageToPC(oPC, "DEBUG: bg_subrace_cv main() entered");
//SendMessageToPC(oPC, "DEBUG: bg_subrace_cv main() entered");
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
int nStage = GetStage(oPC);
@@ -505,8 +504,9 @@ void main()
}
}
AllowExit(DYNCONV_EXIT_FORCE_EXIT, TRUE, oPC);
SetPersistantLocalInt(oPC, "CC0_DONE", 1);
DelayCommand(0.1f, StartDynamicConversation("bg_soclass_cv", oPC));
SetPersistantLocalInt(oPC, "CC0_DONE", 1);
SetPersistantLocalInt(oPC, "Background_Stage", 1);
DelayCommand(0.1f, StartDynamicConversation("bg_soclass_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
}
else
{ // No

View File

@@ -1,11 +1,24 @@
// clear_bg_vars.nss
#include "inc_persist_loca"
#include "bg_inc_p_locals"
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
{
object oItem = GetItemPossessedBy(oPC, "PC_Data_Object");
if (!GetIsObjectValid(oItem))
{
oItem = CreateItemOnObject("pc_data_object", oPC);
SendMessageToPC(oPC, "Language data object recreated");
WriteTimestampedLogEntry("Language data object recreated");
}
return oItem;
}
void main()
{
object oPC = OBJECT_SELF;
object oDataObject = GetItemPossessedBy(oPC, "PC_Data_Object");
object oDataObject = EnsurePlayerDataObject(oPC);
if (!GetIsObjectValid(oDataObject))
{
SendMessageToPC(oPC, "No PC_Data_Object found on this character.");
@@ -61,7 +74,7 @@ void main()
DeleteLocalString(oPC, "TEMP_PROF_VAR");
DeleteLocalString(oPC, "TEMP_PROF_GRANT");
DeleteLocalString(oPC, "TEMP_PROF_DESC");
DeleteLocalString(oPC, "ARR_PROF");
DeleteLocalString(oPC, "ARR_PROF");
DeletePersistantLocalString(oPC, "ARR_PROF");
DeleteLocalInt(oPC, "PROFICIENCY_COUNT");
DeletePersistantLocalInt(oPC, "PROFICIENCY_COUNT");
@@ -74,6 +87,14 @@ void main()
DeleteLocalInt(oDataObject, sSlot);
DeletePersistantLocalInt(oPC, sSlot);
}
// Clear PROFICIENCY_XX variables (new system)
for (i = 0; i < 20; i++)
{
string sSlot = "PROFICIENCY_" + (i < 10 ? "0" : "") + IntToString(i);
DeleteLocalInt(oDataObject, sSlot);
DeletePersistantLocalInt(oPC, sSlot);
}
SendMessageToPC(oPC, "Character creation variables cleared.");
}

84
src/nss/cv_background.nss Normal file
View File

@@ -0,0 +1,84 @@
#include "bg_inc_dynconv"
#include "bg_inc_p_locals"
// Ensure the PC Data Object exists; create if missing
object EnsurePlayerDataObject(object oPC)
{
object oItem = GetItemPossessedBy(oPC, "PC_Data_Object");
if (!GetIsObjectValid(oItem))
{
oItem = CreateItemOnObject("pc_data_object", oPC);
SendMessageToPC(oPC, "Language data object recreated");
WriteTimestampedLogEntry("Language data object recreated");
}
return oItem;
}
void main()
{
object oPC = GetLastUsedBy();
object oItem = EnsurePlayerDataObject(oPC);
int iState = GetPersistantLocalInt(oPC, "Background_Stage");
//int iState = GetLocalInt(oItem, "Background_Stage");
if(iState == 0)
{
SendMessageToPC(oPC,"Resuming from Subrace Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_subrace_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_class",TRUE);
}
else if(iState == 1)
{
SendMessageToPC(oPC,"Resuming from Social Class Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_soclass_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_class",TRUE);
}
else if(iState == 2)
{
SendMessageToPC(oPC,"Resuming from Background Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_background_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_background",TRUE);
}
else if(iState == 3)
{
SendMessageToPC(oPC,"Resuming from Deity Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_deity_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_deity",TRUE);
}
else if(iState == 4)
{
SendMessageToPC(oPC,"Resuming from Language Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_language_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_language",TRUE);
}
else if(iState == 5)
{
SendMessageToPC(oPC,"Resuming from Proficiency Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_profs_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_proficiency",TRUE);
}
else if(iState == 6)
{
SendMessageToPC(oPC,"Resuming from Age Modifier Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_age_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_final",TRUE);
}
else if(iState == 7)
{
SendMessageToPC(oPC,"Resuming from Disfigurement Selection.");
DelayCommand(0.2f, StartDynamicConversation("bg_disfig_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_disfig",TRUE);
}
else if(iState >= 8)
{
SendMessageToPC(oPC,"You have completed the background selection process.");
}
else
{
SendMessageToPC(oPC,"You have not begun the selection process.");
DelayCommand(0.2f, StartDynamicConversation("bg_subrace_cv", oPC, FALSE, FALSE, TRUE, OBJECT_SELF));
//ActionStartConversation(oPC,"bg_subrace_cv",TRUE);
}
}

3695
src/nss/dmfi_onplychat.nss Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -10,7 +10,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -10,7 +10,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()

View File

@@ -11,7 +11,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()
{

View File

@@ -12,7 +12,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
//////////////////////////////////////////////////
/* Constant defintions */

View File

@@ -13,7 +13,7 @@
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
#include "bg_inc_dynconv"
int StartingConditional()

2466
src/nss/ms_name_inc.nss Normal file

File diff suppressed because it is too large Load Diff

1327
src/nss/old_bg_deity_cv.nss Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
//::///////////////////////////////////////////////
//:: start_background.nss
//:: Start the Background selectoin process
//::///////////////////////////////////////////////
void main()
{
object oPC = GetLastUsedBy();
object oPlaceable = OBJECT_SELF;
if(!GetIsObjectValid(oPC))
{
return;
}
AssignCommand(oPC, ActionStartConversation(oPlaceable));
}

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{
@@ -13,5 +13,5 @@ void main()
}
SpeakString("DEBUG: Starting bg_background_cv for " + GetName(oUser));
StartDynamicConversation("bg_background_cv", oUser);
StartDynamicConversation("bg_background_cv", oUser, FALSE, FALSE, TRUE, OBJECT_SELF);
}

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{

View File

@@ -1,4 +1,4 @@
#include "inc_dynconv"
#include "bg_inc_dynconv"
void main()
{
@@ -12,6 +12,6 @@ void main()
return;
}
SpeakString("DEBUG: Starting bg_subrace_cv for " + GetName(oUser));
StartDynamicConversation("bg_subrace_cv", oUser);
SpeakString("DEBUG: Starting bg_subrace_cv for " + GetName(oUser));
StartDynamicConversation("bg_subrace_cv", oUser, FALSE, FALSE, TRUE, OBJECT_SELF);
}

View File

@@ -1,17 +1,17 @@
#include "inc_dynconv"
void main()
{
object oUser = GetLastUsedBy();
if (!GetIsObjectValid(oUser)) return;
SpeakString("I was last used by: " + GetName(oUser));
if (IsInConversation(oUser)) {
SpeakString("DEBUG: PC already in conversation; aborting dynconv start.");
return;
}
SpeakString("DEBUG: Starting bg_soclass_cv for " + GetName(oUser));
StartDynamicConversation("bg_soclass_cv", oUser);
}
#include "bg_inc_dynconv"
void main()
{
object oUser = GetLastUsedBy();
if (!GetIsObjectValid(oUser)) return;
SpeakString("I was last used by: " + GetName(oUser));
if (IsInConversation(oUser)) {
SpeakString("DEBUG: PC already in conversation; aborting dynconv start.");
return;
}
SpeakString("DEBUG: Starting bg_soclass_cv for " + GetName(oUser));
StartDynamicConversation("bg_soclass_cv", oUser);
}

View File

@@ -1,4 +1,4 @@
#include "prc_effect_inc"
void main()
{
@@ -7,7 +7,7 @@ void main()
if (GetHasSpellEffect(nSpellID, oPC))
{
PRCRemoveSpellEffects(nSpellID, oPC, oPC);
RemoveSpellEffects(nSpellID, oPC, oPC);
}
else
{