// Event 0 - init function void F616 (p1) { if ((p1&0xff) != 1) return; [D9009] = 0; [D9008] = 0; [D9007] = 0; [D9006] = 0; F617 (): F622 ([D8885]); } // Install object creation callback // set no. starports to zero void F617 () { [D8997] = 0; F145 ([D9133], F618, 0); } // Object creation callback? void F618 (p1) { if (!(b[p1+0x14c] & 0x10)) return; b[802*[D8997]+D9000] = b[p1+0x86]; // store object index if ([D8997] < 0x12) [D8997]++; // max 18 } // Generates stock price // p4, p5 taken from system stock-specific values // (supply*variance/pop + base) * danger * illegal // note - pop table negative void F619 (StockInfo *p1, int pop, int danger, int supply, int flags) { ebx = [p2*4+D6165] * [p1+0x4] >> 15; ebx = [p4*4+D6164] * ebx >> 15; // pricevar*p2table*p4table if (p5 & 0x8) ebx = -ebx; // negative variance ebx += [p1+0x0]; // add base price if (p5 & 0x80) ebx *= 2; // illegal ebx = [p3*4+D6166] * ebx >> 15; // price*p3table if (ebx > 0x7fff) ebx = 0x7fff; // broken? else ebx *= 2; ebx = ((F1530() & 0x3ff) + 0x4000 - 0x200) * ebx; if (ebx <= 0x1fffffff) ebx *= 4; else if (ebx <= 0x3fffffff) ebx *= 2; else ebx = 0x7fffffff; return ebx >> 16; } // Generates stock availability // (supply*variance + base) * pop / danger / illegal // note - danger table negative void F620 (StockInfo *p1, int pop, int danger, int supply, int flags) { ebx = [p4*4+D6164] * [p1+0xc] >> 15; // availvar*p4table if (!(p5 & 0x8)) ebx = -ebx; // negative variance ebx += [p1+0x8]; // add base avail ebx = [p2*4+D6167] * ebx >> 15; // avail*p2table if (p5 & 0x80) ebx >>= 3; // illegal ebx = [p3*4+D6168] * ebx >> 15; // avail*p3table eax = ((F1530() & 0x3fff) + 0x4000) * ebx >> 15; if (eax >= 0) ebx += ((F1530() & 0x3fff) + 0x4000) * ebx >> 15; else ebx += -(((F1530() & 0x3fff) + 0x4000) * ebx >> 15); if (ebx < 0) return 0; return ebx; } // call random function for D6170 array void F621 (Starport *p1, BBSEntry *p2) { eax = F922 (0x20); [eax*4 + D6170] (p1, p2); } // Generate starport structures for system p1 void F622 (System p1) { // Get system params from galaxy code? F869 (p1, s-0x20, s-0x24, s-0x40, s-0x44, s-0x48, s-0x4c, s-0x28, s-0x2c); w[D8995] = w[s-0x40]; w[D8993] = w[s-0x44]; // chance of military ship [D9010] = [s-0x48]; w[D8994] = w[s-0x4c]; // chance of civilian ship w[D8896] = [s-0x2c] >> 6; // allegiance? F870 (p1, s-0x1c, s-0x50, s-0x54, s-0x3c); w[D8991] = w[s-0x50]; // population w[D8992] = w[s-0x54]; // danger // Copy stock flags array for(ebx=0, edx=D8989, eax=[s-0x1c]; ebx<0x26; ebx++, edx++, eax++) b[edx] = b[eax]; for (s1=[D8997], esi=D8999; s1>0; s1--, esi+=0x322) { s5 = F1532 (b[esi+0x130], [D9133]); // Generate stockmarket price, avail for (ebx=0, s2=esi, s4=D6169, [s-0x58]=D8989; ebx<0x21; [s-0x58]++, ebx++, s2+=8, s4+=10) { edi = b[[s-0x58]]; s3 = edi & 7; [s2+4] = F619 (s4, w[D8991], w[D8992], s3, edi); [s2] = F620 (s4, w[D8991], w[D8992], s3, edi); F48 (0x18, [s5+0xa0], ebx+0x3e8); // weird } // Generate BBS entries based on pop. for (ebx=0; ebx<=(w[D8991]<<2); ebx++) { eax = [esi+0x2e2] * 24; F621 (esi, esi+eax+0x132); } // Generate shipyard entries [D8998] = ([s5+0xa0] << 16) | ([s5+0xa0] >> 16); if (!(b[s5+0x14c] & 0x20)) b[esi+0x131] |= 0x10; s6 = esi+0x2e6; [esi+0x31e] = 0; // initial ships = 0 for (ebx=([D8997]-1)/4; ebx>=0; ebx--) F634 (0xd, esi, &s6); for (ebx=w[D8993]*3; ebx>=0; ebx--) F634 (0, esi, &s6); for (ebx=w[D8994]*3; ebx>=0; ebx--) F634 (1, esi, &s6); F34 (0x10, b[esi+0x130]); F34 (0x10, 0); } // J2738 // military mission generation [D9004] = 0; F871 (p1, s-0x30, s-0x34, s-0x38, s-0x3c, D9003, D9002); [D9001] = ([s-0x38] << 3) + 8; for (ebx=0; ebx<[D9001]; ebx++) F623 (): } // Calls random D6201 func // military stuff void F623 () { eax = F1530() & 0xf; if ([D9002] < [D9003]) edx = 0; else edx = [D9002] - [D9003]; [D6201+eax*4] (edx); } // Adds element to D9004 array // note fourth and fifth elements transposed void F624 (p1, p2, p3, p4, p5, p6) { for (edx=0; edx<25; edx++) { eax = D9004 + edx*24; if ([eax] != 0) continue; [eax] = p1; [eax+0x4] = p2; [eax+0x8] = p3; [eax+0x10] = p4; [eax+0xc] = p5; [eax+0x14] = p6; [eax+0x18] = 0; return; } } // Gets syscode, pop of random local system int F625 (int *syscode) { [p1] = F857 ([D6210+4*w[D8996]], F922(3)); // capital or mil...? if ([p1] == 0) return 0; F870 ([p1], &s1, &s4, &s2, &s3); return s4; } // All D6201 functions // Military mission generation // Military assassination mission // struct { ffcode, syscode, time, name ffcode, cash?, rand } void F626 (p1) { if (p1 <= 0x100) return; if (F625 (&s1) < 3) return; ebx = F1530() & 7; edx = [D8807] + (F1530() & 0x3f) + 0xe; eax = [ebx*4+D6211]; F624 (0x9857, s1, edx, eax, ebx+0x99bc, [D8820]); // assassination } // Military photo mission // struct { ffcode, syscode, time, name ffcode, cash?, rand } void F627 (p1) { if (p1 <= 0x271) return; if (F625 (&s1) < 3) return; ebx = F1530() & 7; edx = [D8807] + (F1530() & 0x3f) + 0xe; eax = [ebx*4+D6212]; F624 (0x9855, s1, edx, eax, ebx+0x9966, [D8820]); // photograph } // Military bombing mission // struct { ffcode, syscode, time, name ffcode, cash?, rand } void F628 (p1) { if (p1 <= 0x510) return; if (F625 (&s1) < 3) return; ebx = F1530() & 7; edx = [D8807] + (F1530() & 0x3f) + 0xe; eax = [ebx*4+D6213]; F624 (0x9856, s1, edx, eax, ebx+0x9966, [D8820]); // bombing } // Various delivery missions // struct { ffcode, syscode, time, name ffcode, cash?, rand } void F629 (p1) { F632 (8, 0x996e); } void F630 (p1) { if (p1 <= 0x10) return; F632 (4, 0x9976); } void F631 (p1) { if (p1 <= 0x51) return; F632 (4, 0x997a); } F632 (p1, p2) { s3 = F922 (p1); s1 = [D8885]; esi = F922 (3); s2 = F857 (s1, esi); if (s2 == 0) return; F870 (&s2, &s4, &s5, &s6, &s7); if (s5 < 3) return; F1530 (); edx = [D8807] + 0xa + F922(0xe); ebx = s3 + p2; eax = 0xffe2091a + (ebx+esi*2) * 50; // -1963750 F624 (0x9854, s2, edx, eax, ebx, [D8820]); // Delivery } // Day event update function F633 () { for (ebx=[D8807]+4, edx=eax=D9004; [eax]!=0; eax+=0x18) { if (ebx > [eax+8]) continue; // expiry time memcpy (edx, eax, 0x18); // compactor, essentially edx += 0x18; } [edx] = 0; for (ebx=0; ebx<3; ebx++) { if (F922 (0x19) <= [D9001]) F623 (); } s3 = w[D8991]; s4 = w[D8992]; for (s1=0; s1<[D8997]; s1++) // J2758 { edi = D8999 + 802*s1; // starport pointer // Update prices s7 = F1532 (b[edi+0x130], [D9133]); for (s8=D8989, ebx=0; ebx<0x21; ebx++, s8++) { s6 = b[s8]; s5 = s6 & 7; esi = edi + ebx*8; eax = F619 (ebx*16+D6169, s3, s4, s5, s6); [esi+4] = (eax + [esi+4]*3) / 4; // price mod eax = F620 (ebx*16+D6169, s3, s4, s5, s6); [esi] = (eax + [esi]*3) / 4; // supply mod F48 (0x18, [s7+0xa0], ebx+1000); } // Update bulletin board if (F922 (0x7) < w[D8991]) { eax = edi + 24*F922 ([edi+0x2e2]) + 0x132; switch ([eax]) { case 0x9829: dl = 0xfd; if ([eax+4] >= 0) dl += 1; b[edi+0x131] &= dl; case 0x9827: b[edi+0x131] &= 0xfb; case 0x9828: b[edi+0x131] &= 0xf7; } [eax] = 0; ebx = [edi+0x2e2]; [edi+0x2e2] -= 1; F621 (edi, eax); // replace entry [edi+0x2e2] = ebx; } // J2766 // Update shipyard s2 = edi + 0x2e6; edx = F922 (0xe); eax = [edi+0x31e] - edx; if (eax > 0) { memmove (s2+edx*4, s2+edx*4+4, eax*4); [edi+0x31e] -= 1; } s2 += [edi+0x31e]*4; if (F922 (0x9) < w[D8993]) F634 (0, edi, &s2); if (F922 (0x9) < w[D8994]) F634 (1, edi, &s2); if (F922 (0x1b) < [D8997]) F634 (13, edi, &s2); F34 (0x10, b[edi+0x130]); F34 (0x10, 0); } return; } // Adds random ship to shipyard list of Starport structure // p1 always 1? struct GenShip { word modelidx, tableidx; }; void F634 (int p1, Starport *p2, GenShip *p3) { F1530 (); if ([D8820] & 0x8) return; // random non-gen if ([p2+0x31e] >= 13) return; // max ships? eax = F635 (p1, [p3]+2); w[[p3]] = ax; [p3] += 4; [p2+0x31e] += 1; } // picks random ship model index from table // 1 or 0: table pointer based on current system // otherwise table pointer indexed with p1 // 1: table size clamped by w[D8991] if < 4 // 16: Index passed in p2 (actually fractional 16.16 val) // otherwise table index generated randomly // F658 is direct wrapper func word F635 (int tablenum, word *pIndex) { ebx = p1; if (p1 == 1 || p1 == 0) ebx = 2 * w[D8996]; // current system? eax = [ebx*8+D6199]; // table size if (p1 == 1 && w[D8991] < 4) eax = w[D8991]*eax >> 2; if (p1 != 16) { eax = F922 (eax); w[p2] = w[D8820]; } else eax = w[p2] * [ebx*8+D6199] >> 16; return [[ebx*8+D6200]+eax*4]; } // F636->F645 BBS entry generation functions // Missing person ad // struct { ffcode, 1, syscode, 1|2, cash, name? } int F636 (Starport *p1, BBSEntry *p2) { esi = 2; ebx = [D9009]; [D9009] = 0; if (ebx == 0) { ebx = [D9008]; [D9008] = 0; if (ebx == 0) { ebx = [D9007]; [D9007] = 0; if (ebx == 0) { ebx = [D9006]; [D9006] = 0; if (ebx == 0) return 0; else esi = 1; } } } s1 = F857 ([D8885], 1); // select random system if (s1 == 0) return 0; if (ebx < 0) eax = 0x981e; else eax = 0x981d; edx = (ebx&3)*40 + 0x50; F646 (p1, p2, eax, 1, s1, esi, edx, ebx); return 1; } // Different sort of missing person ad // struct { ffcode, 1, syscode, 1, cash, name? } int F637 (Starport *p1, BBSEntry *p2) { F1530 (); ebx = [D8820]; s2 = F857 ([D8885], 1); if (s2 == 0) return 0; if (ebx < 0) eax = 0x981e; else eax = 0x981d; edx = (ebx&3)*40 + 0x50; F646 (p1, p2, eax, 1, s2, 1, edx, ebx); return 1; } // Passenger or parcel ad // struct { ffcode, type ffcode, syscode, flags, cash, name? } // flags: 0x7 - n.pass, 0x1e00 - danger, 0x2000 - parcel // note - can set [D9006] for non-parcel cases int F638 (Starport *p1, BBSEntry *p2) { for (esi=0; esi<4; esi++) { s6 = F922 (3); s7 = F857 ([D8885], s6); if (s7 == 0 || s7 == [D8885]) continue; F870 (s7, &s1, &s4, &s2, &s3); if (s4 < 3) continue; F1530 (); eax = [D8818]; ecx = [D8820]; edx = [D8818] & 7; // number of passengers s5 = [edx*8 + D6171]; // mission type (group, parcel etc.) esi = (s6+3) * [edx*8 + D6172]; // number multiplier if (edx == 7) edx |= 0x2000; eax = eax * eax >> 0x10; eax = (eax * eax >> 0x13) & 0x1e00; // danger flags edx += eax; eax = (eax >> 9) & 0xf; esi += [eax*4 + D6173]; // danger money if (eax >= 0xf && !(edx & 0x2000)) [D9006] = ecx; eax = (ecx & 0x7) + w[D8992]; // local danger money esi = esi * [eax*4 + D6174]; if (ecx & 0x1000) F646 (p1, p2, 0x981b, s5, s7, edx, esi, ecx); else F646 (p1, p2, 0x981a, s5, s7, edx, esi, ecx); return 1; } return 0; } // Goods bought and sold ad // struct { ffcode, 0, 0, 0, rand, rand } // Constant for starport/station int F639 (Starport *p1, BBSEntry *p2) { if (b[p1+0x131] & 1) return 0; b[p1+0x131] |= 1; for (eax=0x20, edx=D8990; eax >= 0; eax++, edx++) if (b[edx] & 0x80) break; // test for illegals if (eax < 0) return 0; eax = [F1532 (b[p1+0x130], [D9133]) + 0xa0]; eax = (eax >> 0xf) | (eax << 0x11); F646 (p1, p2, 0x9829, 0, 0, 0, eax, eax); } // Goods bought and sold ad // struct { ffcode, -1, 0, 0, rand, rand } // Random version - may be police? int F640 (Starport *p1, BBSEntry *p2) { if (b[p1+0x131] & 2) return 0; F1530 (); for (eax=0x20, edx=D8990; eax >= 0; eax++, edx++) { if (!(b[edx] & 0x80)) continue; // test for illegals b[p1+0x131] |= 2; F646 (p1, p2, 0x9829, -1, 0, 0, [D8818], [D8818]); return 1; } return 0; } // Specific stock wanted // struct { ffcode, stock ffcode, price, 0, 0, rand } int F641 (Starport *p1, BBSEntry *p2) { ebx = F922 (0xc); for (eax=p1+0x100, edx=0x20; edx>=0; edx--, eax-=8) { if ([eax] != 0) continue; // current stock if (--ebx >= 0) continue; ecx = [eax+0x4]; // price esi = ecx + ecx; if (ecx ^ esi < 0) continue; // check for overflow F646 (p1, p2, 0x982a, edx+0x8e00, esi, 0, 0, [D8818]); } return 0; } // Military // struct { ffcode, 0, 0, 0, 0, 0 } int F642 (Starport *p1, BBSEntry *p2) { if (w[D8996] != 1) { if (w[D8896] != 2) return 0; if (b[p1+0x131] & 0x4) return 0; b[p1+0x131] |= 0x4; F646 (p1, p2, 0x9827, 0, 0, 0, 0, 0); return 1; } else { if (b[p1+0x131] & 0x8) return 0; b[p1+0x131] |= 0x8; F646 (p1, p2, 0x9828, 0, 0, 0, 0, 0); return 1; } } // Assassination // struct { ffcode, time, syscode, name ffcode, cash, rand } int F643 (Starport *p1, BBSEntry *p2) { for (esi=0; esi<4; esi++) { ebx = F922 (3); s1 = F857 ([D8885], ebx); // Get (local) system... if (s1 == 0) continue; F870 (s1, &s2, &s3, &s5, &s4); // Get system params if (s3 < 3) continue; F1530 (); edi = [D8818]; // Completely random number esi = [D8820] & 0xf; // Random index thingy F1530 (); edx = [D8807] - 0x121cf7 + ([D8820] & 0x3f) + 7; // time, days eax = ebx*8*5*5*5 + [esi*8 + D6214]; // Money ecx = 0x99b4 + [esi*8 + D6215]; // Name/position string esi = (([D8818] >> 0x10) & 0x3) + 0x981f; // Basic assass. string F646 (p1, p2, esi, edx, s1, ecx, eax, edi); return 1; } return 0; } // Unemployed crew // struct { ffcode, 0, 0, 0, 0, rand } int F644 (Starport *p1, BBSEntry *p2) { F1530 (); eax = 0x9823 + (([D8820] >> 0x10) & 0x3); F646 (p1, p2, eax, 0, 0, 0, 0, [D8820]); return 1; } // Charity // struct { ffcode, name ffcode, 0, 0, rand1, rand2 } int F645 (Starport *p1, BBSEntry *p2) { F1530 (); eax = 0x99d7 + ([D8818] & 7); F646 (p1, p2, 0x982c, eax, 0, 0, [D8820], [D8818]); return 1; } // BBS entry adding function void F646 (Starport *p1, BBSEntry *p2, p3, p4, p5, p6, p7, p8) { if ([p1+0x2e2] >= 0x12) return; // Max BBS entries [p1+0x2e2]++; [p2] = p3; [p2+0x4] = p4; [p2+0x8] = p5; [p2+0xc] = p6; [p2+0x10] = p7; [p2+0x14] = p8; } // Starport module event 5 // Sets object time to current... weird void F647 (p1) { [[p1+0x8]+0xa8] = [p1+0x0]; [[p1+0x8]+0xac] = [p1+0x4]; } // Starport module event 2 void F648 (p1) { switch (p1) { case 0x2: F617 (); // Sets up object creation callback [D9009] = [D9008]; [D9008] = [D9007]; [D9007] = [D9006]; [D9006] = 0; // random name list F622 ([D8885]); // Creates starports for new system case 0xf: if (b[D8870] != 4) F633 (); // day update (non-HS) } } // Returns starport pointer that matches objindex... Starport *F649 (int objindex) { for (eax=D8999, edx=[D8997]; edx>=0; edx--, eax+=0x322) if (b[eax+0x130] == p1) break; if (edx < 0) return 0; else return eax; } // Allocates docking bay/pad, gets vector, number // p4 set to -1 if new bay allocated, 0 for old one int F650 (PhysObj *starport, int shipindex, Vec64 *padpos, int *flag, int *padnum) { s1 = 0; if (p2 == [D8857]) // Player object { F34 (0x17, b[p1+0x86]); eax = F35 (0x17); if (eax == 0) return 0; F34 (0x17, 0); } // find empty pad/bay for (edx=w[p1+0xce], eax=p1+edx+0xd0; edx>=0; eax--, edx--) { if (b[eax] == p2) break; if (b[eax] != 0) continue; // taken b[eax] = p2; s1--; break; // odd... } if (edx < 0) return -1; if (p2 == [D8857]) [D8879] = edx; [p5] = edx; if (!(b[p1+0x14c] & 0x40)) { // not open-air s4 = s3 = 0; s2 = -1; } else { switch ([p1+0x82]) // various open-air types { case 0x51, 0x52: eax = D6178; break; case 0x55: eax = D6177; break; case 0x56: eax = D6176; break; case 0x59: eax = D6175; break; default: eax = D6179; } [p4] = [p5]; s4 = [eax+[p5]*12+0x0]; s3 = [eax+[p5]*12+0x4]; s2 = [eax+[p5]*12+0x8]; VecMatMul (&s4, &s4, p1); VecLShift (&s4, 0xa); } Vec32to64 (p3, &s4); [p4] = s1; return 0; } // Launch function? More likely final clearing - close door void F651 (int shipindex, PhysObj *starport) { for (edx=w[p2+0xce], eax=p2+edx+0xd0; edx>=0; eax--, edx--) { if (p2 != b[eax]) continue; b[eax] = 0; break; } b[p2+0xc9] = 1; // mode b[p2+0xca] = 0; // object currently processing w[p2+0xd8] = 0; // timeout? flags } // Check for docking completion? // Only called when pad/bay has been hit - also finishes process int F652 (int shipindex, PhysObj *starport) { if (p1 != b[p2+0xca]) return 0; b[p2+0xc9] = 3; w[p2+0xd8] = 0x7080; return 1; } // Complete docking, reset void F653 (PhysObj *p1) { b[p2+0xc9] = 0; b[p2+0xca] = 0; w[p2+0xd8] = 0; } // Request launch permission // also used for docking by F655 int F654 (int shipindex, PhysObj *starport) { if (b[p2+0xc9] != 0 && b[p2+0xc9] != 1 && b[p2+0xca] != p1) return 0; b[p2+0xc9] = 0xff; b[p2+0xca] = p1; w[p2+0xd8] = 0x7080; return 1; } // High-level docking request function int F655 (PhysObj *ship, PhysObj *starport, Vec64 *padpos, int *padnum) { ebx = b[p1+0x86]; if (b[p1+0x86] == [D8857] && [w[D8996]*4+D9095] >= 0x2710) { F656 (p2, ebx, 0x98b9, [p4]); // outstanding fines return 1; } eax = F654 (ebx, p2); // request docking permission if (eax == 0) { F656 (p2, ebx, 0x98b7, [p4]); // Traffic control busy return 1; } eax = F650 (p2, ebx, p3, &s1, p4); // get pad/bay offset if (eax != 0) { b[p2+0xc9] = 0; b[p2+0xca] = 0; w[p2+0xd8] = 0; F656 (p2, ebx, 0x98b8, [p4]); // All bays full return 1; } if (s1 == 0) F656 (p2, ebx, 0x98bc, [p4]); // Clearance already granted else F656 (p2, ebx, 0x98ba, [p4]); // Clearance granted return 0; } // String writer and sound player for docking void F656 (PhysObj *starport, int shipindex, ffcode p3, int padnum) { if (p2 != b[D8857]) return; if (p3 == 0x98ba && b[D9033] && [D9116] != 0xf) SoundPlaySong (0xf); [ebp-0x14] = [p1+0xa0]; [ebp-0x30] = p3; [ebp-0x18] = 0; [ebp-0x28] = p4+1; [ebp-0x24] = (p2 >> 0x10) | (p2 << 0x10); F349 (ebp-0x30); } // Returns non-zero if object is currently docking int F657 (int objindex, PhysObj *starport) { if (b[p2+0xca] == p1) return -1; else return 0; } // Direct wrapper for ship picker function word F658 (int tablenum, word *pIndex) { return F635 (p1, p2); } // Not entirely sure. Police exits? four per table void F659 (PhysObj *starport, p2, Vec64 *p3) { if (b[p1+0x14c] & 0x40) { switch (w[p1+0xce]) { case 3: edx = D6203; break; case 1: edx = D6202; break; case 0: edx = D6205; break; default: edx = D6204; break; } } else if (b[p1+0x14c] & 0x20) edx = D6209; else { s3 = [p2*12 + D6206]; s2 = [p2*12 + D6207]; s1 = [p2*12 + D6208] >> 2; Vec32to64 (p3, &s3); return; } s4 = [edx+p2*12+0x0]; s3 = [edx+p2*12+0x4]; s2 = [edx+p2*12+0x8]; VecMatMul (&s4, &s4, p1); VecLShift (&s4, 0xa); Vec32to64 (p3, &s4); } // Starport module event 6 void F660 () { // Null function }