<NME> ConversationVM.cs <BEF> ﻿using UnityEngine; using System.Collections; using UnityEngine.UI; using System.IO; using System.Text.RegularExpressions; /// <summary> /// Implementation of the conversation virtual machine /// based on UWAdventures hacking tools. /// </summary> public class ConversationVM : UWEBase { //TODO:Make sure pickups support containers /// Is the user entering a quantity public static bool EnteringQty; public static bool InConversation; public static int CurrentConversation; ///The NPC is talking public const int NPC_SAY = 0; ///The PC is talking public const int PC_SAY = 1; ///Printed text is displayed public const int PRINT_SAY = 2; //The op codes for the vm. const short cnv_NOP = 0; const short cnv_OPADD = 1; const short cnv_OPMUL = 2; const short cnv_OPSUB = 3; const short cnv_OPDIV = 4; const short cnv_OPMOD = 5; const short cnv_OPOR = 6; const short cnv_OPAND = 7; const short cnv_OPNOT = 8; const short cnv_TSTGT = 9; const short cnv_TSTGE = 10; const short cnv_TSTLT = 11; const short cnv_TSTLE = 12; const short cnv_TSTEQ = 13; const short cnv_TSTNE = 14; const short cnv_JMP = 15; const short cnv_BEQ = 16; const short cnv_BNE = 17; const short cnv_BRA = 18; const short cnv_CALL = 19; const short cnv_CALLI = 20; const short cnv_RET = 21; const short cnv_PUSHI = 22; const short cnv_PUSHI_EFF = 23; const short cnv_POP = 24; const short cnv_SWAP = 25; const short cnv_PUSHBP = 26; const short cnv_POPBP = 27; const short cnv_SPTOBP = 28; const short cnv_BPTOSP = 29; const short cnv_ADDSP = 30; const short cnv_FETCHM = 31; const short cnv_STO = 32; const short cnv_OFFSET = 33; const short cnv_START = 34; const short cnv_SAVE_REG = 35; const short cnv_PUSH_REG = 36; const short cnv_STRCMP = 37; const short cnv_EXIT_OP = 38; const short cnv_SAY_OP = 39; const short cnv_RESPOND_OP = 40; const short cnv_OPNEG = 41; const int import_function = 0x111; const int import_variable = 0x10f; const int return_void = 0; const int return_int = 0x129; const int return_string = 0x12b; //const int TradeAreaOffset=0;//This hack is a bad hack... private static string[] ObjectMasterList; //The input and output controls //private static Text Output; private static Text PlayerInput; private int currConv = 0;//The conversation that is being ran. public int MaxAnswer; private int NPCTalkedToIndex = 0; /// <summary> /// The player will teleport at the end of the conversation /// </summary> private bool Teleport = false; private int TeleportLevel = -1; private int TeleportTileX = -1; private int TeleportTileY = -1; private bool SettingUpFight = false; public static bool VMLoaded = false; /// <summary> /// Imported function and memory data from the conv.ark file /// </summary> struct ImportedFunctions { //0000 Int16 length of function name //0002 n*char name of function cnvHeader[] conv; //char[] cnv_ark; //public string Path; //to cnv.ark //public string StringsPath; //to strings.pak //public StringController stringcontrol; CnvStack stack; public int call_level=1; public int instrp=0; //public int basep = 0; public int result_register; public static int PlayerAnswer; struct cnvHeader { //0000 Int16 unknown, always seems to be 0x0828, or 28 08 //0002 Int16 unknown, always 0x0000 public int CodeSize; //0004 Int16 code size in number of instructions (16-bit words) ////0006 Int16 unknown, always 0x0000 //0008 Int16 unknown, always 0x0000 public int StringBlock;// 000A Int16 game strings block to use for conversation strings public int NoOfMemorySlots;// 000C Int16 number of memory slots reserved for variables (*) public int NoOfImportedGlobals;//000E Int16 number of imported globals (functions + variables) //0010 start of imported functions list public ImportedFunctions[] functions; public short[] instuctions; }; cnvHeader[] conv; /// <summary> /// The memory stack for the VM. /// </summary> CnvStack stack; /// The player answer. public static int PlayerAnswer; ///The text the player has typed in response to a question public static string PlayerTypedAnswer; ///Conversation waiting mode. Player has to enter a menu option public static bool WaitingForInput; ///Conversation waiting mode. Player has to press any key to continue public static bool WaitingForMore; ///Conversation waiting mode. Player has to type an answer. public static bool WaitingForTyping; ///The array that maps menu options in a bablf_menu to their answer numbers public static int[] bablf_array = new int[10]; ///Tells if we are using a bablf_menu public static bool usingBablF; /// The answer from the bablf_menu public static int bablf_ans = 0; public static ConversationVM instance; private void Awake() { instance = this; } public void InitConvVM() { switch (_RES) { case GAME_UW2: LoadCnvArkUW2(Loader.BasePath + "DATA" + sep + "CNV.ARK"); break; default: LoadCnvArk(Loader.BasePath + "DATA" + sep + "CNV.ARK"); break; } VMLoaded = true; } void Update() { if (WaitingForTyping) { UWHUD.instance.InputControl.Select();//Keep focus on input control } } /// <summary> /// Loads the cnv ark file and parses it to initialise the conversation headers and imported functions /// </summary> /// <param name="cnv_ark_path">Cnv ark path.</param> public void LoadCnvArk(string cnv_ark_path) { char[] cnv_ark; if (DataLoader.ReadStreamFile(cnv_ark_path, out cnv_ark)) { int NoOfConversations = (int)DataLoader.getValAtAddress(cnv_ark, 0, 16); conv = new cnvHeader[NoOfConversations]; for (int i = 0; i < NoOfConversations; i++) { int add_ptr = (int)DataLoader.getValAtAddress(cnv_ark, 2 + i * 4, 32); if (add_ptr != 0) { /* 0000 Int16 unknown, always seems to be 0x0828, or 28 08 0002 Int16 unknown, always 0x0000 0004 Int16 code size in number of instructions (16-bit words) 0006 Int16 unknown, always 0x0000 0008 Int16 unknown, always 0x0000 000A Int16 game strings block to use for conversation strings 000C Int16 number of memory slots reserved for variables (*) 000E Int16 number of imported globals (functions + variables) 0010 start of imported functions list */ conv[i].CodeSize = (int)DataLoader.getValAtAddress(cnv_ark, add_ptr + 0x4, 16); conv[i].StringBlock = (int)DataLoader.getValAtAddress(cnv_ark, add_ptr + 0xA, 16); conv[i].NoOfMemorySlots = (int)DataLoader.getValAtAddress(cnv_ark, add_ptr + 0xC, 16); conv[i].NoOfImportedGlobals = (int)DataLoader.getValAtAddress(cnv_ark, add_ptr + 0xE, 16); conv[i].functions = new ImportedFunctions[conv[i].NoOfImportedGlobals]; int funcptr = add_ptr + 0x10; for (int f = 0; f < conv[i].NoOfImportedGlobals; f++) { /*0000 Int16 length of function name 0002 n*char name of function n+02 Int16 ID (imported func.) / memory address (variable) n+04 Int16 unknown, always seems to be 1 n+06 Int16 import type (0x010F=variable, 0x0111=imported func.) n+08 Int16 return type (0x0000=void, 0x0129=int, 0x012B=string)*/ int len = (int)DataLoader.getValAtAddress(cnv_ark, funcptr, 16); for (int j = 0; j < len; j++) { conv[i].functions[f].functionName += (char)DataLoader.getValAtAddress(cnv_ark, funcptr + 2 + j, 8); } conv[i].functions[f].ID_or_Address = (int)DataLoader.getValAtAddress(cnv_ark, funcptr + len + 2, 16); conv[i].functions[f].import_type = (int)DataLoader.getValAtAddress(cnv_ark, funcptr + len + 6, 16); conv[i].functions[f].return_type = (int)DataLoader.getValAtAddress(cnv_ark, funcptr + len + 8, 16); funcptr += len + 10; } conv[i].instuctions = new short[conv[i].CodeSize]; int counter = 0; for (int c = 0; c < conv[i].CodeSize * 2; c = c + 2) { conv[i].instuctions[counter++] = (short)DataLoader.getValAtAddress(cnv_ark, funcptr + c, 16); } } } } } /// <summary> /// Loads the cnv ark file and parses it to initialise the conversation headers and imported functions /// </summary> /// <param name="cnv_ark_path">Cnv ark path.</param> public void LoadCnvArkUW2(string cnv_ark_path) { char[] tmp_ark; int address_pointer = 2; if (!DataLoader.ReadStreamFile(cnv_ark_path, out tmp_ark)) { Debug.Log("unable to load uw2 conv ark"); return; } int NoOfConversations = (int)DataLoader.getValAtAddress(tmp_ark, 0, 32); conv = new cnvHeader[NoOfConversations]; for (int i = 0; i < NoOfConversations; i++) { int compressionFlag = (int)DataLoader.getValAtAddress(tmp_ark, address_pointer + (NoOfConversations * 4), 32); int isCompressed = (compressionFlag >> 1) & 0x01; /// <returns>The conversation V.</returns> private IEnumerator RunConversationVM(NPC npc) { call_level=1; instrp=0; //basep = 0; result_register = 1;//Set a default value bool finished = false; stack=new CnvStack(4096); stack.set_stackp(100);//Skip over imported memory for the moment stack.basep=0; //Import the variables ImportVariableMemory(npc); // execute one instruction //switch(code[instrp]) while ( (finished==false)) { switch(conv[currConv].instuctions[instrp]) { case cnv_NOP: break; case cnv_OPADD: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg1 + arg2); } break; case cnv_OPMUL: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg1 * arg2); } break; case cnv_OPSUB: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg2 - arg1); } break; case cnv_OPDIV: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); //if (arg1==0) // throw ua_ex_div_by_zero; stack.Push(arg2 / arg1); } break; case cnv_OPMOD: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); //if (arg1==0) // throw ua_ex_div_by_zero; stack.Push(arg2 % arg1); } break; case cnv_OPOR: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg2 | arg1); } break; case cnv_OPAND: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg2 & arg1); } break; case cnv_OPNOT: { int arg1 = stack.Pop(); if (arg1==0) { stack.Push(1); } else { stack.Push(0); } //stack.Push(!stack.Pop()); break; } case cnv_TSTGT: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2>arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 > arg1); } break; case cnv_TSTGE: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2>=arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 >= arg1); } break; case cnv_TSTLT: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2<arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 < arg1); } break; case cnv_TSTLE: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2<=arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 <= arg1); } break; case cnv_TSTEQ: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2==arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 == arg1); } break; case cnv_TSTNE: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2!=arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 != arg1); } break; case cnv_JMP: //Debug.Log("instr = " +instrp + " JMP to " + conv[currConv].instuctions[instrp+1]); instrp = conv[currConv].instuctions[instrp+1]-1; //if (conv[currConv].instuctions[instrp+1] == cnv_BRA) //{//Skip over a branch when jumping // instrp+=2; //} break; case cnv_BEQ: { int arg1 = stack.Pop(); if (arg1 == 0) instrp += conv[currConv].instuctions[instrp+1]; else instrp++; } break; case cnv_BNE: { int arg1 = stack.Pop(); if (arg1 != 0) instrp += conv[currConv].instuctions[instrp+1]; else instrp++; } break; case cnv_BRA: { int offset = conv[currConv].instuctions[instrp+1]; if (offset >0) { instrp += offset; } else { instrp += offset; } //if (conv[currConv].instuctions[instrp+1]<=conv[currConv].instuctions.GetUpperBound(0)) //{ //} //else //{//Skip over an invalid instruction address //instrp++; //Go backwards // int offset = conv[currConv].instuctions[instrp+1] ^ 0xffff ; // offset++; // instrp -=offset; //} break; } case cnv_CALL: // local function // stack value points to next instruction after call //Debug.Log("inst=" + instrp + "stack ptr" + stack.stackptr + " new inst=" + (conv[currConv].instuctions[instrp+1]-1)); stack.Push(instrp+1); instrp = conv[currConv].instuctions[instrp+1]-1; call_level++; break; case cnv_CALLI: // imported function { int arg1 = conv[currConv].instuctions[++instrp]; for (int i=0; i<=conv[currConv].functions.GetUpperBound(0);i++) { if ((conv[currConv].functions[i].ID_or_Address==arg1) && (conv[currConv].functions[i].import_type==0x0111)) { //Debug.Log("Calling function " + arg1 + " which is currently : " + conv[currConv].functions[i].functionName ); yield return StartCoroutine( run_imported_function(conv[currConv].functions[i] , npc)); break; } } /* std::string funcname; if (imported_funcs.find(arg1) == imported_funcs.end()) throw ua_ex_imported_na; imported_func(imported_funcs[arg1].name);*/ } break; case cnv_RET: { if (--call_level<0) { // conversation ended finished = true; } else { int arg1 = stack.Pop(); //Debug.Log("instr = " +instrp + " returning to " + arg1); instrp = arg1; } } break; case cnv_PUSHI: { //Debug.Log("Instruction:" + instrp +" Pushing Immediate value :" +conv[currConv].instuctions[instrp+1] + " => " + stack.stackptr); stack.Push(conv[currConv].instuctions[++instrp]); break; } case cnv_PUSHI_EFF: { //int offset = conv[currConv].instuctions[instrp+1]; //if ( (offset >> 15) == 1) //{ //signed value // offset ^= 0xffff; // offset =(offset)*-1; //Debug.Log("offset = " + offset); //} //int offset = conv[currConv].instuctions[instrp+1] ^ 0xffff ; //Debug.Log("Instruction:" + instrp +" Pushing Effective Address :" + (stack.basep +conv[currConv].instuctions[instrp+1]) + " => " + stack.stackptr); int offset = conv[currConv].instuctions[instrp+1]; if (offset>=0) { stack.Push(stack.basep + offset); } else { offset--; //to skip over base ptr; stack.Push(stack.basep + offset); } instrp++; //stack.Push(stack.basep + offset); //instrp++; break; } case cnv_POP: stack.Pop(); break; case cnv_SWAP: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg1); stack.Push(arg2); } break; case cnv_PUSHBP: //Debug.Log("Instruction:" + instrp +" Pushing Base Ptr :" + stack.basep + " => " + stack.stackptr); stack.Push(stack.basep); break; case cnv_POPBP: { int arg1 = stack.Pop(); stack.basep = arg1; } break; case cnv_SPTOBP: stack.basep = stack.get_stackp(); break; case cnv_BPTOSP: stack.set_stackp(stack.basep); break; case cnv_ADDSP: { int arg1 = stack.Pop(); /// fill reserved stack space with dummy values for(int i=0; i<=arg1; i++) stack.Push(0); //stack.set_stackp(stack.stackptr+arg1); } break; case cnv_FETCHM: { //Debug.Log("Instruction:" + instrp +" Fetching address :" + stack.TopValue + " => " + stack.at(stack.TopValue)); int arg1 = stack.at(stack.Pop()); //fetch_value(arg1); stack.Push(arg1); } break; case cnv_STO: { int value = stack.Pop(); //int value = stack.at(stack.stackptr-1); int index = stack.Pop(); //int index = stack.at(stack.stackptr-2); //store_value(arg2,arg1); stack.Set(index,value); } break; case cnv_OFFSET: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); arg1 += arg2 - 1 ; //Debug.Log("Instruction:" + instrp +" Offset pushed : " + arg1 + " => " + stack.stackptr); stack.Push(arg1); } break; case cnv_START: // do nothing break; case cnv_SAVE_REG: { int arg1 = stack.Pop(); result_register = arg1; } break; case cnv_PUSH_REG: //Debug.Log("instr = " +instrp + " saving result " + result_register + " to " + stack.stackptr ); //Debug.Log("Instruction:" + instrp +" Pushing Result :" + result_register + " => " + stack.stackptr); stack.Push(result_register); break; case cnv_EXIT_OP: // finish processing (we still might be in some sub function) finished = true; break; case cnv_SAY_OP: { int arg1 = stack.Pop(); yield return StartCoroutine(say_op(arg1)); } break; case cnv_RESPOND_OP: // do nothing break; case cnv_OPNEG: { int arg1 = stack.Pop(); stack.Push(-arg1); } break; default: // unknown opcode //throw ua_ex_unk_opcode; break; } // process next instruction ++instrp; if (instrp>conv[currConv].instuctions.GetUpperBound(0)) { finished=true; } } yield return StartCoroutine(EndConversation(npc)); } case cnv_TSTGT: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2 > arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 > arg1); break; } case cnv_TSTGE: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2 >= arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 >= arg1); break; } case cnv_TSTLT: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2 < arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 < arg1); break; } case cnv_TSTLE: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); if (arg2 <= arg1) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 <= arg1); break; } case cnv_TSTEQ: { if (stack.Pop() == stack.Pop()) { stack.Push(1); } else { stack.Push(0); } break; } case cnv_TSTNE: { //int val1 = stack.Pop(); //int val2 = stack.Pop(); if (stack.Pop() != stack.Pop()) //if ((val1) != (val2)) { stack.Push(1); } else { stack.Push(0); } //stack.Push(arg2 != arg1); break; } case cnv_JMP: {//Debug.Log("instr = " +stack.instrp + " JMP to " + conv[currConv].instuctions[stack.instrp+1]); stack.instrp = conv[currConv].instuctions[stack.instrp + 1] - 1; break; } case cnv_BEQ: { //int origInstrp= stack.instrp; if (stack.Pop() == 0) { stack.instrp += conv[currConv].instuctions[stack.instrp + 1]; } else { stack.instrp++; } //Debug.Log("BEQ to " + stack.instrp + " at " + origInstrp); break; } case cnv_BNE: { //int origInstrp= stack.instrp; if (stack.Pop() != 0) { stack.instrp += conv[currConv].instuctions[stack.instrp + 1]; } else { stack.instrp++; } //Debug.Log("BNE to " + stack.instrp + " at " + origInstrp); break; } case cnv_BRA: { //int origInstrp= stack.instrp; stack.instrp += conv[currConv].instuctions[stack.instrp + 1]; //Debug.Log("BRA to " + stack.instrp + " at " + origInstrp); /*int offset = conv[currConv].instuctions[stack.instrp+1]; if (offset >0) { stack.instrp += offset; } else { stack.instrp += offset; }*/ break; } case cnv_CALL: // local function { //int origInstrp= stack.instrp; // stack value points to next instruction after call //Debug.Log("inst=" + stack.instrp + "stack ptr" + stack.stackptr + " new inst=" + (conv[currConv].instuctions[stack.instrp+1]-1)); stack.Push(stack.instrp + 1); stack.instrp = conv[currConv].instuctions[stack.instrp + 1] - 1; stack.call_level++; //Debug.Log("CALL to " + stack.instrp + " at " + origInstrp); break; } case cnv_CALLI: // imported function { int arg1 = conv[currConv].instuctions[++stack.instrp]; for (int i = 0; i <= conv[currConv].functions.GetUpperBound(0); i++) { if ((conv[currConv].functions[i].ID_or_Address == arg1) && (conv[currConv].functions[i].import_type == import_function)) { //Debug.Log("Calling function " + arg1 + " which is currently : " + conv[currConv].functions[i].functionName ); yield return StartCoroutine(run_imported_function(conv[currConv].functions[i], npc)); break; } } break; } case cnv_RET: { if (--stack.call_level < 0) { // conversation ended finished = true; } else { //Debug.Log("instr = " +stack.instrp + " returning to " + arg1); stack.instrp = stack.Pop(); } break; } case cnv_PUSHI: { //Debug.Log("Instruction:" + stack.instrp +" Pushing Immediate value :" +conv[currConv].instuctions[stack.instrp+1] + " => " + stack.stackptr); stack.Push(conv[currConv].instuctions[++stack.instrp]); break; } case cnv_PUSHI_EFF: { int offset = conv[currConv].instuctions[stack.instrp + 1]; if (offset >= 0) { stack.Push(stack.basep + offset); } else { offset--; //to skip over base ptr; stack.Push(stack.basep + offset); } stack.instrp++; break; } case cnv_POP: { stack.Pop(); break; } case cnv_SWAP: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); stack.Push(arg1); stack.Push(arg2); break; } case cnv_PUSHBP: { //Debug.Log("Instruction:" + stack.instrp +" Pushing Base Ptr :" + stack.basep + " => " + stack.stackptr); stack.Push(stack.basep); break; } case cnv_POPBP: { int arg1 = stack.Pop(); stack.basep = arg1; break; } case cnv_SPTOBP: { stack.basep = stack.stackptr; break; } case cnv_BPTOSP: { stack.set_stackp(stack.basep); break; } case cnv_ADDSP: { int arg1 = stack.Pop(); /// fill reserved stack space with dummy values for (int i = 0; i <= arg1; i++) stack.Push(0); //stack.Set_stackp(stack.stackptr+arg1);//This will probably cause problems down the line.... //stack.Set_stackp(stack.stackptr+arg1); break; } case cnv_FETCHM: { //Debug.Log("Instruction:" + stack.instrp +" Fetching address :" + stack.TopValue + " => " + stack.at(stack.TopValue)); //stack.at(arg1); stack.Push(stack.at(stack.Pop())); break; } //stack.Pop(); //int index= stack.at(stack.Pop()); //int index= stack.at( stack.at( stack.stackptr-2 ) ); result_register = get_quest(args[0]); break; } { PrintImportedVariable(index, value); } stack.Set(index, value); break; } case cnv_OFFSET: { int arg1 = stack.Pop(); int arg2 = stack.Pop(); //Debug.Log("Offset " +arg1 + " & " + arg2 + "= " + (arg1+arg2-1)); arg1 += arg2 - 1; //Debug.Log("Instruction:" + stack.instrp +" Offset pushed : " + arg1 + " => " + stack.stackptr); stack.Push(arg1); break; } int val2 = stack.Pop(); int val3 = stack.Pop(); int val4 = stack.Pop(); result_register = x_skills(val1,val2,val3,val4);//Or the other way around. break; } case cnv_SAVE_REG: { stack.result_register = stack.Pop(); break; } case cnv_PUSH_REG: { stack.Push(stack.result_register); break; } case cnv_EXIT_OP: { // finish processing (we still might be in some sub function) //int arg1=stack.Pop(); if (GameWorldController.instance.playerUW.isFemale) { result_register=stack.at(args[1]); //2 } else { result_register=stack.at(args[0]);//1 } break; } case cnv_RESPOND_OP: {// do nothing Debug.Log("Respond_Op"); stack.Pop(); //stack.Pop(); int arg1=stack.Pop(); result_register=Random.Range(1,stack.at(arg1)+1); result_register=Random.Range(1,arg1+1); break; } //stack.Pop(); int arg1 = stack.at(stack.stackptr-2); int arg2 = stack.at(stack.stackptr-3); result_register= show_inv(arg1,arg2); break; } if (stack.instrp > conv[currConv].instuctions.GetUpperBound(0)) { finished = true; stack.Pop(); int arg1= stack.Pop(); int arg2= stack.Pop(); result_register = give_to_npc(npc, stack.at(arg1), stack.at(arg2)); break; } /// Ends the conversation. /// </summary> public IEnumerator EndConversation(NPC npc) { int arg = stack.at(stack.stackptr-2);//ptr to value result_register = take_from_npc(npc, stack.at(arg)); break; } if (ConversationVM.CurrentConversation == GameWorldController.instance.bGlobals[c].ConversationNo) { GameWorldController.instance.bGlobals[c].Globals[NPCTalkedToIndex] = 1; for (int x = 0; x <= GameWorldController.instance.bGlobals[c].Globals.GetUpperBound(0); x++) { //Copy Private variables GameWorldController.instance.bGlobals[c].Globals[x] = stack.at(x); } break; } } int maxAddress = 0;//where does the imported memory end //Copy back npc related variables that need to update. Eg attitude. Talked to etc. for (int i = 0; i <= conv[currConv].functions.GetUpperBound(0); i++) { if (conv[currConv].functions[i].import_type == import_variable) { int address = conv[currConv].functions[i].ID_or_Address; if (address > maxAddress) { maxAddress = address; } switch (conv[currConv].functions[i].functionName.ToLower()) { case "npc_talkedto": npc.npc_talkedto = 1; break; //npc.npc_talkedto = stack.at(address);break; case "npc_gtarg": npc.npc_gtarg = (short)stack.at(address); break; case "npc_attitude": npc.npc_attitude = (short)stack.at(address); break; case "npc_goal": npc.npc_goal = (short)stack.at(address); break; case "npc_power": npc.npc_power = (short)stack.at(address); break; case "npc_arms": npc.npc_arms = (short)stack.at(address); break; case "npc_hp": npc.npc_hp = (short)stack.at(address); break; case "npc_health": npc.npc_health = (short)stack.at(address); break; case "npc_hunger": npc.npc_hunger = (short)stack.at(address); break; case "npc_whoami": npc.npc_whoami = (short)stack.at(address); break; case "npc_yhome": npc.npc_yhome = (short)stack.at(address); break; case "npc_xhome": npc.npc_xhome = (short)stack.at(address); break; } } } if (_RES == GAME_UW2) {//Hack to fix quest flag settings for garg if (currConv == 5) { Quest.instance.QuestVariables[0] = stack.at(31); } } ClearConversationOptions(); ///Give movement back to the player UWCharacter.Instance.playerMotor.enabled = true; Container cn = UWCharacter.Instance.playerInventory.currentContainer; ///Return any items in the trade area to their owner for (int i = 0; i <= TradeSlot.TradeSlotUBound; i++) { TradeSlot npcSlot = UWHUD.instance.playerTrade[i]; if (npcSlot.objectInSlot != null) {///Moves the object to the players container or to the ground if (Container.GetFreeSlot(cn) != -1)//Is there space in the container. { npc.GetComponent<Container>().RemoveItemFromContainer(npcSlot.objectInSlot); cn.AddItemToContainer(npcSlot.objectInSlot); GameObject itemAtSlot = npcSlot.GetGameObjectInteraction().gameObject; itemAtSlot.transform.parent = GameWorldController.instance.InventoryMarker.transform; GameWorldController.MoveToInventory(itemAtSlot); npcSlot.clear(); UWCharacter.Instance.GetComponent<PlayerInventory>().Refresh(); } else { //GameObject demanded = GameObject.Find(npcSlot.objectInSlot); npc.GetComponent<Container>().RemoveItemFromContainer(npcSlot.objectInSlot); case "find_inv": { int[] args=argsArray(); result_register = find_inv(npc, args[0], args[1]); break; } } } } ///Return any items in the trade area to their owner for (int i = 0; i <= TradeSlot.TradeSlotUBound; i++) { UWHUD.instance.npcTrade[i].clear(); } args[2]= stack.at(stack.stackptr-4);//ptr to value args[3]= stack.at(stack.stackptr-5);//ptr to value //int[] args=argsArray(); result_register = identify_inv(args[0],args[1],args[2],args[3]) ; break; } UWHUD.instance.Conversation_tl.Clear(); UWHUD.instance.MessageScroll.Clear(); UWCharacter.InteractionMode = UWCharacter.InteractionModeTalk; if (MusicController.instance != null) { MusicController.instance.InMap = false; } if (CurrentObjectInHand != null) { UWCharacter.InteractionMode = UWCharacter.InteractionModePickup; } StopAllCoroutines(); ///Resets the UI UWHUD.instance.RefreshPanels(UWHUD.HUD_MODE_INVENTORY); //Process scheduled events if ((_RES == GAME_UW2) && (EditorMode == false)) { if (GameWorldController.instance.events != null) { GameWorldController.instance.events.ProcessEvents(); } } if (SettingUpFight == false) { Quest.instance.FightingInArena = false;//Clear the arena flag } if (Teleport) { if (TeleportLevel == GameWorldController.instance.LevelNo) {//stay on this level float targetX = (float)TeleportTileX * 1.2f + 0.6f; float targetY = (float)TeleportTileY * 1.2f + 0.6f; float Height = ((float)(CurrentTileMap().GetFloorHeight(TeleportTileX, TeleportTileY))) * 0.15f; UWCharacter.Instance.transform.position = new Vector3(targetX, Height + 0.1f, targetY); UWCharacter.Instance.TeleportPosition = UWCharacter.Instance.transform.position; } else { UWCharacter.Instance.JustTeleported = true; UWCharacter.Instance.teleportedTimer = 0f; UWCharacter.Instance.playerMotor.movement.velocity = Vector3.zero; GameWorldController.instance.SwitchLevel((short)TeleportLevel, (short)TeleportTileX, (short)TeleportTileY); } } } void ImportVariableMemory(NPC npc) { //Copy the stored values from glob first for (int c = 0; c <= GameWorldController.instance.bGlobals.GetUpperBound(0); c++) { if (npc.npc_whoami == GameWorldController.instance.bGlobals[c].ConversationNo) { //cnv.privateVariables = new int[GameWorldController.instance.bGlobals[c].Globals.GetUpperBound(0)+1]; for (int x = 0; x <= GameWorldController.instance.bGlobals[c].Globals.GetUpperBound(0); x++) { //Copy Private variables //cnv.privateVariables[x] = GameWorldController.instance.bGlobals[c].Globals[x]; stack.Set(x, GameWorldController.instance.bGlobals[c].Globals[x]); yield return StartCoroutine(WaitForInput()); int AnswerIndex=stack.at(Start+PlayerAnswer-1); yield return StartCoroutine(say_op(AnswerIndex, PC_SAY)); result_register = PlayerAnswer; yield return 0; } for (int i = 0; i <= conv[currConv].functions.GetUpperBound(0); i++) { if (conv[currConv].functions[i].import_type == import_variable) { int address = conv[currConv].functions[i].ID_or_Address; switch (conv[currConv].functions[i].functionName.ToLower()) { case "game_mins": stack.Set(address, GameClock.game_min()); break; case "game_days": stack.Set(address, GameClock.day()); break; case "game_time"://What shou //stack.Set(address,GameClock.); stack.Set(address, GameClock.second()); break; case "riddlecounter": stack.Set(address, 0); break; case "dungeon_level": stack.Set(address, GameWorldController.instance.LevelNo + 1); break; case "npc_name": stack.Set(address, StringController.instance.AddString(conv[currConv].StringBlock, StringController.instance.GetString(7, npc.npc_whoami + 16))); break; case "npc_level": stack.Set(address, npc.npc_level); break; case "npc_talkedto": NPCTalkedToIndex = address; stack.Set(address, npc.npc_talkedto); break; case "npc_gtarg": stack.Set(address, npc.npc_gtarg); break; case "npc_attitude": stack.Set(address, npc.npc_attitude); break; case "npc_goal": stack.Set(address, npc.npc_goal); break; case "npc_power": stack.Set(address, npc.npc_power); break; case "npc_arms": stack.Set(address, npc.npc_arms); break; case "npc_hp": stack.Set(address, npc.npc_hp); break; case "npc_health": stack.Set(address, npc.npc_health); break; case "npc_hunger": //tmp= StringController.instance.GetString (stringcontrol.GetString(conv[currConv].StringBlock,bablf_array[bablf_ans-1]); //yield return StartCoroutine(say (tmp,PC_SAY)); yield return StartCoroutine(say_op(bablf_array[bablf_ans-1])); //result_register=bablf_array[bablf_ans-1]; result_register=PlayerAnswer; yield return 0; } { if (UWCharacter.Instance.isFemale) { stack.Set(address, 1); } else { stack.Set(address, 0); } break; } //case "play_drawn": case "play_poison": stack.Set(address, UWCharacter.Instance.play_poison); break; case "play_name": stack.Set(address, StringController.instance.AddString(conv[currConv].StringBlock, UWCharacter.Instance.CharName)); break; //case "new_player_exp": case "play_level": stack.Set(address, UWCharacter.Instance.CharLevel); break; case "play_mana": stack.Set(address, UWCharacter.Instance.PlayerMagic.CurMana); break; case "play_hp": stack.Set(address, UWCharacter.Instance.CurVIT); break; //case "play_power": //case "play_arms": // case "play_health": case "play_hunger": stack.Set(address, UWCharacter.Instance.FoodLevel); break; default: //Debug.Log("unimplemented memory import " + conv[currConv].functions[i].functionName); break; } } } } IEnumerator say_op(int arg1) { yield return StartCoroutine(say_op(arg1, NPC_SAY)); yield return 0; } IEnumerator say_op(int arg1, int PrintType) { yield return StartCoroutine(say_op(StringController.instance.GetString(conv[currConv].StringBlock, arg1), PrintType)); yield return 0; } IEnumerator say_op(string text, int PrintType) { //Debug.Log("Saying :" + text); yield return new WaitForSecondsRealtime(0.2f); if (text.Trim() == "") { yield return 0; } if (text.Contains("@")) { text = TextSubstitute(text); } string[] Lines = text.Split(new string[] { "\n" }, System.StringSplitOptions.None); for (int s = 0; s <= Lines.GetUpperBound(0); s++) {//Lines if (Lines[s].Trim() != "") { string[] Paragraphs = Lines[s].Split(new string[] { "\\m" }, System.StringSplitOptions.None); for (int i = 0; i <= Paragraphs.GetUpperBound(0); i++) { string Markup = ""; switch (PrintType) { case PC_SAY: Markup = "<color=red>"; break;//[FF0000] case PRINT_SAY: Markup = "<color=purple>"; break;//[000000] default: Markup = "<color=black>"; break;//[00FF00] } // UWHUD.instance.Conversation_tl.Add(Markup + Paragraphs[i] + "</color>"); //\n UWHUD.instance.Conversation_tl.Add(Paragraphs[i],Markup); //\n if (i < Paragraphs.GetUpperBound(0)) { //UWHUD.instance.Conversation_tl.Add("<color=white>MORE</color>"); UWHUD.instance.Conversation_tl.Add("MORE", "<color=white>"); yield return StartCoroutine(WaitForMore()); } } } } yield return new WaitForSecondsRealtime(0.2f); yield return 0; } string TextSubstitute(string input) { //X: source of variable to substitute, one of these: GSP //G: game global variable //S: stack variable //P: pointer variable //Y: type of variable, one of these: SI //S: value is a string number into current string block //I: value is an integer value //<num>: decimal value //<extension>: format: C<number>: use array index <number> string RegExForFindingReplacements = "([@][GSP][SI])([0-9]*)([S][I])?([0-9]*)?([C][0-9]*)?"; //"(@)([GSP])([SI])([0-9])*([S][I][0-9]*)*([C][0-9])*"; //string RegExForFindingReplacementsTypes = "(@)([GSP])([SI])"; MatchCollection matches = Regex.Matches(input, RegExForFindingReplacements); for (int sm = 0; sm < matches.Count; sm++) { string ReplacementString = matches[sm].Value; if (matches[sm].Success) { string ReplacementType = ""; int ReplacementValue = 0; string OffsetType = ""; int OffsetValue = 0; string formatting = ""; string FoundString = ""; for (int sg = 0; sg < matches[sm].Groups.Count; sg++) { if (matches[sm].Groups[sg].Success) { switch (sg) { case 1: //Replacement Type ReplacementType = matches[sm].Groups[sg].Value; break; case 2: //Replacement value { int val = 0; if (int.TryParse(matches[sm].Groups[sg].Value, out val)) { ReplacementValue = val; } else { ReplacementValue = 0; } break; } case 3: //Offset Type (should only be SI?) OffsetType = matches[sm].Groups[sg].Value; break; case 4: //Offset value { int val = 0; if (int.TryParse(matches[sm].Groups[sg].Value, out val)) { OffsetValue = val; } else { OffsetValue = 0; } break; } case 5: //formatting specifier (unimplemented formatting = matches[sm].Groups[sg].Value; break; } } //Debug.Log("group " + matches[sm].Groups[sg].Success + " " + matches[sm].Groups[sg].Value); } //Now replace switch (ReplacementType) { case "@GS": //Global string. { FoundString = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(ReplacementValue)); break; } case "@GI": //Global integer { Debug.Log("@GI String replacement (" + ReplacementValue + ")");//Sometimes this works with val+1 other times val!! FoundString = stack.at(ReplacementValue).ToString(); break; } case "@SS": //Stack string { if (OffsetValue != 0) { int actualptr = stack.at(stack.basep + OffsetValue); FoundString = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(stack.basep + actualptr)); } else { FoundString = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(stack.basep + ReplacementValue)); } break; } case "@SI": //Stack integer {//TODO: this +1 behaves inconsistently. UW1 or UW2 difference??? if (_RES == GAME_UW2) { FoundString = stack.at(stack.basep + ReplacementValue).ToString(); } else { FoundString = stack.at(stack.basep + ReplacementValue + 1).ToString();//Skip over 1 for basepointer } break; } case "@PS": //Pointer string { FoundString = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(stack.at(stack.basep + ReplacementValue))); break; } case "@PI": //Pointer integer { if (ReplacementValue < 0) { FoundString = stack.at(stack.at(stack.basep + ReplacementValue - 1)).ToString();//-1 for params } else { FoundString = stack.at(stack.at(stack.basep + ReplacementValue)).ToString(); } break; } } if (FoundString != "") { input = input.Replace(ReplacementString, FoundString); } } } return input; } /* string TextSubstitute(string input) { //X: source of variable to substitute, one of these: GSP //G: game global variable //S: stack variable //P: pointer variable //Y: type of variable, one of these: SI //S: value is a string number into current string block //I: value is an integer value //<num>: decimal value //<extension>: format: C<number>: use array index <number> string regexForStringReplacement="@[GSP][SI]([-+]?[0-9]*\\.?[0-9]+)"; string regexForStringReplacementType="@[GSP][SI]"; string regexForStringReplacementValue="([-+]?[0-9]*\\.?[0-9]+)"; MatchCollection matches=Regex.Matches(input, regexForStringReplacement); for (int s = 0; s<matches.Count; s++) { if (matches[s].Success) { string ReplacementString=matches[s].Groups[0].Value; Match ReplacementValue = Regex.Match(ReplacementString, regexForStringReplacementValue); if (ReplacementValue.Success) { int value = int.Parse(ReplacementValue.Groups[0].Value); //Try and find what type of replacement this is Match ReplacementType = Regex.Match(ReplacementString, regexForStringReplacementType); string FoundString=""; if (ReplacementType.Success) { switch (ReplacementType.Groups[0].Value) { case "@GS": //Global string. { FoundString= StringController.instance.GetString(conv[currConv].StringBlock,stack.at(value)); break; } case "@GI": //Global integer { Debug.Log("@GI String replacement (" + value + ")");//Sometimes this works with val+1 other times val!! //Shak works with val + 1 /*if (value < conv[currConv].NoOfMemorySlots - conv[currConv].NoOfImportedGlobals) { FoundString= stack.at(value+1).ToString(); } else {*/ /* here FoundString= stack.at(value).ToString(); //} //FoundString= stack.at(value).ToString(); break; } case "@SS": //Stack string {//TODO: Miranda's conversation in UW2 where she tells you about the lines of power that are cut is of format @SS1SI10 FoundString= StringController.instance.GetString(conv[currConv].StringBlock,stack.at(stack.basep+value)); break; } case "@SI": //Stack integer {//TODO: this +1 behaves inconsistently. UW1 or UW2 difference??? if (_RES==GAME_UW2) { FoundString= stack.at(stack.basep+value).ToString(); } else { FoundString= stack.at(stack.basep+value+1).ToString();//Skip over 1 for basepointer } break; } case "@PS": //Pointer string { FoundString= StringController.instance.GetString(conv[currConv].StringBlock,stack.at(stack.at(stack.basep+value))); break; } case "@PI": //Pointer integer { if (value <0) { FoundString= stack.at(stack.at(stack.basep+value-1)).ToString();//-1 for params } else { FoundString= stack.at(stack.at(stack.basep+value)).ToString(); } break; } } if (FoundString!="") { //Debug.Log("To Replace "+ ReplacementString + " Type=" + ReplacementType.Groups[0].Value + " value=" + value + " replacing with " + FoundString); input=input.Replace(ReplacementString,FoundString); } } } } } return input.Replace("C2",""); }*/ IEnumerator run_imported_function(ImportedFunctions func, NPC npc) { //if (func.functionName!="babl_menu") //{ // Debug.Log("Calling " + func.functionName + " at " + stack.instrp); //} switch (func.functionName.ToLower()) { case "babl_menu": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value yield return StartCoroutine(babl_menu(args[0])); break; } case "babl_fmenu": {///FMENU appears bugged. Causes stackptr issues further down the line (see conversation 88 and door opening) //stack.Pop(); int start = stack.at(stack.stackptr - 2);//Not sure if this is correct for all conversations but lets try it anyway! int flagstart = stack.at(stack.stackptr - 3); yield return StartCoroutine(babl_fmenu(start, flagstart)); break; } case "babl_ask": { yield return StartCoroutine(babl_ask()); break; } case "get_quest": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value //int[] args = argsArray(); //stack.Pop(); //int index= stack.at(stack.Pop()); //int index= stack.at( stack.at( stack.stackptr-2 ) ); stack.result_register = get_quest(stack.at(args[0])); break; } case "set_quest": { //int[] args = argsArray(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value //int val = stack.Pop(); //int index= stack.at(stack.Pop()); //stack.at( stack.at( stack.stackptr-5 ) ); //stack.at( stack.at( stack.stackptr-4 ) ) ; set_quest(stack.at(args[0]), stack.at(args[1]));//Or the other way around. break; } case "print": {//TODO:review use of argsarray //int[] args = argsArray(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value yield return StartCoroutine(say_op(stack.at(args[0]), PRINT_SAY)); break; } case "x_skills": { //int val1 = stack.Pop(); //int val2 = stack.Pop(); //int val3 = stack.Pop(); //int val4 = stack.Pop(); int[] args = new int[4]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value stack.result_register = x_skills(stack.at(args[0]), stack.at(args[1]), stack.at(args[2]), stack.at(args[3]));//Or the other way around. break; } case "set_likes_dislikes": { //stack.Pop(); //int index1= stack.Pop(); //int index2= stack.Pop(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value set_likes_dislikes(stack.at(args[0]), stack.at(args[1])); break; } case "sex": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value stack.result_register = sex(stack.at(args[0]), stack.at(args[1])); break; } case "random": { // int[] args = argsArray(); //stack.Pop(); //stack.Pop(); //int arg1=stack.Pop(); //PlayerAnswer = int NpcAnswer=Random.Range (0,2); result_register= NpcAnswer; if (NpcAnswer==1) { yield return StartCoroutine (say_op (arg5)); case "show_inv": { //stack.Pop(); int arg1 = stack.at(stack.stackptr - 2); int arg2 = stack.at(stack.stackptr - 3); stack.result_register = show_inv(arg1, arg2); break; } case "give_to_npc": { //stack.Pop(); //int arg1= stack.Pop(); //int arg2= stack.Pop(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value stack.result_register = give_to_npc(npc, args[0], stack.at(args[1])); break; } case "take_from_npc": { //stack.Pop(); //int arg1 = stack.Pop(); int arg = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = take_from_npc(npc, stack.at(arg)); break; } case "setup_to_barter": { //stack.Pop(); setup_to_barter(npc); break; } case "do_offer": {//TODO:review use of argsarray //int noOfArgs=stack.Pop(); //int[] args = argsArray(); switch (stack.TopValue)//(args.GetUpperBound(0)) { case 7: { int[] args = new int[7]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value args[4] = stack.at(stack.stackptr - 6);//ptr to value args[5] = stack.at(stack.stackptr - 7);//ptr to value args[6] = stack.at(stack.stackptr - 8);//ptr to value yield return StartCoroutine(do_offer(npc, stack.at(args[0]), stack.at(args[1]), stack.at(args[2]), stack.at(args[3]), stack.at(args[4]), stack.at(args[5]), stack.at(args[6]))); break; } case 5: { int[] args = new int[5]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value args[4] = stack.at(stack.stackptr - 5);//ptr to value yield return StartCoroutine(do_offer(npc, stack.at(args[0]), stack.at(args[1]), stack.at(args[2]), stack.at(args[3]), stack.at(args[4]), -1, -1)); break; } //Move the players items back to his inventory; RestorePCsInventory (npc); result_register=DemandResult; } break; } case "do_demand": {//TODO:review use of argsarray //int[] args = argsArray(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value yield return StartCoroutine(do_demand(npc, stack.at(args[0]), stack.at(args[1]))); break; } case "do_judgement": { //stack.Pop(); yield return StartCoroutine(do_judgement(npc)); break; } case "do_decline": { do_decline(npc); break; } case "gronk_door": {//TODO:review use of argsarray //int[] args = argsArray(); //stack.Pop();//no of args int[] args = new int[3]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value stack.result_register = gronk_door(stack.at(args[0]), stack.at(args[1]), stack.at(args[2])); break; } case "x_obj_stuff": {//This is totally wrong! //x_obj_stuff( 9,locals[9], locals[8], locals[7], locals[2], locals[6], locals[5], locals[4], locals[3], param2 ); //int[] args = argsArrayPtr(); // int[] args=new int[4]; //stack.Pop();//no of args int[] args = new int[9]; //stack.Pop();//no of args args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value args[4] = stack.at(stack.stackptr - 6);//ptr to value args[5] = stack.at(stack.stackptr - 7);//ptr to value args[6] = stack.at(stack.stackptr - 8);//ptr to value args[7] = stack.at(stack.stackptr - 9);//ptr to value args[8] = stack.at(stack.stackptr - 10);//ptr to value x_obj_stuff(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break; } case "find_inv": {//TODO:review use of argsarray //int[] args=argsArray(); int[] args = new int[2]; //stack.Pop();//no of args args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value stack.result_register = find_inv(npc, stack.at(args[0]), stack.at(args[1])); break; } case "identify_inv": { //Pop No of args. //stack.Pop(); //pop that array ptr // identify_inv( 4,locals, 17, 15, 16, locals[6+i] ); int[] args = new int[4]; //stack.Pop();//no of args args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value //int[] args=argsArray(); stack.result_register = identify_inv(args[0], args[1], args[2], args[3]); break; } case "contains": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value stack.result_register = contains(args[0], args[1]); break; } case "set_race_attitude": { //TODO:review use of argsarray //int[] args=argsArray(); int[] args = new int[3]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value set_race_attitude(npc, stack.at(args[0]), stack.at(args[1]), stack.at(args[2])); break; } case "set_attitude": {//TODO:review use of argsarray //int[] args=argsArray(); int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value set_attitude(stack.at(args[0]), stack.at(args[1])); break; } case "compare": {//TODO:review use of argsarray int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value stack.result_register = compare(stack.at(args[0]), stack.at(args[1])); break; } case "count_inv": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = count_inv(stack.at(args[0])); break; } case "remove_talker": { remove_talker(npc); } else { Debug.Log (instrp+ " Unable to find doorcontrol to gronk " + " at " + tileX + " " + tileY); return 0; } give_ptr_npc(npc, stack.at(args[0]), args[1]); break; } case "take_from_npc_inv": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = take_from_npc_inv(npc, stack.at(args[0])); break; } case "take_id_from_npc": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = take_id_from_npc(npc, stack.at(args[0])); break; } case "find_barter": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = find_barter(stack.at(args[0])); break; } case "length": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = length(stack.at(args[0])); break; } case "find_barter_total": { int[] args = new int[4]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value stack.result_register = find_barter_total(args[0], args[1], args[2], stack.at(args[3])); break; } case "do_inv_create": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = do_inv_create(npc, stack.at(args[0])); break; } case "place_object": { int[] args = new int[3]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value place_object(stack.at(args[0]), stack.at(args[1]), stack.at(args[2])); break; } case "do_inv_delete": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value do_inv_delete(npc, stack.at(args[0])); break; } case "x_traps": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value if (stack.at(args[0]) == 10001) { stack.result_register = x_traps(stack.at(args[0]), stack.at(args[1])); } else { x_traps(stack.at(args[0]), stack.at(args[1])); } break; } case "switch_pic": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value switch_pic(stack.at(args[0])); break; } case "x_clock": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value x_clock(stack.at(args[0]), stack.at(args[1])); break; } case "x_exp": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value x_exp(stack.at(args[0])); break; } case "check_inv_quality": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value stack.result_register = check_inv_quality(stack.at(args[0])); break; } case "set_inv_quality": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value set_inv_quality(stack.at(args[0]), stack.at(args[1])); break; } case "x_obj_pos": { int[] args = new int[5]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value args[4] = stack.at(stack.stackptr - 5);//ptr to value x_obj_pos(stack.at(args[0]), stack.at(args[1]), stack.at(args[2]), stack.at(args[3]), stack.at(args[4])); break; } case "teleport_talker": { int[] args = new int[2]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value teleport_talker(npc, stack.at(args[0]), stack.at(args[1])); break; } case "babl_hack": { int typeofbablhack = stack.at(stack.at(stack.stackptr - 2)); switch (typeofbablhack)//babl_hack mode { case 0://Challenge a fighter { SettingUpFight = true; Quest.instance.ArenaOpponents[0] = npc.objInt().BaseObjectData.index; Quest.instance.FightingInArena = true; break; } case 1://Are you in a fight { if (Quest.instance.FightingInArena) { stack.result_register = 1; } else { stack.result_register = 0; } break; } case 2://Set up arena fight. { int[] args = new int[4]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value args[3] = stack.at(stack.stackptr - 5);//ptr to value babl_hackSetUpFight(stack.at(args[0]), stack.at(args[1]), stack.at(args[2]), stack.at(args[3])); break; } case 3://Jospur arena debt { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value babl_hackJospurDebt(stack.at(args[0])); break; } default: { Debug.Log("Unimplemented babl hack " + typeofbablhack); break; } } break; } case "teleport_player": { int[] args = new int[3]; args[0] = stack.at(stack.stackptr - 2);//ptr to value args[1] = stack.at(stack.stackptr - 3);//ptr to value args[2] = stack.at(stack.stackptr - 4);//ptr to value teleport_player(stack.at(args[0]), stack.at(args[1]), stack.at(args[2])); break; } case "pause": { int[] args = new int[1]; args[0] = stack.at(stack.stackptr - 2);//ptr to value yield return StartCoroutine(pause(stack.at(args[0]))); break; } default: { Debug.Log("Conversation : " + npc.npc_whoami + "unimplemented function " + func.functionName + " instr at " + stack.instrp); break; } } yield return 0; } /// <summary> /// Waits for a number of seconds /// </summary> /// <param name="waittime"></param> /// <returns></returns> public IEnumerator pause(int waittime) { yield return new WaitForSecondsRealtime((float)waittime); } public IEnumerator babl_menu(int Start) { UWHUD.instance.MessageScroll.Clear(); yield return new WaitForSecondsRealtime(0.2f); usingBablF = false; MaxAnswer = 0; int j = 1; ClearConversationOptions(); for (int i = Start; i <= stack.Upperbound(); i++) { if (stack.at(i) > 0) { string TextLine = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(i)); if (TextLine.Contains("@")) { TextLine = TextSubstitute(TextLine); } UWHUD.instance.ConversationOptions[j - 1].SetText(j + "." + TextLine + ""); UWHUD.instance.EnableDisableControl(UWHUD.instance.ConversationOptions[j - 1], true); j++; MaxAnswer++; } else { break; } } yield return StartCoroutine(WaitForInput()); int AnswerIndex = stack.at(Start + PlayerAnswer - 1); yield return StartCoroutine(say_op(AnswerIndex, PC_SAY)); stack.result_register = PlayerAnswer; yield return 0; } /// <summary> /// Removes and disables conversation option text /// </summary> private static void ClearConversationOptions() { for (int i = 0; i <= UWHUD.instance.ConversationOptions.GetUpperBound(0); i++) { UWHUD.instance.ConversationOptions[i].SetText(""); UWHUD.instance.EnableDisableControl(UWHUD.instance.ConversationOptions[i], false); } } /// <summary> /// Dialog menu with choices that may or may not show based on the flags /// </summary> /// <param name="unknown">Unknown.</param> /// <param name="localsArray">Array of local variables from the conversation</param> /// <param name="Start">Index to start taking values from the array</param> /// <param name="flagIndex">Index to start flagging if a value is allowed from the array</param> public IEnumerator babl_fmenu(int Start, int flagIndex) { ClearConversationOptions(); UWHUD.instance.MessageScroll.Clear(); yield return new WaitForSecondsRealtime(0.2f); usingBablF = true; for (int i = 0; i <= bablf_array.GetUpperBound(0); i++) {//Reset the answers array bablf_array[i] = 0; } int j = 1; MaxAnswer = 0; for (int i = Start; i <= stack.Upperbound(); i++) { if (stack.at(i) != 0) { if (stack.at(flagIndex++) != 0) { string TextLine = StringController.instance.GetString(conv[currConv].StringBlock, stack.at(i)); if (TextLine.Contains("@")) { TextLine = TextSubstitute(TextLine); } bablf_array[j - 1] = stack.at(i); //tmp = tmp + j++ + "." + StringController.instance.GetString(StringBlock,localsArray[i]) + "\n"; // UWHUD.instance.MessageScroll.Add(j++ + "." + TextLine + ""); UWHUD.instance.ConversationOptions[j - 1].SetText(j + "." + TextLine + ""); UWHUD.instance.EnableDisableControl(UWHUD.instance.ConversationOptions[j - 1], true); j++; MaxAnswer++; } } else { break; } } yield return StartCoroutine(WaitForInput()); yield return StartCoroutine(say_op(bablf_array[bablf_ans - 1], PC_SAY)); stack.result_register = PlayerAnswer; yield return 0; } /// <summary> /// Sets up for typed input /// </summary> public IEnumerator babl_ask() { PlayerTypedAnswer = ""; //tl_input.Set(">"); //PlayerInput.text = ">"; for (int j=0; j <= UWHUD.instance.ConversationOptions.GetUpperBound(0);j++) { UWHUD.instance.ConversationOptions[j].SetText(""); } UWHUD.instance.ConversationOptions[0].SetText(">"); InputField inputctrl = UWHUD.instance.InputControl; inputctrl.gameObject.SetActive(true); inputctrl.gameObject.GetComponent<InputHandler>().target = this.gameObject; inputctrl.gameObject.GetComponent<InputHandler>().currentInputMode = InputHandler.InputConversationWords; inputctrl.contentType = InputField.ContentType.Standard; inputctrl.text = ""; inputctrl.Select(); yield return StartCoroutine(WaitForTypedInput()); yield return StartCoroutine(say_op(PlayerTypedAnswer, PC_SAY)); inputctrl.text = ""; UWHUD.instance.MessageScroll.Clear(); stack.result_register = StringController.instance.AddString(conv[currConv].StringBlock, PlayerTypedAnswer); } /// <summary> /// Responds to player typed input submission. /// </summary> /// <param name="PlayerTypedAnswerIN">The string the player has typed</param> public static void OnSubmitPickup(string PlayerTypedAnswerIN) { InputField inputctrl = UWHUD.instance.InputControl; WaitingForTyping = false; inputctrl.gameObject.SetActive(false); PlayerTypedAnswer = PlayerTypedAnswerIN; } /// <summary> /// Waits for input in babl_menu and bablf_menu /// </summary> IEnumerator WaitForInput() { WaitingForInput = true; while (WaitingForInput) { yield return null; } } /// <summary> /// Waits for typed input from the player when in babl_ask /// </summary> IEnumerator WaitForTypedInput() { WaitingForTyping = true; while (WaitingForTyping) { UWHUD.instance.ConversationOptions[0].SetText(">" + UWHUD.instance.InputControl.text); yield return null; } } /// <summary> /// Processes key presses from the player when waiting for input. /// </summary> void OnGUI() { if (EnteringQty == true) { return; } if (WaitingForInput) { if (CurrentObjectInHand != null) { return; }//no conversation options allowed while holding an item if (Input.GetKeyDown(KeyCode.Alpha1)) { CheckAnswer(1); } else if (Input.GetKeyDown(KeyCode.Alpha2)) { CheckAnswer(2); } else if (Input.GetKeyDown(KeyCode.Alpha3)) { CheckAnswer(3); } else if (Input.GetKeyDown(KeyCode.Alpha4)) { CheckAnswer(4); } else if (Input.GetKeyDown(KeyCode.Alpha5)) { CheckAnswer(5); } else if (Input.GetKeyDown(KeyCode.Alpha6)) { CheckAnswer(6); } } else if (WaitingForMore) { if (Input.GetKeyDown(KeyCode.Space)) { WaitingForMore = false; } } } /// <summary> /// Checks the answer the player has entered to see if it in within the bounds of the valid options. /// Sets the PlayerAnswer variable for checking within the conversations /// </summary> /// <param name="AnswerNo">The answer number from the menu entered by the player</param> public void CheckAnswer(int AnswerNo) { if (usingBablF == false) { if ((AnswerNo > 0) && (AnswerNo <= MaxAnswer)) { PlayerAnswer = AnswerNo; WaitingForInput = false; } } else { if ((AnswerNo > 0) && (AnswerNo <= MaxAnswer)) { ///For babl_fmenus convert the answer using the bablf_array bablf_ans = AnswerNo; PlayerAnswer = bablf_array[AnswerNo - 1]; WaitingForInput = false; usingBablF = false; } } } /// <summary> /// Gets the quest variable. /// </summary> /// <returns>The quest.</returns> /// <param name="unk">Unk.</param> /// <param name="QuestNo">Quest no to lookup</param> public int get_quest(int QuestNo) { if (_RES == GAME_UW2) { Debug.Log("Checking Quest no " + QuestNo + " it's value is " + Quest.instance.QuestVariables[QuestNo]); } if (QuestNo > Quest.instance.QuestVariables.GetUpperBound(0)) { Debug.Log("invalid quest no " + QuestNo); return 0; } return Quest.instance.QuestVariables[QuestNo]; } /// <summary> /// Sets the quest variable /// </summary> /// <param name="value">Value to change to</param> /// <param name="QuestNo">Quest no to change</param> public void set_quest(int value, int QuestNo) { if (_RES == GAME_UW2) { Debug.Log("Setting Quest no " + QuestNo + " to " + value); } if (QuestNo > Quest.instance.QuestVariables.GetUpperBound(0)) { Debug.Log("Setting invalid quest no " + QuestNo); return; } Quest.instance.QuestVariables[QuestNo] = value; } /// <summary> /// Probably returns the skill value at the index. /// </summary> /// <returns>The skills.</returns> /// <param name="index">Index.</param> /// IN UW2 the return value seems to indicate if the skill gain occurred. public int x_skills(int mode, int skillToChange, int val3, int val4) { Debug.Log("X_skills (" + mode + "," + skillToChange + "," + val3 + "," + val4 + ")"); if (_RES != GAME_UW2) { switch (mode) { case 10001: Debug.Log("Returning skill " + UWCharacter.Instance.PlayerSkills.GetSkillName(skillToChange + 1)); return UWCharacter.Instance.PlayerSkills.GetSkill(skillToChange); case 10000: Debug.Log("Possibly setting skill to " + UWCharacter.Instance.PlayerSkills.GetSkillName(skillToChange + 1) + " " + 6); UWCharacter.Instance.PlayerSkills.AdvanceSkill(skillToChange, 6); return UWCharacter.Instance.PlayerSkills.GetSkill(skillToChange); default: Debug.Log("Possibly setting skill to " + UWCharacter.Instance.PlayerSkills.GetSkillName(skillToChange + 1) + " " + mode); UWCharacter.Instance.PlayerSkills.AdvanceSkill(skillToChange, mode); return UWCharacter.Instance.PlayerSkills.GetSkill(skillToChange); } } else {//In uw2 skill numbers are zero based? skillToChange++; switch (mode) { case 9999://Return the skill value return UWCharacter.Instance.PlayerSkills.GetSkill(skillToChange); case 10001: //Increase the skill if points are available. Returns 1 if sucess 0 if fail if (UWCharacter.Instance.TrainingPoints > 0) { UWCharacter.Instance.PlayerSkills.AdvanceSkill(skillToChange, 1); UWCharacter.Instance.TrainingPoints--; return 1; } else { return 0; } default://Set the skill to the specified value. UWCharacter.Instance.PlayerSkills.SetSkill(skillToChange, mode); return UWCharacter.Instance.PlayerSkills.GetSkill(skillToChange); } } } /// <summary> /// Sets the likes dislikes. /// </summary> /// <param name="index1">Index1.</param> /// <param name="index2">Index2.</param> public void set_likes_dislikes(int index1, int index2) { Debug.Log("set_likes_dislikes(" + index1 + "," + index2 + ")"); } /// <summary> /// Copies inventory item ids and slot positions into the array indices specified. /// </summary> /// <returns>The number of items found</returns> /// <param name="startObjectPos">Start index of object position.</param> /// <param name="startObjectIDs">Start index of object Ids.</param> public int show_inv(int startObjectPos, int startObjectIDs) { int j = 0; for (int i = 0; i <= TradeSlot.TradeSlotUBound; i++) { TradeSlot pcSlot = UWHUD.instance.playerTrade[i]; if (pcSlot.isSelected()) { stack.Set(startObjectPos + j, FindObjectIndexInObjectList(pcSlot.objectInSlot.name)); //stack.Set(startObjectPos+j, TradeAreaOffset + i + 1); //Make them stand out. stack.Set(startObjectIDs + j, pcSlot.GetObjectID()); j++; } } //Debug.Log(j + " items saved to pos:" + startObjectPos + " w/id:" + startObjectIDs); return j; } /// <summary> /// Gives the items at the specified positions in the array to the NPC /// </summary> /// <returns>1 if something given</returns> /// <param name="start">Start index of slots to transfer from</param> /// <param name="NoOfItems">No of items to transfer</param> public int give_to_npc(NPC npc, int start, int NoOfItems) { Container cn = npc.gameObject.GetComponent<Container>(); bool SomethingGiven = false; ObjectInteraction[] objsGiven = new ObjectInteraction[4]; for (int i = 0; i < NoOfItems; i++) { //int slotNo = stack.at(start+i)-1 - TradeAreaOffset ;//locals[start+i] ; int slotNo = stack.at(start + i); //if (slotNo<=3) //{ //TradeSlot pcSlot = UWHUD.instance.playerTrade[slotNo]; //GameObject demanded = GameObject.Find (pcSlot.objectInSlot); ObjectInteraction demanded = FindGameObjectInObjectList(slotNo); //Give the item to the npc if (Container.GetFreeSlot(cn) != -1) { if (demanded != null) { ClearTradeSlotWithObject(slotNo); //demanded.transform.parent=GameWorldController.instance.DynamicObjectMarker(); //GameWorldController.MoveToWorld(demanded);//ok objsGiven[i] = demanded;//These have to be moved to world after this function ends or else the master list will get messed up demanded.transform.position = GameWorldController.instance.InventoryMarker.transform.position; SomethingGiven = true; cn.AddItemToContainer(demanded); //pcSlot.clear (); } SomethingGiven = true; } else { if (demanded != null) { ClearTradeSlotWithObject(slotNo); //demanded.transform.parent=GameWorldController.instance.DynamicObjectMarker(); //GameWorldController.MoveToWorld(demanded);//ok objsGiven[i] = demanded;//These have to be moved to world after this function ends or else the master list will get messed up demanded.transform.position = npc.NPC_Launcher.transform.position; SomethingGiven = false; } //pcSlot.clear(); } //} } for (int i = 0; i <= objsGiven.GetUpperBound(0); i++) { if (objsGiven[i] != null) { GameWorldController.MoveToWorld(objsGiven[i]); stack.Set(start + i, objsGiven[i].GetComponent<ObjectInteraction>().BaseObjectData.index);//Update the object index in the stack so I keep track of it. } } if (SomethingGiven == true) { return 1; } else { return 0; } } /// <summary> /// transfers an item from npc inventory to player inventory,based on an item id. /// </summary> /// when the value is > 1000, all items of /// a category are copied. category item start = (arg1-1000)*16 /// My currenty example is lanugo (10) who is passing a value greater than 1000*/ /// Until It get more examples I'm doing the following*/ /// Get the items in the npcs container. If their ITEM id is between the calculated category value and +16 of that I take that item*/ /// Another example goldthirst who specifically has an item id to pass. /// /// <returns>1: ok, 2: player has no space left</returns> /// <param name="unk">Unk.</param> /// <param name="arg1">Arg1.</param> public int take_from_npc(NPC npc, int arg1) { /* id=0015 name="take_from_npc" ret_type=int parameters: arg1: item id (can also be an item category value, > 1000) description: transfers an item from npc inventory to player inventory, based on an item id. when the value is > 1000, all items of a category are copied. category item start = (arg1-1000)*16 return value: 1: ok, 2: player has no space left */ /*My currenty example is lanugo (10) who is passing a value greater than 1000*/ /*Until It get more examples I'm doing the following*/ /*Get the items in the npcs container. If their ITEM id is between the calculated category value and +16 of that I take that item*/ //Debug.Log ("Item Category is " + (arg1-1000)*16); //Another example goldthirst who specifically has an item id to pass. int playerHasSpace = 1; Container cn = npc.gameObject.GetComponent<Container>(); Container PlayerContainer = UWCharacter.Instance.gameObject.GetComponent<Container>(); if (arg1 < 1000) {//I'm taking a specific item. for (short i = 0; i <= cn.MaxCapacity(); i++) { if (cn.GetItemAt(i) != null) { ObjectInteraction objInt = cn.GetItemAt(i);//cn.GetGameObjectAt(i).GetComponent<ObjectInteraction>(); //GameObject.Find (itemName).GetComponent<ObjectInteraction>(); //lastObjectTraded=objInt; if (objInt != null) { if (objInt.item_id == arg1) { playerHasSpace = TakeItemFromNPCCOntainer(npc, PlayerContainer, i); return playerHasSpace; } } } } } else { int rangeS = (arg1 - 1000) * 16; int rangeE = rangeS + 16; for (short i = 0; i <= cn.MaxCapacity(); i++) { if (cn.GetItemAt(i) != null) { ObjectInteraction objInt = cn.GetItemAt(i);// cn.GetGameObjectAt(i).GetComponent<ObjectInteraction>(); //GameObject.Find (itemName).GetComponent<ObjectInteraction>(); //lastObjectTraded=objInt; if ( ((arg1 >= 1000) && (objInt.item_id >= rangeS) && (objInt.item_id <= rangeE)) || ((arg1 < 1000) && (objInt.item_id == arg1)) ) { playerHasSpace = TakeItemFromNPCCOntainer(npc, PlayerContainer, i); } } } } return playerHasSpace; } static int TakeItemFromNPCCOntainer(NPC npc, Container PlayerContainer, int index) { //Give to PC ObjectInteraction demanded = npc.GetComponent<Container>().GetItemAt((short)index); if (Container.GetFreeSlot(PlayerContainer) != -1)//Is there space in the container. { npc.GetComponent<Container>().RemoveItemFromContainer(demanded); UWCharacter.Instance.Pickup(demanded.GetComponent<ObjectInteraction>(), UWCharacter.Instance.playerInventory); return 1; } else { npc.GetComponent<Container>().RemoveItemFromContainer(demanded); if (demanded.transform.parent != GameWorldController.instance.DynamicObjectMarker()) {//Items needs to be moved to world //demanded.transform.parent = GameWorldController.instance.DynamicObjectMarker (); GameWorldController.MoveToWorld(demanded);//ok } demanded.transform.position = npc.NPC_Launcher.transform.position; if (demanded.GetComponent<Container>()) { Container cn = demanded.GetComponent<Container>(); for (short i = 0; i <= cn.MaxCapacity(); i++) { ObjectInteraction containerItem = cn.GetItemAt(i); if (containerItem != null) { npc.GetComponent<Container>().RemoveItemFromContainer(containerItem); } } } CurrentObjectInHand = demanded; GameWorldController.MoveToInventory(demanded); return 2; } } /// <summary> /// Waits for the player to press any key when printing text /// </summary> IEnumerator WaitForMore() { WaitingForMore = true; while (WaitingForMore) { yield return null; } } /// <summary> /// Setups the barter windows /// </summary> /// TODO: Figure out where generic NPCs get their inventory for trading from???? Is
A bug fixes itself.