plantbase.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. enum EPlantState
  2. {
  3. PAUSED = 0,
  4. GROWING,
  5. MATURE,
  6. SPOILED,
  7. DRY
  8. }
  9. class PlantBase extends ItemBase
  10. {
  11. private float m_SprayUsage; // How much spray is needed to stop infestation of plant
  12. private float m_InfestationChance;
  13. private int m_GrowthStagesCount;
  14. private int m_CropsCount;
  15. private bool m_HasCrops;
  16. private string m_CropsType;
  17. private float m_PlantMaterialMultiplier;
  18. private int m_PlantStateIndex;
  19. private float m_CurrentPlantMaterialQuantity;
  20. protected EPlantState m_PlantState;
  21. private bool m_IsInfested;
  22. private float m_SprayQuantity;
  23. bool m_MarkForDeletion = false;
  24. int m_DeleteDryPlantTime; // For how long in seconds can an unwatered plant exist before it disappears
  25. int m_SpoiledRemoveTime; // For how long in seconds a spoiled plant will exist
  26. int m_FullMaturityTime; // How much time needs plant to be full grown in seconds
  27. int m_SpoilAfterFullMaturityTime; // How long in seconds it takes for plant to be spoiled after it is full grown
  28. float m_StateChangeTime; // For how long in seconds will plant stay in one state before its going to next state
  29. protected ref Timer m_TimeTicker;
  30. protected float m_TimeTracker;
  31. private GardenBase m_GardenBase = NULL;
  32. private ref Slot m_Slot = NULL;
  33. private PluginHorticulture m_ModuleHorticulture;
  34. private const float SPOIL_AFTER_MATURITY_TIME = 14400.0; //The time it takes for a fully grown plant to spoil, in seconds (4 hours)
  35. private const int TICK_FREQUENCY = 1; // seconds
  36. // debug
  37. static int m_DebugFullMaturityTime;
  38. static int m_DebugSpoilTime;
  39. static int m_DebugSpoilRemoveTime;
  40. static int m_DebugDeleteDryTime;
  41. static float m_DebugTickSpeedMultiplier = 1;
  42. void PlantBase()
  43. {
  44. m_ModuleHorticulture = PluginHorticulture.Cast( GetPlugin( PluginHorticulture ) );
  45. m_SprayUsage = 5;
  46. m_DeleteDryPlantTime = (60 * 10) + Math.RandomInt(0, 60 * 2);
  47. m_SpoiledRemoveTime = (60 * 20) + Math.RandomInt(0, 60 * 5);
  48. string plant_type = this.GetType();
  49. m_GrowthStagesCount = GetGame().ConfigGetInt( "cfgVehicles " + plant_type + " Horticulture GrowthStagesCount" );
  50. m_CropsCount = GetGame().ConfigGetInt( "cfgVehicles " + plant_type + " Horticulture CropsCount" );
  51. GetGame().ConfigGetText( "cfgVehicles " + plant_type + " Horticulture CropsType", m_CropsType );
  52. if (m_GrowthStagesCount == 0)
  53. m_GrowthStagesCount = 1;
  54. m_InfestationChance = 0.2 / m_GrowthStagesCount; //Must be between 0 and 1
  55. m_PlantStateIndex = -1;
  56. m_CurrentPlantMaterialQuantity = 0;
  57. m_IsInfested = false;
  58. m_SprayQuantity = 0.0;
  59. m_HasCrops = true;
  60. SetTakeable( false );
  61. RegisterNetSyncVariableBool("m_HasCrops");
  62. RegisterNetSyncVariableInt("m_PlantState");
  63. RegisterNetSyncVariableInt("m_PlantStateIndex");
  64. if (GetGame().IsServer())
  65. {
  66. m_TimeTicker = new Timer( CALL_CATEGORY_SYSTEM );
  67. m_TimeTicker.Run(TICK_FREQUENCY, this, "Tick", NULL, true);
  68. }
  69. }
  70. void ~PlantBase()
  71. {
  72. if (m_TimeTicker)
  73. m_TimeTicker.Stop();
  74. if (!m_MarkForDeletion && !IsPendingDeletion())
  75. {
  76. DestroyPlant();
  77. }
  78. }
  79. void Init( GardenBase garden_base, float fertility, float harvesting_efficiency, float water )
  80. {
  81. m_GardenBase = garden_base;
  82. if (m_DebugFullMaturityTime != 0)
  83. m_FullMaturityTime = m_DebugFullMaturityTime;
  84. else
  85. m_FullMaturityTime += Math.RandomInt(-60,180);
  86. if (m_DebugSpoilTime != 0)
  87. m_SpoilAfterFullMaturityTime = m_DebugSpoilTime;
  88. else
  89. m_SpoilAfterFullMaturityTime = SPOIL_AFTER_MATURITY_TIME;
  90. if (m_DebugSpoilRemoveTime != 0)
  91. m_SpoiledRemoveTime = m_DebugSpoilRemoveTime;
  92. if (m_DebugDeleteDryTime != 0)
  93. m_DeleteDryPlantTime = m_DebugDeleteDryTime;
  94. m_StateChangeTime = m_FullMaturityTime / (m_GrowthStagesCount - 2);
  95. float count = m_CropsCount * fertility * harvesting_efficiency;
  96. m_CropsCount = (int)Math.Ceil( count );
  97. m_PlantMaterialMultiplier = 0.1 * harvesting_efficiency;
  98. float rain_intensity = GetGame().GetWeather().GetRain().GetActual();
  99. if (m_PlantState < EPlantState.MATURE && !NeedsWater())
  100. {
  101. SetPlantState(EPlantState.GROWING);
  102. GrowthTimerTick(); // first tick happens straight away
  103. }
  104. if (rain_intensity <= 0.0)
  105. {
  106. if (NeedsWater())
  107. SetPlantState(EPlantState.PAUSED);
  108. }
  109. }
  110. void Tick()
  111. {
  112. m_TimeTracker += m_TimeTicker.GetDuration() * m_DebugTickSpeedMultiplier;
  113. switch (m_PlantState)
  114. {
  115. case (EPlantState.GROWING):
  116. if (m_TimeTracker >= m_StateChangeTime)
  117. GrowthTimerTick();
  118. break;
  119. case (EPlantState.MATURE):
  120. if (m_TimeTracker >= m_SpoilAfterFullMaturityTime)
  121. SetSpoiled();
  122. break;
  123. case (EPlantState.SPOILED):
  124. if (m_TimeTracker >= m_SpoiledRemoveTime)
  125. RemoveSlot();
  126. break;
  127. case (EPlantState.DRY):
  128. if (m_TimeTracker >= m_DeleteDryPlantTime)
  129. RemoveSlot();
  130. break;
  131. }
  132. }
  133. override bool OnStoreLoad( ParamsReadContext ctx, int version )
  134. {
  135. if ( !super.OnStoreLoad( ctx, version ) )
  136. return false;
  137. GardenBase garden = GardenBase.Cast( GetHierarchyParent() );
  138. int slot_index = -1;
  139. if (!ctx.Read(slot_index))
  140. return false;
  141. Slot slot = garden.GetSlotByIndex(slot_index);
  142. SetSlot(slot);
  143. if ( !OnStoreLoadCustom( ctx, version ) )
  144. return false;
  145. return true;
  146. }
  147. override void OnStoreSave( ParamsWriteContext ctx )
  148. {
  149. super.OnStoreSave( ctx );
  150. Slot slot = GetSlot();
  151. if (slot)
  152. {
  153. int slot_index = slot.GetSlotIndex();
  154. slot.SetPlant(this); // hack
  155. ctx.Write( slot_index );
  156. OnStoreSaveCustom( ctx );
  157. }
  158. else
  159. {
  160. ErrorEx("[Warning] A plant existed without a garden. Therefore it was deleted from the world to prevent issues! Position: " + GetPosition(), ErrorExSeverity.INFO);
  161. GetGame().ObjectDelete(this); // Plants that exist without a garden must be deleted. Otherwise they might cause problems.
  162. }
  163. }
  164. string GetCropsType()
  165. {
  166. return m_CropsType;
  167. }
  168. bool OnStoreLoadCustom(ParamsReadContext ctx, int version)
  169. {
  170. if (!ctx.Read(m_SprayUsage))
  171. return false;
  172. if (!ctx.Read(m_DeleteDryPlantTime))
  173. return false;
  174. if (!ctx.Read(m_SpoiledRemoveTime))
  175. return false;
  176. if (!ctx.Read(m_FullMaturityTime))
  177. return false;
  178. if (!ctx.Read(m_SpoilAfterFullMaturityTime))
  179. return false;
  180. if (!ctx.Read(m_StateChangeTime))
  181. return false;
  182. if (!ctx.Read(m_InfestationChance))
  183. return false;
  184. if (!ctx.Read(m_GrowthStagesCount))
  185. return false;
  186. if (!ctx.Read(m_CropsCount))
  187. return false;
  188. if (!ctx.Read(m_CropsType))
  189. return false;
  190. if (!ctx.Read(m_PlantMaterialMultiplier))
  191. return false;
  192. if (!ctx.Read(m_PlantState))
  193. return false;
  194. if (!ctx.Read(m_PlantStateIndex))
  195. return false;
  196. if (!ctx.Read(m_CurrentPlantMaterialQuantity))
  197. return false;
  198. if (!ctx.Read(m_IsInfested))
  199. return false;
  200. if (!ctx.Read(m_SprayQuantity))
  201. return false;
  202. bool loadBool; // deprec
  203. if (!ctx.Read(loadBool))
  204. return false;
  205. float loadFloat = 0.0;
  206. if (!ctx.Read(loadFloat)) // deprec
  207. return false;
  208. loadFloat = 0.0;
  209. if (ctx.Read(loadFloat))
  210. {
  211. if (loadFloat > 0.0)
  212. m_TimeTracker = loadFloat; // spoil
  213. }
  214. else
  215. {
  216. return false;
  217. }
  218. loadFloat = 0.0;
  219. if (ctx.Read(loadFloat))
  220. {
  221. if (loadFloat > 0.0)
  222. m_TimeTracker = loadFloat; // spoil delete
  223. }
  224. else
  225. {
  226. return false;
  227. }
  228. loadFloat = 0.0;
  229. if (ctx.Read(loadFloat))
  230. {
  231. if ( loadFloat > 0.0 )
  232. m_TimeTracker = loadFloat; // dry delete
  233. }
  234. else
  235. {
  236. return false;
  237. }
  238. if (m_StateChangeTime != (m_FullMaturityTime / (m_GrowthStagesCount - 2)))
  239. {
  240. m_StateChangeTime = m_FullMaturityTime / (m_GrowthStagesCount - 2);
  241. ErrorEx("[Warning] A plant loaded from storage had a corrupted state change time. Time was now adjusted! Position: " + GetPosition(), ErrorExSeverity.INFO);
  242. }
  243. if (version >= 142)
  244. {
  245. if (!ctx.Read(m_HasCrops))
  246. return false;
  247. }
  248. UpdatePlant();
  249. return true;
  250. }
  251. void OnStoreSaveCustom( ParamsWriteContext ctx )
  252. {
  253. ctx.Write(m_SprayUsage);
  254. ctx.Write(m_DeleteDryPlantTime);
  255. ctx.Write(m_SpoiledRemoveTime);
  256. ctx.Write(m_FullMaturityTime);
  257. ctx.Write(m_SpoilAfterFullMaturityTime);
  258. ctx.Write(m_StateChangeTime);
  259. ctx.Write(m_InfestationChance);
  260. ctx.Write(m_GrowthStagesCount);
  261. ctx.Write(m_CropsCount);
  262. ctx.Write(m_CropsType);
  263. ctx.Write(m_PlantMaterialMultiplier);
  264. ctx.Write(m_PlantState);
  265. ctx.Write(m_PlantStateIndex);
  266. ctx.Write(m_CurrentPlantMaterialQuantity);
  267. ctx.Write(m_IsInfested);
  268. ctx.Write(m_SprayQuantity);
  269. bool saveBool = false; // deprec
  270. ctx.Write( saveBool );
  271. float saveFloat = 0.0; // deprec
  272. ctx.Write( saveFloat );
  273. saveFloat = 0.0;
  274. if (m_PlantState == EPlantState.MATURE)
  275. {
  276. saveFloat = m_TimeTracker;
  277. }
  278. ctx.Write( saveFloat );
  279. saveFloat = 0.0;
  280. if (m_PlantState == EPlantState.SPOILED)
  281. {
  282. saveFloat = m_TimeTracker;
  283. }
  284. ctx.Write( saveFloat );
  285. saveFloat = 0.0;
  286. if (m_PlantState == EPlantState.DRY)
  287. {
  288. saveFloat = m_TimeTracker;
  289. }
  290. ctx.Write( saveFloat );
  291. ctx.Write(m_HasCrops);
  292. }
  293. void PrintValues()
  294. {
  295. Print("PRINT ALL VALUES OF PLANT...");
  296. Print(this);
  297. Print(m_GrowthStagesCount);
  298. Print(m_HasCrops);
  299. Print(typename.EnumToString(EPlantState, m_PlantState));
  300. Print(m_PlantStateIndex);
  301. Print(m_CurrentPlantMaterialQuantity);
  302. Print(m_IsInfested);
  303. Print(m_SprayQuantity);
  304. Print(m_Slot);
  305. Print(m_GardenBase);
  306. Print(m_StateChangeTime);
  307. Print(m_FullMaturityTime);
  308. Print(m_SpoilAfterFullMaturityTime);
  309. Print(m_TimeTracker);
  310. Print("----------------------------------------------------------");
  311. }
  312. override bool CanPutInCargo( EntityAI parent )
  313. {
  314. return super.CanPutInCargo(parent);
  315. }
  316. override bool CanPutIntoHands( EntityAI parent )
  317. {
  318. return super.CanPutIntoHands(parent);
  319. }
  320. override bool CanRemoveFromHands( EntityAI parent )
  321. {
  322. return false;
  323. }
  324. void ChangeInfestation( bool is_infested )
  325. {
  326. m_IsInfested = is_infested;
  327. string plant_type = GetType();
  328. PlantMaterialHealth material = m_ModuleHorticulture.GetPlantMaterial( plant_type );
  329. if ( m_IsInfested )
  330. {
  331. if ( material.m_InfestedTex != "" )
  332. {
  333. SetObjectTexture( 0, material.m_InfestedTex );
  334. }
  335. if ( material.m_InfestedMat != "" )
  336. {
  337. SetObjectMaterial( 0, material.m_InfestedMat );
  338. }
  339. }
  340. else
  341. {
  342. if ( material.m_HealthyTex != "" )
  343. {
  344. SetObjectTexture( 0, material.m_HealthyTex );
  345. }
  346. if ( material.m_HealthyMat != "" )
  347. {
  348. SetObjectMaterial( 0, material.m_HealthyMat );
  349. }
  350. }
  351. }
  352. void UpdatePlant()
  353. {
  354. if ( m_PlantStateIndex > 0 )
  355. {
  356. string plant_state_index = m_PlantStateIndex.ToStringLen(2);
  357. string prev_plant_state_index = ( m_PlantStateIndex - 1 ).ToStringLen( 2 );
  358. // HIDING PREVIOUS PLANT STATE AND SHOWING THE CURRENT ONE
  359. ShowSelection( "plantStage_" + plant_state_index ); // SHOW!
  360. HideSelection( "plantStage_" + prev_plant_state_index ); // HIDE!
  361. // HIDING PREVIOUS CROPS STATE AND SHOWING THE CURRENT ONE
  362. if ( HasCrops() )
  363. {
  364. ShowSelection( "plantStage_" + plant_state_index + "_crops" ); // SHOW!
  365. HideSelection( "plantStage_" + prev_plant_state_index + "_crops" ); // HIDE!
  366. }
  367. else
  368. {
  369. HideSelection( "plantStage_" + plant_state_index + "_crops" ); // HIDE!
  370. HideSelection( "plantStage_" + prev_plant_state_index + "_crops" ); // HIDE!
  371. }
  372. // HIDING PREVIOUS SHADOW STATE AND SHOWING THE CURRENT ONE
  373. ShowSelection( "plantStage_" + plant_state_index + "_shadow" ); // SHOW!
  374. HideSelection( "plantStage_" + prev_plant_state_index + "_shadow" ); // HIDE!
  375. }
  376. float float_plant_state_index = (float)m_PlantStateIndex;
  377. m_CurrentPlantMaterialQuantity = m_PlantMaterialMultiplier * float_plant_state_index;
  378. }
  379. void GrowthTimerTick()
  380. {
  381. m_TimeTracker = 0;
  382. if ( m_PlantStateIndex < m_GrowthStagesCount - 2 )
  383. {
  384. m_PlantStateIndex++;
  385. UpdatePlant();
  386. SetSynchDirty();
  387. float infestation_rnd = Math.RandomFloat01();
  388. if ( m_InfestationChance > infestation_rnd )
  389. ChangeInfestation(true);
  390. if ( m_PlantStateIndex == m_GrowthStagesCount - 2 )
  391. {
  392. if (m_IsInfested)
  393. SetDry();
  394. else
  395. SetPlantState(EPlantState.MATURE);
  396. }
  397. }
  398. }
  399. void SetSpoiled()
  400. {
  401. if (m_PlantState != EPlantState.SPOILED)
  402. {
  403. m_PlantStateIndex++;
  404. UpdatePlant();
  405. SetPlantState(EPlantState.SPOILED);
  406. }
  407. }
  408. void SetDry()
  409. {
  410. if (m_PlantState != EPlantState.DRY)
  411. {
  412. m_PlantStateIndex++;
  413. UpdatePlant();
  414. SetPlantState(EPlantState.DRY);
  415. }
  416. }
  417. //NEW METHOD FOR PLANT SPRAYING
  418. void SprayPlant( float consumed_quantity )
  419. {
  420. //Rework this to have something smooth
  421. m_SprayQuantity += consumed_quantity;
  422. if (m_SprayQuantity >= m_SprayUsage)
  423. {
  424. m_IsInfested = false;
  425. m_InfestationChance = 0;
  426. ChangeInfestation( false );
  427. UpdatePlant();
  428. }
  429. }
  430. void RemovePlantEx( vector pos )
  431. {
  432. if ( GetGame() && GetGame().IsServer() )
  433. {
  434. UnlockFromParent();
  435. if ( m_CurrentPlantMaterialQuantity > 0.0 )
  436. {
  437. ItemBase item = ItemBase.Cast( GetGame().CreateObjectEx( "PlantMaterial", pos, ECE_PLACE_ON_SURFACE ) );
  438. item.SetQuantity( m_CurrentPlantMaterialQuantity * 1000.0 );
  439. }
  440. RemoveSlot();
  441. }
  442. }
  443. void DestroyPlant()
  444. {
  445. if ( GetGame() && GetGame().IsServer() )
  446. {
  447. UnlockFromParent();
  448. RemoveSlot();
  449. }
  450. }
  451. void Harvest( PlayerBase player )
  452. {
  453. if (IsHarvestable())
  454. {
  455. for ( int i = 0; i < m_CropsCount; i++ )
  456. {
  457. vector pos = player.GetPosition();
  458. ItemBase item = ItemBase.Cast( GetGame().CreateObjectEx( m_CropsType, pos, ECE_PLACE_ON_SURFACE ) );
  459. item.SetQuantity( item.GetQuantityMax() );
  460. }
  461. }
  462. m_HasCrops = false;
  463. SetSynchDirty();
  464. UpdatePlant();
  465. m_GardenBase.SyncSlots();
  466. }
  467. void SetPlantState(int state)
  468. {
  469. m_PlantState = state;
  470. m_TimeTracker = 0;
  471. SetSynchDirty();
  472. }
  473. EPlantState GetPlantState()
  474. {
  475. return m_PlantState;
  476. }
  477. int GetPlantStateIndex()
  478. {
  479. return m_PlantStateIndex;
  480. }
  481. float GetWater()
  482. {
  483. if ( GetSlot() )
  484. return GetSlot().GetWater();
  485. return 0;
  486. }
  487. float GetWaterMax()
  488. {
  489. if ( GetSlot() )
  490. return GetSlot().GetWaterUsage();
  491. return 0;
  492. }
  493. bool NeedsWater()
  494. {
  495. Slot slotPlant = m_Slot;
  496. if ( m_PlantState == EPlantState.PAUSED && slotPlant && slotPlant.GetWater() < slotPlant.GetWaterUsage() )
  497. return true;
  498. return false;
  499. }
  500. float GetSprayQuantity()
  501. {
  502. return m_SprayQuantity;
  503. }
  504. float GetSprayUsage()
  505. {
  506. return m_SprayUsage;
  507. }
  508. void RemoveSlot()
  509. {
  510. GardenBase garden = GardenBase.Cast( GetHierarchyParent() );
  511. if ( garden )
  512. garden.RemoveSlotPlant( this );
  513. }
  514. void SetSlot(Slot slot)
  515. {
  516. if ( slot )
  517. {
  518. m_Slot = slot;
  519. }
  520. }
  521. Slot GetSlot()
  522. {
  523. return m_Slot;
  524. }
  525. void SetGarden(GardenBase gardenBase)
  526. {
  527. m_GardenBase = gardenBase;
  528. }
  529. GardenBase GetGarden()
  530. {
  531. return m_GardenBase;
  532. }
  533. bool IsSprayable()
  534. {
  535. if (m_PlantState == EPlantState.GROWING && m_SprayQuantity < m_SprayUsage)
  536. return true;
  537. return false;
  538. }
  539. bool IsHarvestable()
  540. {
  541. if (m_PlantState == EPlantState.MATURE && m_HasCrops)
  542. return true;
  543. return false;
  544. }
  545. bool HasCrops()
  546. {
  547. return m_HasCrops;
  548. }
  549. override void SetActions()
  550. {
  551. super.SetActions();
  552. AddAction(ActionHarvestCrops);
  553. AddAction(ActionRemovePlant);
  554. }
  555. void DebugSetTimes(int maturity, int spoil, int spoilRemove, int dryDelete)
  556. {
  557. if (maturity != 0)
  558. {
  559. m_FullMaturityTime = maturity;
  560. m_StateChangeTime = m_FullMaturityTime / (m_GrowthStagesCount - 2);
  561. }
  562. if (spoil != 0)
  563. m_SpoilAfterFullMaturityTime = spoil;
  564. if (spoilRemove != 0)
  565. m_SpoiledRemoveTime = spoilRemove;
  566. if (dryDelete != 0)
  567. m_DeleteDryPlantTime = dryDelete;
  568. }
  569. static void DebugSetGlobalTimes(int maturity, int spoil, int spoilRemove, int dryDelete)
  570. {
  571. m_DebugFullMaturityTime = maturity;
  572. m_DebugSpoilTime = spoil;
  573. m_DebugSpoilRemoveTime = spoilRemove;
  574. m_DebugDeleteDryTime = dryDelete;
  575. }
  576. static void DebugSetTickSpeedMultiplier(float multiplier)
  577. {
  578. m_DebugTickSpeedMultiplier = multiplier;
  579. }
  580. // DEPRECATED
  581. static const int STATE_DRY = 0;
  582. static const int STATE_GROWING = 1;
  583. static const int STATE_MATURE = 2;
  584. static const int STATE_SPOILED = 3;
  585. ref Timer m_SpoiledRemoveTimer;
  586. ref Timer m_DeleteDryPlantTimer;
  587. ref Timer m_SpoilAfterFullMaturityTimer;
  588. ref Timer m_GrowthTimer;
  589. ref Timer m_InfestationTimer;
  590. void DeleteDryPlantTick();
  591. void SpoiledRemoveTimerTick();
  592. void InfestationTimerTick();
  593. void CheckWater();
  594. bool IsMature();
  595. bool IsSpoiled();
  596. bool IsDry();
  597. bool IsGrowing();
  598. bool NeedsSpraying();
  599. void RemovePlant();
  600. string StopInfestation( float consumed_quantity )
  601. {
  602. return "";
  603. }
  604. }