gardenbase.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. class GardenBase extends ItemBase //BuildingSuper
  2. {
  3. // Paths to slot textures. Slots can have multiple states, so multiple textures must be generated
  4. static const string SLOT_TEXTURE_DIGGED_WET_LIME = "dz\\gear\\cultivation\\data\\soil_digged_wet_lime_CO.paa";
  5. static const string SLOT_TEXTURE_DIGGED_WET_PLANT = "dz\\gear\\cultivation\\data\\soil_digged_wet_plant_CO.paa";
  6. // Wet/dry material
  7. static const string SLOT_MATERIAL_WET = "dz\\gear\\cultivation\\data\\soil_cultivated_wet.rvmat";
  8. static const string SLOT_MATERIAL_DRY = "dz\\gear\\cultivation\\data\\soil_cultivated.rvmat";
  9. static const string SLOT_MATERIAL_LIMED_WET = "dz\\gear\\cultivation\\data\\soil_cultivated_limed_wet.rvmat";
  10. static const string SLOT_MATERIAL_LIMED_DRY = "dz\\gear\\cultivation\\data\\soil_cultivated_limed.rvmat";
  11. static const string SLOT_MATERIAL_COMPOST_WET = "dz\\gear\\cultivation\\data\\soil_cultivated_compost_wet.rvmat";
  12. static const string SLOT_MATERIAL_COMPOST_DRY = "dz\\gear\\cultivation\\data\\soil_cultivated_compost.rvmat";
  13. // slot names -> MUST BE LOWERCASE
  14. private static const string SLOT_SELECTION_DIGGED_PREFIX = "seedbase_";
  15. private static const string SLOT_SELECTION_COVERED_PREFIX = "slotCovered_";
  16. private static const string SLOT_MEMORY_POINT_PREFIX = "slot_";
  17. private static const string SLOT_SEEDBASE_PREFIX = "seedbase_";
  18. private static const int CHECK_RAIN_INTERVAL = 15;
  19. private static const float CREATE_PLANT_DELAY = 1000.0;
  20. private static const float RAIN_INTENSITY_THRESHOLD = 0.05;
  21. protected ref array<ref Slot> m_Slots;
  22. protected int m_SlotFertilityState = 0; //Used to store fertility state of all slots
  23. protected int m_SlotWateredState = 0; //Used to store watered state of all slots
  24. protected int m_MaxWateredStateVal = 0; //Used to store water max state of all slots
  25. protected int m_SlotState = 0; //Used to handle and sync slot states
  26. protected int m_SlotWaterBitmap0; // Slots 1–4
  27. protected int m_SlotWaterBitmap1; // Slots 5–8
  28. protected int m_SlotWaterBitmap2; // Slot 9 (and could hold up to 3 more if needed)
  29. protected int m_SlotFertilizerBitmap0; // Slots 1–4
  30. protected int m_SlotFertilizerBitmap1; // Slots 5–8
  31. protected int m_SlotFertilizerBitmap2; // Slot 9 (and could hold up to 3 more if needed)
  32. protected float m_DefaultFertility = 1;
  33. ref Timer m_CheckRainTimer;
  34. private static ref map<string,string> m_map_slots; // For the 'attachment slot -> plant slot' conversion. It is possible that this will be removed later.
  35. void GardenBase()
  36. {
  37. RegisterNetSyncVariableInt("m_SlotState");
  38. RegisterNetSyncVariableInt("m_SlotFertilityState");
  39. RegisterNetSyncVariableInt("m_SlotWateredState");
  40. RegisterNetSyncVariableInt("m_SlotWaterBitmap0");
  41. RegisterNetSyncVariableInt("m_SlotWaterBitmap1");
  42. RegisterNetSyncVariableInt("m_SlotWaterBitmap2");
  43. RegisterNetSyncVariableInt("m_SlotFertilizerBitmap0");
  44. RegisterNetSyncVariableInt("m_SlotFertilizerBitmap1");
  45. RegisterNetSyncVariableInt("m_SlotFertilizerBitmap2");
  46. m_map_slots = new map<string,string>;
  47. SetEventMask(EntityEvent.INIT); // Enable EOnInit event
  48. // Prepare m_map_slots
  49. for (int i = 1; i <= GetGardenSlotsCount(); ++i)
  50. {
  51. // m_map_slots is supposed to be: <input, output>
  52. string input = SLOT_SEEDBASE_PREFIX + i.ToString();
  53. string output = SLOT_MEMORY_POINT_PREFIX;
  54. if (i < 10)
  55. output = output + "0"; // Example: '1' changes to '01'
  56. output = output + i.ToString();
  57. m_map_slots.Set(input, output);
  58. }
  59. InitializeSlots();
  60. SetMaxWaterStateVal();
  61. if (GetGame().IsServer())
  62. {
  63. CheckRainStart();
  64. }
  65. }
  66. void ~GardenBase()
  67. {
  68. if (GetGame() && m_CheckRainTimer)
  69. {
  70. m_CheckRainTimer.Stop();
  71. m_CheckRainTimer = null;
  72. }
  73. }
  74. override void OnVariablesSynchronized()
  75. {
  76. super.OnVariablesSynchronized();
  77. UpdateSlots();
  78. }
  79. void UpdateSlots()
  80. {
  81. if (!m_Slots || m_Slots.Count() == 0)
  82. return;
  83. //! Set relevant slot values from synced bitmaps
  84. int slotsCount = GetGardenSlotsCount();
  85. for (int i = 0; i < slotsCount; i++)
  86. {
  87. Slot slot = m_Slots.Get(i);
  88. // Read relevant bits and set the synced values on the slots
  89. int fertilityState = (m_SlotFertilityState >> i) & 1;
  90. slot.SetFertilityState(fertilityState);
  91. int wateredState = (m_SlotWateredState >> i) & 1;
  92. slot.SetWateredState(wateredState);
  93. int waterQuantity = GetWaterQuantity(i);
  94. slot.SetWater(waterQuantity);
  95. int fertilizerQuantity = GetFertilizerQuantity(i);
  96. slot.SetFertilizerQuantity(fertilizerQuantity);
  97. int slotState = GetSlotState(i);
  98. slot.SetState(slotState);
  99. }
  100. }
  101. override bool HasProxyParts()
  102. {
  103. return true;
  104. }
  105. override int GetHideIconMask()
  106. {
  107. return EInventoryIconVisibility.HIDE_VICINITY;
  108. }
  109. void SetBaseFertility(float value)
  110. {
  111. m_DefaultFertility = value;
  112. }
  113. float GetBaseFertility()
  114. {
  115. return m_DefaultFertility;
  116. }
  117. override void EOnInit(IEntity other, int extra)
  118. {
  119. CheckRainTick();
  120. }
  121. void InitializeSlots()
  122. {
  123. m_Slots = new array<ref Slot>;
  124. int slots_count = GetGardenSlotsCount();
  125. for (int i = 0; i < slots_count; i++)
  126. {
  127. Slot slot = new Slot(GetBaseFertility());
  128. slot.SetSlotIndex(i);
  129. int i1 = i + 1;
  130. string name = "SeedBase_" + i1;
  131. int slotID = InventorySlots.GetSlotIdFromString(name);
  132. slot.SetSlotId(slotID);
  133. slot.SetGarden(this);
  134. slot.SetState(eGardenSlotState.STATE_DIGGED);
  135. m_Slots.Insert(slot);
  136. SetWaterQuantity(i, 0);
  137. SetFertilizerQuantity(i, 0);
  138. }
  139. UpdateSlots();
  140. }
  141. void SetMaxWaterStateVal()
  142. {
  143. int state = 0;
  144. for ( int i = 0; i < m_Slots.Count(); i++ )
  145. {
  146. state += 1 * Math.Pow( 2, i );
  147. }
  148. m_MaxWateredStateVal = state;
  149. }
  150. int GetMaxWaterStateVal()
  151. {
  152. return m_MaxWateredStateVal;
  153. }
  154. override bool OnStoreLoad(ParamsReadContext ctx, int version)
  155. {
  156. if (version <= 118)
  157. return true;
  158. if (!super.OnStoreLoad(ctx, version))
  159. return false;
  160. if (version < 102)
  161. {
  162. float some_value;
  163. ctx.Read(some_value); // compatibility check
  164. }
  165. int slots_count = GetGardenSlotsCount();
  166. for (int i = 0; i < slots_count; i++)
  167. {
  168. Slot slot = m_Slots.Get(i);
  169. if (!slot.OnStoreLoadCustom(ctx, version))
  170. return false;
  171. float waterQuantity = slot.GetWater();
  172. SetWaterQuantity(i, waterQuantity);
  173. float fertilizerQuantity = slot.GetFertilizerQuantity();
  174. SetFertilizerQuantity(i, fertilizerQuantity);
  175. }
  176. if ( version >= 119 )
  177. {
  178. if(!ctx.Read( m_SlotFertilityState ))
  179. return false;
  180. }
  181. if ( version >= 120 )
  182. {
  183. if (!ctx.Read( m_SlotWateredState ))
  184. return false;
  185. }
  186. return true;
  187. }
  188. override void EEOnAfterLoad()
  189. {
  190. super.EEOnAfterLoad();
  191. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(SyncSlots, 500, false, this);
  192. }
  193. void SyncSlots()
  194. {
  195. if (g_Game.IsServer() || !g_Game.IsMultiplayer())
  196. {
  197. UpdateSlots();
  198. int slotsCount = GetGardenSlotsCount();
  199. for (int i = 0; i < slotsCount; ++i)
  200. {
  201. UpdateSlotTexture(i);
  202. }
  203. if (g_Game.IsDedicatedServer())
  204. SetSynchDirty();
  205. }
  206. }
  207. override void OnStoreSave( ParamsWriteContext ctx )
  208. {
  209. super.OnStoreSave( ctx );
  210. int slots_count = GetGardenSlotsCount();
  211. for ( int i = 0; i < slots_count; i++ )
  212. {
  213. Slot slot = m_Slots.Get( i );
  214. slot.OnStoreSaveCustom( ctx );
  215. }
  216. ctx.Write(m_SlotFertilityState);
  217. ctx.Write( m_SlotWateredState );
  218. }
  219. void PrintSlots()
  220. {
  221. Debug.Log("PRINT ALL SLOTS FROM...");
  222. Debug.Log("" + this + " | Position: " + GetPosition());
  223. int slots = GetInventory().GetAttachmentSlotsCount();
  224. Debug.Log("Nb Slots : " + slots);
  225. for ( int i = 0; i < slots ; i++ )
  226. {
  227. Slot slot = m_Slots.Get(i);
  228. Debug.Log("i : " + i);
  229. Debug.Log("Slot : " + slot);
  230. float slot_fertility = slot.GetFertility();
  231. float slot_fertility_usage = slot.GetFertilityMax();
  232. string slot_fertility_type = slot.GetFertilityType();
  233. float slot_water = slot.GetWater();
  234. float slot_water_usage = slot.GetWaterUsage();
  235. ItemBase slot_seed = slot.GetSeed();
  236. ItemBase slot_plant = slot.GetPlant();
  237. float slot_state= slot.GetState();
  238. float slot_slot_Index = slot.GetSlotIndex();
  239. int slot_slot_ID = slot.GetSlotId();
  240. int slot_wateredState = slot.GetWateredState();
  241. int slot_FertilityState = slot.GetFertilityState();
  242. Debug.Log("Fertility : " + slot_fertility);
  243. Debug.Log("Fertility Usage : " + slot_fertility_usage);
  244. Debug.Log("Fertility Type : " + slot_fertility_type);
  245. Debug.Log("Fertility State : " + slot_FertilityState);
  246. Debug.Log("Water : " + slot_water);
  247. Debug.Log("Water Usage : " + slot_water_usage);
  248. Debug.Log("Watered State : " + typename.EnumToString(eWateredState, slot_wateredState));
  249. Debug.Log("Seed : " + slot_seed);
  250. Debug.Log("Plant : " + slot_plant);
  251. if (slot_plant && PlantBase.Cast(slot_plant))
  252. PlantBase.Cast(slot_plant).PrintValues();
  253. Debug.Log("State : " + slot_state);
  254. Debug.Log("Slot Index : " + slot_slot_Index);
  255. Debug.Log("Slot ID : " + slot_slot_ID);
  256. Debug.Log("///////////////////////////");
  257. }
  258. Debug.Log("END OF ALL SLOTS FOR...");
  259. Debug.Log("" + this);
  260. }
  261. override bool CanPutInCargo( EntityAI parent )
  262. {
  263. if ( !super.CanPutInCargo(parent) ) {return false;}
  264. return false;
  265. }
  266. override bool CanPutIntoHands( EntityAI parent )
  267. {
  268. if ( !super.CanPutIntoHands( parent ) )
  269. {
  270. return false;
  271. }
  272. return false;
  273. }
  274. override bool CanRemoveFromHands( EntityAI parent )
  275. {
  276. return false;
  277. }
  278. int GetGardenSlotsCount()
  279. {
  280. return 0;
  281. }
  282. bool CanPlantSeed(string selection_component)
  283. {
  284. Slot slot = GetSlotBySelection(selection_component);
  285. if (slot != NULL && slot.GetState() == eGardenSlotState.STATE_DIGGED)
  286. {
  287. return true;
  288. }
  289. else
  290. {
  291. return false;
  292. }
  293. }
  294. // Converts attachment slot name into plant slot name. Example: 'seedbase_1' -> 'component02'
  295. string ConvertAttSlotToPlantSlot(string attach_slot)
  296. {
  297. // Give result
  298. if ( m_map_slots.Contains(attach_slot) )
  299. {
  300. string return_value = m_map_slots.Get(attach_slot);
  301. return return_value;
  302. }
  303. return "";
  304. }
  305. override void EEItemAttached(EntityAI item, string slot_name)
  306. {
  307. super.EEItemAttached(item, slot_name);
  308. string path = string.Format("CfgVehicles %1 Horticulture PlantType", item.GetType());
  309. bool IsItemSeed = GetGame().ConfigIsExisting(path); // Is this item a seed?
  310. if (IsItemSeed)
  311. {
  312. string converted_slot_name;
  313. vector pos = GetPosition();
  314. int index = GetSlotIndexByAttachmentSlot(slot_name);
  315. if (index < 10)
  316. {
  317. converted_slot_name = SLOT_MEMORY_POINT_PREFIX + "0" + index.ToString();
  318. }
  319. else
  320. {
  321. converted_slot_name = SLOT_MEMORY_POINT_PREFIX + index.ToString();
  322. }
  323. if (g_Game.IsServer() || !g_Game.IsMultiplayer())
  324. PlantSeed(ItemBase.Cast(item), converted_slot_name);
  325. }
  326. else if (g_Game.IsClient())
  327. {
  328. Slot slot = GetSlotByIndex(GetSlotIndexByAttachmentSlot(slot_name) - 1);
  329. if (slot)
  330. {
  331. slot.SetPlant(PlantBase.Cast(item));
  332. slot.SetState(eGardenSlotState.STATE_PLANTED);
  333. }
  334. }
  335. }
  336. override void EEItemDetached(EntityAI item, string slot_name)
  337. {
  338. super.EEItemDetached(item, slot_name);
  339. slot_name.ToLower();
  340. string path = string.Format("CfgVehicles %1 Horticulture PlantType", item.GetType());
  341. bool IsItemSeed = GetGame().ConfigIsExisting(path); // Is this item a seed?
  342. string converted_slot_name = ConvertAttSlotToPlantSlot(slot_name);
  343. Slot slot = GetSlotBySelection(converted_slot_name);
  344. if (slot)
  345. {
  346. if (IsItemSeed)
  347. {
  348. slot.SetSeed(NULL);
  349. }
  350. slot.SetState(eGardenSlotState.STATE_DIGGED);
  351. }
  352. }
  353. // Plants the seed into slot (selection_component)
  354. void PlantSeed( ItemBase seed, string selection_component )
  355. {
  356. int slot_index = GetSlotIndexBySelection( selection_component );
  357. if ( slot_index != -1 )
  358. {
  359. PluginHorticulture module_horticulture = PluginHorticulture.Cast( GetPlugin( PluginHorticulture ) );
  360. string plant_type = module_horticulture.GetPlantType( seed );
  361. Slot slot = m_Slots.Get( slot_index );
  362. slot.SetState(eGardenSlotState.STATE_PLANTED);
  363. slot.m_PlantType = plant_type;
  364. slot.SetSeed(seed);
  365. if ( !slot.NeedsWater() || slot.GetWateredState() == eWateredState.WET)
  366. {
  367. //! Adjust slot water
  368. if (slot.GetWateredState() == eWateredState.WET && slot.NeedsWater())
  369. {
  370. int waterMax = slot.GetWaterMax();
  371. slot.SetWater(waterMax);
  372. }
  373. seed.LockToParent();
  374. //Take some small amount of time before making a plant out of seeds
  375. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(CreatePlant, CREATE_PLANT_DELAY, false, slot);
  376. }
  377. }
  378. }
  379. // Creates a plant
  380. void CreatePlant(Slot slot)
  381. {
  382. if (g_Game.IsServer() || !g_Game.IsMultiplayer())
  383. {
  384. ItemBase seed = slot.GetSeed();
  385. if (seed)
  386. {
  387. seed.UnlockFromParent();
  388. GetGame().ObjectDelete(seed);
  389. PlantBase plant = PlantBase.Cast( GetInventory().CreateAttachmentEx(slot.m_PlantType, slot.GetSlotId()));
  390. int slot_index = slot.GetSlotIndex();
  391. slot.SetPlant(plant);
  392. slot.SetState(eGardenSlotState.STATE_PLANTED);
  393. plant.Init(this, slot.GetFertility(), slot.m_HarvestingEfficiency, slot.GetWater());
  394. plant.LockToParent();
  395. }
  396. }
  397. }
  398. void SetSlotState(int slotIndex, int value)
  399. {
  400. // value should be 1 or 2
  401. int shift = slotIndex * 2;
  402. int mask = 3 << shift;
  403. int currentState = (m_SlotState & mask) >> shift;
  404. // Clear out the bits for this slot
  405. m_SlotState &= ~mask;
  406. // Set the new value
  407. m_SlotState |= (value << shift);
  408. if (g_Game.IsServer() && currentState != value)
  409. SetSynchDirty();
  410. }
  411. int GetSlotState(int slotIndex)
  412. {
  413. int shift = slotIndex * 2;
  414. int mask = 3 << shift;
  415. int value = (m_SlotState & mask) >> shift;
  416. return value; // Will be 0, 1, or 2
  417. }
  418. void SlotWaterStateUpdate( Slot slot )
  419. {
  420. int idx = slot.GetSlotIndex();
  421. int mask = 1 << idx;
  422. int currentState = (m_SlotWateredState >> idx) & 1;
  423. int newState = slot.GetWateredState();
  424. // Clear the relevant bit first
  425. m_SlotWateredState &= ~mask;
  426. // Set the bit state (1 for WET, 0 for DRY)
  427. m_SlotWateredState |= (newState << idx);
  428. if ((g_Game.IsServer() || !g_Game.IsMultiplayer()) && currentState != newState)
  429. {
  430. UpdateSlotTexture(slot.GetSlotIndex());
  431. if (g_Game.IsServer())
  432. SetSynchDirty();
  433. }
  434. }
  435. void SlotFertilityStateUpdate(Slot slot)
  436. {
  437. int idx = slot.GetSlotIndex();
  438. int mask = 1 << idx;
  439. int currentState = (m_SlotFertilityState >> idx) & 1;
  440. int newState = slot.GetFertilityState();
  441. // Clear the relevant bit first
  442. m_SlotFertilityState &= ~mask;
  443. // Set the bit state (1 for FERTILIZED, 0 for NONE)
  444. m_SlotFertilityState |= (newState << idx);
  445. if ((g_Game.IsServer() || !g_Game.IsMultiplayer()) && currentState != newState)
  446. {
  447. UpdateSlotTexture(slot.GetSlotIndex());
  448. if (g_Game.IsServer())
  449. SetSynchDirty();
  450. }
  451. }
  452. //! This should be only called on server as the selections are synced to clients in C++
  453. void UpdateSlotTexture( int slot_index )
  454. {
  455. if (!m_Slots || m_Slots.Count() - 1 < slot_index)
  456. return;
  457. Slot slot = m_Slots.Get( slot_index );
  458. // Show / Hide selections according to DIGGED or COVERED states.
  459. if ( slot.IsDigged() || slot.IsPlanted() )
  460. {
  461. string str_hide = SLOT_SELECTION_COVERED_PREFIX + (slot_index + 1).ToStringLen(2);
  462. string str_show = SLOT_SELECTION_DIGGED_PREFIX + (slot_index + 1).ToStringLen(1);
  463. HideSelection( str_hide );
  464. ShowSelection( str_show );
  465. }
  466. if ( slot.GetFertilityState() == eFertlityState.FERTILIZED && slot.GetFertilityType() != "" )
  467. {
  468. SetSlotTextureFertilized( slot_index, slot.GetFertilityType() );
  469. }
  470. else
  471. {
  472. SetSlotTextureDigged( slot_index );
  473. }
  474. }
  475. void SetSlotTextureDigged( int slot_index )
  476. {
  477. TStringArray textures = GetHiddenSelectionsTextures();
  478. string str_digged = SLOT_SELECTION_DIGGED_PREFIX + (slot_index + 1).ToStringLen(1);
  479. ShowSelection( str_digged );
  480. string texture = textures.Get(0);
  481. SetObjectTexture( slot_index, texture );
  482. Slot slot = m_Slots.Get( slot_index );
  483. if ( slot.GetWateredState() == 0 )
  484. {
  485. // Set dry material
  486. SetObjectMaterial( slot_index, SLOT_MATERIAL_DRY );
  487. }
  488. else
  489. {
  490. // Set wet material
  491. SetObjectMaterial( slot_index, SLOT_MATERIAL_WET );
  492. }
  493. }
  494. void SetSlotTextureFertilized( int slot_index, string item_type )
  495. {
  496. TStringArray textures = GetHiddenSelectionsTextures();
  497. int tex_id = GetGame().ConfigGetInt( string.Format("cfgVehicles %1 Horticulture TexId", item_type) );
  498. string str_show = SLOT_SELECTION_DIGGED_PREFIX + (slot_index + 1).ToStringLen(2);
  499. ShowSelection( str_show );
  500. SetObjectTexture( slot_index, textures.Get(tex_id) );
  501. Slot slot = m_Slots.Get( slot_index );
  502. int slot_index_offset = 0;
  503. // Set material according to dry / wet states
  504. if ( slot.GetWateredState() == 0 )
  505. {
  506. // Set dry material for garden lime
  507. if ( slot.GetFertilityType() == "GardenLime" )
  508. {
  509. SetObjectMaterial( slot_index + slot_index_offset, SLOT_MATERIAL_LIMED_DRY );
  510. }
  511. else if ( slot.GetFertilityType() == "PlantMaterial" )
  512. {
  513. SetObjectMaterial( slot_index + slot_index_offset, SLOT_MATERIAL_COMPOST_DRY );
  514. }
  515. }
  516. else
  517. {
  518. // Set dry material for compost
  519. if ( slot.GetFertilityType() == "GardenLime" )
  520. {
  521. SetObjectMaterial( slot_index + slot_index_offset, SLOT_MATERIAL_LIMED_WET );
  522. }
  523. else if ( slot.GetFertilityType() == "PlantMaterial" )
  524. {
  525. SetObjectMaterial( slot_index + slot_index_offset, SLOT_MATERIAL_COMPOST_WET );
  526. }
  527. }
  528. }
  529. void RemoveSlot(int index)
  530. {
  531. if (m_Slots)
  532. {
  533. Slot slot = m_Slots.Get(index);
  534. PlantBase plant = slot.GetPlant();
  535. if (plant && !plant.IsPendingDeletion())
  536. {
  537. plant.UnlockFromParent();
  538. plant.m_MarkForDeletion = true;
  539. plant.Delete();
  540. }
  541. slot.Init(GetBaseFertility());
  542. int idx = slot.GetSlotIndex();
  543. int mask = 1 << idx;
  544. // Clear the relevant bits from bitmaps
  545. m_SlotFertilityState &= ~mask;
  546. m_SlotWateredState &= ~mask;
  547. // Reset states
  548. m_SlotFertilityState |= (slot.GetFertilityState() << idx);
  549. m_SlotWateredState |= (slot.GetWateredState() << idx);
  550. // Reset stol quantities
  551. SetWaterQuantity(index, 0);
  552. SetFertilizerQuantity(index, 0);
  553. UpdateSlots();
  554. HideSelection(SLOT_SELECTION_COVERED_PREFIX + (index + 1).ToStringLen(2));
  555. UpdateSlotTexture(idx);
  556. SetSynchDirty();
  557. }
  558. }
  559. void RemoveSlotPlant( Object plant )
  560. {
  561. int index = GetSlotIndexByPlant( plant );
  562. if ( index >= 0 )
  563. {
  564. RemoveSlot( index );
  565. }
  566. }
  567. Slot GetSlotBySelection( string selection_component )
  568. {
  569. int slot_index = GetSlotIndexBySelection( selection_component );
  570. if ( slot_index > -1 )
  571. {
  572. return m_Slots.Get( slot_index );
  573. }
  574. else
  575. {
  576. return NULL;
  577. }
  578. }
  579. // Returns slot array index by selection, starting from 0 as the first one.
  580. int GetSlotIndexBySelection( string selection_component )
  581. {
  582. int slot_index = -1;
  583. if ( m_Slots != NULL )
  584. {
  585. string selection_component_lower = selection_component;
  586. selection_component_lower.ToLower();
  587. int start = selection_component_lower.IndexOf( SLOT_MEMORY_POINT_PREFIX );
  588. if ( start > -1 )
  589. {
  590. start += SLOT_MEMORY_POINT_PREFIX.Length();
  591. int end = start + 2;
  592. int length = selection_component.Length();
  593. if ( length >= end )
  594. {
  595. int length_add = length - end; // Hack-fix for inconsistent component names in p3d
  596. int length_from_end = 2 + length_add;
  597. string num_str = selection_component.Substring( start, length_from_end );
  598. slot_index = num_str.ToInt();
  599. slot_index = slot_index - 1;
  600. }
  601. }
  602. }
  603. return slot_index;
  604. }
  605. int GetSlotIndexByAttachmentSlot( string att_slot )
  606. {
  607. int slot_index = -1;
  608. int start = "SeedBase_".Length();
  609. int end = att_slot.Length();//start + 2;
  610. int len = end - start;
  611. string num_str = att_slot.Substring( start, len );
  612. slot_index = num_str.ToInt();
  613. return slot_index;
  614. }
  615. int GetSlotIndexByPlant( Object plant )
  616. {
  617. if ( m_Slots != NULL )
  618. {
  619. for ( int i = 0; i < m_Slots.Count(); i++ )
  620. {
  621. PlantBase found_plant = m_Slots.Get(i).GetPlant();
  622. if ( found_plant == plant )
  623. {
  624. return i;
  625. }
  626. }
  627. }
  628. return -1;
  629. }
  630. int GetNearestSlotIDByState(vector position, int slot_state)
  631. {
  632. float nearest_distance = 1000.0;
  633. int nearest_slot_index = -1;
  634. int slots_count = GetGardenSlotsCount();
  635. for (int i = 0; i < slots_count; i++)
  636. {
  637. Slot slot = m_Slots.Get(i); // Move this line by a scope higher in this function after debugging
  638. vector slot_pos = GetSlotPosition(i);
  639. float current_distance = vector.Distance(position, slot_pos);
  640. if (current_distance < nearest_distance)
  641. {
  642. if (slot != NULL && slot.GetState() == slot_state)
  643. {
  644. nearest_distance = current_distance;
  645. nearest_slot_index = i;
  646. }
  647. }
  648. }
  649. return nearest_slot_index;
  650. }
  651. vector GetSlotPosition( int index )
  652. {
  653. string memory_point = SLOT_MEMORY_POINT_PREFIX + (index + 1).ToStringLen(2);
  654. vector pos = this.GetSelectionPositionMS( memory_point );
  655. return this.ModelToWorld( pos );
  656. }
  657. void CheckRainStart()
  658. {
  659. if ( !m_CheckRainTimer )
  660. m_CheckRainTimer = new Timer( CALL_CATEGORY_SYSTEM );
  661. m_CheckRainTimer.Run( CHECK_RAIN_INTERVAL, this, "CheckRainTick", NULL, true );
  662. }
  663. void CheckRainTick()
  664. {
  665. float rainIntensity = GetGame().GetWeather().GetRain().GetActual();
  666. float wetness = rainIntensity * 20 * CHECK_RAIN_INTERVAL;
  667. if (rainIntensity > 1 || rainIntensity < 0)
  668. wetness = 0; // hackfix for weird values returned by weather system
  669. if (wetness == 0)
  670. wetness = -0.1 * CHECK_RAIN_INTERVAL;
  671. // At the moment we dont want to remove water from the slot when it is not raining so we check and manipulate water quantity only when we add to it
  672. if (rainIntensity > RAIN_INTENSITY_THRESHOLD)
  673. {
  674. if (wetness != 0) // only change slot water quantity when wetness value can actually add/deduct something
  675. {
  676. int slotsCount = GetGardenSlotsCount();
  677. for (int i = 0; i < slotsCount; i++)
  678. {
  679. if (m_Slots)
  680. {
  681. Slot slot = m_Slots.Get(i);
  682. if (slot)
  683. {
  684. slot.GiveWater(wetness * Math.RandomFloat01());
  685. }
  686. }
  687. }
  688. }
  689. }
  690. }
  691. array<ref Slot> GetSlots()
  692. {
  693. return m_Slots;
  694. }
  695. Slot GetSlotByIndex( int index )
  696. {
  697. return m_Slots.Get(index);
  698. }
  699. override void SetActions()
  700. {
  701. AddAction(ActionHarvestCrops);
  702. AddAction(ActionRemovePlant);
  703. AddAction(ActionRemoveSeed);
  704. }
  705. void SetFertilizerBitmapByIndex(int index, int value)
  706. {
  707. switch (index)
  708. {
  709. case 0:
  710. m_SlotFertilizerBitmap0 = value;
  711. break;
  712. case 1:
  713. m_SlotFertilizerBitmap1 = value;
  714. break;
  715. case 2:
  716. m_SlotFertilizerBitmap2 = value;
  717. break;
  718. }
  719. }
  720. int GetFertilizerBitmapByIndex(int index)
  721. {
  722. switch (index)
  723. {
  724. case 0:
  725. return m_SlotFertilizerBitmap0;
  726. case 1:
  727. return m_SlotFertilizerBitmap1;
  728. case 2:
  729. return m_SlotFertilizerBitmap2;
  730. }
  731. return 0;
  732. }
  733. void SetWaterBitmapByIndex(int index, int value)
  734. {
  735. switch (index)
  736. {
  737. case 0:
  738. m_SlotWaterBitmap0 = value;
  739. break;
  740. case 1:
  741. m_SlotWaterBitmap1 = value;
  742. break;
  743. case 2:
  744. m_SlotWaterBitmap2 = value;
  745. break;
  746. }
  747. }
  748. int GetWaterBitmapByIndex(int index)
  749. {
  750. switch (index)
  751. {
  752. case 0:
  753. return m_SlotWaterBitmap0;
  754. case 1:
  755. return m_SlotWaterBitmap1;
  756. case 2:
  757. return m_SlotWaterBitmap2;
  758. }
  759. return 0;
  760. }
  761. void SetWaterQuantity(int slotIndex, int value)
  762. {
  763. int bitsPerSlot = 8;
  764. int slotsPerInt = 32 / bitsPerSlot;
  765. int groupIndex = slotIndex / slotsPerInt;
  766. int bitOffset = (slotIndex % slotsPerInt) * bitsPerSlot;
  767. int mask = 255 << bitOffset;
  768. value = Math.Clamp(value, 0, 200);
  769. int temp = GetWaterBitmapByIndex(groupIndex);
  770. temp &= ~mask;
  771. temp |= (value << bitOffset);
  772. SetWaterBitmapByIndex(groupIndex, temp);
  773. }
  774. int GetWaterQuantity(int slotIndex)
  775. {
  776. int bitsPerSlot = 8;
  777. int slotsPerInt = 32 / bitsPerSlot;
  778. int groupIndex = slotIndex / slotsPerInt;
  779. int bitOffset = (slotIndex % slotsPerInt) * bitsPerSlot;
  780. int value = GetWaterBitmapByIndex(groupIndex);
  781. return (value >> bitOffset) & 255;
  782. }
  783. void SetFertilizerQuantity(int slotIndex, int value)
  784. {
  785. int bitsPerSlot = 8;
  786. int slotsPerInt = 32 / bitsPerSlot;
  787. int groupIndex = slotIndex / slotsPerInt;
  788. int bitOffset = (slotIndex % slotsPerInt) * bitsPerSlot;
  789. int mask = 255 << bitOffset;
  790. value = Math.Clamp(value, 0, 200);
  791. int temp = GetFertilizerBitmapByIndex(groupIndex);
  792. temp &= ~mask;
  793. temp |= (value << bitOffset);
  794. SetFertilizerBitmapByIndex(groupIndex, temp);
  795. }
  796. int GetFertilizerQuantity(int slotIndex)
  797. {
  798. int bitsPerSlot = 8;
  799. int slotsPerInt = 32 / bitsPerSlot;
  800. int groupIndex = slotIndex / slotsPerInt;
  801. int bitOffset = (slotIndex % slotsPerInt) * bitsPerSlot;
  802. int value = GetFertilizerBitmapByIndex(groupIndex);
  803. return (value >> bitOffset) & 255;
  804. }
  805. //! DEPRECATED
  806. [Obsolete("No replacement")]
  807. bool IsCorrectFertilizer( ItemBase item, string selection_component )
  808. {
  809. Slot slot = GetSlotBySelection( selection_component );
  810. if ( slot != NULL )
  811. {
  812. string item_type = item.GetType();
  813. if ( slot.GetFertilityType() == "" || slot.GetFertilityType() == item_type )
  814. {
  815. return true;
  816. }
  817. }
  818. return false;
  819. }
  820. [Obsolete("No replacement")]
  821. void UpdateTexturesOnAllSlots()
  822. {
  823. int slots_count = GetGardenSlotsCount();
  824. for (int i = 0; i < slots_count; ++i)
  825. {
  826. UpdateSlotTexture(i);
  827. }
  828. }
  829. [Obsolete("No replacement")]
  830. bool NeedsFertilization(string selection_component)
  831. {
  832. Slot slot = GetSlotBySelection(selection_component);
  833. if (slot)
  834. {
  835. if (slot.GetFertilityState() == eFertlityState.NONE)
  836. {
  837. return true;
  838. }
  839. }
  840. return false;
  841. }
  842. [Obsolete("CAContinuousFertilizeGardenSlot::FertilizeSlot is used now instead.")]
  843. void Fertilize( PlayerBase player, ItemBase item, float consumed_quantity, string selection_component )
  844. {
  845. Slot slot = GetSlotBySelection( selection_component );
  846. if ( slot != NULL )
  847. {
  848. string item_type = item.GetType();
  849. if ( slot.GetFertilityType() == "" || slot.GetFertilityType() == item_type )
  850. {
  851. slot.SetFertilityType(item_type);
  852. float add_energy_to_slot = GetGame().ConfigGetFloat( string.Format("cfgVehicles %1 Horticulture AddEnergyToSlot", item_type) );
  853. slot.m_FertilizerUsage = GetGame().ConfigGetFloat( string.Format("cfgVehicles %1 Horticulture ConsumedQuantity", item_type) );
  854. float coef = Math.Clamp( consumed_quantity / slot.m_FertilizerUsage, 0.0, 1.0 );
  855. add_energy_to_slot = coef * add_energy_to_slot;
  856. slot.m_FertilizerQuantity += consumed_quantity;
  857. slot.m_Fertility += add_energy_to_slot;
  858. if ( slot.GetFertilizerQuantity() >= slot.GetFertilizerQuantityMax() )
  859. {
  860. int slot_index = slot.GetSlotIndex();
  861. if (slot_index > -1)
  862. {
  863. UpdateSlotTexture( slot_index );
  864. slot.SetFertilityState(eFertlityState.FERTILIZED);
  865. // Set relevant bit
  866. m_SlotFertilityState |= slot.GetFertilityState() << slot.GetSlotIndex();
  867. }
  868. }
  869. }
  870. else
  871. {
  872. slot.SetFertilizerQuantity(0);
  873. slot.SetFertilityType("");
  874. slot.SetFertilityState(eFertlityState.NONE);
  875. }
  876. SetSynchDirty();
  877. }
  878. }
  879. [Obsolete("No replacement")]
  880. void WaterAllSlots()
  881. {
  882. for (int i = 0; i < m_Slots.Count(); i++)
  883. {
  884. Slot slot = m_Slots[i];
  885. if (!slot)
  886. continue;
  887. slot.SetWateredState(eWateredState.WET);
  888. UpdateSlotTexture(slot.GetSlotIndex());
  889. m_SlotWateredState |= eWateredState.WET << slot.GetSlotIndex();
  890. }
  891. }
  892. }