1# ZCode operations file 2# This file is 'partially evaluated' to generate a (long!) C source file 3# that should provide a performance boost to the execution of instructions 4 5# YMMV, depending on your compilers optimisation abilities 6 7#### ----// 888 \\---- #### 8# 2OPs 9 10# je is weird and is actually treated as a VAR op instead of a 2OP 11OPCODE "je" 2OP:0x01 BRANCH REALLYVAR VERSION all 12%{ 13 result = 1; 14 for (x=1; x<argblock.n_args; x++) 15 { 16 if (argblock.arg[0] == argblock.arg[x]) 17 { 18 goto je_true; 19 } 20 } 21 result = 0; 22je_true: 23 dobranch; 24%} 25 26OPCODE "jl" 2OP:0x02 BRANCH VERSION all 27%{ 28 result = arg1<arg2; 29 dobranch; 30%} 31 32OPCODE "jg" 2OP:0x03 BRANCH VERSION all 33%{ 34 result = arg1>arg2; 35 dobranch; 36%} 37 38OPCODE "dec_chk" 2OP:0x04 BRANCH VERSION all 39%{ 40 ZWord var; 41 42 var = GetVarNoPop(arg1); 43 result = (--var) < arg2; 44 store_nopush(stack, arg1, var); 45 dobranch; 46%} 47 48OPCODE "inc_chk" 2OP:0x05 BRANCH VERSION all 49%{ 50 ZWord var; 51 52 var = GetVarNoPop(arg1); 53 result = (++var) > arg2; 54 store_nopush(stack, arg1, var); 55 dobranch; 56%} 57 58OPCODE "jin" 2OP:0x06 BRANCH VERSION 1,2,3 59%{ 60 ZByte* obj; 61 62 obj = Obj3(uarg1); 63 result = obj[parent_3] == arg2; 64 dobranch; 65%} 66 67OPCODE "jin" 2OP:0x06 BRANCH VERSION 4,5,6,7,8 68%{ 69 ZByte* obj; 70 71 obj = Obj4(uarg1); 72 result = GetParent4(obj) == arg2; 73 dobranch; 74%} 75 76OPCODE "test" 2OP:0x07 BRANCH VERSION all 77%{ 78 result = ((ZUWord)arg1&(ZUWord)arg2)==(ZUWord)arg2; 79 dobranch; 80%} 81 82OPCODE "test_attr" 2OP:0x0a BRANCH VERSION 1,2,3 83%{ 84 ZByte* obj; 85 int byte, bit; 86 87 if (uarg1>255) /* || uarg1 == 0) HHGG bug */ 88 zmachine_fatal("Object %i out of range", uarg1); 89 if (uarg2>31) 90 zmachine_fatal("Attribute out of range"); 91 92 byte = uarg2>>3; 93 bit = uarg2&7; 94 95 if (uarg1 != 0) { 96 obj = Obj3(uarg1); 97 98#ifdef TRACKING 99 if (machine.track_attributes) 100 tracking_print("Testing attribute %i of object \"%s\" (%s)", 101 attr, tracking_object(uarg1), 102 (obj[byte]&(0x80>>bit))?"Set":"Unset"); 103#endif 104 105 result = ((obj[byte]&(0x80>>bit)) != 0); 106 } else { 107 result = 0; 108 } 109 dobranch; 110%} 111 112OPCODE "test_attr" 2OP:0x0a BRANCH VERSION 4,5,6,7,8 113%{ 114 ZByte* obj; 115 int byte, bit; 116 117 if (uarg1 == 0) 118 { 119 zmachine_warning("Object 0 has no attributes"); 120 result = 0; 121 dobranch; 122 goto loop; 123 } 124 if (uarg2 == 48) 125 { 126 zmachine_warning("Attempt to test attribute 48"); 127 goto loop; 128 } 129 if (uarg2>47) 130 zmachine_fatal("Attribute out of range"); 131 132 byte = uarg2>>3; 133 bit = uarg2&7; 134 135 obj = Obj4(uarg1); 136 137#ifdef TRACKING 138 if (machine.track_attributes) 139 tracking_print("Testing attribute %i of object \"%s\" (%s)", 140 arg2, tracking_object(arg1), 141 (obj[byte]&(0x80>>bit))?"Set":"Unset"); 142#endif 143 144 result = (obj[byte]&(0x80>>bit)) != 0; 145 dobranch; 146%} 147 148OPCODE "set_attr" 2OP:0x0b VERSION 1,2,3 149%{ 150 ZByte* obj; 151 int byte, bit; 152 153 if (uarg1 == 0) { 154 /* Technically this is a bug in the game, but The Witness accidentally does this so we allow it in v3 games */ 155 zmachine_warning("Cannot set attributes of object 0"); 156 } else { 157 if (uarg1>255 || uarg1 == 0) 158 zmachine_fatal("Object %i out of range", uarg1); 159 if (uarg2>31) 160 zmachine_fatal("Attribute out of range"); 161 162#ifdef TRACKING 163 if (machine.track_attributes) 164 tracking_print("Setting attribute %i of object \"%s\"", 165 uarg2, tracking_object(uarg1)); 166#endif 167 168 byte = uarg2>>3; 169 bit = uarg2&7; 170 171 obj = Obj3(uarg1); 172 obj[byte] |= 0x80>>bit; 173 } 174%} 175 176OPCODE "set_attr" 2OP:0x0b VERSION 4,5,6,7,8 177%{ 178 ZByte* obj; 179 int byte, bit; 180 181 if (uarg1 == 0) 182 zmachine_fatal("Object 0 cannot be altered"); 183 if (uarg2>47) 184 zmachine_fatal("Attribute out of range"); 185 186#ifdef DEBUG 187 printf_debug("Setting attribute %x of object #%x\n", uarg2, uarg1); 188#endif 189 190#ifdef TRACKING 191 if (machine.track_attributes) 192 tracking_print("Setting attribute %i of object \"%s\"", 193 uarg2, tracking_object(uarg1)); 194#endif 195 196 byte = uarg2>>3; 197 bit = uarg2&7; 198 199 obj = Obj4(uarg1); 200 obj[byte] |= (0x80>>bit); 201%} 202 203OPCODE "clear_attr" 2OP:0x0c VERSION 1,2,3 204%{ 205 ZByte* obj; 206 int byte, bit; 207 208 if (uarg1 == 0) { 209 /* Technically this is a bug in the game, but The Witness accidentally does this so we allow it in v3 games */ 210 zmachine_warning("Cannot clear the attributs of object 0"); 211 } else { 212 if (uarg1>255 || uarg1 == 0) 213 zmachine_fatal("Object %i out of range", uarg1); 214 if (uarg2>31) 215 zmachine_fatal("Attribute out of range"); 216 217#ifdef TRACKING 218 if (machine.track_attributes) 219 tracking_print("Setting attribute %i of object \"%s\"", 220 uarg2, tracking_object(uarg1)); 221#endif 222 223 byte = uarg2>>3; 224 bit = uarg2&7; 225 226 obj = Obj3(uarg1); 227 obj[byte] &= ~(0x80>>bit); 228 } 229%} 230 231OPCODE "clear_attr" 2OP:0x0c VERSION 4,5,6,7,8 232%{ 233 ZByte* obj; 234 int byte, bit; 235 236 if (uarg1 == 0) 237 zmachine_fatal("Object 0 cannot be altered"); 238 if (uarg2>47) 239 zmachine_fatal("Attribute out of range"); 240 241#ifdef DEBUG 242 printf_debug("Setting attribute %x of object #%x\n", uarg2, uarg1); 243#endif 244 245#ifdef TRACKING 246 if (machine.track_attributes) 247 tracking_print("Setting attribute %i of object \"%s\"", 248 uarg2, tracking_object(uarg1)); 249#endif 250 251 byte = uarg2>>3; 252 bit = uarg2&7; 253 254 obj = Obj4(uarg1); 255 obj[byte] &= ~(0x80>>bit); 256%} 257 258OPCODE "insert_obj" 2OP:0x0e VERSION 1,2,3 259%{ 260 ZByte* src_obj; 261 ZByte* dest_obj; 262 ZByte* tmp; 263 264 if (uarg1>255 || uarg1 == 0) 265 zmachine_fatal("Object %i out of range", uarg1); 266 if (uarg2>255) 267 zmachine_fatal("Object %i out of range", uarg2); 268 269 /* Get the address of the object */ 270 src_obj = Obj3(uarg1); 271 272 if (src_obj[parent_3] != 0) 273 { 274 /* Get the address of its parent */ 275 tmp = Obj3(src_obj[parent_3]); 276 277 /* 278 * If the object is a direct child of its parent, set the new child 279 * to the object's sibling 280 */ 281 if (tmp[child_3] == uarg1) 282 { 283 tmp[child_3] = src_obj[sibling_3]; 284 } 285 else 286 { 287 /* Find the object which is a sibling with this object */ 288 tmp = Obj3(tmp[child_3]); 289 290 while (tmp[sibling_3] != uarg1 && tmp[sibling_3] != 0) 291 { 292 tmp = Obj3(tmp[sibling_3]); 293 } 294 295 if (tmp[sibling_3] == 0) 296 zmachine_fatal("Corrupt object tree (object is not a child of its parent)"); 297 298 /* Set its sibling to the sibling of the object */ 299 tmp[sibling_3] = src_obj[sibling_3]; 300 } 301 } 302 303 if (uarg2 != 0) 304 { 305 /* Set the new parent's child to be this object */ 306 dest_obj = Obj3(uarg2); 307 src_obj[sibling_3] = dest_obj[child_3]; 308 dest_obj[child_3] = uarg1; 309 } 310 else 311 src_obj[sibling_3] = 0; 312 313 src_obj[parent_3] = uarg2; 314%} 315 316OPCODE "insert_obj" 2OP:0x0e VERSION 4,5,6,7,8 317%{ 318 ZByte* src_obj; 319 ZByte* dest_obj; 320 ZByte* tmp; 321 322#ifdef DEBUG 323 printf_debug("Inserting object %i into %i\n", uarg1, uarg2); 324#endif 325 326 if (uarg1 == 0) 327 zmachine_fatal("Object 0 cannot be inserted"); 328 329 src_obj = Obj4(uarg1); 330 331 if (GetParent4(src_obj) != 0) 332 { 333 ZUWord sibling; 334 335 /* Get the address of the old parent */ 336 tmp = Obj4(GetParent4(src_obj)); 337 338 if (GetChild4(tmp) == uarg1) 339 { 340 sibling = GetSibling4(src_obj); 341 /* 342 * Object is a direct child, so we make the new child this 343 * object's sibling 344 */ 345 tmp[child_4] = sibling>>8; 346 tmp[child_4+1] = sibling; 347 } 348 else 349 { 350 ZUWord our_sibling; 351 352 /* Find the object which is a sibling with this object */ 353 tmp = Obj4(GetChild4(tmp)); 354 355 sibling = GetSibling4(tmp); 356 while (sibling != uarg1 && sibling != 0) 357 { 358 tmp = Obj4(sibling); 359 sibling = GetSibling4(tmp); 360 } 361 362 if (sibling == 0) 363 zmachine_fatal("Corrupt object tree (object is not a child of its parent)"); 364 365 /* Set its sibling to our sibling */ 366 our_sibling = GetSibling4(src_obj); 367 tmp[sibling_4] = our_sibling>>8; 368 tmp[sibling_4+1] = our_sibling; 369 } 370 } 371 372 if (uarg2 != 0) 373 { 374 ZUWord kid; 375 376 /* Set the new parent's child to be this object */ 377 dest_obj = Obj4(uarg2); 378 kid = GetChild4(dest_obj); 379 src_obj[sibling_4] = kid>>8; 380 src_obj[sibling_4+1] = kid; 381 dest_obj[child_4] = uarg1>>8; 382 dest_obj[child_4+1] = uarg1; 383 } 384 else 385 { 386 src_obj[sibling_4] = 0; 387 src_obj[sibling_4+1] = 0; 388 } 389 390 src_obj[parent_4] = uarg2>>8; 391 src_obj[parent_4+1] = uarg2; 392%} 393 394OPCODE "get_prop" 2OP:0x11 STORE VERSION 1,2,3 395%{ 396 struct prop* p; 397 398 if (uarg1>255 || uarg1 == 0) 399 zmachine_fatal("Object %i out of range", uarg1); 400 arg2 &= 0x1f; 401 if (uarg2>31 || uarg2 == 0) 402 zmachine_fatal("Property %i out of range", uarg2); 403 404 p = get_object_prop_3(uarg1, uarg2); 405 406 switch (p->size) 407 { 408 case 1: 409 store(stack, st, p->prop[0]); 410 break; 411 412 case 2: 413 store(stack, st, (p->prop[0]<<8)|p->prop[1]); 414 break; 415 416 default: 417 zmachine_fatal("Size %i is invalid for get_prop\n", p->size); 418 } 419%} 420 421OPCODE "get_prop" 2OP:0x11 STORE VERSION 4,5,6,7,8 422%{ 423 struct prop* p; 424 425 if (uarg1 == 0) 426 zmachine_warning("Object 0 has no properties"); 427 if (uarg2>63 || uarg2 == 0) 428 zmachine_fatal("Property %i out of range", uarg2); 429 430#ifdef DEBUG 431 printf_debug("Get_prop: object %i prop %i\n", uarg1, uarg2); 432#endif 433 434 p = get_object_prop_4(uarg1, uarg2); 435 436 switch (p->size) 437 { 438 case 1: 439 store(stack, st, p->prop[0]); 440 break; 441 442 /* 443 * Hmm, this is against spec, but some Inform games 444 * (Christminster?) seem to use get_prop on properties with 445 * lengths > 2. So we'll let 'em off with a warning 446 */ 447 default: 448 zmachine_warning("get_prop used on a property with length %i", 449 p->size); 450 store(stack, st, (p->prop[-1]<<8)|p->prop[0]); /* Frotz's behaviour */ 451 break; 452 453 case 2: 454 store(stack, st, (p->prop[0]<<8)|p->prop[1]); 455 break; 456 457 /* default: 458 zmachine_fatal("Size %i is invalid for get_prop\n", p->size); */ 459 } 460%} 461 462OPCODE "get_prop_addr" 2OP:0x12 STORE VERSION 1,2,3 463%{ 464 ZByte* obj_adr; 465 ZUWord prop_adr; 466 ZByte size; 467 468 if (uarg1>255) 469 zmachine_fatal("Object %i out of range", uarg1); 470 471 if (uarg1 == 0) 472 { 473 /* Zork 2 has an occasional bug that causes a crash here if we make this error fatal */ 474 zmachine_warning("Attempt to get the address of a property for invalid object number 0"); 475 store(stack, st, 0); 476 goto loop; 477 } 478 479 arg2 &= 0x1f; 480 if (uarg2 > 31 || uarg2 == 0) 481 { 482 zmachine_warning("Attempt to get address of out of range property %i", uarg2); 483 store(stack, st, 0); 484 goto loop; 485 } 486 487 obj_adr = Obj3(uarg1); 488 489 prop_adr = (obj_adr[7]<<8)|obj_adr[8]; 490 prop_adr += ReadByte(prop_adr)*2 + 1; 491 492 while ((size = ReadByte(prop_adr)) != 0) 493 { 494 if ((size&0x1f) == uarg2) 495 { 496 store(stack, st, prop_adr + 1); 497 goto loop; 498 } 499 500 prop_adr += (size>>5) + 2; 501 } 502 503 store(stack, st, 0); 504%} 505 506OPCODE "get_prop_addr" 2OP:0x12 STORE VERSION 4,5,6,7,8 507%{ 508 ZByte* obj_adr; 509 ZUWord prop_adr; 510 struct propinfo* pinfo; 511 512 if (uarg1 == 0) 513 { 514 zmachine_warning("Object 0 has no properties"); 515 store(stack, st, 0); 516 } 517 if (uarg2 > 63 || uarg2 == 0) 518 { 519 zmachine_warning("Attempt to get address of out of range property %i", uarg2); 520 store(stack, st, 0); 521 } 522 523 obj_adr = Obj4(uarg1); 524 525 prop_adr = GetPropAddr4(obj_adr); 526 prop_adr += (ReadByte(prop_adr)*2)+1; 527 528 do 529 { 530 pinfo = get_object_propinfo_4(Address(prop_adr)); 531 532 if (pinfo->number == uarg2) 533 { 534 store(stack, st, (ZUWord)(prop_adr+pinfo->header)); 535 goto loop; 536 } 537 538 prop_adr += pinfo->datasize + pinfo->header; 539 } 540 while (pinfo->number != 0); 541 542 store(stack, st, 0); 543%} 544 545OPCODE "get_next_prop" 2OP:0x13 STORE VERSION 1,2,3 546%{ 547 ZByte* obj_adr; 548 ZWord prop_adr; 549 ZByte size; 550 int state; 551 552 obj_adr = Obj3(uarg1); 553 554 prop_adr = (obj_adr[7]<<8)|obj_adr[8]; 555 prop_adr += ReadByte(prop_adr)*2 + 1; 556 557 if (uarg2 == 0) 558 { 559 store(stack, st, ReadByte(prop_adr)&0x1f); 560 goto loop; 561 } 562 563 state = 0; 564 while ((size = ReadByte(prop_adr)) != 0) 565 { 566 if (state) 567 { 568 store(stack, st, size&0x1f); 569 goto loop; 570 } 571 if ((size&0x1f) == uarg2) 572 { 573 state = 1; 574 } 575 576 prop_adr += (size>>5) + 2; 577 } 578 579 store(stack, st, 0); 580%} 581 582OPCODE "get_next_prop" 2OP:0x13 STORE VERSION 4,5,6,7,8 583%{ 584 struct prop* property; 585 struct propinfo* inf; 586 587 if (uarg1 == 0) 588 zmachine_fatal("Object 0 has no properties"); 589 if (uarg2 > 63) 590 zmachine_fatal("Property %i out of range", uarg2); 591 592 if (uarg2 == 0) 593 { 594 ZByte* obj_adr; 595 ZUWord prop_adr; 596 597 obj_adr = Obj4(uarg1); 598 599 prop_adr = GetPropAddr4(obj_adr); 600 prop_adr += (ReadByte(prop_adr)*2)+1; 601 602 inf = get_object_propinfo_4(Address(prop_adr)); 603 store(stack, st, inf->number); 604 goto loop; 605 } 606 607 property = get_object_prop_4(uarg1, uarg2); 608 609 if (property->isdefault) 610 zmachine_fatal("Can't get next property of a default"); 611 612 inf = get_object_propinfo_4(property->prop - property->pad); 613 if (inf->number != 0) 614 { 615 ZByte *next_prop; 616 617 next_prop = property->prop + inf->datasize; 618 inf = get_object_propinfo_4(next_prop); 619 620 store(stack, st, inf->number); 621 } 622 else /* Huh? We retrieved property 0? */ 623 zmachine_fatal("Programmer is a spoon"); 624%} 625 626OPCODE "store" 2OP:0x0d VERSION all 627%{ 628 store_nopush(stack, arg1, arg2); 629%} 630 631OPCODE "loadw" 2OP:0x0f STORE VERSION all 632%{ 633#ifdef DEBUG 634 printf_debug("Loading word at #%x\n", (ZUWord)arg1+((ZWord)arg2*2)); 635#endif 636 store(stack, st, Word((ZUWord)((ZUWord)arg1+((ZWord)arg2*2)))); 637%} 638OPCODE "loadb" 2OP:0x10 STORE VERSION all 639%{ 640#ifdef DEBUG 641 printf_debug("Loading byte at #%x\n", (ZUWord)arg1+(ZWord)arg2); 642#endif 643 store(stack, st, ReadByte((ZUWord)((ZUWord)arg1+(ZWord)arg2))); 644%} 645 646OPCODE "or" 2OP:0x08 STORE VERSION all 647%{ store(stack, st, arg1|arg2); %} 648 649OPCODE "and" 2OP:0x09 STORE VERSION all 650%{ store(stack, st, arg1&arg2); %} 651 652OPCODE "add" 2OP:0x14 STORE VERSION all 653%{ store(stack, st, arg1+arg2); %} 654 655OPCODE "sub" 2OP:0x15 STORE VERSION all 656%{ store(stack, st, arg1-arg2); %} 657 658OPCODE "mul" 2OP:0x16 STORE VERSION all 659%{ store(stack, st, arg1*arg2); %} 660 661OPCODE "div" 2OP:0x17 STORE VERSION all 662%{ 663 if (arg2 == 0) 664 zmachine_fatal("Division by 0"); 665 store(stack, st, arg1/arg2); 666%} 667 668OPCODE "mod" 2OP:0x18 STORE VERSION all 669%{ 670 if (arg2 == 0) 671 zmachine_fatal("Modulo by 0"); 672 store(stack, st, arg1%arg2); 673%} 674 675OPCODE "call_2s" 2OP:0x19 CANJUMP STORE VERSION 4,5,6,7,8 676%{ 677 ZDWord new_routine; 678 ZFrame* newframe; 679 680 if (arg1 == 0) 681 { 682 store(stack, st, 0); 683 goto loop; 684 } 685 686 new_routine = UnpackR(uarg1); 687 newframe = call_routine(&pc, stack, new_routine); 688 689 newframe->local[1] = arg2; 690 newframe->flags |= 1; 691 692 newframe->storevar = st; 693%} 694 695OPCODE "call_2n" 2OP:0x1a CANJUMP VERSION 5,6,7,8 696%{ 697 ZDWord new_routine; 698 ZFrame* newframe; 699 700 if (uarg1 == 0) 701 { 702 goto loop; 703 } 704 705 new_routine = UnpackR(uarg1); 706 newframe = call_routine(&pc, stack, new_routine); 707 708 newframe->local[1] = arg2; 709 newframe->flags |= 1; 710 711 newframe->discard = 1; 712%} 713 714OPCODE "set_colour" 2OP:0x1b VERSION 5,7,8 715%{ 716#ifdef DEBUG 717 printf_debug("Setting colours to %i, %i\n", arg1, arg2); 718#endif 719 stream_flush_buffer(); 720 display_set_colour(convert_colour(arg1), convert_colour(arg2)); 721%} 722 723OPCODE "throw" 2OP:0x1c CANJUMP VERSION 5,6,7,8 724%{ 725 if (stack->current_frame == NULL) 726 zmachine_fatal("Throw attempted after function with catch has returned"); 727 if (stack->current_frame->frame_num < arg1) 728 zmachine_fatal("Throw attempted after function with catch has returned"); 729 730 /* Unroll the stack to the appropriate frame */ 731 while (stack->current_frame->frame_num != arg2) 732 { 733 ZFrame* oldframe; 734 735 oldframe = stack->current_frame; 736 stack->current_frame = oldframe->last_frame; 737 stack->stack_size += oldframe->frame_size; 738 stack->stack_top -= oldframe->frame_size; 739 740 free(oldframe); 741 } 742 743 /* Do a return */ 744 goto op_ret; 745%} 746 747#### ----// 888 \\---- #### 748# 1OPs 749 750OPCODE "jz" 1OP:0x00 BRANCH VERSION all 751%{ 752 result = arg1==0; 753 dobranch; 754%} 755 756OPCODE "get_sibling" 1OP:0x01 BRANCH STORE VERSION 1,2,3 757%{ 758 ZByte* obj; 759 760 obj = Obj3(uarg1); 761 store(stack, st, obj[sibling_3]); 762 result = obj[sibling_3] != 0; 763 dobranch; 764%} 765 766OPCODE "get_child" 1OP:0x02 BRANCH STORE VERSION 1,2,3 767%{ 768 ZByte* obj; 769 770 obj = Obj3(uarg1); 771 store(stack, st, obj[child_3]); 772 result = obj[child_3] != 0; 773 dobranch; 774%} 775 776OPCODE "get_parent" 1OP:0x03 STORE VERSION 1,2,3 777%{ 778 ZByte* obj; 779 780 obj = Obj3(uarg1); 781 store(stack, st, obj[parent_3]); 782%} 783 784OPCODE "get_prop_len" 1OP:0x04 STORE VERSION 1,2,3 785%{ 786 if (arg1 == 0) 787 store(stack, st, 0); 788 else 789 store(stack, st, (machine.memory[uarg1-1]>>5)+1); 790%} 791 792OPCODE "get_sibling" 1OP:0x01 BRANCH STORE VERSION 4,5,6,7,8 793%{ 794 ZByte* obj_adr; 795 ZUWord sibling; 796 797 if (uarg1 == 0) 798 { 799 zmachine_warning("Object 0 has no siblings"); 800 store(stack, st, 0); 801 goto loop; 802 } 803 804 obj_adr = Obj4(uarg1); 805 sibling = GetSibling4(obj_adr); 806 807 store(stack, st, sibling); 808 809 result = sibling != 0; 810 dobranch; 811%} 812 813OPCODE "get_child" 1OP:0x02 BRANCH STORE VERSION 4,5,6,7,8 814%{ 815 ZByte* obj_adr; 816 ZUWord child; 817 818 if (uarg1 == 0) 819 { 820 zmachine_warning("Object 0 has no siblings"); 821 store(stack, st, 0); 822 goto loop; 823 } 824 825 obj_adr = Obj4(uarg1); 826 child = GetChild4(obj_adr); 827 828 store(stack, st, child); 829 830 result = child != 0; 831 dobranch; 832%} 833 834OPCODE "get_parent" 1OP:0x03 STORE VERSION 4,5,6,7,8 835%{ 836 ZByte* obj_adr; 837 ZUWord parent; 838 839 if (uarg1 == 0) 840 { 841 zmachine_warning("Object 0 has no siblings"); 842 store(stack, st, 0); 843 goto loop; 844 } 845 846 obj_adr = Obj4(uarg1); 847 parent = GetParent4(obj_adr); 848 849 store(stack, st, parent); 850%} 851 852OPCODE "get_prop_len" 1OP:0x04 STORE VERSION 4,5,6,7,8 853%{ 854 ZByte* p; 855 struct propinfo* inf; 856 857 if (arg1 == 0) 858 store(stack, st, 0); 859 else 860 { 861 p = machine.memory + uarg1; 862 if (p[-1]&0x80) 863 p -= 2; 864 else 865 p -= 1; 866 867 inf = get_object_propinfo_4(p); 868 869 store(stack, st, inf->datasize); 870 } 871%} 872 873OPCODE "inc" 1OP:0x05 VERSION all 874%{ 875 ZWord var; 876 877#ifdef DEBUG 878 printf_debug("Inc: increasing variable %i by 1\n", arg1); 879#endif 880 881 var = GetVarNoPop(arg1); 882 var++; 883 store_nopush(stack, arg1, var); 884%} 885 886OPCODE "dec" 1OP:0x06 VERSION all 887%{ 888 ZWord var; 889 890#ifdef DEBUG 891 printf_debug("Dec: decreasing variable %i by 1\n", arg1); 892#endif 893 894 var = GetVarNoPop(arg1); 895 var--; 896 store_nopush(stack, arg1, var); 897%} 898 899OPCODE "print_addr" 1OP:0x07 VERSION all 900%{ 901 int len; 902 903#ifdef DEBUG 904 printf_debug(">%s<\n", zscii_to_ascii(machine.memory + uarg1, &len)); 905#endif 906 907 stream_prints(zscii_to_unicode(machine.memory + uarg1, &len)); 908%} 909 910OPCODE "call_1s" 1OP:0x08 CANJUMP STORE VERSION 4,5,6,7,8 911%{ 912 ZDWord new_routine; 913 ZFrame* newframe; 914 915 if (arg1 == 0) 916 { 917 store(stack, st, 0); 918 goto loop; 919 } 920 921 new_routine = UnpackR(arg1); 922 newframe = call_routine(&pc, stack, new_routine); 923 924 newframe->storevar = st; 925%} 926 927OPCODE "remove_obj" 1OP:0x09 VERSION 1,2,3 928%{ 929 arg2 = 0; 930 goto op_insert_obj_123; 931%} 932 933OPCODE "remove_obj" 1OP:0x09 VERSION 4,5,6,7,8 934%{ 935 arg2 = 0; 936 goto op_insert_obj_45678; 937%} 938 939OPCODE "print_obj" 1OP:0x0a VERSION 1,2,3 940%{ 941 ZByte* obj; 942 ZByte* prop; 943 int len; 944 945 obj = Obj3(uarg1); 946 prop = machine.memory + ((obj[7]<<8)|obj[8]) + 1; 947 948#ifdef DEBUG 949 printf_debug(">%s<\n", zscii_to_ascii(prop, &len)); 950#endif 951 952 stream_prints(zscii_to_unicode(prop, &len)); 953%} 954 955OPCODE "print_obj" 1OP:0x0a VERSION 4,5,6,7,8 956%{ 957 ZByte* obj; 958 ZByte* prop; 959 int len; 960 961 obj = Obj4(uarg1); 962 prop = Address((ZUWord)GetPropAddr4(obj)+1); 963 964#ifdef DEBUG 965 printf_debug(">%s<\n", zscii_to_ascii(prop, &len)); 966#endif 967 968 stream_prints(zscii_to_unicode(prop, &len)); 969%} 970 971OPCODE "ret" 1OP:0x0b CANJUMP VERSION all 972%{ 973 ZFrame* oldframe; 974 int end_func; 975 976 oldframe = stack->current_frame; 977 stack->current_frame = oldframe->last_frame; 978 stack->stack_top -= oldframe->frame_size; 979 stack->stack_size += oldframe->frame_size; 980 981 pc = oldframe->ret; 982 983 if (oldframe->discard == 0) 984 store(stack, oldframe->storevar, arg1); 985 986 if (oldframe->v4read != NULL) 987 (oldframe->v4read)(&pc, stack, &oldframe->readblock); 988 if (oldframe->v5read != NULL) 989 { 990#ifdef DEBUG 991 printf_debug("Stack: Calling V5 callback routine\n"); 992#endif 993 (oldframe->v5read)(&pc, stack, &oldframe->readblock, oldframe->readstore); 994 end_func = 1; 995 } 996 997#ifdef DEBUG 998 if (oldframe->discard == 0) 999 printf_debug("Returned %i into V%x\n", arg1, oldframe->storevar); 1000 if (stack->current_frame != NULL) 1001 printf_debug("Stack: returned, discarded %i outstanding items (stack top now #%x, size %i, frame usage %i)\n", 1002 oldframe->frame_size, stack->stack_top, stack->stack_size, 1003 stack->current_frame!=NULL?stack->current_frame->frame_size:-1); 1004#endif 1005 1006 end_func = oldframe->end_func; 1007 1008 free(oldframe); 1009 1010 if (stack->current_frame && stack->current_frame->break_on_return) 1011 { 1012 /* Treat as a breakpoint */ 1013 debug_run_breakpoint(pc); 1014 } 1015 1016 if (end_func) 1017 { 1018#ifdef DEBUG 1019 printf_debug("Stack: Exit from interpreter loop\n"); 1020#endif 1021 return; 1022 } 1023%} 1024 1025OPCODE "jump" 1OP:0x0c CANJUMP VERSION all 1026%{ pc += arg1-2; %} 1027 1028OPCODE "print_paddr" 1OP:0x0d VERSION 1,2,3 1029%{ 1030 int len; 1031 1032#ifdef DEBUG 1033 printf_debug(">%s<\n", zscii_to_ascii(machine.memory + (((ZDWord)uarg1)<<1), &len)); 1034#endif 1035 1036 stream_prints(zscii_to_unicode(machine.memory + (((ZDWord)uarg1)<<1), &len)); 1037%} 1038 1039OPCODE "print_paddr" 1OP:0x0d VERSION 4,5,6,7,8 1040%{ 1041 int len; 1042 1043#ifdef DEBUG 1044 printf_debug(">%s<\n", zscii_to_ascii(machine.memory + UnpackS(uarg1), &len)); 1045#endif 1046 1047 stream_prints(zscii_to_unicode(machine.memory + UnpackS(uarg1), &len)); 1048%} 1049 1050OPCODE "load" 1OP:0x0e STORE VERSION all 1051%{ 1052 store(stack, st, GetVarNoPop(uarg1)); 1053%} 1054 1055OPCODE "not" 1OP:0x0f STORE VERSION 1,2,3,4 1056%{ 1057 store(stack, st, ~GetVar(arg1)); 1058%} 1059 1060OPCODE "call_1n" 1OP:0x0f CANJUMP VERSION 5,6,7,8 1061%{ 1062 ZDWord new_routine; 1063 ZFrame* newframe; 1064 1065 if (arg1 == 0) 1066 { 1067 store(stack, st, 0); 1068 goto loop; 1069 } 1070 1071 new_routine = UnpackR(arg1); 1072 newframe = call_routine(&pc, stack, new_routine); 1073 1074 newframe->discard = 1; 1075%} 1076 1077#### ----// 888 \\---- #### 1078# 0OPs 1079 1080OPCODE "rtrue" 0OP:0x00 CANJUMP VERSION all 1081%{ 1082 arg1 = 1; goto op_ret; 1083%} 1084 1085OPCODE "rfalse" 0OP:0x01 CANJUMP VERSION all 1086%{ 1087 arg1 = 0; goto op_ret; 1088%} 1089 1090OPCODE "print" 0OP:0x02 STRING VERSION all 1091%{ 1092#ifdef DEBUG 1093 printf_debug(">%s<\n", string); 1094#endif 1095 stream_prints((int*)string); 1096%} 1097 1098OPCODE "print_ret" 0OP:0x03 CANJUMP STRING VERSION all 1099%{ 1100#ifdef DEBUG 1101 printf_debug(">%s<\n", string); 1102#endif 1103 stream_prints((int*)string); 1104 stream_printf("\n"); 1105 stream_flush_buffer(); 1106 goto op_rtrue; 1107%} 1108 1109OPCODE "nop" 0OP:0x04 VERSION all 1110%{ /* zzz */ %} 1111 1112OPCODE "save" 0OP:0x05 BRANCH VERSION 1,2,3 1113%{ 1114 ZDWord newpc; 1115 1116 if (branch == 0 || branch == 1) 1117 { 1118 zmachine_warning("This interpreter does not support returning from v3 save statements correctly"); 1119 newpc = pc; 1120 } 1121 else 1122 { 1123 newpc = pc; 1124 if (negate) 1125 newpc += branch-2; 1126 } 1127 1128 result = save_1234(newpc, stack, -1); 1129 dobranch; 1130%} 1131 1132OPCODE "save" 0OP:0x05 STORE CANJUMP VERSION 4 1133%{ 1134 if (save_1234(pc, stack, st)) 1135 store(stack, st, 1); 1136 else 1137 store(stack, st, 0); 1138%} 1139 1140OPCODE "restore" 0OP:0x06 BRANCH VERSION 1,2,3 1141%{ 1142 if (!restore_1234(&pc, stack)) 1143 { 1144 result = 0; 1145 dobranch; 1146 } 1147%} 1148 1149OPCODE "restore" 0OP:0x06 STORE CANJUMP VERSION 4 1150%{ 1151 if (!restore_1234(&pc, stack)) 1152 { 1153 store(stack, st, 0); 1154 } 1155%} 1156 1157OPCODE "restart" 0OP:0x07 CANJUMP VERSION 3,4,5,7,8 1158%{ 1159 /* Unwind stack */ 1160 while (stack->current_frame->last_frame != NULL) 1161 { 1162 ZFrame* oldframe; 1163 1164 oldframe = stack->current_frame; 1165 stack->current_frame = oldframe->last_frame; 1166 1167 stack->stack_size += oldframe->frame_size; 1168 stack->stack_top -= oldframe->frame_size; 1169 1170 free(oldframe); 1171 } 1172 1173 display_join(0, 2); 1174 display_set_window(0); 1175 display_erase_window(); 1176 if (ReadByte(0) > 4) 1177 display_set_cursor(0,0); 1178 1179 read_block2(machine.memory, machine.file, 1180 machine.story_offset, machine.story_offset+machine.dynamic_ceiling); 1181 pc = Word(ZH_initpc); 1182 1183 restart_machine(); 1184%} 1185 1186OPCODE "ret_popped" 0OP:0x08 CANJUMP VERSION all 1187%{ 1188 arg1 = pop(stack); 1189 goto op_ret; 1190%} 1191 1192OPCODE "pop" 0OP:0x09 VERSION 1,2,3,4 1193%{ pop(stack); %} 1194 1195OPCODE "catch" 0OP:0x09 STORE VERSION 5,6,7,8 1196%{ 1197 if (stack->current_frame == NULL) 1198 zmachine_fatal("Catch attempted while no frame is current"); 1199 store(stack, st, stack->current_frame->frame_num); 1200%} 1201 1202OPCODE "quit" 0OP:0x0a CANJUMP VERSION all 1203%{ 1204 pc = -1; 1205 return; 1206%} 1207 1208OPCODE "new_line" 0OP:0x0b VERSION all 1209%{ 1210 stream_printf("\n"); 1211%} 1212 1213OPCODE "show_status" 0OP:0x0c VERSION 3 1214%{ 1215 draw_statusbar_123(stack); 1216%} 1217 1218OPCODE "status_nop" 0OP:0x0c VERSION 4,5,6,7,8 1219%{ 1220 debug_breakpoint* bp; 1221 1222 /* Zzzz */ 1223 1224 if ((bp=debug_get_breakpoint(pc-1)) != NULL) 1225 { 1226 pc--; 1227 instr = bp->original; 1228 debug_run_breakpoint(pc); 1229 goto execute_instr; 1230 } 1231%} 1232 1233OPCODE "verify" 0OP:0x0d BRANCH VERSION all # 3,4,5,6,7,8 1234%{ 1235 result = 1; 1236 dobranch; 1237%} 1238 1239OPCODE "piracy" 0OP:0x0f BRANCH VERSION 5,6,7,8 1240%{ 1241 result = 1; 1242 dobranch; 1243%} 1244 1245#### ----// 888 \\---- #### 1246# VAR ops 1247 1248OPCODE "call" VAR:0x00 STORE CANJUMP VERSION 1,2,3 1249%{ 1250 ZDWord new_routine; 1251 ZFrame* newframe; 1252 int x; 1253 1254 if (argblock.n_args < 1) 1255 zmachine_fatal("call must have 1 argument"); 1256 1257 if (argblock.arg[0] == 0) 1258 { 1259 store(stack, st, 0); 1260 goto loop; 1261 } 1262 1263 new_routine = 2*(ZUWord)argblock.arg[0]; 1264 1265#ifdef DEBUG 1266 printf_debug("CALL $%x -> V%03i\n", new_routine, st); 1267#endif 1268 1269 newframe = call_routine(&pc, stack, new_routine); 1270 1271 for (x=1; x<argblock.n_args; x++) 1272 { 1273 newframe->flags |= 1<<(x-1); 1274 newframe->local[x] = argblock.arg[x]; 1275 } 1276 1277 newframe->storevar = st; 1278%} 1279 1280OPCODE "call_vs" VAR:0x00 STORE CANJUMP VERSION 4,5,6,7,8 1281%{ 1282 ZDWord new_routine; 1283 ZFrame* newframe; 1284 int x; 1285 1286 if (argblock.n_args < 1) 1287 zmachine_fatal("call must have 1 argument"); 1288 1289 if (argblock.arg[0] == 0) 1290 { 1291 store(stack, st, 0); 1292 goto loop; 1293 } 1294 1295 new_routine = UnpackR((ZUWord)argblock.arg[0]); 1296 1297#ifdef DEBUG 1298 printf_debug("CALL $%x -> V%03i\n", new_routine, st); 1299#endif 1300 1301 newframe = call_routine(&pc, stack, new_routine); 1302 1303 for (x=1; x<argblock.n_args; x++) 1304 { 1305 newframe->flags |= 1<<(x-1); 1306 newframe->local[x] = argblock.arg[x]; 1307 } 1308 1309 newframe->storevar = st; 1310%} 1311 1312OPCODE "storew" VAR:0x01 ARGS:3 VERSION all 1313%{ 1314 ZByte* mem; 1315 1316#ifdef DEBUG 1317 printf_debug("Storing word value %i at #%x\n", 1318 argblock.arg[2], 1319 ((ZUWord) argblock.arg[0] + (ZUWord) (argblock.arg[1]*2))&0xffff); 1320#endif 1321#ifdef SAFE 1322 if (((ZUWord) argblock.arg[0] + ((ZWord) argblock.arg[1]*2)+1) > 1323 machine.dynamic_ceiling) 1324 zmachine_fatal("Out of range storew (tried to store at $%x, but ceiling is at $%x)", 1325 ((ZUWord) argblock.arg[0] + ((ZUWord) argblock.arg[1]*2)), 1326 machine.dynamic_ceiling); 1327#endif 1328 1329 if ((ZUWord) argblock.arg[0] + ((ZWord) argblock.arg[1]*2) == ZH_flags2) 1330 { 1331 ZArgblock a; 1332 1333 stream_flush_buffer(); 1334 1335 a.n_args = 1; 1336 a.arg[0] = (argblock.arg[2]&1)?2:-2; 1337 1338 zcode_op_output_stream(stack, &a); 1339 1340 argblock.arg[2] &= ~1; 1341 argblock.arg[2] |= Word(ZH_flags2)&1; 1342 } 1343 1344 mem = Address(((ZUWord) argblock.arg[0] + ((ZWord) argblock.arg[1]*2))&0xffff); 1345 mem[0] = argblock.arg[2]>>8; 1346 mem[1] = argblock.arg[2]; 1347%} 1348 1349OPCODE "storeb" VAR:0x02 ARGS:3 VERSION all 1350%{ 1351 ZByte* mem; 1352 1353#ifdef DEBUG 1354 printf_debug("Storing byte value %i at #%x\n", 1355 argblock.arg[2], 1356 ((ZUWord) argblock.arg[0] + (ZWord) argblock.arg[1])&0xffff); 1357#endif 1358#ifdef SAFE 1359 if (((ZUWord) argblock.arg[0] + (ZWord) argblock.arg[1]) > 1360 machine.dynamic_ceiling) 1361 zmachine_fatal("Out of range storeb (store to $%x, ceiling at $%x)", ((ZUWord) argblock.arg[0] + (ZUWord) argblock.arg[1]), machine.dynamic_ceiling); 1362#endif 1363 1364 mem = Address(((ZUWord) argblock.arg[0] + (ZWord) argblock.arg[1])&0xffff); 1365 mem[0] = argblock.arg[2]; 1366%} 1367 1368OPCODE "put_prop" VAR:0x03 ARGS:3 VERSION 1,2,3 1369%{ 1370 struct prop* p; 1371 1372 if (argblock.arg[0]>255 || argblock.arg[0] == 0) 1373 zmachine_fatal("Object %i out of range", argblock.arg[0]); 1374 argblock.arg[1] &= 0x1f; 1375 if (argblock.arg[1]>31) 1376 zmachine_fatal("Property %i out of range", argblock.arg[1]); 1377 1378 p = get_object_prop_3(argblock.arg[0], argblock.arg[1]); 1379 if (p->isdefault) 1380 zmachine_fatal("No such property %i for object %i", argblock.arg[1], argblock.arg[0]); 1381 1382 switch (p->size) 1383 { 1384 case 1: 1385 p->prop[0] = argblock.arg[2]; 1386 break; 1387 1388 case 2: 1389 p->prop[0] = argblock.arg[2]>>8; 1390 p->prop[1] = argblock.arg[2]; 1391 break; 1392 1393 default: 1394 zmachine_fatal("%i is an invalid size for put_prop", p->size); 1395 } 1396%} 1397 1398OPCODE "put_prop" VAR:0x03 ARGS:3 VERSION 4,5,6,7,8 1399%{ 1400 struct prop* p; 1401 1402 if (argblock.arg[0] == 0) 1403 { 1404 zmachine_warning("Object 0 has no properties"); 1405 goto loop; 1406 } 1407 if (argblock.arg[1]>63) 1408 zmachine_fatal("Property %i out of range", argblock.arg[1]); 1409 1410 p = get_object_prop_4(argblock.arg[0], argblock.arg[1]); 1411 if (p->isdefault) 1412 { 1413 zmachine_warning("No such property %i for object %i", argblock.arg[1], argblock.arg[0]); 1414 goto loop; 1415 } 1416 1417 switch (p->size) 1418 { 1419 case 1: 1420 p->prop[0] = argblock.arg[2]; 1421 break; 1422 1423 case 2: 1424 p->prop[0] = argblock.arg[2]>>8; 1425 p->prop[1] = argblock.arg[2]; 1426 break; 1427 1428 default: 1429 zmachine_fatal("%i is an invalid size for put_prop", p->size); 1430 } 1431%} 1432 1433OPCODE "sread" VAR:0x04 ARGS:2 VERSION 1,2,3 1434%{ 1435 ZByte* mem; 1436 int* buf; 1437 int x; 1438 1439 //pc -= (2+padding); /* HACK: allow autosave */ 1440 machine.autosave_pc = pc - (2+padding); 1441 1442 stream_flush_buffer(); 1443 1444 mem = machine.memory + (ZUWord) argblock.arg[0]; 1445 buf = malloc(sizeof(int)*(mem[0]+1)); 1446 1447 buf[0] = 0; 1448 draw_statusbar_123(stack); 1449 stream_readline(buf, mem[0], 0); 1450 1451 for (x=0; buf[x] != 0; x++) 1452 { 1453 buf[x] = unicode_to_lower(buf[x]); 1454 mem[x+1] = zscii_get_char(buf[x]); 1455 } 1456 mem[x+1] = 0; 1457 1458 if (argblock.n_args > 1) 1459 { 1460 tokenise_string((int*)buf, 1461 Word(ZH_dict), 1462 machine.memory + (ZUWord) argblock.arg[1], 1463 0, 1464 1); 1465 1466#ifdef DEBUG 1467 { 1468 ZByte* tokbuf; 1469 tokbuf = machine.memory + (ZUWord) argblock.arg[1]; 1470 for (x=0; x<tokbuf[1]; x++) 1471 { 1472 printf_debug("Token $%x%x word at %i, length %i\n", 1473 tokbuf[2+x*4], 1474 tokbuf[3+x*4], 1475 tokbuf[5+x*4], 1476 tokbuf[4+x*4]); 1477 } 1478 } 1479#endif 1480 } 1481 1482 free(buf); 1483 1484 machine.autosave_pc = 0; 1485 //pc += (2+padding); /* HACK: allow autosave */ 1486%} 1487 1488OPCODE "sread" VAR:0x04 ARGS:4 CANJUMP VERSION 4 1489%{ 1490 //pc -= (2+padding); /* HACK: allow autosave */ 1491 machine.autosave_pc = pc - (2+padding); 1492 zcode_op_sread_4(&pc, stack, &argblock); 1493 machine.autosave_pc = 0; 1494 //pc += (2+padding); /* HACK: allow autosave */ 1495%} 1496 1497OPCODE "aread" VAR:0x04 ARGS:4 STORE CANJUMP VERSION 5,7,8 1498%{ 1499 //pc -= (3+padding); /* HACK: allow autosave */ 1500 machine.autosave_pc = pc - (3+padding); 1501 zcode_op_aread_5678(&pc, stack, &argblock, st); 1502 machine.autosave_pc = 0; 1503 //pc += (3+padding); /* HACK: allow autosave */ 1504%} 1505 1506OPCODE "print_char" VAR:0x05 ARGS:1 VERSION all 1507%{ 1508 int ch[2]; 1509 1510#ifdef DEBUG 1511 printf_debug(">%c<\n", argblock.arg[0]); 1512#endif 1513 if (argblock.arg[0] >= 256) 1514 argblock.arg[0] = '?'; 1515 if (argblock.arg[0] == 0) 1516 argblock.arg[0] = 32; 1517 ch[0] = zscii_unicode[argblock.arg[0]]; 1518 ch[1] = 0; 1519 stream_prints((int*)ch); 1520%} 1521 1522OPCODE "print_num" VAR:0x06 ARGS:1 VERSION all 1523%{ 1524#ifdef DEBUG 1525 printf_debug(">%i<\n", argblock.arg[0]); 1526#endif 1527 stream_printf("%i", argblock.arg[0]); 1528%} 1529 1530OPCODE "random" VAR:0x07 ARGS:1 STORE VERSION all 1531%{ 1532 if (argblock.arg[0] > 0) 1533 { 1534 unsigned int random = random_number()>>8; 1535 random = random&0xffff; 1536 random = (random*argblock.arg[0])/0x10000; 1537 store(stack, st, random+1); 1538 1539 #ifdef DEBUG 1540 printf_debug("Random(%i) = %i\n", argblock.arg[0], random+1); 1541 #endif 1542 } 1543 else if (argblock.arg[0] < 0) 1544 { 1545 random_seed(argblock.arg[0]); 1546 store(stack, st, 0); 1547 } 1548 else 1549 { 1550#ifdef HAVE_GETTIMEOFDAY 1551 struct timeval tv; 1552 1553 /* Reseed RNG */ 1554 gettimeofday(&tv, NULL); 1555 random_seed(tv.tv_sec^tv.tv_usec); 1556#else 1557 random_seed((unsigned int) time(NULL)); 1558#endif 1559 1560 store(stack, st, 0); 1561 } 1562%} 1563 1564OPCODE "push" VAR:0x08 ARGS:1 VERSION all 1565%{ 1566 push(stack, argblock.arg[0]); 1567%} 1568 1569OPCODE "pull" VAR:0x09 ARGS:1 VERSION 3,4,5,7,8 1570%{ 1571 ZUWord val; 1572 1573 val = pop(stack); 1574 store_nopush(stack, argblock.arg[0], val); 1575%} 1576 1577OPCODE "split_window" VAR:0x0a ARGS:1 VERSION 3,4,5,7,8 1578%{ 1579 stream_flush_buffer(); 1580 1581 if (argblock.arg[0] != 0) 1582 { 1583 int win; 1584 int ver; 1585 1586 ver = ReadByte(0); 1587 1588#ifdef DEBUG 1589 printf_debug("Top window bottom is now %i\n", argblock.arg[0]); 1590#endif 1591 1592 win = display_get_window(); 1593 1594 if (ver == 3) 1595 { 1596 display_set_window(2); 1597 display_erase_window(); 1598 } 1599 1600 display_set_window(0); 1601 display_join(0, 2); 1602 display_split(argblock.arg[0], 2); 1603 display_set_window(2); 1604 if (ver == 3) 1605 { 1606 display_set_cursor(0,1); 1607 display_erase_window(); 1608 } 1609 display_force_fixed(2, 1); 1610 1611 display_set_window(win); 1612 } 1613 else 1614 { 1615 if (ReadByte(0) == 3) 1616 { 1617 display_set_window(2); 1618 display_erase_window(); 1619 } 1620 1621 display_join(0, 2); 1622 display_set_window(0); 1623 } 1624 1625 if (machine.transcript_on == 2 && display_get_window() == 0) 1626 machine.transcript_on = 1; 1627%} 1628 1629OPCODE "set_window" VAR:0x0b ARGS:1 VERSION 3,4,5,7,8 1630%{ 1631 stream_flush_buffer(); 1632 1633 switch (argblock.arg[0]) 1634 { 1635 case 0: 1636 stream_buffering(machine.buffering); 1637 display_set_window(0); 1638 1639 if (machine.transcript_on == 2) 1640 machine.transcript_on = 1; 1641 break; 1642 case 1: 1643 stream_buffering(0); 1644 display_set_window(2); 1645 if (ReadByte(0) == 3) 1646 display_set_cursor(0,1); 1647 1648 if (machine.transcript_on == 1) 1649 machine.transcript_on = 2; 1650 break; 1651 default: 1652 zmachine_warning("Window %i not available", argblock.arg[0]); 1653 } 1654%} 1655 1656 1657OPCODE "call_vs2" VAR:0x0c STORE LONG CANJUMP VERSION 4,5,6,7,8 1658%{ 1659 goto op_call_vs_45678; 1660%} 1661 1662OPCODE "erase_window" VAR:0x0d ARGS:1 VERSION 4,5,7,8 1663%{ 1664 int old_win; 1665 1666 stream_flush_buffer(); 1667 old_win = display_get_window(); 1668 1669 switch (argblock.arg[0]) 1670 { 1671 case 0: 1672 display_set_window(0); 1673 display_erase_window(); 1674 if (ReadByte(0) != 4) 1675 display_set_cursor(0,0); 1676 display_set_window(old_win); 1677 break; 1678 1679 case 1: 1680 display_set_window(2); 1681 display_erase_window(); 1682 display_set_cursor(0,0); 1683 display_set_window(old_win); 1684 break; 1685 1686 case -1: 1687 display_join(0, 2); 1688 display_set_window(0); 1689 display_erase_window(); 1690 if (ReadByte(0) != 4) 1691 display_set_cursor(0,0); 1692 break; 1693 1694 case -2: 1695 old_win = display_get_window(); 1696 display_set_window(0); 1697 display_erase_window(); 1698 display_set_window(2); 1699 display_erase_window(); 1700 display_set_window(old_win); 1701 break; 1702 } 1703%} 1704 1705OPCODE "erase_line" VAR:0x0e ARGS:1 VERSION 4,5,7,8 1706%{ 1707 if (arg1 == 1) 1708 { 1709 display_erase_line(1); 1710 } 1711%} 1712 1713OPCODE "set_cursor" VAR:0x0f ARGS:2 VERSION 4,5,7,8 1714%{ 1715 stream_flush_buffer(); 1716#ifdef DEBUG 1717 printf_debug("Cursor moved to %i, %i\n", argblock.arg[1]-1, argblock.arg[0]-1); 1718#endif 1719 if (display_get_window() == 2) 1720 { 1721 display_set_cursor(argblock.arg[1]-1, argblock.arg[0]-1); 1722 } 1723%} 1724 1725OPCODE "get_cursor" VAR:0x10 ARGS:1 VERSION 4,5,7,8 1726%{ 1727 ZByte* dest; 1728 int x, y; 1729 1730 dest = Address((ZUWord)argblock.arg[0]); 1731 x = display_get_cur_x()+1; 1732 y = display_get_cur_y()+1; 1733 1734 dest[0] = y>>8; 1735 dest[1] = y; 1736 dest[2] = x>>8; 1737 dest[3] = x; 1738%} 1739 1740OPCODE "set_text_style" VAR:0x11 ARGS:1 VERSION 4,5,7,8 1741%{ 1742 stream_flush_buffer(); 1743#ifndef SPEC_11 1744 if (argblock.arg[0] != 0 && 1745 argblock.arg[0] != 1 && 1746 argblock.arg[0] != 2 && 1747 argblock.arg[0] != 4 && 1748 argblock.arg[0] != 8 && 1749 argblock.arg[0] != 16) 1750 { 1751 zmachine_warning("Multiple styles not (officially) supported in standard 1.0", argblock.arg[0]); 1752 } 1753#endif 1754 display_set_style(argblock.arg[0]); 1755%} 1756 1757OPCODE "buffer_mode" VAR:0x12 ARGS:1 VERSION 4,5,6,7,8 1758%{ 1759 machine.buffering = argblock.arg[0]; 1760 stream_buffering(argblock.arg[0]); 1761%} 1762 1763OPCODE "output_stream" VAR:0x13 ARGS:1 VERSION 3 1764%{ 1765 zcode_op_output_stream(stack, &argblock); 1766%} 1767 1768OPCODE "output_stream" VAR:0x13 ARGS:2 VERSION 4,5,7,8 1769%{ 1770 zcode_op_output_stream(stack, &argblock); 1771%} 1772 1773OPCODE "input_stream" VAR:0x14 ARGS:1 VERSION all # 3,4,5,7,8 1774%{ 1775 switch (argblock.arg[0]) 1776 { 1777 case 0: 1778 machine.script_on = 0; 1779 break; 1780 1781 case 1: 1782 machine.script_on = 0; 1783 if (!machine.script_file) 1784 { 1785 int sz; 1786 machine.script_file = get_file_read(&sz, script_fname, ZFile_transcript); 1787 } 1788 machine.script_on = 1; 1789 if (!machine.script_file) 1790 { 1791 stream_printf("Couldn't open %s for reading.\n", script_fname); 1792 machine.script_on = 0; 1793 } 1794 if (machine.script_file && end_of_file(machine.script_file)) 1795 { 1796 close_file(machine.script_file); 1797 stream_printf("Couldn't read any data from %s\n", script_fname); 1798 machine.script_file = NULL; 1799 machine.script_on = 0; 1800 } 1801 break; 1802 1803 default: 1804 zmachine_warning("Input stream %i not supported", argblock.arg[0]); 1805 } 1806%} 1807 1808OPCODE "sound_effect" VAR:0x15 VERSION all # 3,4,5,6,7,8 1809%{ 1810 display_beep(); 1811%} 1812 1813OPCODE "read_char" VAR:0x16 ARGS:3 STORE CANJUMP VERSION 4,5,7,8 1814%{ 1815 //pc -= (3+padding); /* HACK: allow autosave */ 1816 machine.autosave_pc = pc - (3+padding); 1817 1818 stream_flush_buffer(); 1819 1820 if (argblock.n_args < 2) 1821 { 1822 zcode_op_readchar(&pc, stack, &argblock, st); 1823 } 1824 else 1825 { 1826 zcode_op_readchar(&pc, stack, &argblock, st); 1827 } 1828 1829 machine.autosave_pc = 0; 1830 //pc += (3+padding); /* HACK: allow autosave */ 1831%} 1832 1833OPCODE "scan_table" VAR:0x17 BRANCH STORE VERSION 4,5,6,7,8 1834%{ 1835 ZDWord adr; 1836 1837 if (argblock.n_args < 4) 1838 argblock.arg[3] = 0x82; 1839 1840 adr = scan_table(argblock.arg[0], 1841 argblock.arg[1], 1842 argblock.arg[2], 1843 argblock.arg[3]); 1844 1845 if (adr > 0) 1846 { 1847 store(stack, st, adr); 1848 result = 1; 1849 } 1850 else 1851 { 1852 store(stack, st, 0); 1853 result = 0; 1854 } 1855 dobranch; 1856%} 1857 1858OPCODE "not" VAR:0x18 ARGS:1 STORE VERSION 5,6,7,8 1859%{ 1860 store(stack, st, ~argblock.arg[0]); 1861%} 1862 1863OPCODE "call_vn" VAR:0x19 CANJUMP VERSION 5,6,7,8 1864%{ 1865 ZDWord new_routine; 1866 ZFrame* newframe; 1867 int x; 1868 1869 if (argblock.n_args < 1) 1870 zmachine_fatal("call must have 1 argument"); 1871 1872 if (argblock.arg[0] == 0) 1873 { 1874 store(stack, st, 0); 1875 goto loop; 1876 } 1877 1878 new_routine = UnpackR((ZUWord)argblock.arg[0]); 1879 1880#ifdef DEBUG 1881 printf_debug("CALL $%x -> V%03i\n", new_routine, st); 1882#endif 1883 1884 newframe = call_routine(&pc, stack, new_routine); 1885 1886 for (x=1; x<argblock.n_args; x++) 1887 { 1888 newframe->flags |= 1<<(x-1); 1889 newframe->local[x] = argblock.arg[x]; 1890 } 1891 1892 newframe->discard = 1; 1893%} 1894 1895OPCODE "call_vn2" VAR:0x1a CANJUMP LONG VERSION 5,6,7,8 1896%{ 1897 goto op_call_vn_5678; 1898%} 1899 1900OPCODE "tokenise" VAR:0x1b ARGS:4 VERSION 5,6,7,8 1901%{ 1902 ZByte* text; 1903 int* buf; 1904 int x; 1905 1906 text = Address((ZUWord)argblock.arg[0]); 1907 buf = malloc(sizeof(int)*(text[1]+1)); 1908 for (x=0; x<text[1]; x++) 1909 buf[x] = zscii_unicode[text[x+2]]; 1910 buf[x] = 0; 1911 1912 tokenise_string(buf, 1913 argblock.arg[2]==0?Word(ZH_dict):argblock.arg[2], 1914 Address((ZUWord)argblock.arg[1]), 1915 argblock.arg[3] != 0, 1916 2); 1917 1918#ifdef DEBUG 1919 { 1920 ZByte* tokbuf; 1921 int x; 1922 1923 tokbuf = machine.memory + (ZUWord) argblock.arg[1]; 1924 for (x=0; x<tokbuf[1]; x++) 1925 { 1926 printf_debug("Token $%x%x word at %i, length %i\n", 1927 tokbuf[2+x*4], 1928 tokbuf[3+x*4], 1929 tokbuf[5+x*4], 1930 tokbuf[4+x*4]); 1931 } 1932 } 1933#endif 1934 1935 free(buf); 1936%} 1937 1938OPCODE "encode_text" VAR:0x1c ARGS:4 VERSION 5,6,7,8 1939%{ 1940 int* buf; 1941 int x; 1942 char* d; 1943 1944 buf = malloc(sizeof(int)*(argblock.arg[1]+1)); 1945 d = Address((ZUWord)argblock.arg[0]) + argblock.arg[2]; 1946 1947 for (x=0; x<argblock.arg[1]; x++) 1948 buf[x] = zscii_get_char(d[x]); 1949 buf[x] = 0; 1950 1951 /* Note: I haven't tested this yet */ 1952 pack_zscii(buf, 1953 argblock.arg[1], 1954 Address((ZUWord)argblock.arg[3]), 1955 9); 1956 1957 free(buf); 1958%} 1959 1960OPCODE "copy_table" VAR:0x1d ARGS:3 VERSION 5,6,7,8 1961%{ 1962 if (argblock.arg[1] != 0) 1963 { 1964#ifdef DEBUG 1965 printf_debug("Copying #%x bytes from #%x to #%x\n", argblock.arg[2], 1966 (ZUWord)argblock.arg[0], (ZUWord)argblock.arg[1]); 1967#endif 1968 1969 if (argblock.arg[2] >= 0) /* Move memory */ 1970 memmove(Address((ZUWord)argblock.arg[1]), 1971 Address((ZUWord)argblock.arg[0]), 1972 (ZUWord)argblock.arg[2]); 1973 else /* Copy forwards */ 1974 { 1975 ZUWord x; 1976 ZByte* src; 1977 ZByte* dest; 1978 1979 src = Address((ZUWord)argblock.arg[0]); 1980 dest = Address((ZUWord)argblock.arg[1]); 1981 1982 for (x = 0; x<-argblock.arg[2]; x++) 1983 { 1984 dest[x] = src[x]; 1985 } 1986 } 1987 } 1988 else 1989 { 1990 ZUWord x; 1991 ZByte* mem; 1992 1993#ifdef DEBUG 1994 printf_debug("Blanking %i bytes from #%x\n", argblock.arg[2], (ZUWord)argblock.arg[0]); 1995#endif 1996 1997 mem = Address((ZUWord)argblock.arg[0]); 1998 1999 for (x=0; x<argblock.arg[2]; x++) 2000 { 2001 mem[x] = 0; 2002 } 2003 } 2004%} 2005 2006OPCODE "print_table" VAR:0x1e VERSION 5,7,8 2007%{ 2008 ZByte* table; 2009 int x,y; 2010 int xpos, ypos; 2011 2012 stream_flush_buffer(); 2013 xpos = display_get_cur_x(); 2014 ypos = display_get_cur_y(); 2015 2016 if (argblock.arg[2] == 0) 2017 argblock.arg[2] = 1; 2018 2019#ifdef DEBUG 2020 printf_debug("Printing table #%x (%ix%i), offset %i\n", argblock.arg[0], argblock.arg[1], argblock.arg[2], argblock.arg[3]); 2021#endif 2022 2023 table = Address((ZUWord) argblock.arg[0]); 2024 2025 for (y=0; y<argblock.arg[2]; y++) 2026 { 2027 if (y != 0) 2028 { 2029 stream_flush_buffer(); 2030 if (machine.screen_on) 2031 display_set_cursor(xpos, ypos+y); 2032 } 2033 2034 for (x=0; x<argblock.arg[1]; x++) 2035 { 2036 unsigned char c; 2037 2038 c = (table++)[0]; 2039 if (c == 0) 2040 c = 32; 2041 if (c>31) 2042 stream_printf("%c", c); 2043 } 2044 2045 table += argblock.arg[3]; 2046 } 2047 stream_flush_buffer(); 2048%} 2049 2050OPCODE "check_argcount" VAR:0x1f ARGS:1 BRANCH VERSION 5,6,7,8 2051%{ 2052 result = (stack->current_frame->flags&(1<<(argblock.arg[0]-1)))!=0; 2053 dobranch; 2054%} 2055 2056#### ----// 888 \\---- #### 2057# EXT ops 2058 2059OPCODE "save" EXT:0x00 ARGS:3 STORE CANJUMP VERSION 5,6,7,8 2060%{ 2061 stream_flush_buffer(); 2062 2063 if (argblock.n_args == 0) 2064 { 2065 ZWord tmp; 2066 ZFile* f; 2067 2068 stream_printf("\nPlease supply a filename for save\n"); 2069 f = get_file_write(NULL, save_fname, ZFile_save); 2070 2071 store(stack, st, 2); 2072 if (state_save(f, stack, pc)) 2073 { 2074 tmp = GetVar(st); /* Pop the variable if it was on the stack */ 2075 store(stack, st, 1); 2076 } 2077 else 2078 { 2079 tmp = GetVar(st); 2080 store(stack, st, 0); 2081 2082 if (state_fail()) 2083 stream_printf("(Save failed, reason: %s)\n", state_fail()); 2084 else 2085 stream_printf("(Save failed, reason unknown)\n"); 2086 } 2087 } 2088 else 2089 { 2090 char fname[256]; 2091 ZFile* file; 2092 int prompt = 1; 2093 2094#ifdef SPEC_11 2095 if (argblock.n_args > 3) 2096 prompt = argblock.arg[3]; 2097#endif 2098 2099 if (argblock.arg[2] != 0) 2100 { 2101 strncpy(fname, 2102 Address(argblock.arg[2]+1), 2103 ReadByte(argblock.arg[2])); 2104 fname[ReadByte(argblock.arg[2])] = 0; 2105 } 2106 else 2107 strcpy(fname, "table.dat"); 2108 2109 if (prompt) 2110 { 2111 stream_printf("\nPlease supply a filename for data save\n"); 2112 file = get_file_write(NULL, fname, ZFile_data); 2113 } 2114 else 2115 { 2116 char* newname; 2117 2118 newname = malloc(strlen(rc_get_savedir()) + 2119 strlen(fname) + 3); 2120 2121 sprintf(newname, "%s/%s", rc_get_savedir(), fname); /* Safe: see above */ 2122 2123 file = open_file_write(newname); 2124 2125 free(newname); 2126 } 2127 2128 if (!(file)) 2129 { 2130 store(stack, st, 0); 2131 goto loop; 2132 } 2133 2134 write_block(file, Address(argblock.arg[0]), (ZUWord)argblock.arg[1]); 2135 2136 close_file(file); 2137 2138 store(stack, st, argblock.arg[1]); 2139 } 2140%} 2141 2142OPCODE "restore" EXT:0x01 ARGS:3 STORE CANJUMP VERSION 5,6,7,8 2143%{ 2144 if (argblock.n_args == 0) 2145 { 2146 ZFile* f; 2147 ZDWord sz; 2148 2149 stream_printf("\nPlease supply a filename for restore\n"); 2150 f = get_file_read(&sz, save_fname, ZFile_save); 2151 2152 if (state_load(f, sz, stack, &pc)) 2153 { 2154 zmachine_setup_header(); 2155 goto loop; 2156 } 2157 2158 if (state_fail()) 2159 stream_printf("(Restore failed, reason: %s)\n", state_fail()); 2160 else 2161 stream_printf("(Restore failed, reason unknown)\n"); 2162 2163 store(stack, st, 0); 2164 } 2165 else 2166 { 2167 char fname[256]; 2168 ZFile* file; 2169 int sz; 2170 int prompt = 1; 2171 2172#ifdef SPEC_11 2173 if (argblock.n_args > 3) 2174 prompt = argblock.arg[3]; 2175#endif 2176 2177 if (argblock.arg[2] != 0) 2178 { 2179 strncpy(fname, 2180 Address(argblock.arg[2]+1), 2181 ReadByte(argblock.arg[2])); 2182 fname[ReadByte(argblock.arg[2])] = 0; 2183 } 2184 else 2185 strcpy(fname, "table.dat"); 2186 2187 if (prompt) 2188 { 2189 stream_printf("\nPlease supply a filename for data restore\n"); 2190 file = get_file_read(&sz, fname, ZFile_data); 2191 } 2192 else 2193 { 2194 char* newname = NULL; 2195 2196 newname = malloc(strlen(rc_get_savedir()) + 2197 strlen(fname) + 3); 2198 2199 sprintf(newname, "%s/%s", rc_get_savedir(), fname); /* Safe: see above */ 2200 2201 sz = get_file_size(newname); 2202 file = open_file(newname); 2203 2204 free(newname); 2205 } 2206 2207 if (!(file)) 2208 { 2209 store(stack, st, 0); 2210 goto loop; 2211 } 2212 2213 if (sz < (ZUWord)argblock.arg[1]) 2214 argblock.arg[1] = (ZUWord) sz; 2215 read_block2(Address(argblock.arg[0]), 2216 file, 0, (ZUWord)argblock.arg[1]); 2217 2218 close_file(file); 2219 2220 store(stack, st, argblock.arg[1]); 2221 } 2222%} 2223 2224OPCODE "log_shift" EXT:0x02 ARGS:2 STORE VERSION 5,6,7,8 2225%{ 2226 if (argblock.arg[1] >= 0) 2227 { 2228 store(stack, st, argblock.arg[0]<<argblock.arg[1]); 2229 } 2230 else 2231 { 2232 ZUWord result; 2233 2234 result = argblock.arg[0]; 2235 result >>= -argblock.arg[1]; 2236 store(stack, st, result); 2237 } 2238%} 2239 2240OPCODE "art_shift" EXT:0x03 ARGS:2 STORE VERSION 5,6,7,8 2241%{ 2242 if (argblock.arg[1] >= 0) 2243 { 2244 store(stack, st, argblock.arg[0]<<argblock.arg[1]); 2245 } 2246 else 2247 { 2248 store(stack, st, argblock.arg[0]>>-argblock.arg[1]); 2249 } 2250%} 2251 2252OPCODE "set_font" EXT:0x04 ARGS:1 STORE VERSION 5,7,8 2253%{ 2254 stream_flush_buffer(); 2255 2256 store(stack, st, 1); 2257 2258 switch (argblock.arg[0]) 2259 { 2260 case 1: 2261 display_set_style(-16); 2262 display_set_style(-8); 2263 break; 2264 2265 case 3: 2266 display_set_style(16); 2267 break; 2268 2269 case 4: 2270 display_set_style(-16); 2271 display_set_style(8); 2272 break; 2273 2274 default: 2275 zmachine_warning("Font %i not supported", argblock.arg[0]); 2276 store(stack, st, 0); 2277 } 2278%} 2279 2280OPCODE "save_undo" EXT:0x09 ARGS:0 STORE CANJUMP VERSION 5,6,7,8 2281%{ 2282#ifdef CAN_UNDO 2283 ZWord tmp; 2284 int x; 2285 2286 if (machine.undo[UNDO_LEVEL-1]) 2287 free(machine.undo[UNDO_LEVEL-1]); 2288 2289 for (x=UNDO_LEVEL-2; x>=0; x--) 2290 { 2291 machine.undo[x+1] = machine.undo[x]; 2292 machine.undo_len[x+1] = machine.undo_len[x]; 2293 } 2294 2295 store(stack, st, 2); 2296 machine.undo[0] = state_compile(stack, pc, &machine.undo_len[0], 2297#ifdef SQUEEZE_UNDO 2298 1 2299#else 2300 0 2301#endif 2302 ); 2303 tmp = GetVar(st); /* (Pop the value again if it's on the stack) */ 2304 2305 if (machine.undo) 2306 store(stack, st, 1); 2307 else 2308 store(stack, st, 0); 2309#else 2310 store(stack, st, -1); 2311#endif 2312%} 2313 2314OPCODE "restore_undo" EXT:0x0a ARGS:0 STORE CANJUMP VERSION 5,6,7,8 2315%{ 2316#ifdef CAN_UNDO 2317 if (machine.undo[0]) 2318 { 2319 if (state_decompile(machine.undo[0], stack, &pc, machine.undo_len[0])) 2320 { 2321 int x; 2322 2323 free(machine.undo[0]); 2324 for (x=1; x<UNDO_LEVEL; x++) 2325 { 2326 machine.undo[x-1] = machine.undo[x]; 2327 machine.undo_len[x-1] = machine.undo_len[x]; 2328 } 2329 machine.undo[UNDO_LEVEL-1] = NULL; 2330 2331 goto loop; 2332 } 2333 if (state_fail()) 2334 { 2335 stream_printf("[ Undo failed, %s ]\n", state_fail()); 2336 } 2337 store(stack, st, 0); 2338 } 2339#endif 2340 store(stack, st, 0); 2341%} 2342 2343OPCODE "print_unicode" EXT:0x0b ARGS:1 VERSION 5,7,8 2344%{ 2345 stream_printc(argblock.arg[0]); 2346%} 2347 2348OPCODE "check_unicode" EXT:0x0c ARGS:1 STORE VERSION 5,7,8 2349%{ 2350 store(stack, st, 1); 2351%} 2352 2353#### ----// 888 \\---- #### 2354# Version 6 opcodes 2355 2356OPCODE "aread" VAR:0x04 ARGS:4 STORE CANJUMP VERSION 6 2357%{ 2358 //pc -= (3+padding); /* HACK: allow autosave */ 2359 machine.autosave_pc = pc - (3+padding); 2360 2361 stream_flush_buffer(); 2362 v6_set_caret(); 2363 zcode_op_aread_5678(&pc, stack, &argblock, st); 2364 2365 machine.autosave_pc = 0; 2366 //pc += (3+padding); 2367%} 2368 2369OPCODE "split_window" VAR:0x0a ARGS:1 VERSION 6 2370%{ 2371 int owin; 2372 int oldx0, oldy0; 2373 int oldx1, oldy1; 2374 2375 stream_flush_buffer(); 2376 2377 owin = v6_get_window(); 2378 2379 v6_set_window(0); 2380 oldx0 = v6_get_cursor_x(); 2381 oldy0 = v6_get_cursor_y(); 2382 2383 v6_set_window(1); 2384 oldx1 = v6_get_cursor_x(); 2385 oldy1 = v6_get_cursor_y(); 2386 2387 windows[0].x = 0; 2388 windows[0].y = argblock.arg[0]+1; 2389 windows[0].xsize = machine.dinfo->width; 2390 windows[0].ysize = machine.dinfo->height-argblock.arg[0]-1; 2391 windows[1].scrolling = 0; 2392 windows[1].x = 0; 2393 windows[1].y = 0; 2394 windows[1].xsize = machine.dinfo->width; 2395 windows[1].ysize = argblock.arg[0]; 2396 zcode_setup_window(0); 2397 zcode_setup_window(1); 2398 2399 v6_set_window(0); 2400 v6_set_cursor(oldx0, oldy0); 2401 2402 v6_set_window(1); 2403 v6_set_cursor(oldx1, oldy1); 2404 2405#ifdef DEBUG 2406 printf_debug("Defining windows as a result of split_window\n"); 2407#endif 2408 2409 v6_set_window(owin); 2410%} 2411 2412OPCODE "set_text_style" VAR:0x11 ARGS:1 VERSION 6 2413%{ 2414 int cwin; 2415 2416 stream_flush_buffer(); 2417 2418 cwin = v6_get_window(); 2419 2420 if (argblock.arg[0] > 0) 2421 windows[cwin].style |= argblock.arg[0]; 2422 else 2423 windows[cwin].style |= ~(-argblock.arg[0]); 2424 2425 if (argblock.arg[0] == 0) 2426 windows[cwin].style = 0; 2427 2428 v6_set_style(argblock.arg[0]); 2429 if (windows[cwin].font_num == 4 && argblock.arg[0] == 0) 2430 v6_set_style(8); 2431 if (windows[cwin].font_num == 3 && argblock.arg[0] == 0) 2432 v6_set_style(16); 2433%} 2434 2435OPCODE "read_char" VAR:0x16 ARGS:3 STORE CANJUMP VERSION 6 2436%{ 2437 //pc -= (3+padding); /* HACK: allow autosave */ 2438 machine.autosave_pc = pc - (3+padding); 2439 2440 stream_flush_buffer(); 2441 v6_set_caret(); 2442 2443 if (argblock.n_args < 2) 2444 { 2445 zcode_op_readchar(&pc, stack, &argblock, st); 2446 } 2447 else 2448 { 2449 zcode_op_readchar(&pc, stack, &argblock, st); 2450 } 2451 2452 machine.autosave_pc = 0; 2453 //pc += (3+padding); /* HACK: allow autosave */ 2454%} 2455 2456OPCODE "print_table" VAR:0x1e VERSION 6 2457%{ 2458 ZByte* table; 2459 int x,y; 2460 int xpos; 2461 2462 stream_flush_buffer(); 2463 xpos = v6_get_cursor_x(); 2464 2465 if (argblock.arg[2] == 0) 2466 argblock.arg[2] = 1; 2467 2468#ifdef DEBUG 2469 printf_debug("Printing table #%x (%ix%i), offset %i\n", argblock.arg[0], argblock.arg[1], argblock.arg[2], argblock.arg[3]); 2470#endif 2471 2472 table = Address((ZUWord) argblock.arg[0]); 2473 2474 for (y=0; y<argblock.arg[2]; y++) 2475 { 2476 if (y != 0) 2477 { 2478 stream_printf("\n"); 2479 stream_flush_buffer(); 2480 if (machine.screen_on) 2481 v6_set_cursor(xpos, v6_get_cursor_y()); 2482 } 2483 2484 for (x=0; x<argblock.arg[1]; x++) 2485 { 2486 unsigned char c; 2487 2488 c = (table++)[0]; 2489 if (c == 0) 2490 c = 32; 2491 if (c>31) 2492 stream_printf("%c", c); 2493 } 2494 2495 table += argblock.arg[3]; 2496 } 2497 stream_flush_buffer(); 2498%} 2499 2500OPCODE "restart" 0OP:0x07 CANJUMP VERSION 6 2501%{ 2502 int x; 2503 2504 stream_flush_buffer(); 2505 2506 /* Unwind stack */ 2507 while (stack->current_frame->last_frame != NULL) 2508 { 2509 ZFrame* oldframe; 2510 2511 oldframe = stack->current_frame; 2512 stack->current_frame = oldframe->last_frame; 2513 2514 stack->stack_size += oldframe->frame_size; 2515 stack->stack_top -= oldframe->frame_size; 2516 2517 free(oldframe); 2518 } 2519 2520 read_block2(machine.memory, machine.file, 2521 machine.story_offset, machine.story_offset + machine.dynamic_ceiling); 2522 2523 v6_reset(); 2524 2525 for (x=0; x<8; x++) 2526 { 2527 windows[x].wrapping = 0; 2528 windows[x].scrolling = 1; 2529 windows[x].buffering = 1; 2530 windows[x].transcript = 0; 2531 windows[x].x = windows[x].y = 0; 2532 windows[x].xsize = machine.dinfo->width; 2533 windows[x].ysize = machine.dinfo->height; 2534 } 2535 2536 call_routine(&pc, stack, 2537 (4*GetWord(machine.header, ZH_initpc)) + 2538 machine.routine_offset); 2539 zcode_v6_initialise(); 2540 2541 restart_machine(); 2542%} 2543 2544OPCODE "set_colour" 2OP:0x1b REALLYVAR VERSION 6 2545%{ 2546 int win = 0; 2547 int working; 2548 2549 int fg, bg; 2550 2551 stream_flush_buffer(); 2552 2553 win = working = v6_get_window(); 2554 if (argblock.n_args > 2) 2555 { 2556 win = v6_get_window(); 2557 v6_set_window(WinNum(argblock.arg[2])); 2558 working = WinNum(argblock.arg[2]); 2559 } 2560 2561 fg = convert_colour(arg1); 2562 bg = convert_colour(arg2); 2563 2564 v6_set_colours(fg, bg); 2565 2566 fg = v6_get_fg_colour(); 2567 bg = v6_get_bg_colour(); 2568 2569 if (fg >= 0) 2570 { 2571 windows[working].colour = (windows[working].colour&~0xff)|((fg+2)&0xff); 2572 if (fg <= 16) 2573 windows[working].fg_true = true_colour(fg); 2574 else 2575 windows[working].fg_true = fg - 16; 2576 } 2577 if (bg >= 0) 2578 { 2579 windows[working].colour = (windows[working].colour&~0xff00)|(((bg+2)&0xff)<<8); 2580 if (bg <= 16) 2581 windows[working].bg_true = true_colour(bg); 2582 else 2583 windows[working].bg_true = bg - 16; 2584 } 2585 2586 v6_set_window(win); 2587%} 2588 2589OPCODE "set_true_colour" EXT:0x0d VERSION 6 2590%{ 2591#ifndef SPEC_11 2592 zmachine_warning("set_true_colour has no effect before standard 1.1"); 2593#else 2594 int fore, back; 2595 int win, working; 2596 2597 stream_flush_buffer(); 2598 2599 win = working = v6_get_window(); 2600 if (argblock.n_args > 2) 2601 { 2602 win = v6_get_window(); 2603 v6_set_window(WinNum(argblock.arg[2])); 2604 working = WinNum(argblock.arg[2]); 2605 } 2606 2607 fore = argblock.arg[0]; 2608 back = argblock.arg[1]; 2609 2610 if (fore >= 0) 2611 fore += 16; 2612 if (back >= 0) 2613 back += 16; 2614 2615 v6_set_colours(fore, back); 2616 2617 windows[working].colour = 0x4040; 2618 2619 fore = v6_get_fg_colour(); 2620 back = v6_get_bg_colour(); 2621 2622 if (fore >= 16) 2623 fore -= 16; 2624 if (back >= 16) 2625 back -= 16; 2626 2627 windows[working].fg_true = fore; 2628 windows[working].bg_true = back; 2629 2630 v6_set_window(win); 2631#endif 2632%} 2633 2634OPCODE "pull" VAR:0x09 ARGS:1 STORE VERSION 6 2635%{ 2636 if (argblock.arg[0] != 0) 2637 { 2638 ZByte* us; 2639 ZByte* val; 2640 ZUWord len; 2641 2642 /* User stack */ 2643 us = Address(argblock.arg[0]); 2644 len = (us[0]<<8)|us[1]; 2645 len++; 2646 us[0] = len>>8; us[1] = len; 2647 val = us + len*2; 2648 2649 store(stack, st, (val[0]<<8)|val[1]); 2650 } 2651 else 2652 { 2653 /* Game stack */ 2654 store(stack, st, pop(stack)); 2655 } 2656%} 2657 2658OPCODE "erase_window" VAR:0x0d ARGS:1 VERSION 6 2659%{ 2660 int old_win, ewin; 2661 2662 stream_flush_buffer(); 2663 old_win = v6_get_window(); 2664 2665 if (argblock.n_args == 0) 2666 argblock.arg[0] = -3; 2667 2668 ewin = WinNum(argblock.arg[0]); 2669 2670 if (argblock.arg[0] == -1) 2671 { 2672 old_win = 0; 2673 ewin = 0; 2674 v6_reset_windows(); 2675 2676#ifdef DEBUG 2677 printf_debug("Defining windows as a result of erase_window\n"); 2678#endif 2679 2680 for (x=0; x<8; x++) 2681 { 2682 v6_set_window(x); 2683 2684 windows[x].wrapping = 1; 2685 windows[x].scrolling = 1; 2686 windows[x].buffering = 1; 2687 windows[x].transcript = 0; 2688 windows[x].x = windows[x].y = 1; 2689 windows[x].xsize = machine.dinfo->width; 2690 windows[x].ysize = machine.dinfo->height; 2691 windows[x].font_num = 0; 2692 2693 /* windows[x].colour = ((machine.dinfo->back+2)<<8)|(machine.dinfo->fore+2); 2694 v6_set_colours(machine.dinfo->fore, machine.dinfo->back); */ 2695 zcode_setup_window(x); 2696 } 2697 } 2698 2699 if (ewin < 0) 2700 zmachine_fatal("Attempt to erase invalid window %i", ewin); 2701 2702 v6_set_window(ewin); 2703 v6_erase_window(); 2704 v6_set_cursor(1,1); 2705 v6_set_window(old_win); 2706%} 2707 2708OPCODE "erase_line" VAR:0x0e ARGS:1 VERSION 6 2709%{ 2710 stream_flush_buffer(); 2711 v6_erase_line(argblock.arg[0]); 2712%} 2713 2714OPCODE "set_window" VAR:0x0b ARGS:1 VERSION 6 2715%{ 2716 stream_flush_buffer(); 2717 2718 v6_set_window(WinNum(argblock.arg[0])); 2719 machine.transcript_on = (machine.transcript_file!=NULL&& 2720 (windows[WinNum(argblock.arg[0])].transcript != 0)); 2721 stream_buffering(windows[WinNum(argblock.arg[0])].buffering); 2722%} 2723 2724OPCODE "set_cursor" VAR:0x0f ARGS:3 VERSION 6 2725%{ 2726 int owin; 2727 2728 stream_flush_buffer(); 2729 2730 if (argblock.n_args < 3) 2731 argblock.arg[2] = v6_get_window(); 2732 2733 if (argblock.arg[0] > 0) 2734 { 2735 owin = v6_get_window(); 2736 v6_set_window(WinNum(argblock.arg[2])); 2737 v6_set_cursor(argblock.arg[1], 2738 argblock.arg[0]); 2739 v6_set_window(owin); 2740 } 2741 else 2742 { 2743 /* FIXME: implement cursor hiding */ 2744 } 2745%} 2746 2747OPCODE "get_cursor" VAR:0x10 ARGS:1 VERSION 6 2748%{ 2749 ZByte* dest; 2750 int x, y; 2751 int win; 2752 2753 win = v6_get_window(); 2754 2755 dest = Address((ZUWord)argblock.arg[0]); 2756 x = v6_get_cursor_x(); 2757 y = v6_get_cursor_y(); 2758 2759 dest[0] = y>>8; 2760 dest[1] = y; 2761 dest[2] = x>>8; 2762 dest[3] = x; 2763%} 2764 2765OPCODE "output_stream" VAR:0x13 ARGS:3 VERSION 6 2766%{ 2767 stream_flush_buffer(); 2768 zcode_op_output_stream(stack, &argblock); 2769%} 2770 2771OPCODE "set_font" EXT:0x04 ARGS:1 STORE VERSION 6 2772%{ 2773 int win = 0; 2774 int working; 2775 2776 stream_flush_buffer(); 2777 2778 win = working = v6_get_window(); 2779 if (argblock.n_args > 2) 2780 { 2781 win = v6_get_window(); 2782 v6_set_window(WinNum(argblock.arg[2])); 2783 working = WinNum(argblock.arg[2]); 2784 } 2785 2786 switch (argblock.arg[0]) 2787 { 2788 case 1: 2789 v6_set_style(-16); 2790 v6_set_style(-8); 2791 2792 windows[working].font_num = argblock.arg[0]; 2793 2794 windows[working].style &= ~(16|8); 2795 store(stack, st, 1); 2796 break; 2797 2798 case 3: 2799 windows[working].font_num = argblock.arg[0]; 2800 v6_set_style(16); 2801 windows[working].style |= 16; 2802 store(stack, st, 1); 2803 break; 2804 2805 case 4: 2806 windows[working].font_num = argblock.arg[0]; 2807 v6_set_style(-16); 2808 v6_set_style(8); 2809 windows[working].style &= ~16; 2810 windows[working].style |= 8; 2811 store(stack, st, 1); 2812 break; 2813 2814 default: 2815 zmachine_warning("Font %i not supported", argblock.arg[0]); 2816 store(stack, st, 0); 2817 } 2818 2819 v6_set_window(win); 2820%} 2821 2822OPCODE "draw_picture" EXT:0x05 ARGS:3 VERSION 6 2823%{ 2824 BlorbImage* img; 2825 int win; 2826 2827 stream_flush_buffer(); 2828 2829 win = v6_get_window(); 2830 2831 if (machine.blorb != NULL) 2832 { 2833 img = blorb_findimage(machine.blorb, argblock.arg[0]); 2834 // img = blorb_findimage(machine.blorb, 1); 2835 } 2836 else 2837 img = NULL; 2838 2839 if (img != NULL && img->loaded != NULL) 2840 { 2841 int x,y; 2842 2843 x = argblock.arg[2]; 2844 y = argblock.arg[1]; 2845 if (argblock.n_args < 3) 2846 x = v6_get_cursor_x(); 2847 if (argblock.n_args < 2) 2848 y = v6_get_cursor_y(); 2849 2850#ifdef DEBUG 2851 printf_debug("Drawing image %i @ (%i, %i)\n", argblock.arg[0], 2852 x, y); 2853#endif 2854 2855 display_plot_image(img, x+windows[win].x-1, y+windows[win].y-1); 2856 } 2857%} 2858 2859OPCODE "picture_data" EXT:0x06 BRANCH VERSION 6 2860%{ 2861 unsigned char* d; 2862 int width, height; 2863 BlorbImage* img; 2864 2865 if (argblock.arg[0] == 0) 2866 { 2867 if (machine.blorb != NULL) 2868 { 2869 result = 1; 2870 if (argblock.n_args > 1) 2871 { 2872 unsigned char* mem; 2873 2874 mem = Address(argblock.arg[1]); 2875 mem[0] = machine.blorb->index.npictures>>8; 2876 mem[1] = machine.blorb->index.npictures; 2877 2878 mem[2] = machine.blorb->release>>8; 2879 mem[3] = machine.blorb->release; 2880 } 2881 } 2882 else 2883 result = 0; 2884 2885 goto draw_pict_branch; 2886 } 2887 2888 d = Address((ZUWord)argblock.arg[1]); 2889 2890 if (machine.blorb != NULL) 2891 { 2892 img = blorb_findimage(machine.blorb, argblock.arg[0]); 2893 } 2894 else 2895 img = NULL; 2896 2897 if (img != NULL) 2898 { 2899 int sc_n, sc_d; 2900 2901 width = img->width; 2902 height = img->height; 2903 2904 v6_scale_image(img, &sc_n, &sc_d); 2905 2906#ifdef DEBUG 2907 printf_debug("Image data for %i: %ix%i (scaled %i, %i)\n", 2908 argblock.arg[0], width, height, sc_n, sc_d); 2909#endif 2910 2911 width = (width*sc_n)/sc_d; 2912 height = (height*sc_n)/sc_d; 2913 2914 d[0] = height>>8; 2915 d[1] = height; 2916 d[2] = width>>8; 2917 d[3] = width; 2918 2919 result = 1; 2920 } 2921 else 2922 { 2923 result = 0; 2924 } 2925 2926 draw_pict_branch: 2927 dobranch; 2928%} 2929 2930OPCODE "erase_picture" EXT:0x07 VERSION 6 2931%{ 2932 int width, height; 2933 BlorbImage* img; 2934 2935 stream_flush_buffer(); 2936 2937 if (machine.blorb != NULL) 2938 { 2939 img = blorb_findimage(machine.blorb, argblock.arg[0]); 2940 } 2941 else 2942 img = NULL; 2943 2944 if (img != NULL) 2945 { 2946 int sc_n, sc_d; 2947 2948 width = img->width; 2949 height = img->height; 2950 2951 v6_scale_image(img, &sc_n, &sc_d); 2952 2953 width = (width*sc_n)/sc_d; 2954 height = (height*sc_n)/sc_d; 2955 2956 display_pixmap_cols(v6_get_bg_colour(), 0); 2957 display_plot_rect(windows[v6_get_window()].x + argblock.arg[2], 2958 windows[v6_get_window()].y + argblock.arg[1], 2959 width, height); 2960 } 2961%} 2962 2963OPCODE "set_margins" EXT:0x08 ARGS:3 VERSION 6 2964%{ 2965 int win, yp; 2966 2967 stream_flush_buffer(); 2968 2969 if (argblock.n_args < 3) 2970 argblock.arg[2] = v6_get_window(); 2971 win = v6_get_window(); 2972 v6_set_window(WinNum(argblock.arg[2])); 2973 2974#ifdef DEBUG 2975 printf_debug("Margins set to %i, %i\n", argblock.arg[0], argblock.arg[1]); 2976#endif 2977 2978 windows[argblock.arg[2]].leftmar = argblock.arg[0]; 2979 windows[argblock.arg[2]].rightmar = argblock.arg[1]; 2980 2981 zcode_setup_window(argblock.arg[2]); 2982 if (v6_get_cursor_x() < windows[argblock.arg[2]].leftmar) 2983 { 2984 yp = v6_get_cursor_y(); 2985 2986 v6_set_cursor(windows[argblock.arg[2]].leftmar, 2987 yp); 2988 } 2989 v6_set_window(win); 2990%} 2991 2992OPCODE "move_window" EXT:0x10 VERSION 6 2993%{ 2994 int xmove, ymove; 2995 int win; 2996 2997 stream_flush_buffer(); 2998 2999 win = v6_get_window(); 3000 v6_set_window(WinNum(argblock.arg[0])); 3001 3002 xmove = argblock.arg[2]-windows[argblock.arg[0]].x; 3003 ymove = argblock.arg[1]-windows[argblock.arg[0]].y; 3004 3005 v6_set_cursor(v6_get_cursor_x()+xmove, 3006 v6_get_cursor_y()+ymove); 3007 3008 windows[argblock.arg[0]].x = argblock.arg[2]; 3009 windows[argblock.arg[0]].y = argblock.arg[1]; 3010 windows[argblock.arg[0]].leftmar = 0; 3011 windows[argblock.arg[0]].rightmar = 0; 3012 3013#ifdef DEBUG 3014 printf_debug("Window %i position is now %i, %i\n", 3015 argblock.arg[0], 3016 windows[argblock.arg[0]].x, 3017 windows[argblock.arg[0]].y); 3018#endif 3019 3020 zcode_setup_window(argblock.arg[0]); 3021 v6_set_window(win); 3022%} 3023 3024OPCODE "window_size" EXT:0x11 VERSION 6 3025%{ 3026 stream_flush_buffer(); 3027 3028 windows[WinNum(argblock.arg[0])].xsize = argblock.arg[2]; 3029 windows[WinNum(argblock.arg[0])].ysize = argblock.arg[1]; 3030 windows[WinNum(argblock.arg[0])].leftmar = 0; 3031 windows[WinNum(argblock.arg[0])].rightmar = 0; 3032 3033#ifdef DEBUG 3034 printf_debug("Window %i size is now %i, %i\n", 3035 argblock.arg[0], 3036 windows[argblock.arg[0]].xsize, 3037 windows[argblock.arg[0]].ysize); 3038#endif 3039 3040 { 3041 int win; 3042 win = v6_get_window(); 3043 zcode_setup_window(argblock.arg[0]); 3044 v6_set_window(win); 3045 } 3046%} 3047 3048OPCODE "window_style" EXT:0x12 VERSION 6 3049%{ 3050 int win, owin; 3051 3052 win = WinNum(argblock.arg[0]); 3053 3054 stream_flush_buffer(); 3055 3056#ifdef DEBUG 3057 printf_debug("Window_style: %i %i %i\n", argblock.arg[0], argblock.arg[1], argblock.arg[2]); 3058#endif 3059 3060 StyleSet(windows[win].wrapping, argblock.arg[1]&1); 3061 StyleSet(windows[win].scrolling, argblock.arg[1]&2); 3062 StyleSet(windows[win].transcript, argblock.arg[1]&4); 3063 StyleSet(windows[win].buffering, argblock.arg[1]&8); 3064 3065 owin = v6_get_window(); 3066 zcode_setup_window(win); 3067 v6_set_window(owin); 3068%} 3069 3070OPCODE "get_wind_prop" EXT:0x13 STORE VERSION 6 3071%{ 3072 int win; 3073 3074 stream_flush_buffer(); 3075 win = v6_get_window(); 3076 3077 argblock.arg[0] = v6_window(argblock.arg[0]); 3078 if (argblock.arg[0] < 0) 3079 zmachine_fatal("Bad window for get_wind_prop: %i", argblock.arg[0]); 3080 v6_set_window(WinNum(argblock.arg[0])); 3081 3082 switch(argblock.arg[1]) 3083 { 3084 case 0: 3085 store(stack, st, windows[argblock.arg[0]].y); 3086 break; 3087 case 1: 3088 store(stack, st, windows[argblock.arg[0]].x); 3089 break; 3090 case 2: 3091 store(stack, st, windows[argblock.arg[0]].ysize); 3092 break; 3093 case 3: 3094 store(stack, st, windows[argblock.arg[0]].xsize); 3095 break; 3096 case 4: 3097 store(stack, st, v6_get_cursor_y()); 3098 break; 3099 case 5: 3100 store(stack, st, v6_get_cursor_x()); 3101 break; 3102 case 6: 3103 store(stack, st, windows[argblock.arg[0]].leftmar); 3104 break; 3105 case 7: 3106 store(stack, st, windows[argblock.arg[0]].rightmar); 3107 break; 3108 case 8: 3109 store(stack, st, windows[argblock.arg[0]].newline_routine); 3110 break; 3111 case 9: 3112 store(stack, st, windows[argblock.arg[0]].countdown); 3113 break; 3114 case 10: 3115 store(stack, st, windows[argblock.arg[0]].style); 3116 break; 3117 case 11: 3118 store(stack, st, windows[argblock.arg[0]].colour); 3119 break; 3120 case 12: 3121 store(stack, st, windows[argblock.arg[0]].font_num); 3122 break; 3123 case 13: 3124 store(stack, st, ((int)(display_get_font_height(windows[argblock.arg[0]].style)+0.5)<<8)| 3125 (int)(display_get_font_width(windows[argblock.arg[0]].style)+0.5)); 3126 break; 3127 case 14: 3128 store(stack, st, 3129 windows[argblock.arg[0]].wrapping| 3130 (windows[argblock.arg[0]].scrolling<<1)| 3131 (windows[argblock.arg[0]].transcript<<2)| 3132 (windows[argblock.arg[0]].buffering<<3)); 3133 break; 3134 case 15: 3135 store(stack, st, 3136 windows[argblock.arg[0]].line_count); 3137 break; 3138 case 16: 3139 store(stack, st, 3140 windows[argblock.arg[0]].fg_true); 3141 break; 3142 case 17: 3143 store(stack, st, 3144 windows[argblock.arg[0]].bg_true); 3145 break; 3146 3147 default: 3148 zmachine_fatal("Attempt to access out of range window property %i", argblock.arg[1]); 3149 } 3150 v6_set_window(win); 3151%} 3152 3153OPCODE "scroll_window" EXT:0x14 VERSION 6 3154%{ 3155 int win; 3156 3157 win = WinNum(argblock.arg[0]); 3158 3159 if (win == v6_get_window()) 3160 stream_flush_buffer(); 3161 3162 v6_scroll_window(win, argblock.arg[1]); 3163%} 3164 3165OPCODE "pop_stack" EXT:0x15 VERSION 6 3166%{ 3167 if (argblock.arg[1] == 0) 3168 { 3169 int x; 3170 3171 for (x=0; x<(ZUWord) argblock.arg[0]; x++) 3172 pop(stack); 3173 } 3174 else 3175 { 3176 ZByte* s; 3177 ZUWord len; 3178 3179 s = Address(argblock.arg[1]); 3180 len = (s[0]<<8)|s[1]; 3181 len += argblock.arg[0]; 3182 s[0] = len>>8; 3183 s[1] = len; 3184 } 3185%} 3186 3187OPCODE "read_mouse" EXT:0x16 VERSION 6 3188%{ 3189 unsigned char* d; 3190 3191 d = Address(argblock.arg[0]); 3192 display_read_mouse(); 3193 3194 d[0] = (unsigned)display_get_pix_mouse_y()>>8; 3195 d[1] = (unsigned)display_get_pix_mouse_y(); 3196 d[2] = (unsigned)display_get_pix_mouse_x()>>8; 3197 d[3] = (unsigned)display_get_pix_mouse_x(); 3198 d[4] = (unsigned)display_get_pix_mouse_b()>>8; 3199 d[5] = (unsigned)display_get_pix_mouse_b(); 3200 d[6] = 0; 3201 d[7] = 0; 3202%} 3203 3204OPCODE "mouse_window" EXT:0x17 VERSION 6 3205%{ 3206 v6_set_mouse_win(WinNum(argblock.arg[0])); 3207%} 3208 3209OPCODE "push_stack" EXT:0x18 BRANCH VERSION 6 3210%{ 3211 result = zcode_v6_push_stack(stack, argblock.arg[1], argblock.arg[0]); 3212 dobranch; 3213%} 3214 3215OPCODE "put_wind_prop" EXT:0x19 VERSION 6 3216%{ 3217 int win; 3218 3219 stream_flush_buffer(); 3220 3221 win = v6_get_window(); 3222 v6_set_window(WinNum(argblock.arg[0])); 3223 switch(argblock.arg[1]) 3224 { 3225 case 0: 3226 zmachine_warning("Bad put_wind_prop: should use move_window instead"); 3227 windows[argblock.arg[0]].y = argblock.arg[2]; 3228 break; 3229 case 1: 3230 zmachine_warning("Bad put_wind_prop: should use move_window instead"); 3231 windows[argblock.arg[0]].x = argblock.arg[2]; 3232 break; 3233 case 2: 3234 zmachine_warning("Bad put_wind_prop: should use window_size instead"); 3235 windows[argblock.arg[0]].ysize = argblock.arg[2]; 3236 break; 3237 case 3: 3238 zmachine_warning("Bad put_wind_prop: should use window_size instead"); 3239 windows[argblock.arg[0]].xsize = argblock.arg[2]; 3240 break; 3241 case 4: 3242 zmachine_warning("Bad put_wind_prop: should use set_cursor instead"); 3243 v6_set_cursor(v6_get_cursor_x(), argblock.arg[2]); 3244 break; 3245 case 5: 3246 zmachine_warning("Bad put_wind_prop: should use set_cursor instead"); 3247 v6_set_cursor(argblock.arg[2], v6_get_cursor_y()); 3248 break; 3249 case 6: 3250 windows[argblock.arg[0]].leftmar = argblock.arg[2]; 3251 break; 3252 case 7: 3253 windows[argblock.arg[0]].rightmar = argblock.arg[2]; 3254 break; 3255 case 8: 3256 windows[argblock.arg[0]].newline_routine = argblock.arg[2]; 3257 break; 3258 case 9: 3259 windows[argblock.arg[0]].countdown = argblock.arg[2]; 3260 break; 3261 case 10: 3262 zmachine_warning("Bad put_wind_prop: should use set_text_style instead"); 3263 break; 3264 case 11: 3265 zmachine_warning("Bad put_wind_prop: should use set_colour instead"); 3266 break; 3267 case 12: 3268 zmachine_warning("Bad put_wind_prop: should use set_font instead"); 3269 break; 3270 case 13: 3271 zmachine_warning("Bad put_wind_prop: should use set_font instead"); 3272 break; 3273 case 14: 3274 zmachine_warning("Bad put_wind_prop: should use window_style instead"); 3275 break; 3276 case 15: 3277 windows[argblock.arg[0]].line_count = argblock.arg[2]; 3278 break; 3279 3280 default: 3281 zmachine_fatal("Attempt to access out of range window property %i", argblock.arg[1]); 3282 } 3283 v6_set_window(win); 3284%} 3285 3286OPCODE "print_form" EXT:0x1a VERSION 6 3287%{ 3288 ZByte* table; 3289 int len; 3290 int first; 3291 3292 table = Address((ZUWord) argblock.arg[0]); 3293 first = 1; 3294 3295 do 3296 { 3297 int x; 3298 3299 len = (table[0]<<8)|(table[1]); 3300 if (!first && len > 0) 3301 stream_printf("\n"); 3302 first = 0; 3303 3304 for (x=0; x<len; x++) 3305 { 3306 stream_printf("%c", table[x+2]); 3307 } 3308 3309 table += len+2; 3310 } 3311 while (len != 0); 3312%} 3313 3314OPCODE "make_menu" EXT:0x1b BRANCH VERSION 6 3315%{ 3316 /* Hum, the spec is unclear on what the branch does... */ 3317 /* printf_debug("make_menu not implemented\n"); */ 3318 3319 result = 0; 3320 dobranch; 3321%} 3322 3323OPCODE "picture_table" EXT:0x1c VERSION 6 3324%{ 3325 /* Does nothing */ 3326%} 3327 3328OPCODE "buffer_screen" EXT:0x1d STORE VERSION 6 3329%{ 3330 /* Not really supported */ 3331 /* Zoom really has no choice with screen buffering, especially in the cocoa version */ 3332 if (arg1 == 0 || arg1 == 1) { 3333 /* Exactly the same for zoom */ 3334 } else if (arg1 == -1) { 3335 /* Implement me! */ 3336 display_flush(); 3337 } else { 3338 zmachine_warning("buffer_screen opcode cannot take values other than 0, 1 or -1"); 3339 } 3340 3341 store(stack, st, 0); 3342%} 3343 3344#### ----// 888 \\---- #### 3345# Standard 1.1 opcodes 3346 3347OPCODE "set_true_colour" EXT:0x0d VERSION 5,7,8 3348%{ 3349 int fore, back; 3350 3351#ifndef SPEC_11 3352 zmachine_warning("set_true_colour has no effect before standard 1.1"); 3353#else 3354 stream_flush_buffer(); 3355 3356 fore = arg1+16; 3357 back = arg2+16; 3358 3359 if (arg1 < 0) 3360 fore = arg1; 3361 if (arg2 < 0) 3362 back = arg2; 3363 3364 display_set_colour(fore, back); 3365#endif 3366%} 3367 3368OPCODE "sound_data" EXT:0x0e BRANCH VERSION 5,6,7,8 3369%{ 3370#ifndef SPEC_11 3371 zmachine_warning("sound_data has no effect before standard 1.1"); 3372#else 3373#endif 3374 3375 result = 0; 3376 dobranch; 3377%} 3378 3379#### ----// 888 \\---- #### 3380# Our own extensions - benchmarking/profiling operations 3381OPCODE "start_timer" EXT:0x80 VERSION 4,5,6,7,8 3382%{ 3383 start_clock = clock(); 3384%} 3385 3386OPCODE "stop_timer" EXT:0x81 VERSION 4,5,6,7,8 3387%{ 3388 end_clock = clock(); 3389%} 3390 3391OPCODE "read_timer" EXT:0x82 STORE VERSION 4,5,6,7,8 3392%{ 3393 clock_t now; 3394 3395 now = end_clock - start_clock; 3396 3397 store(stack, st, (ZUWord) (now*100)/CLOCKS_PER_SEC); 3398%} 3399 3400OPCODE "print_timer" EXT:0x83 VERSION 4,5,6,7,8 3401%{ 3402 clock_t now; 3403 3404 now = end_clock - start_clock; 3405 3406 stream_printf("%i.%02i secs", (signed int) (now/CLOCKS_PER_SEC), 3407 (signed int) ((now*100)/CLOCKS_PER_SEC)%100); 3408%} 3409 3410OPCODE "print_stack" EXT:0x84 VERSION 5,7,8 3411%{ 3412 zmachine_dump_stack(stack); 3413%} 3414