diff --git a/package.json b/package.json index 64bf6e4..486fd81 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,16 @@ } } }, + "nwscript-ee-lsp.definition": { + "type": "object", + "properties": { + "preferImplementation": { + "type": "boolean", + "default": true, + "description": "When using Go to Definition on a function, prefer jumping to the implementation (with body) over the forward declaration. When disabled, jumps to the first occurrence found." + } + } + }, "nwscript-ee-lsp.compiler": { "type": "object", "properties": { diff --git a/server/resources/compiler/linux/nwn_script_comp b/server/resources/compiler/linux/nwn_script_comp index 5a188d8..0c984d7 100755 Binary files a/server/resources/compiler/linux/nwn_script_comp and b/server/resources/compiler/linux/nwn_script_comp differ diff --git a/server/resources/compiler/mac/nwn_script_comp b/server/resources/compiler/mac/nwn_script_comp index 88791f0..0c984d7 100644 Binary files a/server/resources/compiler/mac/nwn_script_comp and b/server/resources/compiler/mac/nwn_script_comp differ diff --git a/server/resources/compiler/windows/nwn_script_comp.exe b/server/resources/compiler/windows/nwn_script_comp.exe index c76bdc0..acd87a2 100644 Binary files a/server/resources/compiler/windows/nwn_script_comp.exe and b/server/resources/compiler/windows/nwn_script_comp.exe differ diff --git a/server/src/Providers/DiagnosticsProvider.ts b/server/src/Providers/DiagnosticsProvider.ts index 2246163..7449e89 100644 --- a/server/src/Providers/DiagnosticsProvider.ts +++ b/server/src/Providers/DiagnosticsProvider.ts @@ -25,20 +25,27 @@ export default class DiagnoticsProvider extends Provider { private generateDiagnostics(uris: string[], files: FilesDiagnostics, severity: DiagnosticSeverity) { return (line: string) => { - const uri = uris.find((uri) => basename(fileURLToPath(uri)) === lineFilename.exec(line)![2]); - - if (uri) { - const linePosition = Number(lineNumber.exec(line)![1]) - 1; - const diagnostic = { - severity, - range: { - start: { line: linePosition, character: 0 }, - end: { line: linePosition, character: Number.MAX_VALUE }, - }, - message: lineMessage.exec(line)![2].trim(), - }; - - files[uri].push(diagnostic); + const lineFilenameMatch = lineFilename.exec(line); + if (lineFilenameMatch) { + const reportedFileName = lineFilenameMatch[2]; + const uri = uris.find((uri) => basename(fileURLToPath(uri)) === reportedFileName); + if (uri) { + const lineNumberMatch = lineNumber.exec(line); + const lineMessageMatch = lineMessage.exec(line); + if (lineNumberMatch && lineMessageMatch) { + const linePosition = Number(lineNumberMatch[1]) - 1; + const diagnostic = { + severity, + range: { + start: { line: linePosition, character: 0 }, + end: { line: linePosition, character: Number.MAX_VALUE }, + }, + message: lineMessageMatch[2].trim(), + }; + + files[uri].push(diagnostic); + } + } } }; } @@ -101,7 +108,10 @@ export default class DiagnoticsProvider extends Provider { // The compiler command: // - y; continue on error // - s; dry run - const args = ["-y", "-s"]; + // - n; no entry point required (for include files) + // - E; collect and report all errors (not just the first) + // Note: -E requires compiler binary with ABI v2+ + const args = ["-y", "-s", "-n", "-E"]; if (Boolean(nwnHome)) { args.push("--userdirectory"); args.push(`"${nwnHome}"`); @@ -114,12 +124,25 @@ export default class DiagnoticsProvider extends Provider { } else if (verbose) { this.server.logger.info("Trying to resolve Neverwinter Nights installation directory automatically."); } - if (children.length > 0) { + // Collect directories from ALL indexed documents so the compiler can + // resolve the full transitive include chain, not just direct children. + const allDirs: Set = new Set(); + this.server.documentsCollection.forEach((doc) => { + if (doc.uri && doc.uri.startsWith("file://")) { + allDirs.add(dirname(fileURLToPath(doc.uri))); + } + }); + // Also add the compiled file's own directory + allDirs.add(dirname(fileURLToPath(uri))); + if (allDirs.size > 0) { args.push("--dirs"); - args.push(`"${[...new Set(uris.map((uri) => dirname(fileURLToPath(uri))))].join(",")}"`); + args.push(`"${[...allDirs].join(",")}"`); } + + const filePath = fileURLToPath(uri); + this.server.logger.info(`Compiling file: ${filePath}`); args.push("-c"); - args.push(`"${fileURLToPath(uri)}"`); + args.push(`"${filePath}"`); let stdout = ""; let stderr = ""; @@ -186,6 +209,7 @@ export default class DiagnoticsProvider extends Provider { for (const [uri, diagnostics] of Object.entries(files)) { this.server.connection.sendDiagnostics({ uri, diagnostics }); } + resolve(true); }); }); diff --git a/server/src/Providers/GotoDefinitionProvider.ts b/server/src/Providers/GotoDefinitionProvider.ts index 86e8900..27cabd5 100644 --- a/server/src/Providers/GotoDefinitionProvider.ts +++ b/server/src/Providers/GotoDefinitionProvider.ts @@ -3,7 +3,7 @@ import { TextDocument } from "vscode-languageserver-textdocument"; import type { OwnedComplexTokens, OwnedStructComplexTokens } from "../Documents/Document"; import type { ServerManager } from "../ServerManager"; -import type { ComplexToken } from "../Tokenizer/types"; +import type { ComplexToken, FunctionComplexToken } from "../Tokenizer/types"; import { Document } from "../Documents"; import Provider from "./Provider"; @@ -71,12 +71,43 @@ export default class GotoDefinitionProvider extends Provider { tokensWithRef.push({ owner: localStandardLibDefinitions?.uri, tokens: localStandardLibDefinitions?.complexTokens }); } - loop: for (let i = 0; i < tokensWithRef.length; i++) { - ref = tokensWithRef[i]; + if (this.server.config.definition.preferImplementation) { + // Two-pass: prefer function definitions (with bodies) over forward declarations + let fallbackToken: ComplexToken | undefined; + let fallbackRef: OwnedComplexTokens | undefined; + + loop: for (let i = 0; i < tokensWithRef.length; i++) { + ref = tokensWithRef[i]; + + for (const candidate of ref?.tokens ?? []) { + if (candidate.identifier !== rawContent) continue; + + const funcCandidate = candidate as FunctionComplexToken; + if (funcCandidate.tokenType === CompletionItemKind.Function && funcCandidate.isForwardDeclaration) { + if (!fallbackToken) { + fallbackToken = candidate; + fallbackRef = ref; + } + } else { + token = candidate; + break loop; + } + } + } - token = ref?.tokens.find((candidate) => candidate.identifier === rawContent); - if (token) { - break loop; + if (!token && fallbackToken) { + token = fallbackToken; + ref = fallbackRef; + } + } else { + // Jump to first occurrence found + loop: for (let i = 0; i < tokensWithRef.length; i++) { + ref = tokensWithRef[i]; + + token = ref?.tokens.find((candidate) => candidate.identifier === rawContent); + if (token) { + break loop; + } } } break; diff --git a/server/src/ServerManager/Config.ts b/server/src/ServerManager/Config.ts index d02703e..e2eb4bf 100644 --- a/server/src/ServerManager/Config.ts +++ b/server/src/ServerManager/Config.ts @@ -33,6 +33,9 @@ const defaultServerConfiguration = { nwnHome: "", nwnInstallation: "", }, + definition: { + preferImplementation: true, + }, }; /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/server/src/ServerManager/ServerManager.ts b/server/src/ServerManager/ServerManager.ts index fd229ab..ce733be 100644 --- a/server/src/ServerManager/ServerManager.ts +++ b/server/src/ServerManager/ServerManager.ts @@ -145,11 +145,12 @@ export default class ServerManger { } private async loadConfig() { - const { completion, hovering, formatter, compiler, ...rest } = await this.connection.workspace.getConfiguration("nwscript-ee-lsp"); + const { completion, hovering, formatter, compiler, definition, ...rest } = await this.connection.workspace.getConfiguration("nwscript-ee-lsp"); this.config = { ...this.config, ...rest }; this.config.completion = { ...this.config.completion, ...completion }; this.config.hovering = { ...this.config.hovering, ...hovering }; this.config.formatter = { ...this.config.formatter, ...formatter }; this.config.compiler = { ...this.config.compiler, ...compiler }; + this.config.definition = { ...this.config.definition, ...definition }; } } diff --git a/server/src/Tokenizer/Tokenizer.ts b/server/src/Tokenizer/Tokenizer.ts index 52db3b6..47821ee 100644 --- a/server/src/Tokenizer/Tokenizer.ts +++ b/server/src/Tokenizer/Tokenizer.ts @@ -166,12 +166,11 @@ export default class Tokenizer { return isFunctionDeclaration; } - private isGlobalFunctionDeclaration(lineIndex: number, tokenIndex: number, token: IToken, tokensArrays: (IToken[] | undefined)[]) { + private isGlobalFunctionDeclarationOrDefinition(lineIndex: number, tokenIndex: number, token: IToken, tokensArrays: (IToken[] | undefined)[]) { return ( !(tokenIndex === 0 && lineIndex === 0) && // Not sure why we need this !token.scopes.includes(LanguageScopes.block) && - token.scopes.includes(LanguageScopes.functionIdentifier) && - this.isFunctionDeclaration(lineIndex, tokensArrays) + token.scopes.includes(LanguageScopes.functionIdentifier) ); } @@ -256,7 +255,8 @@ export default class Tokenizer { break; } - if (this.isGlobalFunctionDeclaration(lineIndex, tokenIndex, token, tokensArrays)) { + if (this.isGlobalFunctionDeclarationOrDefinition(lineIndex, tokenIndex, token, tokensArrays)) { + const isForwardDeclaration = this.isFunctionDeclaration(lineIndex, tokensArrays); scope.complexTokens.push({ position: { line: lineIndex, character: token.startIndex }, identifier: this.getRawTokenContent(line, token), @@ -264,6 +264,7 @@ export default class Tokenizer { returnType: tokenIndex === 0 ? this.getTokenLanguageType(lines[lineIndex - 1], tokensArrays[lineIndex - 1]!, 0) : this.getTokenLanguageType(line, tokensArray, tokenIndex - 2), params: this.getFunctionParams(lineIndex, lines, tokensArrays), comments: this.getFunctionComments(lines, tokensArrays, tokenIndex === 0 ? lineIndex - 2 : lineIndex - 1), + isForwardDeclaration, }); break; diff --git a/server/src/Tokenizer/types.ts b/server/src/Tokenizer/types.ts index be51b9d..9a64c28 100644 --- a/server/src/Tokenizer/types.ts +++ b/server/src/Tokenizer/types.ts @@ -18,6 +18,7 @@ type LanguageFunction = { params: FunctionParamComplexToken[]; variables?: VariableComplexToken[]; comments: string[]; + isForwardDeclaration?: boolean; }; type LanguageFunctionParam = { tokenType: typeof CompletionItemKind.TypeParameter; diff --git a/server/test/static/globalScopeTokens.json b/server/test/static/globalScopeTokens.json index bf005da..91fecb5 100644 --- a/server/test/static/globalScopeTokens.json +++ b/server/test/static/globalScopeTokens.json @@ -1,552 +1,846 @@ { "complexTokens": [ - { + { + "position": { + "line": 7, + "character": 13 + }, + "identifier": "NWNX_SkillRanks", + "tokenType": 21, + "valueType": "string", + "value": "\"NWNX_SkillRanks\"" + }, + { + "position": { + "line": 14, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_STRENGTH", + "tokenType": 21, + "valueType": "int", + "value": "1" + }, + { + "position": { + "line": 15, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_DEXTERITY", + "tokenType": 21, + "valueType": "int", + "value": "2" + }, + { + "position": { + "line": 16, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CONSTITUTION", + "tokenType": 21, + "valueType": "int", + "value": "4" + }, + { + "position": { + "line": 17, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_INTELLIGENCE", + "tokenType": 21, + "valueType": "int", + "value": "8" + }, + { + "position": { + "line": 18, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_WISDOM", + "tokenType": 21, + "valueType": "int", + "value": "16" + }, + { + "position": { + "line": 19, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CHARISMA", + "tokenType": 21, + "valueType": "int", + "value": "32" + }, + { + "position": { + "line": 28, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_MIN", + "tokenType": 21, + "valueType": "int", + "value": "64" + }, + { + "position": { + "line": 29, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_MAX", + "tokenType": 21, + "valueType": "int", + "value": "128" + }, + { + "position": { + "line": 30, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_AVERAGE", + "tokenType": 21, + "valueType": "int", + "value": "256" + }, + { + "position": { + "line": 31, + "character": 10 + }, + "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_SUM", + "tokenType": 21, + "valueType": "int", + "value": "512" + }, + { + "position": { + "line": 84, + "character": 4 + }, + "identifier": "NWNX_SkillRanks_GetSkillFeatCountForSkill", + "tokenType": 3, + "returnType": "int", + "params": [ + { "position": { - "line": 7, - "character": 13 + "line": 84, + "character": 50 }, - "identifier": "NWNX_SkillRanks", - "tokenType": 21, - "valueType": "string", - "value": "\"NWNX_SkillRanks\"" + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @param iSkill The skill to check the feat count.", + "/// @return The count of feats for a specific skill." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 90, + "character": 33 }, - { + "identifier": "NWNX_SkillRanks_GetSkillFeat", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { "position": { - "line": 14, - "character": 10 + "line": 91, + "character": 6 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_STRENGTH", - "tokenType": 21, - "valueType": "int", - "value": "1" + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 92, + "character": 6 + }, + "identifier": "iFeat", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Returns a skill feat.", + "/// @param iSkill The skill.", + "/// @param iFeat The feat.", + "/// @return A constructed NWNX_SkillRanks_SkillFeat." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 101, + "character": 0 }, - { + "identifier": "NWNX_SkillRanks_GetSkillFeatForSkillByIndex", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { "position": { - "line": 15, - "character": 10 + "line": 101, + "character": 48 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_DEXTERITY", - "tokenType": 21, - "valueType": "int", - "value": "2" + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 101, + "character": 60 + }, + "identifier": "iIndex", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Returns a skill feat by index.", + "/// @remark Generally used in a loop with NWNX_SkillRanks_GetSkillFeatCountForSkill().", + "/// @param iSkill The skill.", + "/// @param iIndex The index in the list of feats for the skill.", + "/// @return A constructed NWNX_SkillRanks_SkillFeat." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 107, + "character": 0 }, - { + "identifier": "NWNX_SkillRanks_SetSkillFeat", + "tokenType": 3, + "returnType": "void", + "params": [ + { "position": { - "line": 16, - "character": 10 + "line": 108, + "character": 35 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CONSTITUTION", - "tokenType": 21, + "identifier": "skillFeat", + "tokenType": 25, + "valueType": "NWNX_SkillRanks_SkillFeat" + }, + { + "position": { + "line": 109, + "character": 6 + }, + "identifier": "createIfNonExistent", + "tokenType": 25, "valueType": "int", - "value": "4" + "defaultValue": "FALSE" + } + ], + "comments": [ + "/// @brief Modifies or creates a skill feat.", + "/// @param skillFeat The defined NWNX_SkillRanks_SkillFeat.", + "/// @param createIfNonExistent TRUE to create if the feat does not exist." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 119, + "character": 0 }, - { + "identifier": "NWNX_SkillRanks_AddSkillFeatClass", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { "position": { - "line": 17, - "character": 10 + "line": 120, + "character": 35 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_INTELLIGENCE", - "tokenType": 21, - "valueType": "int", - "value": "8" + "identifier": "skillFeat", + "tokenType": 25, + "valueType": "NWNX_SkillRanks_SkillFeat" + }, + { + "position": { + "line": 121, + "character": 6 + }, + "identifier": "iClass", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Add classes to a skill feat instead of working with the NWNX_SkillRanks_SkillFeat::sClasses string.", + "///", + "/// Manipulating the sClasses string in the NWNX_SkillRanks_SkillFeat struct can be difficult. This", + "/// function allows the builder to enter one class at a time.", + "/// @param skillFeat The NWNX_SkillRanks_SkillFeat for which the sClasses field will be modifier.", + "/// @param iClass The class to add to the Skill Feat.", + "/// @return The updated NWNX_SkillRanks_SkillFeat." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 130, + "character": 5 }, - { + "identifier": "NWNX_SkillRanks_SetSkillFeatFocusModifier", + "tokenType": 3, + "returnType": "void", + "params": [ + { + "position": { + "line": 130, + "character": 51 + }, + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + }, + { "position": { - "line": 18, - "character": 10 + "line": 130, + "character": 66 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_WISDOM", - "tokenType": 21, + "identifier": "iEpic", + "tokenType": 25, "valueType": "int", - "value": "16" + "defaultValue": "FALSE" + } + ], + "comments": [ + "/// @brief Change the modifier value for Skill Focus and Epic Skill Focus feats.", + "///", + "/// The stock modifier on Skill Focus and Epic Skill Focus are 3 and 10 respectively, these can be", + "/// changed with this function.", + "/// @param iModifier The new value for the feat modifier.", + "/// @param iEpic Set to TRUE to change the value for Epic Skill Focus." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 134, + "character": 4 + }, + "identifier": "NWNX_SkillRanks_GetBlindnessPenalty", + "tokenType": 3, + "returnType": "int", + "params": [], + "comments": [ + "/// @brief Gets the current penalty to Dexterity based skills when blind.", + "/// @return The penalty to Dexterity when blind." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 139, + "character": 5 }, - { + "identifier": "NWNX_SkillRanks_SetBlindnessPenalty", + "tokenType": 3, + "returnType": "void", + "params": [ + { "position": { - "line": 19, - "character": 10 + "line": 139, + "character": 45 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CHARISMA", - "tokenType": 21, - "valueType": "int", - "value": "32" + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Set the value the Dexterity based skills get decreased due to blindness.", + "/// @remark Default is 4.", + "/// @param iModifier The penalty to Dexterity when blind." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 145, + "character": 4 }, - { + "identifier": "NWNX_SkillRanks_GetAreaModifier", + "tokenType": 3, + "returnType": "int", + "params": [ + { "position": { - "line": 28, - "character": 10 + "line": 145, + "character": 43 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_MIN", - "tokenType": 21, - "valueType": "int", - "value": "64" + "identifier": "oArea", + "tokenType": 25, + "valueType": "object" + }, + { + "position": { + "line": 145, + "character": 54 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Get a skill modifier for an area.", + "/// @param oArea The area.", + "/// @param iSkill The skill to check.", + "/// @return The modifier to that skill in the area." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 151, + "character": 5 }, - { + "identifier": "NWNX_SkillRanks_SetAreaModifier", + "tokenType": 3, + "returnType": "void", + "params": [ + { "position": { - "line": 29, - "character": 10 + "line": 151, + "character": 44 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_MAX", - "tokenType": 21, - "valueType": "int", - "value": "128" + "identifier": "oArea", + "tokenType": 25, + "valueType": "object" + }, + { + "position": { + "line": 151, + "character": 55 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 151, + "character": 67 + }, + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [ + "/// @brief Sets a skill modifier for the area.", + "/// @param oArea The area.", + "/// @param iSkill The skill to change.", + "/// @param iModifier The modifier to the skill in the area." + ], + "isForwardDeclaration": true + }, + { + "position": { + "line": 155, + "character": 4 + }, + "identifier": "NWNX_SkillRanks_GetSkillFeatCountForSkill", + "tokenType": 3, + "returnType": "int", + "params": [ + { + "position": { + "line": 155, + "character": 50 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 165, + "character": 33 + }, + "identifier": "NWNX_SkillRanks_GetSkillFeatForSkillByIndex", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { + "position": { + "line": 165, + "character": 81 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 165, + "character": 93 + }, + "identifier": "iIndex", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 190, + "character": 5 }, - { + "identifier": "NWNX_SkillRanks_SetSkillFeat", + "tokenType": 3, + "returnType": "void", + "params": [ + { + "position": { + "line": 190, + "character": 67 + }, + "identifier": "skillFeat", + "tokenType": 25, + "valueType": "NWNX_SkillRanks_SkillFeat" + }, + { "position": { - "line": 30, - "character": 10 + "line": 190, + "character": 82 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_AVERAGE", - "tokenType": 21, + "identifier": "createIfNonExistent", + "tokenType": 25, "valueType": "int", - "value": "256" + "defaultValue": "FALSE" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 210, + "character": 33 + }, + "identifier": "NWNX_SkillRanks_AddSkillFeatClass", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { + "position": { + "line": 210, + "character": 100 + }, + "identifier": "skillFeat", + "tokenType": 25, + "valueType": "NWNX_SkillRanks_SkillFeat" + }, + { + "position": { + "line": 210, + "character": 115 + }, + "identifier": "iClass", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 223, + "character": 5 }, - { + "identifier": "NWNX_SkillRanks_SetSkillFeatFocusModifier", + "tokenType": 3, + "returnType": "void", + "params": [ + { + "position": { + "line": 223, + "character": 51 + }, + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + }, + { "position": { - "line": 31, - "character": 10 + "line": 223, + "character": 66 }, - "identifier": "NWNX_SKILLRANKS_KEY_ABILITY_CALC_SUM", - "tokenType": 21, + "identifier": "epicFocus", + "tokenType": 25, "valueType": "int", - "value": "512" - }, - { - "position": { - "line": 84, - "character": 4 - }, - "identifier": "NWNX_SkillRanks_GetSkillFeatCountForSkill", - "tokenType": 3, - "returnType": "int", - "params": [ - { - "position": { - "line": 84, - "character": 50 - }, - "identifier": "iSkill", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @param iSkill The skill to check the feat count.", - "/// @return The count of feats for a specific skill." - ] - }, - { - "position": { - "line": 90, - "character": 33 - }, - "identifier": "NWNX_SkillRanks_GetSkillFeat", - "tokenType": 3, - "returnType": "NWNX_SkillRanks_SkillFeat", - "params": [ - { - "position": { - "line": 91, - "character": 6 - }, - "identifier": "iSkill", - "tokenType": 25, - "valueType": "int" - }, - { - "position": { - "line": 92, - "character": 6 - }, - "identifier": "iFeat", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Returns a skill feat.", - "/// @param iSkill The skill.", - "/// @param iFeat The feat.", - "/// @return A constructed NWNX_SkillRanks_SkillFeat." - ] - }, - { - "position": { - "line": 101, - "character": 0 - }, - "identifier": "NWNX_SkillRanks_GetSkillFeatForSkillByIndex", - "tokenType": 3, - "returnType": "NWNX_SkillRanks_SkillFeat", - "params": [ - { - "position": { - "line": 101, - "character": 48 - }, - "identifier": "iSkill", - "tokenType": 25, - "valueType": "int" - }, - { - "position": { - "line": 101, - "character": 60 - }, - "identifier": "iIndex", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Returns a skill feat by index.", - "/// @remark Generally used in a loop with NWNX_SkillRanks_GetSkillFeatCountForSkill().", - "/// @param iSkill The skill.", - "/// @param iIndex The index in the list of feats for the skill.", - "/// @return A constructed NWNX_SkillRanks_SkillFeat." - ] - }, - { - "position": { - "line": 107, - "character": 0 - }, - "identifier": "NWNX_SkillRanks_SetSkillFeat", - "tokenType": 3, - "returnType": "void", - "params": [ - { - "position": { - "line": 108, - "character": 35 - }, - "identifier": "skillFeat", - "tokenType": 25, - "valueType": "NWNX_SkillRanks_SkillFeat" - }, - { - "position": { - "line": 109, - "character": 6 - }, - "identifier": "createIfNonExistent", - "tokenType": 25, - "valueType": "int", - "defaultValue": "FALSE" - } - ], - "comments": [ - "/// @brief Modifies or creates a skill feat.", - "/// @param skillFeat The defined NWNX_SkillRanks_SkillFeat.", - "/// @param createIfNonExistent TRUE to create if the feat does not exist." - ] - }, - { - "position": { - "line": 119, - "character": 0 - }, - "identifier": "NWNX_SkillRanks_AddSkillFeatClass", - "tokenType": 3, - "returnType": "NWNX_SkillRanks_SkillFeat", - "params": [ - { - "position": { - "line": 120, - "character": 35 - }, - "identifier": "skillFeat", - "tokenType": 25, - "valueType": "NWNX_SkillRanks_SkillFeat" - }, - { - "position": { - "line": 121, - "character": 6 - }, - "identifier": "iClass", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Add classes to a skill feat instead of working with the NWNX_SkillRanks_SkillFeat::sClasses string.", - "///", - "/// Manipulating the sClasses string in the NWNX_SkillRanks_SkillFeat struct can be difficult. This", - "/// function allows the builder to enter one class at a time.", - "/// @param skillFeat The NWNX_SkillRanks_SkillFeat for which the sClasses field will be modifier.", - "/// @param iClass The class to add to the Skill Feat.", - "/// @return The updated NWNX_SkillRanks_SkillFeat." - ] - }, - { - "position": { - "line": 130, - "character": 5 - }, - "identifier": "NWNX_SkillRanks_SetSkillFeatFocusModifier", - "tokenType": 3, - "returnType": "void", - "params": [ - { - "position": { - "line": 130, - "character": 51 - }, - "identifier": "iModifier", - "tokenType": 25, - "valueType": "int" - }, - { - "position": { - "line": 130, - "character": 66 - }, - "identifier": "iEpic", - "tokenType": 25, - "valueType": "int", - "defaultValue": "FALSE" - } - ], - "comments": [ - "/// @brief Change the modifier value for Skill Focus and Epic Skill Focus feats.", - "///", - "/// The stock modifier on Skill Focus and Epic Skill Focus are 3 and 10 respectively, these can be", - "/// changed with this function.", - "/// @param iModifier The new value for the feat modifier.", - "/// @param iEpic Set to TRUE to change the value for Epic Skill Focus." - ] - }, - { - "position": { - "line": 134, - "character": 4 - }, - "identifier": "NWNX_SkillRanks_GetBlindnessPenalty", - "tokenType": 3, - "returnType": "int", - "params": [], - "comments": [ - "/// @brief Gets the current penalty to Dexterity based skills when blind.", - "/// @return The penalty to Dexterity when blind." - ] - }, - { - "position": { - "line": 139, - "character": 5 - }, - "identifier": "NWNX_SkillRanks_SetBlindnessPenalty", - "tokenType": 3, - "returnType": "void", - "params": [ - { - "position": { - "line": 139, - "character": 45 - }, - "identifier": "iModifier", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Set the value the Dexterity based skills get decreased due to blindness.", - "/// @remark Default is 4.", - "/// @param iModifier The penalty to Dexterity when blind." - ] - }, - { - "position": { - "line": 145, - "character": 4 - }, - "identifier": "NWNX_SkillRanks_GetAreaModifier", - "tokenType": 3, - "returnType": "int", - "params": [ - { - "position": { - "line": 145, - "character": 43 - }, - "identifier": "oArea", - "tokenType": 25, - "valueType": "object" - }, - { - "position": { - "line": 145, - "character": 54 - }, - "identifier": "iSkill", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Get a skill modifier for an area.", - "/// @param oArea The area.", - "/// @param iSkill The skill to check.", - "/// @return The modifier to that skill in the area." - ] - }, - { - "position": { - "line": 151, - "character": 5 - }, - "identifier": "NWNX_SkillRanks_SetAreaModifier", - "tokenType": 3, - "returnType": "void", - "params": [ - { - "position": { - "line": 151, - "character": 44 - }, - "identifier": "oArea", - "tokenType": 25, - "valueType": "object" - }, - { - "position": { - "line": 151, - "character": 55 - }, - "identifier": "iSkill", - "tokenType": 25, - "valueType": "int" - }, - { - "position": { - "line": 151, - "character": 67 - }, - "identifier": "iModifier", - "tokenType": 25, - "valueType": "int" - } - ], - "comments": [ - "/// @brief Sets a skill modifier for the area.", - "/// @param oArea The area.", - "/// @param iSkill The skill to change.", - "/// @param iModifier The modifier to the skill in the area." - ] - } + "defaultValue": "FALSE" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 232, + "character": 4 + }, + "identifier": "NWNX_SkillRanks_GetBlindnessPenalty", + "tokenType": 3, + "returnType": "int", + "params": [], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 241, + "character": 5 + }, + "identifier": "NWNX_SkillRanks_SetBlindnessPenalty", + "tokenType": 3, + "returnType": "void", + "params": [ + { + "position": { + "line": 241, + "character": 45 + }, + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 249, + "character": 4 + }, + "identifier": "NWNX_SkillRanks_GetAreaModifier", + "tokenType": 3, + "returnType": "int", + "params": [ + { + "position": { + "line": 249, + "character": 43 + }, + "identifier": "oArea", + "tokenType": 25, + "valueType": "object" + }, + { + "position": { + "line": 249, + "character": 54 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 260, + "character": 5 + }, + "identifier": "NWNX_SkillRanks_SetAreaModifier", + "tokenType": 3, + "returnType": "void", + "params": [ + { + "position": { + "line": 260, + "character": 44 + }, + "identifier": "oArea", + "tokenType": 25, + "valueType": "object" + }, + { + "position": { + "line": 260, + "character": 55 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 260, + "character": 67 + }, + "identifier": "iModifier", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + }, + { + "position": { + "line": 270, + "character": 33 + }, + "identifier": "NWNX_SkillRanks_GetSkillFeat", + "tokenType": 3, + "returnType": "NWNX_SkillRanks_SkillFeat", + "params": [ + { + "position": { + "line": 270, + "character": 66 + }, + "identifier": "iSkill", + "tokenType": 25, + "valueType": "int" + }, + { + "position": { + "line": 270, + "character": 78 + }, + "identifier": "iFeat", + "tokenType": 25, + "valueType": "int" + } + ], + "comments": [], + "isForwardDeclaration": false + } ], "structComplexTokens": [ - { - "position": { - "line": 35, - "character": 7 - }, - "identifier": "NWNX_SkillRanks_SkillFeat", - "tokenType": 22, - "properties": [ - { - "position": { - "line": 37, - "character": 8 - }, - "identifier": "iSkill", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 38, - "character": 8 - }, - "identifier": "iFeat", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 41, - "character": 8 - }, - "identifier": "iModifier", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 45, - "character": 8 - }, - "identifier": "iFocusFeat", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 55, - "character": 11 - }, - "identifier": "sClasses", - "tokenType": 10, - "valueType": "string" - }, - { - "position": { - "line": 59, - "character": 10 - }, - "identifier": "fClassLevelMod", - "tokenType": 10, - "valueType": "float" - }, - { - "position": { - "line": 62, - "character": 8 - }, - "identifier": "iAreaFlagsRequired", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 65, - "character": 8 - }, - "identifier": "iAreaFlagsForbidden", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 69, - "character": 8 - }, - "identifier": "iDayOrNight", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 72, - "character": 8 - }, - "identifier": "bBypassArmorCheckPenalty", - "tokenType": 10, - "valueType": "int" - }, - { - "position": { - "line": 79, - "character": 8 - }, - "identifier": "iKeyAbilityMask", - "tokenType": 10, - "valueType": "int" - } - ] - } + { + "position": { + "line": 35, + "character": 7 + }, + "identifier": "NWNX_SkillRanks_SkillFeat", + "tokenType": 22, + "properties": [ + { + "position": { + "line": 37, + "character": 8 + }, + "identifier": "iSkill", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 38, + "character": 8 + }, + "identifier": "iFeat", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 41, + "character": 8 + }, + "identifier": "iModifier", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 45, + "character": 8 + }, + "identifier": "iFocusFeat", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 55, + "character": 11 + }, + "identifier": "sClasses", + "tokenType": 10, + "valueType": "string" + }, + { + "position": { + "line": 59, + "character": 10 + }, + "identifier": "fClassLevelMod", + "tokenType": 10, + "valueType": "float" + }, + { + "position": { + "line": 62, + "character": 8 + }, + "identifier": "iAreaFlagsRequired", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 65, + "character": 8 + }, + "identifier": "iAreaFlagsForbidden", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 69, + "character": 8 + }, + "identifier": "iDayOrNight", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 72, + "character": 8 + }, + "identifier": "bBypassArmorCheckPenalty", + "tokenType": 10, + "valueType": "int" + }, + { + "position": { + "line": 79, + "character": 8 + }, + "identifier": "iKeyAbilityMask", + "tokenType": 10, + "valueType": "int" + } + ] + } ], "children": [ - "nwnx" + "nwnx" ] } \ No newline at end of file