Process.pas 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. {
  2. Copyright (C) 2005 Remco Mulder
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  14. For source notes please refer to Notes.txt
  15. For license terms please refer to GPL.txt.
  16. These files should be stored in the root of the compression you
  17. received this source in.
  18. }
  19. // This unit controls all processing and recording of data
  20. unit
  21. Process;
  22. interface
  23. uses
  24. Core,
  25. Observer,
  26. SysUtils,
  27. DataBase,
  28. Classes;
  29. type
  30. TSectorPosition = (spNormal, spPorts, spPlanets, spShips, spMines, spTraders);
  31. TDisplay = (dNone, dSector, dDensity, dWarpLane, dCIM, dPortCIM, dPort, dWarpCIM);
  32. TModExtractor = class(TTWXModule, IModExtractor)
  33. private
  34. FCurrentSectorIndex : Integer;
  35. FSectorPosition : TSectorPosition;
  36. FCurrentDisplay : TDisplay;
  37. FLastWarp : Integer;
  38. FSectorSaved : Boolean;
  39. FCurrentTrader : TTrader;
  40. FCurrentShip : TShip;
  41. FCurrentMessage : string;
  42. FTraderList,
  43. FShipList,
  44. FPlanetList : TList;
  45. FCurrentLine,
  46. FCurrentANSILine : string;
  47. FCurrentSector : TSector;
  48. FInAnsi : Boolean;
  49. FMenuKey : Char;
  50. procedure SectorCompleted;
  51. procedure ResetSectorLists;
  52. procedure ProcessPrompt(Line : string);
  53. procedure AddWarp(SectNum, Warp : Integer);
  54. procedure ProcessWarpLine(Line : String);
  55. procedure ProcessCIMLine(Line : String);
  56. procedure ProcessSectorLine(Line : String);
  57. procedure ProcessLine(Line : String);
  58. procedure ProcessPortLine(Line : String);
  59. procedure StripANSI(var S : string);
  60. protected
  61. function GetMenuKey: Char;
  62. procedure SetMenuKey(Value: Char);
  63. public
  64. procedure AfterConstruction; override;
  65. procedure BeforeDestruction; override;
  66. procedure Reset;
  67. procedure ProcessInBound(var InData : string);
  68. function ProcessOutBound(OutData : string; ClientIndex : Byte) : Boolean;
  69. property CurrentLine: string read FCurrentLine write FCurrentLine;
  70. property CurrentANSILine: string read FCurrentANSILine write FCurrentANSILine;
  71. published
  72. property MenuKey: Char read GetMenuKey write SetMenuKey;
  73. end;
  74. implementation
  75. uses
  76. Global,
  77. Utility,
  78. Ansi;
  79. procedure TModExtractor.AfterConstruction;
  80. begin
  81. inherited;
  82. // Create lists to store ships, traders and planets
  83. FShipList := TList.Create;
  84. FTraderList := TList.Create;
  85. FPlanetList := TList.Create;
  86. MenuKey := '$';
  87. end;
  88. procedure TModExtractor.BeforeDestruction;
  89. begin
  90. ResetSectorLists;
  91. FShipList.Free;
  92. FTraderList.Free;
  93. FPlanetList.Free;
  94. inherited;
  95. end;
  96. procedure TModExtractor.Reset;
  97. begin
  98. // Reset state values
  99. CurrentLine := '';
  100. CurrentANSILine := '';
  101. FInAnsi := FALSE;
  102. ResetSectorLists;
  103. end;
  104. function TModExtractor.GetMenuKey: Char;
  105. begin
  106. Result := FMenuKey;
  107. end;
  108. procedure TModExtractor.SetMenuKey(Value: Char);
  109. begin
  110. FMenuKey := Value;
  111. end;
  112. // ********************************************************************
  113. // Process inbound data
  114. procedure TModExtractor.ResetSectorLists;
  115. begin
  116. // Reset all ship, planet and trader lists
  117. while (FShipList.Count > 0) do
  118. begin
  119. FreeMem(FShipList[0], SizeOf(TShip));
  120. FShipList.Delete(0);
  121. end;
  122. while (FPlanetList.Count > 0) do
  123. begin
  124. FreeMem(FPlanetList[0], SizeOf(TPlanet));
  125. FPlanetList.Delete(0);
  126. end;
  127. while (FTraderList.Count > 0) do
  128. begin
  129. FreeMem(FTraderList[0], SizeOf(TTrader));
  130. FTraderList.Delete(0);
  131. end;
  132. end;
  133. procedure TModExtractor.SectorCompleted;
  134. var
  135. I,
  136. WarpIndex : Integer;
  137. begin
  138. if (FCurrentSectorIndex = 0) then
  139. Exit;
  140. FCurrentSector.UpDate := Now;
  141. FCurrentSector.Explored := etHolo;
  142. FSectorSaved := TRUE;
  143. WarpIndex := 0;
  144. for I := 1 to 6 do
  145. if (FCurrentSector.Warp[I] = 0) then
  146. begin
  147. WarpIndex := I;
  148. Break;
  149. end;
  150. if (WarpIndex = 0) then
  151. FCurrentSector.Warps := 0
  152. else if (FCurrentSector.Warp[WarpIndex] = 0) then
  153. FCurrentSector.Warps := WarpIndex - 1
  154. else
  155. FCurrentSector.Warps := 6;
  156. TWXDatabase.SaveSector(FCurrentSector, FCurrentSectorIndex, FShipList, FTraderList, FPlanetList);
  157. FCurrentSectorIndex := 0;
  158. ResetSectorLists;
  159. end;
  160. procedure TModExtractor.ProcessPrompt(Line : string);
  161. begin
  162. // This procedure checks command prompts. It is called from both
  163. // processline and processinbound, as it can come in as part of
  164. // a large packet or still be waiting for the user.
  165. if (Copy(Line, 1, 12) = 'Command [TL=') then
  166. begin
  167. // Save current sector if not done already
  168. if not (FSectorSaved) then
  169. SectorCompleted;
  170. // No displays anymore, all done
  171. FCurrentDisplay := dNone;
  172. FLastWarp := 0;
  173. end
  174. else if (Copy(Line, 1, 23) = 'Probe entering sector :') or (Copy(Line, 1, 20) = 'Probe Self Destructs') then
  175. begin
  176. // mid probe - save the sector
  177. if not (FSectorSaved) then
  178. SectorCompleted;
  179. // No displays anymore, all done
  180. FCurrentDisplay := dNone;
  181. end
  182. else if (Copy(Line, 1, 21) = 'Computer command [TL=') then
  183. begin
  184. // in computer prompt, kill all displays and clear warp data
  185. FCurrentDisplay := dNone;
  186. FLastWarp := 0;
  187. end
  188. else if (Copy(Line, 1, 25) = 'Citadel treasury contains') then
  189. begin
  190. // In Citadel - Save current sector if not done already
  191. if not (FSectorSaved) then
  192. SectorCompleted;
  193. // No displays anymore, all done
  194. FCurrentDisplay := dNone;
  195. end
  196. else if (Copy(Line, 1, 19) = 'Stop in this sector') or (Copy(Line, 1, 21) = 'Engage the Autopilot?') then
  197. begin
  198. // Save current sector if not done already
  199. if not (FSectorSaved) then
  200. SectorCompleted;
  201. // No displays anymore, all done
  202. FCurrentDisplay := dNone;
  203. end
  204. else if (Copy(Line, 1, 2) = ': ') then
  205. begin
  206. // at the CIM prompt
  207. if (FCurrentDisplay <> dCIM) then
  208. FCurrentDisplay := dNone;
  209. FLastWarp := 0;
  210. end;
  211. TWXInterpreter.TextEvent(CurrentLine, FALSE);
  212. end;
  213. procedure TModExtractor.AddWarp(SectNum, Warp : Integer);
  214. var
  215. S : TSector;
  216. I,
  217. X,
  218. Pos : Integer;
  219. begin
  220. // Used by ProcessWarpLine to add a warp to a sector
  221. S := TWXDatabase.LoadSector(SectNum);
  222. // see if the warp is already in there
  223. for I := 1 to 6 do
  224. if (S.Warp[I] = Warp) then
  225. Exit;
  226. // find where it should fit
  227. Pos := 7;
  228. for I := 1 to 6 do
  229. if (S.Warp[I] > Warp) or (S.Warp[I] = 0) then
  230. begin
  231. Pos := I;
  232. Break;
  233. end;
  234. if (Pos = 1) then
  235. X := 2
  236. else
  237. X := Pos;
  238. // move them all up one
  239. if (Pos < 6) then
  240. for I := 6 downto X do
  241. S.Warp[I] := S.Warp[I - 1];
  242. if (Pos < 7) then
  243. S.Warp[Pos] := Warp;
  244. if (S.Explored = etNo) then
  245. begin
  246. S.Constellation := '???' + ANSI_9 + ' (warp calc only)';
  247. S.Explored := etCalc;
  248. S.Update := Now;
  249. end;
  250. TWXDatabase.SaveSector(S, SectNum, nil, nil, nil);
  251. end;
  252. procedure TModExtractor.ProcessWarpLine(Line : String);
  253. var
  254. I,
  255. CurSect,
  256. LastSect : Integer;
  257. S : String;
  258. begin
  259. // A WarpLine is a line of warps plotted using the ship's computer. Add new warps to
  260. // any sectors listed in the warp lane (used extensively for ZTM).
  261. // e.g: 3 > 300 > 5362 > 13526 > 149 > 434
  262. LastSect := FLastWarp;
  263. StripChar(Line, ')');
  264. StripChar(Line, '(');
  265. I := 1;
  266. S := GetParameter(Line, I);
  267. while (S <> '') do
  268. begin
  269. if (S <> '>') then
  270. begin
  271. CurSect := StrToIntSafe(S);
  272. if (CurSect < 1) or (CurSect > TWXDatabase.DBHeader.Sectors) then
  273. // doesn't look like this line is what we thought it was.
  274. // Best to leave it alone
  275. exit;
  276. if (LastSect > 0) then
  277. AddWarp(LastSect, CurSect);
  278. LastSect := CurSect;
  279. FLastWarp := CurSect;
  280. end;
  281. Inc(I);
  282. S := GetParameter(Line, I);
  283. end;
  284. end;
  285. procedure TModExtractor.ProcessCIMLine(Line : String);
  286. function GetCIMValue(M : String; Num : Integer) : Integer;
  287. var
  288. S : String;
  289. begin
  290. S := GetParameter(M, Num);
  291. if (S = '') then
  292. Result := 0
  293. else
  294. try
  295. Result := StrToInt(S);
  296. except
  297. Result := -1;
  298. end;
  299. end;
  300. var
  301. Sect : Integer;
  302. S : TSector;
  303. X,
  304. I,
  305. Len,
  306. Ore,
  307. Org,
  308. Equip,
  309. POre,
  310. POrg,
  311. PEquip : Integer;
  312. M : String;
  313. begin
  314. if (FCurrentDisplay = dWarpCIM) then
  315. begin
  316. // save warp CIM data
  317. Sect := GetCIMValue(Line, 1);
  318. if (Sect <= 0) or (Sect > TWXDatabase.DBHeader.Sectors) then
  319. begin
  320. FCurrentDisplay := dNone;
  321. Exit;
  322. end;
  323. S := TWXDatabase.LoadSector(Sect);
  324. for I := 1 to 6 do
  325. begin
  326. X := GetCIMValue(Line, I + 1);
  327. if (X < 0) or (X > TWXDatabase.DBHeader.Sectors) then
  328. begin
  329. FCurrentDisplay := dNone;
  330. Exit;
  331. end
  332. else
  333. S.Warp[I] := X;
  334. end;
  335. if (S.Explored = etNo) then
  336. begin
  337. S.Constellation := '???' + ANSI_9 + ' (warp calc only)';
  338. S.Explored := etCalc;
  339. S.Update := Now;
  340. end;
  341. TWXDatabase.SaveSector(S, Sect, nil, nil, nil);
  342. end
  343. else
  344. begin
  345. // save port CIM data
  346. Sect := GetCIMValue(Line, 1);
  347. Len := Length(IntToStr(TWXDatabase.DBHeader.Sectors));
  348. if (Sect <= 0) or (Sect > TWXDatabase.DBHeader.Sectors) or (Length(Line) < Len + 36) then
  349. begin
  350. FCurrentDisplay := dNone;
  351. Exit;
  352. end;
  353. M := StringReplace(Line, '-', '', [rfReplaceAll]);
  354. M := StringReplace(M, '%', '', [rfReplaceAll]);
  355. S := TWXDatabase.LoadSector(Sect);
  356. Ore := GetCIMValue(M, 2);
  357. Org := GetCIMValue(M, 4);
  358. Equip := GetCIMValue(M, 6);
  359. POre := GetCIMValue(M, 3);
  360. POrg := GetCIMValue(M, 5);
  361. PEquip := GetCIMValue(M, 7);
  362. if (Ore < 0) or (Org < 0) or (Equip < 0)
  363. or (POre < 0) or (POre > 100)
  364. or (POrg < 0) or (POrg > 100)
  365. or (PEquip < 0) or (PEquip > 100) then
  366. begin
  367. FCurrentDisplay := dNone;
  368. Exit;
  369. end;
  370. S.SPort.ProductAmount[ptFuelOre] := Ore;
  371. S.SPort.ProductAmount[ptOrganics] := Org;
  372. S.SPort.ProductAmount[ptEquipment] := Equip;
  373. S.SPort.ProductPercent[ptFuelOre] := POre;
  374. S.SPort.ProductPercent[ptOrganics] := POrg;
  375. S.SPort.ProductPercent[ptEquipment] := PEquip;
  376. S.SPort.UpDate := Now;
  377. if (S.SPort.Name = '') then
  378. begin
  379. // port not saved/seen before - get its details
  380. if (Line[Len + 2] = '-') then
  381. S.SPort.BuyProduct[ptFuelOre] := TRUE
  382. else
  383. S.SPort.BuyProduct[ptFuelOre] := FALSE;
  384. if (Line[Len + 14] = '-') then
  385. S.SPort.BuyProduct[ptOrganics] := TRUE
  386. else
  387. S.SPort.BuyProduct[ptOrganics] := FALSE;
  388. if (Line[Len + 26] = '-') then
  389. S.SPort.BuyProduct[ptEquipment] := TRUE
  390. else
  391. S.SPort.BuyProduct[ptEquipment] := FALSE;
  392. if (S.SPort.BuyProduct[ptFuelOre]) and (S.SPort.BuyProduct[ptOrganics]) and (S.SPort.BuyProduct[ptEquipment]) then
  393. S.SPort.ClassIndex := 8
  394. else if (S.SPort.BuyProduct[ptFuelOre]) and (S.SPort.BuyProduct[ptOrganics]) and not (S.SPort.BuyProduct[ptEquipment]) then
  395. S.SPort.ClassIndex := 1
  396. else if (S.SPort.BuyProduct[ptFuelOre]) and not (S.SPort.BuyProduct[ptOrganics]) and (S.SPort.BuyProduct[ptEquipment]) then
  397. S.SPort.ClassIndex := 2
  398. else if not (S.SPort.BuyProduct[ptFuelOre]) and (S.SPort.BuyProduct[ptOrganics]) and (S.SPort.BuyProduct[ptEquipment]) then
  399. S.SPort.ClassIndex := 3
  400. else if not (S.SPort.BuyProduct[ptFuelOre]) and not (S.SPort.BuyProduct[ptOrganics]) and (S.SPort.BuyProduct[ptEquipment]) then
  401. S.SPort.ClassIndex := 4
  402. else if not (S.SPort.BuyProduct[ptFuelOre]) and (S.SPort.BuyProduct[ptOrganics]) and not (S.SPort.BuyProduct[ptEquipment]) then
  403. S.SPort.ClassIndex := 5
  404. else if (S.SPort.BuyProduct[ptFuelOre]) and not (S.SPort.BuyProduct[ptOrganics]) and not (S.SPort.BuyProduct[ptEquipment]) then
  405. S.SPort.ClassIndex := 6
  406. else if not (S.SPort.BuyProduct[ptFuelOre]) and not (S.SPort.BuyProduct[ptOrganics]) and not (S.SPort.BuyProduct[ptEquipment]) then
  407. S.SPort.ClassIndex := 7;
  408. S.SPort.Name := '???';
  409. end;
  410. if (S.Explored = etNo) then
  411. begin
  412. S.Constellation := '???' + ANSI_9 + ' (port data/calc only)';
  413. S.Explored := etCalc;
  414. S.Update := Now;
  415. end;
  416. TWXDatabase.SaveSector(S, Sect, nil, nil, nil);
  417. end;
  418. end;
  419. procedure TModExtractor.ProcessSectorLine(Line : String);
  420. var
  421. S : String;
  422. I : Integer;
  423. NewPlanet : PPlanet;
  424. NewShip : PShip;
  425. NewTrader : PTrader;
  426. begin
  427. if (Copy(Line, 1, 10) = 'Beacon : ') then
  428. begin
  429. // Get beacon text
  430. FCurrentSector.Beacon := Copy(Line, 11, length(Line) - 10);
  431. end
  432. else if (Copy(Line, 1, 10) = 'Ports : ') then
  433. begin
  434. // Save port data
  435. if (Pos('<=-DANGER-=>', Line) > 0) then
  436. // Port is destroyed
  437. FCurrentSector.SPort.Dead := TRUE
  438. else
  439. begin
  440. FCurrentSector.SPort.Dead := FALSE;
  441. FCurrentSector.SPort.BuildTime := 0;
  442. FCurrentSector.SPort.Name := Copy(Line, 11, Pos(', Class', Line) - 11);
  443. FCurrentSector.SPort.ClassIndex := StrToIntSafe(Copy(Line, Pos(', Class', Line) + 8, 1));
  444. if (Line[length(Line) - 3] = 'B') then
  445. FCurrentSector.SPort.BuyProduct[ptFuelOre] := TRUE
  446. else
  447. FCurrentSector.SPort.BuyProduct[ptFuelOre] := FALSE;
  448. if (Line[length(Line) - 2] = 'B') then
  449. FCurrentSector.SPort.BuyProduct[ptOrganics] := TRUE
  450. else
  451. FCurrentSector.SPort.BuyProduct[ptOrganics] := FALSE;
  452. if (Line[length(Line) - 1] = 'B') then
  453. FCurrentSector.SPort.BuyProduct[ptEquipment] := TRUE
  454. else
  455. FCurrentSector.SPort.BuyProduct[ptEquipment] := FALSE;
  456. end;
  457. FSectorPosition := spPorts;
  458. end
  459. else if (Copy(Line, 1, 10) = 'Planets : ') then
  460. begin
  461. // Get planet data
  462. NewPlanet := AllocMem(SizeOf(TPlanet));
  463. TWXDatabase.NULLPlanet(NewPlanet^);
  464. NewPlanet^.Name := Copy(Line, 11, length(Line) - 10);
  465. FPlanetList.Add(NewPlanet);
  466. FSectorPosition := spPlanets;
  467. end
  468. else if (Copy(Line, 1, 10) = 'Traders : ') then
  469. begin
  470. // Save traders
  471. I := Pos(', w/', Line);
  472. FCurrentTrader.Name := Copy(Line, 11, I - 11);
  473. S := Copy(Line, I + 5, Pos(' ftrs', Line) - I - 5);
  474. StripChar(S, ',');
  475. FCurrentTrader.Figs := StrToIntSafe(S);
  476. FSectorPosition := spTraders;
  477. end
  478. else if (Copy(Line, 1, 10) = 'Ships : ') then
  479. begin
  480. // Save ships
  481. I := Pos('[Owned by]', Line);
  482. FCurrentShip.Name := Copy(Line, 11, I - 12);
  483. FCurrentShip.Owner := Copy(Line, I + 11, Pos(', w/', Line) - I - 11);
  484. I := Pos(', w/', Line);
  485. S := Copy(Line, I + 5, Pos(' ftrs,', Line) - I - 5);
  486. StripChar(S, ',');
  487. FCurrentShip.Figs := StrToIntSafe(S);
  488. FSectorPosition := spShips;
  489. end
  490. else if (Copy(Line, 1, 10) = 'Fighters: ') then
  491. begin
  492. // Get fig details
  493. S := GetParameter(Line, 2);
  494. StripChar(S, ',');
  495. FCurrentSector.Figs.Quantity := StrToIntSafe(S);
  496. I := GetParameterPos(Line, 3) + 1;
  497. FCurrentSector.Figs.Owner := Copy(Line, I, Pos(')', Line) - I);
  498. if (Copy(Line, length(Line) - 5, 6) = '[Toll]') then
  499. FCurrentSector.Figs.FigType := ftToll
  500. else if (Copy(Line, length(Line) - 10, 11) = '[Defensive]') then
  501. FCurrentSector.Figs.FigType := ftDefensive
  502. else
  503. FCurrentSector.Figs.FigType := ftOffensive;
  504. end
  505. else if (Copy(Line, 1, 10) = 'NavHaz : ') then
  506. begin
  507. S := GetParameter(Line, 3);
  508. S := Copy(S, 1, length(S) - 1);
  509. FCurrentSector.NavHaz := StrToIntSafe(S);
  510. end
  511. else if (Copy(Line, 1, 10) = 'Mines : ') then
  512. begin
  513. // Save mines
  514. FSectorPosition := spMines;
  515. I := GetParameterPos(Line, 7) + 1;
  516. S := Copy(Line, I, length(Line) - I);
  517. if (GetParameter(Line, 6) = 'Armid)') then
  518. begin
  519. FCurrentSector.Mines_Armid.Quantity := StrToIntSafe(GetParameter(Line, 3));
  520. FCurrentSector.Mines_Armid.Owner := S;
  521. end
  522. else
  523. begin
  524. FCurrentSector.Mines_Limpet.Quantity := StrToIntSafe(GetParameter(Line, 3));
  525. FCurrentSector.Mines_Limpet.Owner := S;
  526. end;
  527. end
  528. else if (Copy(Line, 1, 8) = ' ') then
  529. begin
  530. // Continue from last occurance
  531. if (FSectorPosition = spMines) then
  532. begin
  533. I := GetParameterPos(Line, 6) + 1;
  534. FCurrentSector.Mines_Limpet.Quantity := StrToIntSafe(GetParameter(Line, 2));
  535. FCurrentSector.Mines_Limpet.Owner := Copy(Line, I, length(Line) - I);
  536. end
  537. else if (FSectorPosition = spPorts) then
  538. FCurrentSector.SPort.BuildTime := StrToIntSafe(GetParameter(Line, 4))
  539. else if (FSectorPosition = spPlanets) then
  540. begin
  541. // Get planet data
  542. NewPlanet := AllocMem(SizeOf(TPlanet));
  543. TWXDatabase.NULLPlanet(NewPlanet^);
  544. NewPlanet^.Name := Copy(Line, 11, length(Line) - 10);
  545. FPlanetList.Add(NewPlanet);
  546. end
  547. else if (FSectorPosition = spTraders) then
  548. begin
  549. if (GetParameter(Line, 1) = 'in') then
  550. begin
  551. // Still working on one trader
  552. NewTrader := AllocMem(SizeOf(TTrader));
  553. I := GetParameterPos(Line, 2);
  554. NewTrader^.ShipName := Copy(Line, I, Pos('(', Line) - I - 1);
  555. I := Pos('(', Line);
  556. NewTrader^.ShipType := Copy(Line, I + 1, Pos(')', Line) - I - 1);
  557. NewTrader^.Name := FCurrentTrader.Name;
  558. NewTrader^.Figs := FCurrentTrader.Figs;
  559. FTraderList.Add(NewTrader);
  560. end
  561. else
  562. begin
  563. // New trader
  564. I := Pos(', w/', Line);
  565. FCurrentTrader.Name := Copy(Line, 11, I - 11);
  566. S := Copy(Line, I + 5, Pos(' ftrs', Line) - I - 5);
  567. StripChar(S, ',');
  568. FCurrentTrader.Figs := StrToIntSafe(S);
  569. end;
  570. end
  571. else if (FSectorPosition = spShips) then
  572. begin
  573. if (Copy(Line, 12, 1) = '(') then
  574. begin
  575. // Get the rest of the ship info
  576. NewShip := AllocMem(SizeOf(TShip));
  577. NewShip^.Name := FCurrentShip.Name;
  578. NewShip^.Owner := FCurrentShip.Owner;
  579. NewShip^.Figs := FCurrentShip.Figs;
  580. NewShip^.ShipType := Copy(Line, 13, Pos(')', Line) - 13);
  581. FShipList.Add(NewShip);
  582. end
  583. else
  584. begin
  585. // New ship
  586. I := Pos('[Owned by]', Line);
  587. FCurrentShip.Name := Copy(Line, 11, I - 12);
  588. FCurrentShip.Owner := Copy(Line, I + 11, Pos(', w/', Line) - I - 11);
  589. I := Pos(', w/', Line);
  590. S := Copy(Line, I + 5, Pos(' ftrs,', Line) - I - 5);
  591. StripChar(S, ',');
  592. FCurrentShip.Figs := StrToIntSafe(S);
  593. FSectorPosition := spShips;
  594. end;
  595. end;
  596. end
  597. else if (Copy(Line, 9, 1) = ':') then
  598. FSectorPosition := spNormal
  599. else if (Copy(Line, 1, 20) = 'Warps to Sector(s) :') then
  600. begin
  601. StripChar(Line, '(');
  602. StripChar(Line, ')');
  603. // Get sector warps
  604. FCurrentSector.Warp[1] := StrToIntSafe(GetParameter(Line, 5));
  605. FCurrentSector.Warp[2] := StrToIntSafe(GetParameter(Line, 7));
  606. FCurrentSector.Warp[3] := StrToIntSafe(GetParameter(Line, 9));
  607. FCurrentSector.Warp[4] := StrToIntSafe(GetParameter(Line, 11));
  608. FCurrentSector.Warp[5] := StrToIntSafe(GetParameter(Line, 13));
  609. FCurrentSector.Warp[6] := StrToIntSafe(GetParameter(Line, 15));
  610. // sector done
  611. if not (FSectorSaved) then
  612. SectorCompleted;
  613. // No displays anymore, all done
  614. FCurrentDisplay := dNone;
  615. FSectorPosition := spNormal;
  616. end;
  617. end;
  618. procedure TModExtractor.ProcessPortLine(Line : String);
  619. begin
  620. // Process a line from the CR port display
  621. end;
  622. procedure TModExtractor.ProcessLine(Line : String);
  623. var
  624. S,
  625. X : String;
  626. I : Integer;
  627. Sect : TSector;
  628. begin
  629. // Every line is passed to this procedure to be processed and recorded
  630. if (FCurrentMessage <> '') then
  631. begin
  632. if (Line <> '') then
  633. begin
  634. if (FCurrentMessage = 'Figs') then
  635. TWXGUI.AddToHistory(htFighter, TimeToStr(Time) + ' ' + StripChars(Line))
  636. else if (FCurrentMessage = 'Comp') then
  637. TWXGUI.AddToHistory(htComputer, TimeToStr(Time) + ' ' + StripChars(Line))
  638. else
  639. TWXGUI.AddToHistory(htMsg, TimeToStr(Time) + ' ' + StripChars(Line));
  640. FCurrentMessage := '';
  641. end;
  642. end
  643. else if (Copy(Line, 1, 2) = 'R ') or (Copy(Line, 1, 2) = 'F ') then
  644. TWXGUI.AddToHistory(htMsg, TimeToStr(Time) + ' ' + StripChars(Line))
  645. else if (Copy(Line, 1, 2) = 'P ') then
  646. begin
  647. if (GetParameter(Line, 2) <> 'indicates') then
  648. TWXGUI.AddToHistory(htMsg, TimeToStr(Time) + ' ' + StripChars(Line))
  649. end
  650. else if (Copy(Line, 1, 26) = 'Incoming transmission from') or (Copy(Line, 1, 28) = 'Continuing transmission from') then
  651. begin
  652. // Transmission with ansi off
  653. I := GetParameterPos(Line, 4);
  654. if (Copy(Line, Length(Line) - 9, 10) = 'comm-link:') then
  655. begin
  656. // Fedlink
  657. FCurrentMessage := 'F ' + Copy(Line, I, Pos(' on Federation', Line) - I) + ' ';
  658. end
  659. else if (GetParameter(Line, 5) = 'Fighters:') then
  660. begin
  661. // Fighters
  662. FCurrentMessage := 'Figs';
  663. end
  664. else if (GetParameter(Line, 5) = 'Computers:') then
  665. begin
  666. // Computer
  667. FCurrentMessage := 'Comp';
  668. end
  669. else if (Pos(' on channel ', Line) <> 0) then
  670. begin
  671. // Radio
  672. FCurrentMessage := 'R ' + Copy(Line, I, Pos(' on channel ', Line) - I) + ' ';
  673. end
  674. else
  675. begin
  676. // hail
  677. FCurrentMessage := 'P ' + Copy(Line, I, Length(Line) - I) + ' ';
  678. end
  679. end
  680. else if (Copy(Line, 1, 31) = 'Deployed Fighters Report Sector') then
  681. TWXGUI.AddToHistory(htFighter, TimeToStr(Time) + ' ' + Copy(Line, 19, Length(Line)))
  682. else if (Copy(Line, 1, 20) = 'Shipboard Computers ') then
  683. TWXGUI.AddToHistory(htComputer, TimeToStr(Time) + ' ' + Copy(Line, 21, Length(Line)))
  684. else if (Copy(Line, 1, 19) = 'The shortest path (') or (Copy(Line, 1, 7) = ' TO > ') then
  685. begin
  686. FCurrentDisplay := dWarpLane;
  687. FLastWarp := 0;
  688. end
  689. else if (FCurrentDisplay = dWarpLane) then
  690. ProcessWarpLine(Line)
  691. else if (FCurrentDisplay = dWarpCIM) or (FCurrentDisplay = dPortCIM) then
  692. ProcessCIMLine(Line)
  693. else if (FCurrentDisplay = dCIM) then
  694. begin
  695. // find out what kind of CIM this is
  696. if (Length(Line) > 2) then
  697. begin
  698. if (Line[Length(Line) - 1] = '%') then
  699. begin
  700. TWXDatabase.LastPortCIM := Now;
  701. FCurrentDisplay := dPortCIM;
  702. end
  703. else
  704. FCurrentDisplay := dWarpCIM;
  705. ProcessCIMLine(Line);
  706. end;
  707. end
  708. else if (Copy(Line, 1, 10) = 'Sector : ') then
  709. begin
  710. // Check if this is a probe or holoscan (no warp pickup)
  711. if not (FSectorSaved) then
  712. SectorCompleted;
  713. // Begin recording of sector data
  714. FCurrentDisplay := dSector;
  715. FSectorSaved := FALSE;
  716. // Clear sector variables
  717. TWXDatabase.NULLSector(FCurrentSector);
  718. FCurrentSectorIndex := StrToIntSafe(GetParameter(Line, 3));
  719. I := GetParameterPos(Line, 5);
  720. FCurrentSector.Constellation := Copy(Line, I, length(Line) - I + 1);
  721. end
  722. else if (FCurrentDisplay = dSector) then
  723. ProcessSectorLine(Line)
  724. else if (FCurrentDisplay = dPort) then
  725. ProcessPortLine(Line)
  726. else if (Copy(Line, 27, 16) = 'Relative Density') then
  727. begin
  728. // A density scanner is being used - lets grab some data
  729. FCurrentDisplay := dDensity;
  730. end
  731. else if (FCurrentDisplay = dDensity) and (Copy(Line, 1, 6) = 'Sector') then
  732. begin
  733. // Save all density data into sector database
  734. X := Line;
  735. StripChar(X, '(');
  736. StripChar(X, ')');
  737. I := StrToIntSafe(GetParameter(X, 2));
  738. Sect := TWXDatabase.LoadSector(I);
  739. S := GetParameter(X, 4);
  740. StripChar(S, ',');
  741. Sect.Density := StrToIntSafe(S);
  742. if (GetParameter(X, 13) = 'Yes') then
  743. // Sector has anomoly
  744. Sect.Anomoly := TRUE
  745. else
  746. Sect.Anomoly := FALSE;
  747. S := GetParameter(X, 10);
  748. S := Copy(S, 1, length(S) - 1);
  749. Sect.NavHaz := StrToIntSafe(S);
  750. Sect.Warps := StrToIntSafe(GetParameter(X, 7));
  751. if (Sect.Explored in [etNo, etCalc]) then
  752. begin
  753. // Sector hasn't been scanned or seen before
  754. Sect.Constellation := '???' + ANSI_9 + ' (Density only)';
  755. Sect.Explored := etDensity;
  756. Sect.Update := Now;
  757. end;
  758. TWXDatabase.SaveSector(Sect, I, nil, nil, nil);
  759. end
  760. else if (Copy(Line, 1, 28) = 'What sector is the port in? ') then
  761. begin
  762. // begin port data download
  763. end
  764. else if (Copy(Line, 1, 2) = ': ') then
  765. begin
  766. // begin CIM download
  767. FCurrentDisplay := dCIM;
  768. end;
  769. TWXInterpreter.TextLineEvent(Line, FALSE);
  770. ProcessPrompt(Line);
  771. // Reactivate script triggers
  772. TWXInterpreter.ActivateTriggers;
  773. end;
  774. procedure TModExtractor.StripANSI(var S : String);
  775. var
  776. I : Integer;
  777. X : String;
  778. begin
  779. // Remove ANSI codes from text
  780. X := '';
  781. for I := 1 to length(S) do
  782. begin
  783. if (S[I] = #27) then
  784. FInAnsi := TRUE;
  785. if (FInAnsi = FALSE) then
  786. X := X + S[I];
  787. if ((Byte(S[I]) >= 65) and (Byte(S[I]) <= 90)) or ((Byte(S[I]) >= 97) and (Byte(S[I]) <= 122)) then
  788. FInAnsi := FALSE;
  789. end;
  790. S := X;
  791. end;
  792. procedure TModExtractor.ProcessInBound(var InData : String);
  793. var
  794. X : Integer;
  795. I : Integer;
  796. S,
  797. ANSIS,
  798. ANSILine,
  799. Line : string;
  800. begin
  801. S := InData;
  802. // Remove null chars
  803. StripChar(S, #0);
  804. // strip the ANSI
  805. AnsiS := S;
  806. StripANSI(S);
  807. TWXLog.DoLogData(S, InData);
  808. // Remove linefeed
  809. StripChar(S, #10);
  810. StripChar(AnsiS, #10);
  811. // Form and process lines out of data
  812. I := 1;
  813. Line := CurrentLine + S;
  814. AnsiLine := CurrentANSILine + AnsiS;
  815. while (I <= Length(Line)) do
  816. begin
  817. if (Line[I] = #13) then
  818. begin
  819. // find the matching carriage return in the ansi line
  820. X := 1;
  821. if (Length(ANSILine) > 0) then
  822. while (ANSILine[X] <> #13) and (X < Length(ANSILine)) do
  823. Inc(X);
  824. CurrentLine := Copy(Line, 1, I - 1);
  825. CurrentANSILine := Copy(ANSILine, 1, X - 1);
  826. ProcessLine(CurrentLine);
  827. if (I < Length(Line)) then
  828. begin
  829. Line := Copy(Line, I + 1, Length(Line) - I);
  830. ANSILine := Copy(ANSILine, X + 1, Length(ANSILine) - X);
  831. end
  832. else
  833. begin
  834. Line := '';
  835. ANSILine := '';
  836. Break;
  837. end;
  838. I := 0;
  839. end;
  840. Inc(I);
  841. end;
  842. // Process what we have left
  843. CurrentLine := Line;
  844. CurrentANSILine := ANSILine;
  845. ProcessPrompt(CurrentLine);
  846. end;
  847. // ********************************************************************
  848. // Process outbound data
  849. function TModExtractor.ProcessOutBound(OutData : string; ClientIndex : Byte) : Boolean;
  850. begin
  851. Result := TRUE;
  852. if (OutData[1] = MenuKey) and (TWXMenu.CurrentMenu = nil) then
  853. begin
  854. // Activate menu
  855. if not (TWXClient.Connected) then
  856. begin
  857. // User trying to access database while not connected
  858. if not (TWXDatabase.DataBaseOpen) then
  859. TWXServer.ClientMessage(endl + ANSI_12 + 'Warning: This database is corrupt or does not exist. No data is available.' + ANSI_7 + endl);
  860. end;
  861. TWXMenu.OpenMenu('TWX_MAIN', ClientIndex);
  862. // run the rest of the text through the menus
  863. if (Length(OutData) > 1) then
  864. ProcessOutBound(Copy(OutData, 2, Length(OutData)), ClientIndex);
  865. Result := FALSE;
  866. end
  867. else if (TWXMenu.CurrentMenu <> nil) then
  868. begin
  869. if (OutData[1] = MenuKey) then
  870. // De-activate menu
  871. TWXMenu.CloseMenu(TRUE)
  872. else
  873. // Send commands to menu
  874. TWXMenu.MenuText(OutData, ClientIndex);
  875. Result := FALSE;
  876. end;
  877. // don't return a value if trigger had this key
  878. if (Result) and (OutData <> '') then
  879. Result := not TWXInterpreter.TextOutEvent(OutData, nil);
  880. end;
  881. end.