MEGS - This is the economy gamescript running on Midgard, a public OpenTTD server. It's a heavily changed version of https://openttd-polska.pl/Thread-Inne-Projekt-skrypt-New-World-Disorder

nwd.nut 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. require ("config.nut");
  5. class NWD
  6. {
  7. p = null;
  8. towns = null;
  9. industries = null;
  10. wait = null;
  11. constructor (v)
  12. {
  13. p = v;
  14. industries = [];
  15. towns = [];
  16. wait = 0;
  17. }
  18. function Init ()
  19. {
  20. GSLog.Info ("--------------------------------------");
  21. GSLog.Info ("New World Disorder v0.2.1 - 12.10.2016");
  22. GSLog.Info ("Design by LaChupacabra");
  23. GSLog.Info ("Programming by Milek7");
  24. GSLog.Info ("--------------------------------------");
  25. GSLog.Info ("Initialization...");
  26. local list;
  27. list = GSIndustryList ();
  28. for (local v = list.Begin (); !list.IsEnd (); v = list.Next ())
  29. industries.push(Industry (v));
  30. list = GSTownList ();
  31. for (local v = list.Begin (); !list.IsEnd (); v = list.Next ())
  32. towns.push (Town (this, v));
  33. GSLog.Info ("OK!");
  34. GSLog.Info ("--------------------------------------");
  35. }
  36. function AssignStation (station)
  37. {
  38. foreach (v in towns)
  39. if (GSStation.GetDistanceManhattanToTile (station, GSTown.GetLocation (v.t)) < Config.StationDistance ||
  40. GSStation.IsWithinTownInfluence (station, v.t))
  41. v.stations.push(station);
  42. }
  43. function AssignIndustry (industry)
  44. {
  45. local i = Industry(industry);
  46. industries.push(i);
  47. foreach (v in towns)
  48. v.PushIndustry(i);
  49. }
  50. function OnLoop ()
  51. {
  52. wait--;
  53. if (wait > 0)
  54. return;
  55. local bdate = GSDate.GetCurrentDate();
  56. GSLog.Info ("--------------------------------------");
  57. GSLog.Info ("Calculating...");
  58. foreach (k, v in industries)
  59. if (!GSIndustry.IsValidIndustry (v.i))
  60. industries.remove (k);
  61. foreach (v in towns)
  62. v.ComputeGrowth ();
  63. GSLog.Info ("OK!");
  64. GSLog.Info ("--------------------------------------");
  65. wait = Config.UpdateInterval - (GSDate.GetCurrentDate() - bdate);
  66. if (wait < 0)
  67. GSLog.Warning("WARNING: Can't keep up with UpdateInterval by " + (-wait) + " days!");
  68. }
  69. function OnEvent (e)
  70. {
  71. switch (e.GetEventType ())
  72. {
  73. case GSEvent.ET_STATION_FIRST_VEHICLE:
  74. AssignStation (GSEventStationFirstVehicle.Convert (e).GetStationID ());
  75. break;
  76. case GSEvent.ET_INDUSTRY_OPEN:
  77. AssignIndustry (GSEventIndustryOpen.Convert (e).GetIndustryID ());
  78. break;
  79. case GSEvent.ET_TOWN_FOUNDED:
  80. towns.push (Town (this, GSEventTownFounded.Convert (e).GetTownID ()));
  81. break;
  82. }
  83. }
  84. }
  85. class Industry
  86. {
  87. i = null;
  88. nearest_town = null;
  89. nearest_town_distance = null;
  90. constructor (id)
  91. {
  92. i = id;
  93. nearest_town_distance = 10000;
  94. }
  95. }
  96. class Town
  97. {
  98. t = null;
  99. p = null;
  100. industries = null;
  101. stations = null;
  102. lasthouses = null;
  103. lastvalues = null;
  104. lastgrowth = 200;
  105. constructor (v, b)
  106. {
  107. t = b;
  108. p = v;
  109. lasthouses = GSTown.GetHouseCount (t);
  110. RebuildStationsList ();
  111. RebuildIndustriesList ();
  112. GSTown.SetGrowthRate (t, 0);
  113. }
  114. function RebuildStationsList ()
  115. {
  116. stations = [];
  117. local list = GSStationList (GSStation.STATION_ANY);
  118. for (local v = list.Begin (); !list.IsEnd (); v = list.Next ())
  119. {
  120. local distance = GSStation.GetDistanceManhattanToTile (v, GSTown.GetLocation (t));
  121. if (distance < Config.StationDistance || GSStation.IsWithinTownInfluence (v, t))
  122. stations.push (v);
  123. }
  124. }
  125. function RebuildIndustriesList ()
  126. {
  127. industries = [];
  128. foreach (v in p.industries)
  129. PushIndustry(v);
  130. }
  131. function PushIndustry (v)
  132. {
  133. if (!GSIndustry.IsValidIndustry (v.i))
  134. return;
  135. local distance = GSIndustry.GetDistanceManhattanToTile (v.i, GSTown.GetLocation (t));
  136. if (distance < Config.IndustryDistance || GSTile.IsWithinTownInfluence(GSIndustry.GetLocation (v.i), t))
  137. {
  138. industries.push(v);
  139. if (distance < v.nearest_town_distance)
  140. {
  141. v.nearest_town_distance = distance;
  142. v.nearest_town = this;
  143. }
  144. }
  145. }
  146. function GetCategorizedCargo (station, provider, cargo)
  147. {
  148. local t = {};
  149. t.intercity <- 0;
  150. t.innercity <- 0;
  151. local c = provider (station, cargo);
  152. for (local x = c.Begin (); !c.IsEnd (); x = c.Next ())
  153. {
  154. if (station == x)
  155. continue;
  156. local inner = false;
  157. foreach (z in stations)
  158. if (z == x)
  159. {
  160. inner = true;
  161. break;
  162. }
  163. if (inner)
  164. t.innercity += c.GetValue (x);
  165. else
  166. t.intercity += c.GetValue (x);
  167. }
  168. return t;
  169. }
  170. function ComputeInfrastructure()
  171. {
  172. local tl = GSTileList();
  173. local tile = GSTown.GetLocation(t);
  174. local pop = max(ceil(GSTown.GetPopulation(t) / 100), 1);
  175. local radius = (max(pop, 5)).tointeger();
  176. tl.AddRectangle(tile + GSMap.GetTileIndex(radius*-1, radius*-1), tile + GSMap.GetTileIndex(radius, radius));
  177. GSRoad.SetCurrentRoadType(GSRoad.ROADTYPE_ROAD);
  178. /* count road tiles */
  179. local roadList = GSTileList();
  180. roadList.AddList(tl);
  181. roadList.Valuate(GSRoad.IsRoadTile);
  182. roadList.KeepValue(1);
  183. /* count town tiles */
  184. local townList = GSTileList();
  185. townList.AddList(tl);
  186. townList.Valuate(function(tile, town){
  187. return GSTown.IsWithinTownInfluence(town, tile);
  188. }, t);
  189. townList.KeepValue(1);
  190. local roadRatio = clamp((roadList.Count() / (townList.Count()).tofloat()) / 0.25, 0, 2);
  191. //GSLog.Info("road tiles: " + roadList.Count() + " town tiles: "+ townList.Count() + " ratio: " + roadRatio);
  192. /* count station tiles */
  193. local stationList = GSTileList();
  194. stationList.AddList(tl);
  195. stationList.Valuate(GSTile.IsStationTile);
  196. stationList.KeepValue(1);
  197. local stationRatio = clamp((stationList.Count() / pop.tofloat()), 0, 2);
  198. //GSLog.Info("station tiles: " + stationList.Count() + " town pop: "+ pop + " ratio: " + stationRatio);
  199. return (roadRatio + stationRatio) / 2;
  200. }
  201. function ComputeGrowth ()
  202. {
  203. if (GSTown.GetHouseCount (t) > lasthouses + 10)
  204. {
  205. RebuildStationsList();
  206. lasthouses = GSTown.GetHouseCount (t);
  207. }
  208. //GSLog.Info("# Town "+GSTown.GetName(t));
  209. local values =
  210. {
  211. industry = 0
  212. trade = 0
  213. build = 0
  214. infrastructure = 0
  215. transport = 0
  216. transport_in = 0
  217. transport_out = 0
  218. manpower = 0
  219. };
  220. local trans_cargo = 0;
  221. local trans_int_cargo = 0;
  222. local prod_cargo = 0;
  223. local proc_cargo = 0;
  224. local trade_cargo = 0;
  225. foreach (k, v in stations)
  226. {
  227. if (!GSStation.IsValidStation (v))
  228. {
  229. stations.remove (k);
  230. continue;
  231. }
  232. local c;
  233. foreach (h, j in Config.TransportCargo)
  234. {
  235. local addition = 0;
  236. local addition_in = 0;
  237. local addition_out = 0;
  238. //incoming
  239. c = GetCategorizedCargo (v, GSStationList_CargoPlannedByFrom, h);
  240. addition_in += c.intercity * j;
  241. //outcoming
  242. c = GetCategorizedCargo (v, GSStationList_CargoPlannedByVia, h);
  243. addition += c.innercity * j;
  244. addition_out += c.intercity * j;
  245. if (addition>0) {
  246. trans_cargo = trans_cargo|1<<h;
  247. //GSLog.Info("Trans "+GSCargo.GetCargoLabel(h));
  248. }
  249. if (addition_in>0 || addition_out>0) {
  250. trans_int_cargo = trans_int_cargo|1<<h;
  251. //GSLog.Info("TransIn "+GSCargo.GetCargoLabel(h));
  252. }
  253. values.transport += addition;
  254. values.transport_in += addition_in;
  255. values.transport_out += addition_out;
  256. //GSLog.Info(" Transport in Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.intercity * j));
  257. //GSLog.Info(" Transport Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.innercity * j));
  258. //GSLog.Info(" Transport in Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.intercity * j));
  259. }
  260. foreach (h, j in Config.TradeCargoMultipier)
  261. {
  262. local addition = 0;
  263. //incoming
  264. c = GetCategorizedCargo (v, GSStationList_CargoPlannedByFrom, h);
  265. addition += c.intercity * j;
  266. //GSLog.Info(" Trade Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.intercity * j));
  267. //outcoming
  268. c = GetCategorizedCargo (v, GSStationList_CargoPlannedByVia, h);
  269. addition += c.innercity * j /2;
  270. //GSLog.Info(" Trade Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.innercity * j /2));
  271. addition += c.intercity * j;
  272. //GSLog.Info(" Trade Cargo "+GSCargo.GetCargoLabel(h) + " "+ (c.intercity * j));
  273. if (addition>0) {
  274. trade_cargo = trade_cargo|1<<h;
  275. //GSLog.Info("Trade "+GSCargo.GetCargoLabel(h));
  276. }
  277. values.trade += addition;
  278. }
  279. }
  280. foreach (k, v in industries)
  281. {
  282. if (!GSIndustry.IsValidIndustry (v.i))
  283. {
  284. industries.remove (k);
  285. continue;
  286. }
  287. //GSLog.Info("Industry "+GSIndustry.GetName(v.i) + " dist " + GSIndustry.GetDistanceManhattanToTile (v.i, GSTown.GetLocation (t)));
  288. local type = GSIndustry.GetIndustryType (v.i);
  289. local produced = GSIndustryType.GetProducedCargo (type);
  290. local accepted = GSIndustryType.GetAcceptedCargo (type);
  291. local multipier;
  292. if (v.nearest_town == this)
  293. multipier = 1.0;
  294. else
  295. multipier = (1.0 - (GSIndustry.GetDistanceManhattanToTile (v.i, GSTown.GetLocation (t)) / Config.IndustryDistance)) * Config.NonNearestMultipier;
  296. //GSLog.Info(" multiplier "+multipier);
  297. for (local c = produced.Begin (); !produced.IsEnd (); c = produced.Next ())
  298. {
  299. //GSLog.Info("Cargo "+GSCargo.GetCargoLabel(c));
  300. local m = 0, addition = 0;
  301. if (c in Config.IndustryMultipier) {
  302. m = Config.IndustryMultipier[c];
  303. addition += (GSIndustry.GetLastMonthProduction(v.i, c)+GSIndustry.GetLastMonthTransported(v.i, c))/2 * m * multipier;
  304. if (addition>0 ) {
  305. proc_cargo = proc_cargo|1<<c;
  306. //GSLog.Info("Proc "+GSCargo.GetCargoLabel(c));
  307. }
  308. values.industry += addition;
  309. //GSLog.Info(" Process "+ addition);
  310. }
  311. m = 0;
  312. addition = 0;
  313. if (c in Config.BuildCargoMultipier) {
  314. m = Config.BuildCargoMultipier[c];
  315. addition += (GSIndustry.GetLastMonthProduction(v.i, c)+GSIndustry.GetLastMonthTransported(v.i, c))/2 * m * multipier;
  316. if (addition>0) {
  317. prod_cargo = prod_cargo|1<<c;
  318. //GSLog.Info("Prod "+GSCargo.GetCargoLabel(c));
  319. }
  320. values.build += addition;
  321. //GSLog.Info(" Process "+ addition);
  322. }
  323. }
  324. for (local c = accepted.Begin (); !accepted.IsEnd (); c = accepted.Next ())
  325. {
  326. local m, a, addition = 0;
  327. a = MonitorIndustry (c, v.i);
  328. //GSLog.Info("Cargo "+GSCargo.GetCargoLabel(c));
  329. m = 0;
  330. if (c in Config.IndustryMultipier) {
  331. m = Config.IndustryMultipier[c];
  332. addition += a * m * multipier;
  333. if (addition>0) {
  334. proc_cargo = proc_cargo|1<<c;
  335. //GSLog.Info("Proc "+GSCargo.GetCargoLabel(c));
  336. }
  337. values.industry += addition;
  338. //GSLog.Info(" Process "+ addition);
  339. }
  340. m = 0;
  341. addition = 0;
  342. if (c in Config.BuildCargoMultipier) {
  343. m = Config.BuildCargoMultipier[c];
  344. addition += a * m * multipier;
  345. if (addition>0) {
  346. prod_cargo = prod_cargo|1<<c;
  347. //GSLog.Info("Prod "+GSCargo.GetCargoLabel(c));
  348. }
  349. values.industry += addition;
  350. //GSLog.Info(" Process "+ addition);
  351. }
  352. }
  353. local list = GSCargoList();
  354. for (local c = list.Begin(); !list.IsEnd(); c = list.Next())
  355. {
  356. local cargoLabel = GSCargo.GetCargoLabel(c);
  357. if (cargoLabel == "PASS")
  358. {
  359. local a = MonitorIndustry (c, v.i);
  360. values.manpower += max(0, GSIndustry.GetLastMonthTransported(v.i, c) + a);
  361. //GSLog.Info("Manpower " + cargoLabel + ": " + values.manpower);
  362. }
  363. }
  364. }
  365. local population = GSTown.GetPopulation (t);
  366. local total_pax = values.transport + values.transport_in + values.transport_out;
  367. local produced_pax = 0;
  368. foreach (a, b in Config.TransportCargo)
  369. {
  370. produced_pax += GSTown.GetLastMonthProduction (t, a) * b;
  371. }
  372. values.infrastructure = ComputeInfrastructure();
  373. values.manpower = safediv(values.manpower, (population).tofloat());
  374. values.build = safediv(values.build, 100.0 / 1000.0 * population);
  375. values.industry = safediv(values.industry, 200.0 / 1000.0 * population);
  376. values.trade = safediv(values.trade, 100.0 / 1000.0 * population);
  377. values.transport = min(safediv(values.transport, total_pax), 1.0) * safediv(total_pax, produced_pax);
  378. values.transport_inter <- safediv(values.transport_in, produced_pax) * 0.5
  379. + safediv(values.transport_out, produced_pax) * 0.5;
  380. foreach (a, b in values)
  381. {
  382. if (b > 1.0)
  383. values[a] = 1 + sqrt(b - 1.0) * 3.0;
  384. if (lastvalues != null)
  385. values[a] = clamp(lastvalues[a] + (b - lastvalues[a]) / 4.0, 0, 1);
  386. }
  387. lastvalues = values;
  388. local total = (values.industry
  389. + values.trade
  390. + values.build
  391. + values.transport
  392. + values.transport_inter
  393. + values.infrastructure
  394. + values.manpower
  395. ) / 7.0;
  396. local unemployment = max((1 - total) * 0.4, 0)+0.0049;
  397. local growth = (355 * pow(1.0 - total, 2)).tointeger();
  398. growth = lastgrowth = max(1, ((lastgrowth*2)+growth)/3);
  399. GSTown.SetGrowthRate (t, growth < 200 ? growth : GSTown.TOWN_GROWTH_NONE);
  400. local infraRatio = (values.infrastructure+values.transport+values.transport_inter)/3;
  401. local economyRatio = (values.build+values.industry+values.trade)/3;
  402. local windowText = GSText (GSText.STR_INFO_WINDOW,
  403. GetColor(1 - unemployment / 0.4), (unemployment * 100).tointeger(),
  404. GetColor(infraRatio), GetValueText(infraRatio),
  405. GetValueText(values.manpower),
  406. (values.transport * 100).tointeger(), (trans_cargo).tointeger(),
  407. (values.transport_inter * 100).tointeger(), (trans_int_cargo).tointeger(),
  408. GetColor(economyRatio), GetValueText(economyRatio),
  409. (values.build * 100).tointeger(), (prod_cargo).tointeger(),
  410. (values.industry * 100).tointeger(), (proc_cargo).tointeger(),
  411. (values.trade * 100).tointeger(), (trade_cargo).tointeger()
  412. );
  413. GSTown.SetText (t, windowText);
  414. /*local windowText = GSText (GSText.STR_INFO_WINDOW,
  415. GSText(GSText.STR_INFO_UNEMPL, GetColor(1 - unemployment / 0.4), (unemployment * 100).tointeger()),
  416. GSText(GSText.STR_INFO_INFRA, GetColor(infraRatio), GetValueText(infraRatio)),
  417. GSText(GSText.STR_INFO_INFRA_LOCAL, (values.transport * 100).tointeger()),
  418. GSText(GSText.STR_INFO_INFRA_INTER, (values.transport_inter * 100).tointeger()),
  419. GSText(GSText.STR_INFO_ECON, GetColor(economyRatio), GetValueText(economyRatio)),
  420. GSText(GSText.STR_INFO_ECON_PROD, (values.build * 100).tointeger()),
  421. GSText(GSText.STR_INFO_ECON_PROC, (values.industry * 100).tointeger()),
  422. GSText(GSText.STR_INFO_ECON_TRADE, (values.trade * 100).tointeger(), trade_cargo)
  423. );*/
  424. /*local windowText = GSText (GSText.STR_INFO_WINDOW);
  425. windowText.SetParam(1, GSText(GSText.STR_INFO_UNEMPL, GetColor(1 - unemployment / 0.4), (unemployment * 100).tointeger()));
  426. windowText.SetParam(2, GSText(GSText.STR_INFO_INFRA, GetColor(infraRatio), GetValueText(infraRatio)));
  427. windowText.SetParam(3, GSText(GSText.STR_INFO_INFRA_LOCAL, (values.transport * 100).tointeger()));
  428. windowText.SetParam(4, GSText(GSText.STR_INFO_INFRA_INTER, (values.transport_inter * 100).tointeger()));
  429. windowText.SetParam(5, GSText(GSText.STR_INFO_ECON, GetColor(economyRatio), GetValueText(economyRatio)));
  430. windowText.SetParam(6, GSText(GSText.STR_INFO_ECON_PROD, (values.build * 100).tointeger()));
  431. windowText.SetParam(7, GSText(GSText.STR_INFO_ECON_PROC, (values.industry * 100).tointeger()));
  432. if (trade_cargo > 0)
  433. windowText.SetParam(8, GSText(GSText.STR_INFO_ECON_TRADE2, (values.trade * 100).tointeger(), (trade_cargo).tointeger()));
  434. else
  435. windowText.SetParam(8, GSText(GSText.STR_INFO_ECON_TRADE, (values.trade * 100).tointeger()));
  436. GSTown.SetText (t, windowText);*/
  437. }
  438. }
  439. function max (a, b)
  440. {
  441. if (a < b)
  442. return b;
  443. return a;
  444. }
  445. function min (a, b)
  446. {
  447. if (a > b)
  448. return b;
  449. return a;
  450. }
  451. function safediv (a, b)
  452. {
  453. if (b == 0)
  454. return 1;
  455. return a / b;
  456. }
  457. function clamp (a, min, max)
  458. {
  459. if (a < min)
  460. return min;
  461. else if (a > max)
  462. return max;
  463. return a;
  464. }
  465. function GetValueText (v)
  466. {
  467. if (v >= 0.99)
  468. return GSText (GSText.STR_BEST);
  469. if (v >= 0.90)
  470. return GSText (GSText.STR_HIGHER);
  471. if (v >= 0.75)
  472. return GSText (GSText.STR_HIGH);
  473. if (v >= 0.25)
  474. return GSText (GSText.STR_MIDDLE);
  475. return GSText (GSText.STR_LOW);
  476. }
  477. function GetColor (v)
  478. {
  479. if (v >= 0.75)
  480. return GSText (GSText.STR_COLOR_OK);
  481. if (v >= 0.25)
  482. return GSText (GSText.STR_COLOR_MIDDLE);
  483. return GSText (GSText.STR_COLOR_BAD);
  484. }
  485. function MonitorIndustry (cargo, industry) //terrible hack!
  486. {
  487. local r = 0;
  488. for (local i = GSCompany.COMPANY_FIRST; i <= GSCompany.COMPANY_LAST; i++)
  489. if (GSCompany.ResolveCompanyID (i) != GSCompany.COMPANY_INVALID)
  490. r += GSCargoMonitor.GetIndustryDeliveryAmount (i, cargo, industry, true);
  491. return r;
  492. }
  493. function Find (v, c)
  494. {
  495. foreach (x in v)
  496. if (x == c)
  497. return true;
  498. return false;
  499. }