xoreos  0.0.5
ncsfile.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on the NCS specs by Torlack.
26  *
27  * Torlack's own site is down, but our docs repository hosts a
28  * a mirror (<https://github.com/xoreos/xoreos-docs>).
29  */
30 
31 #include <boost/make_shared.hpp>
32 
33 #include "src/common/util.h"
34 #include "src/common/error.h"
35 #include "src/common/maths.h"
36 #include "src/common/ustring.h"
37 #include "src/common/readstream.h"
38 #include "src/common/encoding.h"
39 #include "src/common/debug.h"
40 
41 #include "src/aurora/resman.h"
42 
46 
48 
49 static const uint32 kNCSTag = MKTAG('N', 'C', 'S', ' ');
50 static const uint32 kVersion10 = MKTAG('V', '1', '.', '0');
51 
52 static const uint32 kScriptObjectSelf = 0x00000000;
53 static const uint32 kScriptObjectInvalid = 0x00000001;
54 static const uint32 kScriptObjectInvalid2 = 0xFFFFFFFF;
55 static const uint32 kScriptObjectTypeInvalid = 0x7F000000;
56 
57 namespace Aurora {
58 
59 namespace NWScript {
60 
62  reset();
63 }
64 
66 }
67 
69  clear();
70 
71  _stackPtr = -1;
72  _basePtr = -1;
73 }
74 
75 bool NCSStack::empty() const {
76  return _stackPtr < 0;
77 }
78 
80  if (_stackPtr == -1)
81  throw Common::Exception("NCSStack: Stack underflow");
82 
83  return at(_stackPtr);
84 }
85 
87  if (_stackPtr == -1)
88  throw Common::Exception("NCSStack: Stack underflow");
89 
90  return at(_stackPtr--);
91 }
92 
93 void NCSStack::push(const Variable &obj) {
94  if (_stackPtr == 0x7FFFFFFF) // Like this will ever happen :P
95  throw Common::Exception("NCSStack: Stack overflow");
96 
97  if (_stackPtr == (int32)size() - 1)
98  push_back(obj);
99  else
100  at(_stackPtr + 1) = obj;
101 
102  _stackPtr++;
103 }
104 
106  if ((pos > -4) || ((pos % 4) != 0))
107  throw Common::Exception("NCSStack::get(): Illegal position %d", pos);
108 
109  int32 stackPos = _stackPtr - ((pos / -4) - 1);
110  if (stackPos < 0)
111  throw Common::Exception("NCSStack::get(): Position %d below the bottom", pos);
112 
113  return at(stackPos);
114 }
115 
116 void NCSStack::setRelSP(int32 pos, const Variable &obj) {
117  if ((pos > -4) || ((pos % 4) != 0))
118  throw Common::Exception("NCSStack::set(): Illegal position %d", pos);
119 
120  int32 stackPos = _stackPtr - ((pos / -4) - 1);
121  if (stackPos < 0)
122  throw Common::Exception("NCSStack::set(): Position %d below the bottom", pos);
123 
124  at(stackPos) = obj;
125 }
126 
128  if ((pos > -4) || ((pos % 4) != 0))
129  throw Common::Exception("NCSStack::get(): Illegal position %d", pos);
130 
131  int32 stackPos = _basePtr - ((pos / -4) - 1);
132  if (stackPos < 0)
133  throw Common::Exception("NCSStack::get(): Position %d below the bottom", pos);
134 
135  return at(stackPos);
136 }
137 
138 void NCSStack::setRelBP(int32 pos, const Variable &obj) {
139  if ((pos > -4) || ((pos % 4) != 0))
140  throw Common::Exception("NCSStack::set(): Illegal position %d", pos);
141 
142  int32 stackPos = _basePtr - ((pos / -4) - 1);
143  if (stackPos < 0)
144  throw Common::Exception("NCSStack::set(): Position %d below the bottom", pos);
145 
146  at(stackPos) = obj;
147 }
148 
150  return (_stackPtr + 1) * -4;
151 }
152 
154  if ((pos > 0) || ((pos % 4) != 0))
155  throw Common::Exception("NCSStack::setStackPtr(): Illegal position %d", pos);
156 
157  _stackPtr = (pos / -4) - 1;
158 
159  if ((int32)size() < (_stackPtr + 1))
160  resize(_stackPtr + 1);
161 }
162 
164  return (_basePtr + 1) * -4;
165 }
166 
168  if ((pos > 0) || ((pos % 4) != 0))
169  throw Common::Exception("NCSStack::setBasePtr(): Illegal position %d", pos);
170 
171  _basePtr = (pos / -4) - 1;
172 }
173 
174 void NCSStack::print() const {
175  if (!DebugMan.isEnabled(kDebugScripts, 3))
176  return;
177 
178  debugC(kDebugScripts, 3, ".--- %d ---.", _stackPtr);
179  for (int32 i = _stackPtr; i >= 0; i--) {
180  const Variable &var = at(i);
181 
182  Common::UString str;
183  formatVariable(str, var);
184 
185  debugC(kDebugScripts, 3, "| %04d: %02d - %s", i, var.getType(), str.c_str());
186  }
187  debugC(kDebugScripts, 3, "'--- ---'");
188 }
189 
190 
191 #define OPCODE(x) { &NCSFile::x, #x }
192 #define OPCODE0() { 0, "" }
193 
195  static const Opcode opcodes[] = {
196  // 0x00
197  OPCODE(o_nop), // Doesn't exist
199  OPCODE(o_rsadd),
200  OPCODE(o_cptopsp),
201  // 0x04
202  OPCODE(o_const),
203  OPCODE(o_action),
204  OPCODE(o_logand),
205  OPCODE(o_logor),
206  // 0x08
207  OPCODE(o_incor),
208  OPCODE(o_excor),
209  OPCODE(o_booland),
210  OPCODE(o_eq),
211  // 0x0C
212  OPCODE(o_neq),
213  OPCODE(o_geq),
214  OPCODE(o_gt),
215  OPCODE(o_lt),
216  // 0x10
217  OPCODE(o_leq),
218  OPCODE(o_shleft),
219  OPCODE(o_shright),
221  // 0x14
222  OPCODE(o_add),
223  OPCODE(o_sub),
224  OPCODE(o_mul),
225  OPCODE(o_div),
226  // 0x18
227  OPCODE(o_mod),
228  OPCODE(o_neg),
229  OPCODE(o_comp),
230  OPCODE(o_movsp),
231  // 0x1C
233  OPCODE(o_jmp),
234  OPCODE(o_jsr),
235  OPCODE(o_jz),
236  // 0x20
237  OPCODE(o_retn),
239  OPCODE(o_not),
240  OPCODE(o_decsp),
241  // 0x24
242  OPCODE(o_incsp),
243  OPCODE(o_jnz),
245  OPCODE(o_cptopbp),
246  // 0x28
247  OPCODE(o_decbp),
248  OPCODE(o_incbp),
249  OPCODE(o_savebp),
251  // 0x2C
253  OPCODE(o_nop),
254  OPCODE0(),
255  OPCODE0(),
256  // 0x30
258  OPCODE0(),
260  OPCODE0(),
261  // 0x34
262  OPCODE0(),
263  OPCODE0(),
264  OPCODE0(),
265  OPCODE(o_getref),
266  // 0x38
267  OPCODE0(),
269  };
270 
271  _opcodes = opcodes;
272  _opcodeListSize = ARRAYSIZE(opcodes);
273 }
274 
275 #undef OPCODE
276 
278  assert(_script);
279 
280  load();
281 }
282 
283 NCSFile::NCSFile(const Common::UString &ncs) : _name(ncs) {
284  _script.reset(ResMan.getResource(ncs, kFileTypeNCS));
285  if (!_script)
286  throw Common::Exception("No such NCS \"%s\"", ncs.c_str());
287 
288  load();
289 }
290 
292 }
293 
295  return _name;
296 }
297 
299  return _env;
300 }
301 
303  _env = env;
304 }
305 
307  ScriptState state;
308 
309  state.offset = 13; // 8 byte header + 5 byte program size dummy op
310 
311  return state;
312 }
313 
316 
317  if (_id != kNCSTag)
318  throw Common::Exception("Try to load non-NCS file");
319 
320  if (_version != kVersion10)
321  throw Common::Exception("Unsupported NCS file version %08X", _version);
322 
323  byte lengthOpcode = _script->readByte();
324  if (lengthOpcode != 0x42)
325  throw Common::Exception("Script size opcode != 0x42 (0x%02X)", lengthOpcode);
326 
327  uint32 length = _script->readUint32BE();
328  if (length > ((uint32) _script->size()))
329  throw Common::Exception("Script size %u > stream size %u", length, (uint)_script->size());
330  if (length < ((uint32) _script->size()))
331  warning("TODO: NCSFile::load(): Script size %u < stream size %u", length, (uint)_script->size());
332 
333  setupOpcodes();
334 
335  reset();
336 }
337 
339  _stack.reset();
340 
341  while (!_returnOffsets.empty())
342  _returnOffsets.pop();
343 
346 
347  _script->seek(13); // 8 byte header + 5 byte program size dummy op
348 }
349 
350 const Variable &NCSFile::run(Object *owner, Object *triggerer) {
351  return run(getEmptyState(), ObjectReference(owner), ObjectReference(triggerer));
352 }
353 
354 const Variable &NCSFile::run(const ObjectReference owner, const ObjectReference triggerer) {
355  return run(getEmptyState(), ObjectReference(owner), ObjectReference(triggerer));
356 }
357 
358 const Variable &NCSFile::run(const ScriptState &state, Object *owner, Object *triggerer) {
359  return run(state, ObjectReference(owner), ObjectReference(triggerer));
360 }
361 
362 const Variable &NCSFile::run(const ScriptState &state, const ObjectReference owner, const ObjectReference triggerer) {
363  debugC(kDebugScripts, 1, "=== Running script \"%s\" (%d) ===",
364  _name.c_str(), state.offset);
365 
366  reset();
367 
368  _script->seek(state.offset);
369 
370  // Push global variables
371  std::vector<class Variable>::const_reverse_iterator var;
372  for (var = state.globals.rbegin(); var != state.globals.rend(); ++var)
373  _stack.push(*var);
374 
376 
377  // Push local variables
378  for (var = state.locals.rbegin(); var != state.locals.rend(); ++var)
379  _stack.push(*var);
380 
381  return execute(owner, triggerer);
382 }
383 
384 const Variable &NCSFile::execute(const ObjectReference owner, const ObjectReference triggerer) {
385  _owner = owner;
386  _triggerer = triggerer;
387 
388  while (executeStep())
389  ;
390 
391  if (!_stack.empty())
392  _return = _stack.top();
393 
394  if (!_stack.empty() && (_stack.top().getType() == kTypeInt))
395  debugC(kDebugScripts, 1, "=> Script\"%s\" returns: %d",
396  _name.c_str(), _stack.top().getInt());
397 
398  _owner = 0;
399  _triggerer = 0;
400 
401  return _return;
402 }
403 
405  byte opcode, type;
406 
407  try {
408  opcode = _script->readByte();
409  type = _script->readByte();
410  } catch (...) {
411  return false;
412  }
413 
414  if ((opcode >= _opcodeListSize) || (!_opcodes[opcode].proc))
415  throw Common::Exception("NCSFile::executeStep(): Illegal instruction 0x%02x", opcode);
416 
417  debugC(kDebugScripts, 1, "NWScript opcode %s [0x%02X]", _opcodes[opcode].desc, opcode);
418 
419  (this->*(_opcodes[opcode].proc))((InstructionType)type);
420 
421  _stack.print();
422  debugC(kDebugScripts, 2, "[RETURN: %d]",
423  _returnOffsets.empty() ? -1 : _returnOffsets.top());
424 
425  return true;
426 }
427 
429  uint32 oldScriptPos = _script->pos();
430  _script->seek(13); // 8 byte header + 5 byte program size dummy op
431 
432  // TODO
433 
434  _script->seek(oldScriptPos);
435 }
436 
437 // OPCODES!
438 
441  switch (type) {
442  case kInstTypeInt:
444  break;
445  case kInstTypeFloat:
447  break;
448  case kInstTypeString:
449  case kInstTypeResource:
451  break;
452  case kInstTypeObject:
454  break;
462  break;
463  case kInstTypeIntArray:
464  case kInstTypeFloatArray:
475  break;
476  default:
477  throw Common::Exception("NCSFile::o_rsadd(): Illegal type %d", type);
478  }
479 }
480 
483  switch (type) {
484  case kInstTypeInt:
485  _stack.push(_script->readSint32BE());
486  break;
487 
488  case kInstTypeFloat:
489  _stack.push(_script->readIEEEFloatBE());
490  break;
491 
492  case kInstTypeString:
493  case kInstTypeResource: {
495  break;
496  }
497 
498  case kInstTypeObject: {
499  /* The scripts only know of two constant objects:
500  * - OBJECT_SELF, the owner object of the script
501  * - OBJECT_INVALID, an invalid object
502  *
503  * In the bytecode, the latter can be initialized by a few different
504  * magic values. They *should* all have the same effect, though.
505  */
506 
507  uint32 objectID = _script->readUint32BE();
508 
509  if (objectID == kScriptObjectSelf)
510  _stack.push(_owner);
511  else if (objectID == kScriptObjectInvalid)
512  _stack.push((Object *) 0);
513  else if (objectID == kScriptObjectInvalid2)
514  _stack.push((Object *) 0);
515  else if (objectID == kScriptObjectTypeInvalid)
516  _stack.push((Object *) 0);
517  else
518  throw Common::Exception("NCSFile::o_const(): Illegal object ID %d", objectID);
519 
520  break;
521  }
522 
523  default:
524  throw Common::Exception("NCSFile::o_const(): Illegal type %d", type);
525  }
526 }
527 
530  uint32 function, uint8 argCount) {
531 
532  if ((argCount < ctx.getParamMin()) || (argCount > ctx.getParamMax()))
533  throw Common::Exception("NCSFile::callEngine(): Argument count mismatch (%u vs %u - %u)",
534  argCount, (uint)ctx.getParamMin(), (uint)ctx.getParamMax());
535 
536  ctx.setCurrentScript(this);
537  ctx.setCaller(_owner);
539 
540  // Pop parameters
541  ctx.setParamsSpecified(argCount);
542  for (uint8 i = 0; i < argCount; i++) {
543  Variable &param = ctx.getParams()[i];
544 
545  Type type = param.getType();
546  if (type == kTypeAny)
547  type = _stack.top().getType();
548 
549  switch (type) {
550  case kTypeInt:
551  case kTypeFloat:
552  case kTypeString:
553  case kTypeObject:
554  case kTypeEngineType:
555  case kTypeReference:
556  case kTypeArray:
557  param = _stack.pop();
558  break;
559 
560  case kTypeVector: {
561  // A vector is held as three floats on the stack
562 
563  float z = _stack.pop().getFloat();
564  float y = _stack.pop().getFloat();
565  float x = _stack.pop().getFloat();
566 
567  param.setVector(x, y, z);
568  break;
569  }
570 
571  case kTypeScriptState:
572  // The script state, "action" type, isn't stored on the stack at all
573 
576  break;
577 
578  default:
579  throw Common::Exception("NCSFile::callEngine(): Invalid argument type %d",
580  param.getType());
581  break;
582  }
583 
584  }
585 
586  // Call the engine function
587  debugC(kDebugScripts, 1, "NWScript engine function %s (%d)", ctx.getName().c_str(), function);
588  FunctionMan.call(function, ctx);
589 
590  // Push return values
591  Variable &retVal = ctx.getReturn();
592  switch (retVal.getType()) {
593  case kTypeVoid:
594  break;
595 
596  case kTypeInt:
597  case kTypeFloat:
598  case kTypeString:
599  case kTypeObject:
600  case kTypeEngineType:
601  case kTypeArray:
602  _stack.push(retVal);
603  break;
604 
605  case kTypeVector: {
606  // A vector is held as three floats on the stack
607 
608  float x, y, z;
609  retVal.getVector(x, y, z);
610 
611  _stack.push(x);
612  _stack.push(y);
613  _stack.push(z);
614  break;
615  }
616 
617  default:
618  throw Common::Exception("NCSFile::callEngine(): Invalid return type %d",
619  retVal.getType());
620  break;
621  }
622 }
623 
626  if (type != kInstTypeNone)
627  throw Common::Exception("NCSFile::o_action(): Illegal type %d", type);
628 
629  uint16 routineNumber = _script->readUint16BE();
630  uint8 argCount = _script->readByte();
631 
632  Aurora::NWScript::FunctionContext ctx = FunctionMan.createContext(routineNumber);
633 
634  try {
635  callEngine(ctx, routineNumber, argCount);
636  } catch (Common::Exception &e) {
637  e.add("Failed running engine function \"%s\" (%d)",
638  ctx.getName().c_str(), routineNumber);
639  throw;
640  }
641 }
642 
645  if (type != kInstTypeIntInt)
646  throw Common::Exception("NCSFile::o_logand(): Illegal type %d", type);
647 
648  int32 arg1 = _stack.pop().getInt();
649  int32 arg2 = _stack.pop().getInt();
650  _stack.push(arg1 && arg2);
651 }
652 
655  if (type != kInstTypeIntInt)
656  throw Common::Exception("NCSFile::o_logor(): Illegal type %d", type);
657 
658  int32 arg1 = _stack.pop().getInt();
659  int32 arg2 = _stack.pop().getInt();
660  _stack.push(arg1 || arg2);
661 }
662 
665  if (type != kInstTypeIntInt)
666  throw Common::Exception("NCSFile::o_incor(): Illegal type %d", type);
667 
668  int32 arg1 = _stack.pop().getInt();
669  int32 arg2 = _stack.pop().getInt();
670  _stack.push(arg1 | arg2);
671 }
672 
675  if (type != kInstTypeIntInt)
676  throw Common::Exception("NCSFile::o_excor(): Illegal type %d", type);
677 
678  int32 arg1 = _stack.pop().getInt();
679  int32 arg2 = _stack.pop().getInt();
680  _stack.push(arg1 ^ arg2);
681 }
682 
685  if (type != kInstTypeIntInt)
686  throw Common::Exception("NCSFile::o_booland(): Illegal type %d", type);
687 
688  int32 arg1 = _stack.pop().getInt();
689  int32 arg2 = _stack.pop().getInt();
690  _stack.push(arg1 & arg2);
691 }
692 
695  size_t n = 1;
696 
697  if (type == kInstTypeStructStruct) {
698  // Comparisons between two structs (or two vectors) come with the size of the type
699 
700  const size_t size = _script->readUint16BE();
701 
702  if ((size % 4) != 0)
703  throw Common::Exception("NCSFile::o_eq(): size %% 4 != 0");
704 
705  n = size / 4;
706  }
707 
708  std::vector<Variable> args1, args2;
709 
710  args1.reserve(n);
711  args2.reserve(n);
712 
713  for (size_t i = 0; i < n; i++)
714  args1.push_back(_stack.pop());
715 
716  for (size_t i = 0; i < n; i++)
717  args2.push_back(_stack.pop());
718 
719  _stack.push(args1 == args2);
720 }
721 
724  size_t n = 1;
725 
726  if (type == kInstTypeStructStruct) {
727  // Comparisons between two structs (or two vectors) come with the size of the type
728 
729  const size_t size = _script->readUint16BE();
730 
731  if ((size % 4) != 0)
732  throw Common::Exception("NCSFile::o_neq(): size %% 4 != 0");
733 
734  n = size / 4;
735  }
736 
737  std::vector<Variable> args1, args2;
738 
739  args1.reserve(n);
740  args2.reserve(n);
741 
742  for (size_t i = 0; i < n; i++)
743  args1.push_back(_stack.pop());
744 
745  for (size_t i = 0; i < n; i++)
746  args2.push_back(_stack.pop());
747 
748  _stack.push(args1 != args2);
749 }
750 
753  switch (type) {
754  case kInstTypeIntInt:
755  {
756  int32 arg1 = _stack.pop().getInt();
757  int32 arg2 = _stack.pop().getInt();
758  _stack.push(arg2 >= arg1);
759  }
760  break;
761 
762  case kInstTypeFloatFloat:
763  {
764  float arg1 = _stack.pop().getFloat();
765  float arg2 = _stack.pop().getFloat();
766  _stack.push(arg2 >= arg1);
767  }
768  break;
769 
770  default:
771  throw Common::Exception("NCSFile::o_geq(): Illegal type %d", type);
772  }
773 }
774 
777  switch (type) {
778  case kInstTypeIntInt:
779  {
780  int32 arg1 = _stack.pop().getInt();
781  int32 arg2 = _stack.pop().getInt();
782  _stack.push(arg2 > arg1);
783  }
784  break;
785 
786  case kInstTypeFloatFloat:
787  {
788  float arg1 = _stack.pop().getFloat();
789  float arg2 = _stack.pop().getFloat();
790  _stack.push(arg2 > arg1);
791  }
792  break;
793 
794  default:
795  throw Common::Exception("NCSFile::o_gt(): Illegal type %d", type);
796  }
797 }
798 
801  switch (type) {
802  case kInstTypeIntInt:
803  {
804  int32 arg1 = _stack.pop().getInt();
805  int32 arg2 = _stack.pop().getInt();
806  _stack.push(arg2 < arg1);
807  }
808  break;
809 
810  case kInstTypeFloatFloat:
811  {
812  float arg1 = _stack.pop().getFloat();
813  float arg2 = _stack.pop().getFloat();
814  _stack.push(arg2 < arg1);
815  }
816  break;
817 
818  default:
819  throw Common::Exception("NCSFile::o_lt(): Illegal type %d", type);
820  }
821 }
822 
825  switch (type) {
826  case kInstTypeIntInt:
827  {
828  int32 arg1 = _stack.pop().getInt();
829  int32 arg2 = _stack.pop().getInt();
830  _stack.push(arg2 <= arg1);
831  }
832  break;
833 
834  case kInstTypeFloatFloat:
835  {
836  float arg1 = _stack.pop().getFloat();
837  float arg2 = _stack.pop().getFloat();
838  _stack.push(arg2 <= arg1);
839  }
840  break;
841 
842  default:
843  throw Common::Exception("NCSFile::o_leq(): Illegal type %d", type);
844  }
845 }
846 
849  if (type != kInstTypeIntInt)
850  throw Common::Exception("NCSFile::o_shleft(): Illegal type %d", type);
851 
852  int32 arg1 = _stack.pop().getInt();
853  int32 arg2 = _stack.pop().getInt();
854  _stack.push(arg2 << arg1);
855 }
856 
859  /* According to Skywing's NWNScriptLib
860  * (<https://github.com/SkywingvL/nwn2dev-public/blob/master/NWNScriptLib/NWScriptVM.cpp#L2233>):
861  * "The operation implemented here is actually a complex sequence that, if
862  * the amount to be shifted is negative, involves both a front-loaded and
863  * end-loaded negate built on top of a signed shift." */
864 
865  if (type != kInstTypeIntInt)
866  throw Common::Exception("NCSFile::o_shright(): Illegal type %d", type);
867 
868  int32 arg1 = _stack.pop().getInt();
869  int32 arg2 = _stack.pop().getInt();
870 
871  if (arg2 < 0) {
872  arg2 = -arg2;
873  _stack.push(-(arg2 >> arg1));
874  } else
875  _stack.push(arg2 >> arg1);
876 }
877 
880  /* According to Skywing's NWNScriptLib
881  * (<https://github.com/SkywingvL/nwn2dev-public/blob/master/NWNScriptLib/NWScriptVM.cpp#L2272>):
882  * "While this operator may have originally been intended to implement
883  * an unsigned shift, it actually performs an arithmetic (signed) shift." */
884 
885  if (type != kInstTypeIntInt)
886  throw Common::Exception("NCSFile::o_ushright(): Illegal type %d", type);
887 
888  int32 arg1 = _stack.pop().getInt();
889  int32 arg2 = _stack.pop().getInt();
890  _stack.push(arg2 >> arg1);
891 }
892 
895  if (type != kInstTypeIntInt)
896  throw Common::Exception("NCSFile::o_mod(): Illegal type %d", type);
897 
898  int32 arg1 = _stack.pop().getInt();
899  int32 arg2 = _stack.pop().getInt();
900 
901  if (arg1 == 0)
902  throw Common::Exception("NCSFile::o_mod(): Modulus by zero");
903  else if (arg1 < 0 || arg2 < 0)
904  throw Common::Exception("NCSFile::o_mod(): Modulus by negative number (%d %% %d)", arg2, arg1);
905 
906  _stack.push(arg2 % arg1);
907 }
908 
911  switch (type) {
912  case kInstTypeInt:
913  _stack.push(-_stack.pop().getInt());
914  break;
915 
916  case kInstTypeFloat:
917  _stack.push(-_stack.pop().getFloat());
918  break;
919 
920  default:
921  throw Common::Exception("NCSFile::o_neg(): Illegal type %d", type);
922  }
923 }
924 
927  if (type != kInstTypeInt)
928  throw Common::Exception("NCSFile::o_comp(): Illegal type %d", type);
929 
930  _stack.push(~_stack.pop().getInt());
931 }
932 
935  if (type != kInstTypeNone)
936  throw Common::Exception("NCSFile::o_movsp(): Illegal type %d", type);
937 
938  _stack.setStackPtr(_stack.getStackPtr() - _script->readSint32BE());
939 }
940 
943  if (type != kInstTypeNone)
944  throw Common::Exception("NCSFile::o_jmp(): Illegal type %d", type);
945 
946  int32 offset = _script->readSint32BE();
947  _script->skip(offset - 6);
948 }
949 
952  if (type != kInstTypeNone)
953  throw Common::Exception("NCSFile::o_jz(): Illegal type %d", type);
954 
955  int32 offset = _script->readSint32BE();
956 
957  if (!_stack.pop().getInt())
958  _script->skip(offset - 6);
959 }
960 
963  if (type != kInstTypeInt)
964  throw Common::Exception("NCSFile::o_not(): Illegal type %d", type);
965 
966  _stack.push(!_stack.pop().getInt());
967 }
968 
971  if (type != kInstTypeInt)
972  throw Common::Exception("NCSFile::o_decsp(): Illegal type %d", type);
973 
974  int32 offset = _script->readSint32BE();
975 
976  _stack.setRelSP(offset, _stack.getRelSP(offset).getInt() - 1);
977 }
978 
981  if (type != kInstTypeInt)
982  throw Common::Exception("NCSFile::o_incsp(): Illegal type %d", type);
983 
984  int32 offset = _script->readSint32BE();
985 
986  _stack.setRelSP(offset, _stack.getRelSP(offset).getInt() + 1);
987 }
988 
991  if (type != kInstTypeNone)
992  throw Common::Exception("NCSFile::o_jnz(): Illegal type %d", type);
993 
994  int32 offset = _script->readSint32BE();
995 
996  if (_stack.pop().getInt())
997  _script->skip(offset - 6);
998 }
999 
1002  if (type != kInstTypeInt)
1003  throw Common::Exception("NCSFile::o_decbp(): Illegal type %d", type);
1004 
1005  int32 offset = _script->readSint32BE();
1006 
1007  _stack.setRelBP(offset, _stack.getRelBP(offset).getInt() - 1);
1008 }
1009 
1012  if (type != kInstTypeInt)
1013  throw Common::Exception("NCSFile::o_incbp(): Illegal type %d", type);
1014 
1015  int32 offset = _script->readSint32BE();
1016 
1017  _stack.setRelBP(offset, _stack.getRelBP(offset).getInt() + 1);
1018 }
1019 
1025  if (type != kInstTypeNone)
1026  throw Common::Exception("NCSFile::o_savebp(): Illegal type %d", type);
1027 
1030 }
1031 
1037  if (type != kInstTypeNone)
1038  throw Common::Exception("NCSFile::o_restorebp(): Illegal type %d", type);
1039 
1041 }
1042 
1045  // Nothing! Yay!
1046 }
1047 
1050  if (type != kInstTypeDirect)
1051  throw Common::Exception("NCSFile::o_cpdownsp(): Illegal type %d", type);
1052 
1053  int32 offset = _script->readSint32BE();
1054  int16 size = _script->readSint16BE();
1055 
1056  if ((size % 4) != 0)
1057  throw Common::Exception("NCSFile::o_cpdownsp(): Illegal size %d", size);
1058 
1059  int32 startPos = -size;
1060  while (size > 0) {
1061  _stack.setRelSP(offset, _stack.getRelSP(startPos));
1062 
1063  startPos += 4;
1064  offset += 4;
1065  size -= 4;
1066  }
1067 }
1068 
1071  if (type != kInstTypeDirect)
1072  throw Common::Exception("NCSFile::o_cptopsp(): Illegal type %d", type);
1073 
1074  int32 offset = _script->readSint32BE();
1075  int16 size = _script->readSint16BE();
1076 
1077  if ((size % 4) != 0)
1078  throw Common::Exception("NCSFile::o_cptopsp(): Illegal size %d", size);
1079 
1080  while (size > 0) {
1081  _stack.push(_stack.getRelSP(offset));
1082 
1083  size -= 4;
1084  }
1085 }
1086 
1089  switch (type) {
1090  case kInstTypeIntInt: {
1091  Variable op2 = _stack.pop();
1092  Variable op1 = _stack.pop();
1093 
1094  _stack.push((int32) (op1.getInt() + op2.getInt()));
1095  break;
1096  }
1097 
1098  case kInstTypeFloatFloat: {
1099  Variable op2 = _stack.pop();
1100  Variable op1 = _stack.pop();
1101 
1102  _stack.push(op1.getFloat() + op2.getFloat());
1103  break;
1104  }
1105 
1106  case kInstTypeIntFloat: {
1107  Variable op2 = _stack.pop();
1108  Variable op1 = _stack.pop();
1109 
1110  _stack.push(((float) op1.getInt()) + op2.getFloat());
1111  break;
1112  }
1113 
1114  case kInstTypeFloatInt: {
1115  Variable op2 = _stack.pop();
1116  Variable op1 = _stack.pop();
1117 
1118  _stack.push(op1.getFloat() + ((float) op2.getInt()));
1119  break;
1120  }
1121 
1122  case kInstTypeStringString: {
1123  Variable op2 = _stack.pop();
1124  Variable op1 = _stack.pop();
1125 
1126  _stack.push(op1.getString() + op2.getString());
1127  break;
1128  }
1129 
1130  case kInstTypeVectorVector: {
1131  Variable op2z = _stack.pop();
1132  Variable op2y = _stack.pop();
1133  Variable op2x = _stack.pop();
1134  Variable op1z = _stack.pop();
1135  Variable op1y = _stack.pop();
1136  Variable op1x = _stack.pop();
1137 
1138  _stack.push(op1z.getFloat() + op2z.getFloat());
1139  _stack.push(op1y.getFloat() + op2y.getFloat());
1140  _stack.push(op1x.getFloat() + op2x.getFloat());
1141  break;
1142  }
1143 
1144  default:
1145  throw Common::Exception("NCSFile::o_add(): Illegal type %d", type);
1146  }
1147 }
1148 
1151  switch (type) {
1152  case kInstTypeIntInt: {
1153  Variable op2 = _stack.pop();
1154  Variable op1 = _stack.pop();
1155 
1156  _stack.push((int32) (op1.getInt() - op2.getInt()));
1157  break;
1158  }
1159 
1160  case kInstTypeFloatFloat: {
1161  Variable op2 = _stack.pop();
1162  Variable op1 = _stack.pop();
1163 
1164  _stack.push(op1.getFloat() - op2.getFloat());
1165  break;
1166  }
1167 
1168  case kInstTypeIntFloat: {
1169  Variable op2 = _stack.pop();
1170  Variable op1 = _stack.pop();
1171 
1172  _stack.push(((float) op1.getInt()) - op2.getFloat());
1173  break;
1174  }
1175 
1176  case kInstTypeFloatInt: {
1177  Variable op2 = _stack.pop();
1178  Variable op1 = _stack.pop();
1179 
1180  _stack.push(op1.getFloat() - ((float) op2.getInt()));
1181  break;
1182  }
1183 
1184  case kInstTypeVectorVector: {
1185  Variable op2z = _stack.pop();
1186  Variable op2y = _stack.pop();
1187  Variable op2x = _stack.pop();
1188  Variable op1z = _stack.pop();
1189  Variable op1y = _stack.pop();
1190  Variable op1x = _stack.pop();
1191 
1192  _stack.push(op1z.getFloat() - op2z.getFloat());
1193  _stack.push(op1y.getFloat() - op2y.getFloat());
1194  _stack.push(op1x.getFloat() - op2x.getFloat());
1195  break;
1196  }
1197 
1198  default:
1199  throw Common::Exception("NCSFile::o_sub(): Illegal type %d", type);
1200  }
1201 }
1202 
1205  switch (type) {
1206  case kInstTypeIntInt: {
1207  Variable op2 = _stack.pop();
1208  Variable op1 = _stack.pop();
1209 
1210  _stack.push((int32) (op1.getInt() * op2.getInt()));
1211  break;
1212  }
1213 
1214  case kInstTypeFloatFloat: {
1215  Variable op2 = _stack.pop();
1216  Variable op1 = _stack.pop();
1217 
1218  _stack.push(op1.getFloat() * op2.getFloat());
1219  break;
1220  }
1221 
1222  case kInstTypeIntFloat: {
1223  Variable op2 = _stack.pop();
1224  Variable op1 = _stack.pop();
1225 
1226  _stack.push(((float) op1.getInt()) * op2.getFloat());
1227  break;
1228  }
1229 
1230  case kInstTypeFloatInt: {
1231  Variable op2 = _stack.pop();
1232  Variable op1 = _stack.pop();
1233 
1234  _stack.push(op1.getFloat() * ((float) op2.getInt()));
1235  break;
1236  }
1237 
1238  case kInstTypeVectorFloat: {
1239  Variable op2 = _stack.pop();
1240  Variable op1z = _stack.pop();
1241  Variable op1y = _stack.pop();
1242  Variable op1x = _stack.pop();
1243 
1244  _stack.push(op1z.getFloat() * op2.getFloat());
1245  _stack.push(op1y.getFloat() * op2.getFloat());
1246  _stack.push(op1x.getFloat() * op2.getFloat());
1247  break;
1248  }
1249 
1250  case kInstTypeFloatVector: {
1251  Variable op2z = _stack.pop();
1252  Variable op2y = _stack.pop();
1253  Variable op2x = _stack.pop();
1254  Variable op1 = _stack.pop();
1255 
1256  _stack.push(op1.getFloat() * op2z.getFloat());
1257  _stack.push(op1.getFloat() * op2y.getFloat());
1258  _stack.push(op1.getFloat() * op2x.getFloat());
1259  break;
1260  }
1261 
1262  default:
1263  throw Common::Exception("NCSFile::o_mul(): Illegal type %d", type);
1264  }
1265 }
1266 
1269  switch (type) {
1270  case kInstTypeIntInt: {
1271  Variable op2 = _stack.pop();
1272  Variable op1 = _stack.pop();
1273 
1274  if (op2.getInt() == 0)
1275  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1276 
1277  if (op1.getInt() == INT32_MIN && op2.getInt() == -1)
1278  throw Common::Exception("NCSFile::o_div: Quotient overflow");
1279 
1280  _stack.push((int32) (op1.getInt() / op2.getInt()));
1281  break;
1282  }
1283 
1284  case kInstTypeFloatFloat: {
1285  Variable op2 = _stack.pop();
1286  Variable op1 = _stack.pop();
1287 
1288  if (op2.getFloat() == 0.0f)
1289  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1290 
1291  _stack.push(op1.getFloat() / op2.getFloat());
1292  break;
1293  }
1294 
1295  case kInstTypeIntFloat: {
1296  Variable op2 = _stack.pop();
1297  Variable op1 = _stack.pop();
1298 
1299  if (op2.getFloat() == 0.0f)
1300  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1301 
1302  _stack.push(((float) op1.getInt()) / op2.getFloat());
1303  break;
1304  }
1305 
1306  case kInstTypeFloatInt: {
1307  Variable op2 = _stack.pop();
1308  Variable op1 = _stack.pop();
1309 
1310  if (op2.getInt() == 0)
1311  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1312 
1313  _stack.push(op1.getFloat() / ((float) op2.getInt()));
1314  break;
1315  }
1316 
1317  case kInstTypeVectorFloat: {
1318  Variable op2 = _stack.pop();
1319  Variable op1z = _stack.pop();
1320  Variable op1y = _stack.pop();
1321  Variable op1x = _stack.pop();
1322 
1323  if (op2.getFloat() == 0.0f)
1324  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1325 
1326  _stack.push(op1z.getFloat() / op2.getFloat());
1327  _stack.push(op1y.getFloat() / op2.getFloat());
1328  _stack.push(op1x.getFloat() / op2.getFloat());
1329  break;
1330  }
1331 
1332  case kInstTypeFloatVector: {
1333  Variable op2z = _stack.pop();
1334  Variable op2y = _stack.pop();
1335  Variable op2x = _stack.pop();
1336  Variable op1 = _stack.pop();
1337 
1338  if (op2x.getFloat() == 0.0f || op2y.getFloat() == 0.0f || op2z.getFloat() == 0.0f)
1339  throw Common::Exception("NCSFile::o_div(): Divide by zero");
1340 
1341  _stack.push(op1.getFloat() / op2z.getFloat());
1342  _stack.push(op1.getFloat() / op2y.getFloat());
1343  _stack.push(op1.getFloat() / op2x.getFloat());
1344  break;
1345  }
1346 
1347  default:
1348  throw Common::Exception("NCSFile::o_div(): Illegal type %d", type);
1349  }
1350 }
1351 
1354  uint8 offset = (uint8) type;
1355 
1356  // TODO: NCSFile::o_storestateall(): See o_storestate.
1357  // Supposedly obsolete. Whether it's used anywhere remains to be seen.
1358  warning("TODO: NCSFile::o_storestateall(): %d", offset);
1359 }
1360 
1363  if (type != kInstTypeNone)
1364  throw Common::Exception("NCSFile::o_jsr(): Illegal type %d", type);
1365 
1366  int32 offset = _script->readSint32BE();
1367 
1368  // Push the current script position
1369  _returnOffsets.push(_script->pos());
1370 
1371  _script->skip(offset - 6);
1372 }
1373 
1376  uint32 returnAddress = _script->size();
1377  if (!_returnOffsets.empty()) {
1378  returnAddress = _returnOffsets.top();
1379  _returnOffsets.pop();
1380  }
1381 
1382  _script->seek(returnAddress);
1383 }
1384 
1390  int16 stackSize = _script->readSint16BE();
1391  int16 dontRemoveOffset = _script->readSint16BE();
1392  int16 dontRemoveSize = _script->readSint16BE();
1393 
1394  if ((stackSize % 4) != 0)
1395  throw Common::Exception("NCSFile::o_destruct(): Illegal stack size %d", stackSize);
1396  if ((dontRemoveOffset % 4) != 0)
1397  throw Common::Exception("NCSFile::o_destruct(): Illegal offset %d", dontRemoveOffset);
1398  if ((dontRemoveSize % 4) != 0)
1399  throw Common::Exception("NCSFile::o_destruct(): Illegal size %d", dontRemoveSize);
1400 
1401  std::vector<Variable> tmp;
1402  tmp.reserve(dontRemoveSize / 4);
1403 
1404  while (stackSize > 0) {
1405 
1406  if ((stackSize <= (dontRemoveOffset + dontRemoveSize)) &&
1407  (stackSize > dontRemoveOffset))
1408  tmp.push_back(_stack.top());
1409 
1410  _stack.pop();
1411 
1412  stackSize -= 4;
1413  }
1414 
1415  for (std::vector<Variable>::reverse_iterator t = tmp.rbegin(); t != tmp.rend(); ++t)
1416  _stack.push(*t);
1417 }
1418 
1424  if (type != kInstTypeDirect)
1425  throw Common::Exception("NCSFile::o_cpdownbp(): Illegal type %d", type);
1426 
1427  int32 offset = _script->readSint32BE() - 4;
1428  int16 size = _script->readSint16BE();
1429 
1430  if ((size % 4) != 0)
1431  throw Common::Exception("NCSFile::o_cpdownbp(): Illegal size %d", size);
1432 
1433  int32 startPos = -size;
1434  while (size > 0) {
1435  _stack.setRelBP(offset, _stack.getRelSP(startPos));
1436 
1437  startPos += 4;
1438  offset += 4;
1439  size -= 4;
1440  }
1441 }
1442 
1448  if (type != kInstTypeDirect)
1449  throw Common::Exception("NCSFile::o_cptopbp(): Illegal type %d", type);
1450 
1451  int32 offset = _script->readSint32BE() - 4;
1452  int16 size = _script->readSint16BE();
1453 
1454  if ((size % 4) != 0)
1455  throw Common::Exception("NCSFile::o_cptopbp(): Illegal size %d", size);
1456 
1457  while (size > 0) {
1458  _stack.push(_stack.getRelBP(offset));
1459 
1460  size -= 4;
1461  offset += 4;
1462  }
1463 }
1464 
1471  uint8 offset = (uint8) type;
1472  uint32 sizeBP = _script->readUint32BE();
1473  uint32 sizeSP = _script->readUint32BE();
1474 
1475  if ((sizeBP % 4) != 0)
1476  throw Common::Exception("NCSFile::o_storestate(): Illegal BP size %d", sizeBP);
1477  if ((sizeSP % 4) != 0)
1478  throw Common::Exception("NCSFile::o_storestate(): Illegal SP size %d", sizeSP);
1479 
1482 
1483  state.offset = _script->pos() - 10 + offset;
1484 
1485  sizeBP /= 4;
1486  sizeSP /= 4;
1487 
1488  for (int32 posBP = -4; sizeBP > 0; sizeBP--, posBP -= 4)
1489  state.globals.push_back(_stack.getRelBP(posBP));
1490 
1491  for (int32 posSP = -4; sizeSP > 0; sizeSP--, posSP -= 4)
1492  state.locals.push_back(_stack.getRelSP(posSP));
1493 }
1494 
1507  if (type != kInstTypeDirect)
1508  throw Common::Exception("NCSFile::o_writearray(): Illegal type %d", type);
1509 
1510  int32 offset = _script->readSint32BE();
1511  int16 size = _script->readSint16BE();
1512 
1513  if (size != 4)
1514  throw Common::Exception("NCSFile::o_writearray(): Invalid size %d", size);
1515 
1516  Variable &arrayVar = _stack.getRelSP(offset);
1517 
1518  Variable indexVar = _stack.pop();
1519  Variable &valueVar = _stack.top();
1520 
1521  const int32 index = indexVar.getInt();
1522  if (index < 0)
1523  throw Common::Exception("NCSFile::o_writearray(): Invalid index %d", index);
1524 
1525  arrayVar.growArray(valueVar.getType(), index + 1);
1526  arrayVar.getArray()[index] = boost::make_shared<Variable>(Variable(valueVar));
1527 }
1528 
1542  if (type != kInstTypeDirect)
1543  throw Common::Exception("NCSFile::o_readarray(): Illegal type %d", type);
1544 
1545  int32 offset = _script->readSint32BE();
1546  int16 size = _script->readSint16BE();
1547 
1548  if (size != 4)
1549  throw Common::Exception("NCSFile::o_readarray(): Invalid size %d", size);
1550 
1551  Variable::Array &array = _stack.getRelSP(offset).getArray();
1552 
1553  Variable indexVar = _stack.pop();
1554  const int32 index = indexVar.getInt();
1555 
1556  if ((index < 0) || ((uint)index >= array.size()))
1557  throw Common::Exception("NCSFile::o_readarray(): Index out of range (%d, %u)",
1558  index, (uint) array.size());
1559 
1560  _stack.push(*array[index]);
1561 }
1562 
1574  if (type != kInstTypeDirect)
1575  throw Common::Exception("NCSFile::o_getref(): Illegal type %d", type);
1576 
1577  int32 offset = _script->readSint32BE();
1578  int16 size = _script->readSint16BE();
1579 
1580  if (size != 4)
1581  throw Common::Exception("NCSFile::o_getref(): Invalid size %d", size);
1582 
1583  Variable &var = _stack.getRelSP(offset);
1584 
1586  _stack.top().setReference(&var);
1587 }
1588 
1605  if (type != kInstTypeDirect)
1606  throw Common::Exception("NCSFile::o_getrefarray(): Illegal type %d", type);
1607 
1608  int32 offset = _script->readSint32BE();
1609  int16 size = _script->readSint16BE();
1610 
1611  if (size != 4)
1612  throw Common::Exception("NCSFile::o_getrefarray(): Invalid size %d", size);
1613 
1614  Variable::Array &array = _stack.getRelSP(offset).getArray();
1615 
1616  Variable indexVar = _stack.pop();
1617  const int32 index = indexVar.getInt();
1618 
1619  if ((index < 0) || ((uint)index >= array.size()))
1620  throw Common::Exception("NCSFile::o_getrefarray(): Index out of range (%d, %u)",
1621  index, (uint) array.size());
1622 
1624  _stack.top().setReference(&*array[index]);
1625 }
1626 
1627 } // End of namespace NWScript
1628 
1629 } // End of namespace Aurora
VariableContainer & getEnvironment()
Return the script&#39;s environment variables.
Definition: ncsfile.cpp:298
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
void o_retn(InstructionType type)
RETN: return from a subroutine call.
Definition: ncsfile.cpp:1375
ObjectReference _triggerer
Definition: ncsfile.h:175
void setReference(Variable *reference)
Definition: variable.cpp:415
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
std::vector< boost::shared_ptr< Variable > > Array
Definition: variable.h:58
static const uint32 kVersion10
Definition: ncsfile.cpp:50
void formatVariable(Common::UString &str, const Variable &var)
Print a description of this variable into that string.
Definition: util.cpp:41
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
void o_ushright(InstructionType type)
USHRIGHT: shift the top-most stack element to the right (>>).
Definition: ncsfile.cpp:879
void o_writearray(InstructionType type)
WRITEARRAY: write the value of an array element on the stack.
Definition: ncsfile.cpp:1506
void o_leq(InstructionType type)
LEQ: compare the top-most stack elements, less-or-equal (<=).
Definition: ncsfile.cpp:824
void debugC(Common::DebugChannel channel, uint32 level, const char *s,...)
Definition: debug.cpp:34
void reset()
Reset the script for another execution.
Definition: ncsfile.cpp:338
void o_destruct(InstructionType type)
DESTRUCT: remove elements from the stack.
Definition: ncsfile.cpp:1389
A class holding an UTF-8 string.
Definition: ustring.h:48
void o_getref(InstructionType type)
GETREF: push the reference to a stack element onto the stack.
Definition: ncsfile.cpp:1573
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
Utility functions for debug output.
void o_incsp(InstructionType type)
INCSP: increment the value of a stack element (++).
Definition: ncsfile.cpp:980
void o_decsp(InstructionType type)
DECSP: decrement the value of a stack element (–).
Definition: ncsfile.cpp:970
static const uint32 kScriptObjectTypeInvalid
Definition: ncsfile.cpp:55
uint8_t uint8
Definition: types.h:200
Mathematical helpers.
void setBasePtr(int32 pos)
Definition: ncsfile.cpp:167
Variable & getRelSP(int32 pos)
Definition: ncsfile.cpp:105
void o_movsp(InstructionType type)
MOVSP: pop elements off the stack.
Definition: ncsfile.cpp:934
#define ARRAYSIZE(x)
Macro which determines the number of entries in a fixed size array.
Definition: util.h:131
void o_comp(InstructionType type)
COMP: calculate the 1-complement of the top-most stack element (~).
Definition: ncsfile.cpp:926
bool executeStep()
Execute one script step.
Definition: ncsfile.cpp:404
#define INT32_MIN
Definition: maths.h:51
static const uint32 kVersion10
Definition: erfwriter.cpp:31
ObjectReference _owner
Definition: ncsfile.h:174
void o_lt(InstructionType type)
LT: compare the top-most stack elements, less (<).
Definition: ncsfile.cpp:800
void o_rsadd(InstructionType type)
RSADD: push an empty variable onto the stack.
Definition: ncsfile.cpp:440
void growArray(Type type, size_t size)
Definition: variable.cpp:380
int16_t int16
Definition: types.h:201
void o_jsr(InstructionType type)
JSR: call a subroutine.
Definition: ncsfile.cpp:1362
The NWScript function manager.
Exception that provides a stack of explanations.
Definition: error.h:36
static void readHeader(Common::ReadStream &stream, uint32 &id, uint32 &version, bool &utf16le)
Read the header out of a stream.
Definition: aurorafile.cpp:53
const Variable & execute(const ObjectReference owner=ObjectReference(), const ObjectReference triggerer=ObjectReference())
Definition: ncsfile.cpp:384
void o_excor(InstructionType type)
EXCOR: perform a bit-wise exclusive OR (^).
Definition: ncsfile.cpp:674
void getVector(float &x, float &y, float &z) const
Definition: variable.cpp:344
void o_cptopbp(InstructionType type)
CPTOPBP: push a copy of a base-pointer stack element on top of the stack.
Definition: ncsfile.cpp:1447
Basic exceptions to throw.
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
Variable & getRelBP(int32 pos)
Definition: ncsfile.cpp:127
Common::ScopedPtr< Common::SeekableReadStream > _script
Definition: ncsfile.h:170
uint16_t uint16
Definition: types.h:202
#define UNUSED(x)
Definition: system.h:170
const Variable & run(Object *owner=0, Object *triggerer=0)
Run the current script, from start to finish.
Definition: ncsfile.cpp:350
#define OPCODE0()
Definition: ncsfile.cpp:192
Utility templates and functions.
void o_savebp(InstructionType type)
SAVEBP: set the value of the base-pointer.
Definition: ncsfile.cpp:1024
void o_restorebp(InstructionType type)
RESTOREBP: restore the value of the base-pointer to a prior value.
Definition: ncsfile.cpp:1036
void o_storestate(InstructionType type)
STORESTATE: create a functor of a subroutine with the current stack.
Definition: ncsfile.cpp:1470
void setVector(float x, float y, float z)
Definition: variable.cpp:335
void o_eq(InstructionType type)
EQ: compare the top-most stack elements for equality (==).
Definition: ncsfile.cpp:694
void o_add(InstructionType type)
ADD: add the top-most stack elements (+).
Definition: ncsfile.cpp:1088
void o_jnz(InstructionType type)
JNZ: jump conditionally if the top-most stack element is not 0.
Definition: ncsfile.cpp:990
void o_neq(InstructionType type)
NEQ: compare the top-most stack elements for inequality (!=).
Definition: ncsfile.cpp:723
Utility functions for working with differing string encodings.
A reference/pointer to another variable.
Definition: types.h:47
Common::UString _name
Definition: ncsfile.h:167
"GScripts", global, non-engine scripts.
Definition: debugman.h:46
void o_sub(InstructionType type)
SUB: subtract the top-most stack elements (-).
Definition: ncsfile.cpp:1150
const Common::UString & getName() const
void o_storestateall(InstructionType type)
STORESTATEALL: unused, obsolete opcode.
Definition: ncsfile.cpp:1353
void o_readarray(InstructionType type)
READARRAY: push the value of an array element onto of the stack.
Definition: ncsfile.cpp:1541
uint32 _id
The file&#39;s ID.
Definition: aurorafile.h:77
StackException Exception
Definition: error.h:59
uint32 _version
The file&#39;s version.
Definition: aurorafile.h:78
void o_const(InstructionType type)
CONST: push a constant (predetermined value) variable onto the stack.
Definition: ncsfile.cpp:482
ScriptState & getScriptState()
Definition: variable.cpp:394
void setCurrentScript(NCSFile *script=0)
std::stack< uint32 > _returnOffsets
Definition: ncsfile.h:179
void setStackPtr(int32 pos)
Definition: ncsfile.cpp:153
void warning(const char *s,...)
Definition: util.cpp:33
void setRelSP(int32 pos, const Variable &obj)
Definition: ncsfile.cpp:116
void o_logor(InstructionType type)
LOGOR: perform a logical boolean OR (||).
Definition: ncsfile.cpp:654
void o_mul(InstructionType type)
MUL: multiply the top-most stack elements (*).
Definition: ncsfile.cpp:1204
void o_getrefarray(InstructionType type)
GETREFARRAY: push the reference to an array element onto the stack.
Definition: ncsfile.cpp:1604
Basic reading stream interfaces.
#define DebugMan
Shortcut for accessing the debug manager.
Definition: debugman.h:195
void o_neg(InstructionType type)
NEQ: negate the top-most stack element (unary -).
Definition: ncsfile.cpp:910
static ScriptState getEmptyState()
Definition: ncsfile.cpp:306
void o_cpdownsp(InstructionType type)
CPDOWNSP: copy a value into an existing stack element.
Definition: ncsfile.cpp:1049
Handling BioWare&#39;s NWN Compiled Scripts.
void callEngine(Aurora::NWScript::FunctionContext &ctx, uint32 function, uint8 argCount)
Helper function for o_action(), doing the actual engine function calling.
Definition: ncsfile.cpp:529
Unicode string handling.
Plain, unextended ASCII (7bit clean).
Definition: encoding.h:40
void o_div(InstructionType type)
DIV: divide the top-most stack elements (/).
Definition: ncsfile.cpp:1268
#define OPCODE(x)
Definition: ncsfile.cpp:191
void push(const Variable &obj)
Definition: ncsfile.cpp:93
void o_action(InstructionType type)
ACTION: call a game-specific engine function.
Definition: ncsfile.cpp:625
void setType(Type type)
Definition: variable.cpp:98
An NWScript object.
"effect", "event", "location", "talent"...
Definition: types.h:43
#define FunctionMan
Definition: functionman.h:84
void o_nop(InstructionType type)
NOP: no operation.
Definition: ncsfile.cpp:1044
std::vector< class Variable > locals
Definition: variable.h:53
void o_cptopsp(InstructionType type)
CPTOPSP: push a copy of a stack element on top of the stack.
Definition: ncsfile.cpp:1070
Script, NWScript bytecode.
Definition: types.h:79
void o_logand(InstructionType type)
LOGAND: perform a logical boolean AND (&&).
Definition: ncsfile.cpp:644
void o_mod(InstructionType type)
MOD: calculate the remainder (modulo) of an integer division (%).
Definition: ncsfile.cpp:894
static const uint32 kScriptObjectInvalid2
Definition: ncsfile.cpp:54
uint32_t uint32
Definition: types.h:204
const Array & getArray() const
Definition: variable.cpp:353
Common::UString & getString()
Definition: variable.cpp:314
static const uint32 kScriptObjectInvalid
Definition: ncsfile.cpp:53
NCSFile(Common::SeekableReadStream *ncs)
Definition: ncsfile.cpp:277
void o_jz(InstructionType type)
JZ: jump conditionally if the top-most stack element is 0.
Definition: ncsfile.cpp:951
Any other type.
Definition: types.h:48
void o_cpdownbp(InstructionType type)
CPDOWNBP: copy a value into an existing base-pointer stack element.
Definition: ncsfile.cpp:1423
void o_not(InstructionType type)
NOT: boolean-negate the top-most stack element (!).
Definition: ncsfile.cpp:962
void setRelBP(int32 pos, const Variable &obj)
Definition: ncsfile.cpp:138
void o_incbp(InstructionType type)
INCBP: increment the value of a base-pointer stack element (++).
Definition: ncsfile.cpp:1011
const Common::UString & getName() const
Definition: ncsfile.cpp:294
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
Definition: encoding.cpp:297
VariableContainer _env
Definition: ncsfile.h:177
void o_gt(InstructionType type)
GT: compare the top-most stack elements, greater (>).
Definition: ncsfile.cpp:776
void o_shright(InstructionType type)
SHRIGHT: signed-shift the top-most stack element to the right (>>>).
Definition: ncsfile.cpp:858
void o_decbp(InstructionType type)
DECBP: decrement the value of a base-pointer stack element (–).
Definition: ncsfile.cpp:1001
void o_booland(InstructionType type)
BOOLAND: perform a bit-wise AND (&).
Definition: ncsfile.cpp:684
static const uint32 kNCSTag
Definition: ncsfile.cpp:49
void o_jmp(InstructionType type)
JMP: jump directly to a different script offset.
Definition: ncsfile.cpp:942
const Opcode * _opcodes
Definition: ncsfile.h:188
std::vector< class Variable > globals
Definition: variable.h:52
void o_incor(InstructionType type)
INCOR: perform a bit-wise inclusive OR (|).
Definition: ncsfile.cpp:664
Interface for a seekable & readable data stream.
Definition: readstream.h:265
static const uint32 kScriptObjectSelf
Definition: ncsfile.cpp:52
void o_geq(InstructionType type)
GEQ: compare the top-most stack elements, greater-or-equal (>=).
Definition: ncsfile.cpp:752
void o_shleft(InstructionType type)
SHLEFT: shift the top-most stack element to the left (<<).
Definition: ncsfile.cpp:848
The global resource manager for Aurora resources.
uint8 byte
Definition: types.h:209
void setEnvironment(const VariableContainer &env)
Overwrite the environment.
Definition: ncsfile.cpp:302
unsigned int uint
Definition: types.h:211
int32_t int32
Definition: types.h:203