int CChitemDlg::check_or_scan_trigger(const trigger *tpoi, int checkflags, int check_or_scan, int bcnt) { CString area; int ret, gret; gret=0; if((checkflags&0xff00)==0xff00) { if(checkflags&1) area=CString(tpoi->var2)+tpoi->var1; else area=CString(tpoi->var1)+tpoi->var2; ret=store_variable(area, ADD_VAR, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; } else { varname2=tpoi->var2; ret=store_variable(tpoi->var1, checkflags, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; ret=store_variable(tpoi->var2, checkflags>>8, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; } if(check_or_scan==SCANNING) return gret; //don't store this if just scanning, these are checked, but never SET, so they must be invalid if used alone if (tpoi->trobj.var[0]) { ret = store_variable(tpoi->trobj.var, ADD_DEAD, 0, OBJECT|TRIGGER|check_or_scan, bcnt); gret |= ret; } ret=check_integers(&tpoi->bytes[0], checkflags, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; return gret; }
int CChitemDlg::check_or_scan_action(const action *apoi, int checkflags, int check_or_scan, int bcnt) { CString area; int i; int ret, gret; gret=0; if((checkflags&0xff00)==0xff00) { if(checkflags&1) area=CString(apoi->var2)+apoi->var1; else area=CString(apoi->var1)+apoi->var2; ret=store_variable(area, ADD_VAR, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; } else { varname2=apoi->var2; ret=store_variable(apoi->var1, checkflags, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; ret=store_variable(apoi->var2, checkflags>>8, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; } //don't store these if just scanning, it is checked, but never SET, so it must be invalid if used alone for(i=0;i<3;i++) { if (check_or_scan==SCANNING && !i) continue; //the override variable is never written, so it shouldn't be stored here store_variable(apoi->obj[i].var, ADD_DEAD, i, OBJECT|ACTION|check_or_scan, bcnt); } if(check_or_scan==SCANNING) return gret; ret=check_integers(&apoi->bytes[0], checkflags, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; return gret; }
void store(uint16_t v) { store_variable(BYTE(pc++), v); }
int CChitemDlg::check_script(int check_or_scan) //scans for variables { int ret, gret; int bcnt, tcnt, rcnt, acnt; block *bpoi; trigger *tpoi; response *rpoi; action *apoi; int num_or; int checkflags; CString area; journal_type journal; int opcode; int i; gret=0; if(!the_script.blockcount) { gret=-1; log("Empty script!"); } for(bcnt=0;bcnt<the_script.blockcount; bcnt++) { bpoi=&the_script.blocks[bcnt]; if(!bpoi->triggercount && (check_or_scan!=SCANNING) ) { gret=-1; log("No trigger in block #%d",bcnt+1); } //triggers using variables num_or=0; opcode=0; //initialize opcode to non-TR_FALSE if(check_or_scan!=JOURNAL) //triggers don't have journals { for(tcnt=0;tcnt<bpoi->triggercount; tcnt++) { tpoi=&bpoi->triggers[tcnt]; opcode=tpoi->opcode&0x1fff; if(check_or_scan==CHECKING) { if((opcode>MAX_TRIGGER) || !trigger_defs[opcode].GetLength()) { gret=-1; log("Invalid trigger: %d (%04x) in block #%d trigger #%d",tpoi->opcode, tpoi->opcode,bcnt+1,tcnt+1); continue; } if(pst_compatible_var()) continue; if(opcode==TR_OR) { if(num_or) { gret=-1; log("Bad OR count in block #%d trigger #%d",bcnt+1,tcnt+1); } num_or=tpoi->bytes[0]; if (num_or<2 && check_or_scan!=SCANNING) { gret=-1; log("Incorrect or redundant Or() in block #%d trigger #%d", bcnt+1, tcnt+1); } } else if(num_or) num_or--; } checkflags=handle_trigger(tpoi->opcode); // not only death variable but: waypoints, triggers, doors etc if(store_variable(tpoi->trobj.var, CHECK_DEAD2|(checkflags&0xffff0000),0,OBJECT|TRIGGER|check_or_scan,bcnt)) { log(resolve_scriptelement(opcode, TRIGGER, bcnt)); } if((checkflags&0xff00)==0xff00) { if(checkflags&1) area=CString(tpoi->var2)+tpoi->var1; else area=CString(tpoi->var1)+tpoi->var2; ret=store_variable(area, ADD_VAR, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; } else { varname2=tpoi->var2; ret=store_variable(tpoi->var1, checkflags, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; ret=store_variable(tpoi->var2, checkflags>>8, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; } if(check_or_scan==CHECKING) { ret=check_integers(&tpoi->bytes[0], checkflags, tpoi->opcode, TRIGGER|check_or_scan, bcnt); gret|=ret; } } if(check_or_scan==CHECKING) { if(num_or) { gret=-1; log("Bad OR count in block #%d trigger #%d",bcnt+1,tcnt); } if(!bpoi->responsecount ) { log("No response in block #%d",bcnt+1); } } } for(rcnt=0;rcnt<bpoi->responsecount; rcnt++) { rpoi=&bpoi->responses[rcnt]; //if last opcode is False() then we don't care about the empty response if(opcode!=TR_FALSE && !rpoi->actioncount && (check_or_scan==CHECKING) ) { gret=-1; log("No action in block #%d response #%d",bcnt+1,rcnt+1); } //actions using variables num_or=0; for(acnt=0;acnt<rpoi->actioncount; acnt++) { apoi=&rpoi->actions[acnt]; // not only death variable but: waypoints, triggers, doors etc for(i=0;i<3;i++) { if(store_variable(apoi->obj[i].var, CHECK_DEAD2|(0xffff0000&handle_action(apoi->opcode)),i,OBJECT|ACTION|check_or_scan,bcnt)) { log("%s in response #%d",resolve_scriptelement(apoi->opcode, ACTION, acnt), rcnt+1); } } if(check_or_scan==JOURNAL) { switch(apoi->opcode) { //this is a solved journal entry case AC_REMOVE_JOURNAL_IWD:case AC_QUESTDONE_IWD: if(has_xpvar()) { journal.type=0; journals.Lookup(apoi->bytes[0], journal); journal.string=""; journal.type|=HAS_SOLVED; journals[apoi->bytes[0]]=journal; } break; case AC_REMOVE_JOURNAL_BG: case AC_QUESTDONE_BG: if(!has_xpvar()) { journal.type=0; journals.Lookup(apoi->bytes[0], journal); journal.string=""; journal.type|=HAS_SOLVED; journals[apoi->bytes[0]]=journal; } break; case AC_ADD_JOURNAL: //this is an undone quest journal entry if(has_xpvar() || (apoi->bytes[3]==JT_QUEST)) { if(journals.Lookup(apoi->bytes[0],journal)) { if(!journal.string.IsEmpty()) { if (journal.string.Find(itemname)<0) { journal.string+=", "+itemname; } journal.type|=HAS_QUEST; journals[apoi->bytes[0]]=journal; } } else { journal.string=itemname; journal.type=HAS_QUEST; journals[apoi->bytes[0]]=journal; } } else { if (apoi->bytes[3]==JT_DONE) { journal.type=0; journals.Lookup(apoi->bytes[0], journal); journal.string=""; journal.type|=HAS_SOLVED; journals[apoi->bytes[0]]=journal; } } break; } continue; } if((apoi->opcode>MAX_ACTION) || !action_defs[apoi->opcode].GetLength()) { gret=-1; log("Invalid action: %d in block #%d response #%d action #%d",apoi->opcode,bcnt+1, rcnt+1, acnt+1); continue; } checkflags=handle_action(apoi->opcode); if((checkflags&0xff00)==0xff00) { if(checkflags&1) area=CString(apoi->var2)+apoi->var1; else area=CString(apoi->var1)+apoi->var2; ret=store_variable(area, ADD_VAR, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; } else { varname2=apoi->var2; ret=store_variable(apoi->var1, checkflags, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; ret=store_variable(apoi->var2, checkflags>>8, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; } if(check_or_scan==CHECKING) { ret=check_integers(apoi->bytes, checkflags, apoi->opcode, ACTION|check_or_scan, bcnt); gret|=ret; if(chkflg&NOCUT) continue; if(apoi->opcode==AC_STARTCUT) { if(num_or!=AC_STCUTMD) { log("StartCutScene() without StartCutSceneMode() in block #%d response #%d action #%d", bcnt+1,rcnt+1,acnt+1); gret|=1; } } if((apoi->opcode==AC_STCUTMD) || (apoi->opcode==AC_STARTCUT) || (apoi->opcode==AC_CLRACT) || (apoi->opcode==AC_CLRALLACT)) num_or=apoi->opcode; } } } } return gret; }