diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a25c98a42..14a87231b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1721,6 +1721,25 @@ void FBehavior::SetArrayVal (int arraynum, int index, int value) array->Elements[index] = value; } +inline bool FBehavior::CopyStringToArray(int arraynum, int index, int maxLength, const char *string) +{ + // false if the operation was incomplete or unsuccessful + + if ((unsigned)arraynum >= (unsigned)NumTotalArrays || index < 0) + return false; + const ArrayInfo *array = Arrays[arraynum]; + + if ((signed)array->ArraySize - index < maxLength) maxLength = (signed)array->ArraySize - index; + + while (maxLength-- > 0) + { + array->Elements[index++] = *string; + if (!(*string)) return true; // written terminating 0 + string++; + } + return !(*string); // return true if only terminating 0 was not written +} + BYTE *FBehavior::FindChunk (DWORD id) const { BYTE *chunk = Chunks; @@ -5112,43 +5131,101 @@ int DLevelScript::RunScript () // [JB] Print map character array case PCD_PRINTMAPCHARARRAY: + case PCD_PRINTMAPCHRANGE: { + int capacity, offset; + + if (pcd == PCD_PRINTMAPCHRANGE) + { + capacity = STACK(1); + offset = STACK(2); + if (capacity < 1 || offset < 0) + { + sp -= 4; + break; + } + sp -= 2; + } + else + { + capacity = 0x7FFFFFFF; + offset = 0; + } + int a = *(activeBehavior->MapVars[STACK(1)]); - int offset = STACK(2); + offset += STACK(2); int c; - while((c = activeBehavior->GetArrayVal (a, offset)) != '\0') { + while(capacity-- && (c = activeBehavior->GetArrayVal (a, offset)) != '\0') { work += (char)c; offset++; } - sp-=2; + sp-= 2; } break; // [JB] Print world character array case PCD_PRINTWORLDCHARARRAY: + case PCD_PRINTWORLDCHRANGE: { + int capacity, offset; + if (pcd == PCD_PRINTWORLDCHRANGE) + { + capacity = STACK(1); + offset = STACK(2); + if (capacity < 1 || offset < 0) + { + sp -= 4; + break; + } + sp -= 2; + } + else + { + capacity = 0x7FFFFFFF; + offset = 0; + } + int a = STACK(1); - int offset = STACK(2); + offset += STACK(2); int c; - while((c = ACS_WorldArrays[a][offset]) != '\0') { + while(capacity-- && (c = ACS_WorldArrays[a][offset]) != '\0') { work += (char)c; offset++; } - sp-=2; + sp-= 2; } break; // [JB] Print global character array case PCD_PRINTGLOBALCHARARRAY: + case PCD_PRINTGLOBALCHRANGE: { + int capacity, offset; + if (pcd == PCD_PRINTGLOBALCHRANGE) + { + capacity = STACK(1); + offset = STACK(2); + if (capacity < 1 || offset < 0) + { + sp -= 4; + break; + } + sp -= 2; + } + else + { + capacity = 0x7FFFFFFF; + offset = 0; + } + int a = STACK(1); - int offset = STACK(2); + offset += STACK(2); int c; - while((c = ACS_GlobalArrays[a][offset]) != '\0') { + while(capacity-- && (c = ACS_GlobalArrays[a][offset]) != '\0') { work += (char)c; offset++; } - sp-=2; + sp-= 2; } break; @@ -6731,6 +6808,84 @@ int DLevelScript::RunScript () } break; + case PCD_STRCPYTOMAPCHRANGE: + case PCD_STRCPYTOWORLDCHRANGE: + case PCD_STRCPYTOGLOBALCHRANGE: + // source: stringid(2); stringoffset(1) + // destination: capacity (3); stringoffset(4); arrayid (5); offset(6) + + { + int index = STACK(4); + int capacity = STACK(3); + + if (index < 0 || STACK(1) < 0) + { + // no writable destination, or negative offset to source string + sp -= 5; + Stack[sp-1] = 0; // false + break; + } + + index += STACK(6); + + lookup = FBehavior::StaticLookupString (STACK(2)); + + if (!lookup) { + // no data, operation complete + STRCPYTORANGECOMPLETE: + sp -= 5; + Stack[sp-1] = 1; // true + break; + } + + for (int i = 0;i < STACK(1); i++) + { + if (! (*(lookup++))) + { + // no data, operation complete + goto STRCPYTORANGECOMPLETE; + } + } + + switch (pcd) + { + case PCD_STRCPYTOMAPCHRANGE: + { + Stack[sp-6] = activeBehavior->CopyStringToArray(STACK(5), index, capacity, lookup); + } + break; + case PCD_STRCPYTOWORLDCHRANGE: + { + int a = STACK(5); + + while (capacity-- > 0) + { + ACS_WorldArrays[a][index++] = *lookup; + if (! (*(lookup++))) goto STRCPYTORANGECOMPLETE; // complete with terminating 0 + } + + Stack[sp-6] = !(*lookup); // true/success if only terminating 0 was not copied + } + break; + case PCD_STRCPYTOGLOBALCHRANGE: + { + int a = STACK(5); + + while (capacity-- > 0) + { + ACS_GlobalArrays[a][index++] = *lookup; + if (! (*(lookup++))) goto STRCPYTORANGECOMPLETE; // complete with terminating 0 + } + + Stack[sp-6] = !(*lookup); // true/success if only terminating 0 was not copied + } + break; + + } + sp -= 5; + } + break; + } } diff --git a/src/p_acs.h b/src/p_acs.h index 89a5c0b1f..d1c49c8f0 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -168,6 +168,8 @@ public: ScriptFunction *GetFunction (int funcnum, FBehavior *&module) const; int GetArrayVal (int arraynum, int index) const; void SetArrayVal (int arraynum, int index, int value); + inline bool CopyStringToArray(int arraynum, int index, int maxLength, const char * string); + int FindFunctionName (const char *funcname) const; int FindMapVarName (const char *varname) const; int FindMapArray (const char *arrayname) const; @@ -587,9 +589,15 @@ public: PCD_PRINTBINARY, /*350*/ PCD_PRINTHEX, PCD_CALLFUNC, - PCD_SAVESTRING, // [FDARI] + PCD_SAVESTRING, // [FDARI] create string (temporary) + PCD_PRINTMAPCHRANGE, // [FDARI] output range (print part of array) + PCD_PRINTWORLDCHRANGE, + PCD_PRINTGLOBALCHRANGE, + PCD_STRCPYTOMAPCHRANGE, // [FDARI] input range (copy string to all/part of array) + PCD_STRCPYTOWORLDCHRANGE, + PCD_STRCPYTOGLOBALCHRANGE, -/*353*/ PCODE_COMMAND_COUNT +/*359*/ PCODE_COMMAND_COUNT }; // Some constants used by ACS scripts