Advertisement
ijontichy

arc_targetState.h

Jan 21st, 2016
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.42 KB | None | 0 0
  1.  
  2. // How functions in here fit together:
  3. //
  4. // TGT_FindTID
  5. //  - Given a TID, find the target data row it occupies.
  6. //
  7. // TGT_Add
  8. //  - Add a given TID to the target data table.
  9. //
  10. // TGT_Del
  11. //  - Delete a given row in the target data table.
  12. //
  13. // TGT_DelTID
  14. //  - Delete a given TID from the target data table.
  15. //
  16. // TGT_SetData
  17. //  - Set a column in the target data table to a given value for the given TID.
  18. //
  19. // TGT_SetDataArray
  20. //  - Sets an entire row of target data, save TID, for the given TID. This exists
  21. //    because setting an entire row at once is quicker than using TGT_SetData
  22. //    repeatedly when you need it.
  23. //
  24. // TGT_ApplySlots
  25. //  - Give out friendliness/unfriendliness items based off slot status
  26. //    in the target data. Only gives them if status changed.
  27. //
  28.  
  29.  
  30. // TARGETSLOTS defines how many slots are defined for targeting purposes.
  31. //
  32. // Target slots are used to determine whether an enemy should be marked +FRIENDLY
  33. // or -FRIENDLY. If even one of them is set, the target's friendliness is flipped.
  34. // If all of them are unset, it's flipped back to what it was normally.
  35. //
  36. // The reason this is necessary is so that the arc won't pick up unwanted targets
  37. // multiple times with A_LookEx.
  38. //
  39. // The reason why this complicated system is necessary is because the last time I
  40. // tried this, friendliness tended to break. A lot. It probably still will, since
  41. // dead actors don't show up on ThingCount and TIDs can be shared with actors,
  42. // but there really isn't much of anything I can do about that.
  43. //
  44. // I hate TIDs. I hate juggling them around. I hate what they do to my code.
  45. // I hate the unexplainable bugs that arise from them, the inconsistencies in
  46. // how they're handled, how in the 17 years that ZDoom has had ACS there has been
  47. // no better solution made, how I can't even be goddamn sure that the TID I assign
  48. // to an actor will be *unique* or even *be there* next tic. I hate the fact that
  49. // by changing a TID on *anything*, I am breaking multiple maps out there. I hate
  50. // the dipshit developers who have refused to put in anything better for the past
  51. // 17 years. The whole goddamn system can go to hell.
  52. //
  53. // Just once - just fucking once - I want my code to not fall apart into a pile
  54. // of special cases and incomprehensible gibberish the moment it runs into them.
  55. // I want to be sure that I'm working with the right actor, that I'm not
  56. // accidentally moving some random demon or teleporter halfway across the map.
  57. //
  58. // Is that seriously so much to ask for?
  59. //
  60. // Anyway, enough ranting. Here's what the slots are for.
  61. //
  62. // HITALREADY - used when a target's been hit by an arc
  63. //              can be unset automatically or manually, but always gets cleared
  64. //              every tic, at some point during the tic
  65. //
  66. // CHECKED    - used when looking for targets - this makes them untargetable so
  67. //              A_LookEx doesn't get stuck on them during an arc cycle
  68.  
  69. #define TARGETSLOTS 2
  70.  
  71. #define TSLOT_HITALREADY    0
  72. #define TSLOT_CHECKED       1
  73.  
  74.  
  75. // Columns for TargetData!
  76. //
  77. // T_ROWS is how many targets can be stored. It's high so things don't go bad.
  78. //
  79. // T_COLS just defines how many columns there are.
  80. //
  81. // T_TID corresponds to the TID of the actor being looked at.
  82. //
  83. // T_ORIGTID corresponds to the original TID of the actor being looked at. It's
  84. //  normally equal to T_TID, since it's set to the same value as T_TID in TGT_Add,
  85. //  but it can be set elsewhere, presumably to avoid breaking maps horribly by
  86. //  changing a demon's TID from, say, 5 to 26001. Did I mention I hate TIDs?
  87. //
  88. // T_CURSTATE is there to mark whether the enemy's friendliness is currently flipped
  89. //  or not. Friendliness works in mysterious ways; apparently, making a monster
  90. //  -FRIENDLY multiple times adds to the monster counter every time.
  91. //  False means "original" and true means "flipped".
  92. //
  93. // T_ALREADYFRIEND marks whether the target started friendly or not. This is to
  94. //  reverse friendliness behaviour.
  95. //
  96. // T_SLOTSTART is the column at which the target slots above start at.
  97. //  From that column on, everything is a target slot.
  98.  
  99. #define T_ROWS  65536
  100. #define T_COLS  (4 + TARGETSLOTS)
  101.  
  102. #define T_TID               0
  103. #define T_ORIGTID           1
  104. #define T_CURSTATE          2
  105. #define T_ALREADYFRIEND     3
  106. #define T_SLOTSTART         4
  107.  
  108. // These are for easier access to the slot columns.
  109.  
  110. #define T_HITALREADY        (T_SLOTSTART + TSLOT_HITALREADY)
  111. #define T_CHECKED           (T_SLOTSTART + TSLOT_CHECKED)
  112.  
  113.  
  114. // These are the slot mask constants for TGT_SetDataArray. Combine these with
  115. //  bitwise OR "|" to create the slot mask you want to use to set data with.
  116. //  These correspond with the above columns directly.
  117. //
  118. // TS_ALL specifies all of the columns.
  119. //
  120. // TS_TID isn't included because T_TID should not be changed, only read. The
  121. //  only two functions that should alter T_TID are TGT_Add and TGT_Del. If
  122. //  anything else alters them, duplicate entries could be made, with undefined
  123. //  behaviour.
  124. //
  125. // Alternately, just use the constants directly (1 << colIndex), but that's
  126. //  less readable.
  127.  
  128. #define TS_ALL              ((1 << T_COLS) - 1)
  129.  
  130. #define TS_ORIGTID          (1 << T_ORIGTID)
  131. #define TS_CURSTATE         (1 << T_CURSTATE)
  132. #define TS_ALREADYFRIEND    (1 << T_ALREADYFRIEND)
  133.  
  134. #define TS_HITALREADY       (1 << T_HITALREADY)
  135. #define TS_CHECKED          (1 << T_CHECKED)
  136.  
  137. // How many targets are currently stored in TargetData. This is used not
  138. //  just to keep track of how many targets there are, but also to keep
  139. //  TargetData contiguous - when a target is removed, the topmost target
  140. //  gets moved down into the now-empty slot. This way, when adding a target
  141. //  we can just slap it on the end without looking for an empty slot.
  142. //
  143. //  The less time spent traversing the array, the better.
  144.  
  145. int TargetCount;
  146.  
  147. // This stores the states of enemies that have been set +FRIENDLY as a result
  148. //  of the arc code. Don't touch it manually; down that road lies madness.
  149. //
  150. //  Trust me on that one. I'm rewriting this for a reason.
  151.  
  152. int TargetData[T_ROWS][T_COLS];
  153.  
  154.  
  155.  
  156. // Find the index of a given TID in TargetData. If it doesn't exist,
  157. //  return -1.
  158. //
  159. // Used for many things, like making sure no duplicate TIDs end up in the
  160. //  array. +FRIENDLY is very fragile, so I'm taking precautions.
  161. //
  162. // Special case: TID 0 always returns -1, because messing with TID 0 is horrible.
  163.  
  164. function int TGT_Find(int tid)
  165. {
  166.     if (tid == 0) { return -1; }
  167.  
  168.     int i;
  169.     int checkTID;
  170.  
  171.     for (i = 0; i < TargetCount; i++)
  172.     {
  173.         checkTID = TargetData[i][T_TID];
  174.  
  175.         if (tid == checkTID) { return i; }
  176.     }
  177.  
  178.     return -1;
  179. }
  180.  
  181.  
  182.  
  183. // Add a target to TargetData, with no slots set yet, and return the
  184. //  index of the target. All other columns are set to appropriate values.
  185. //
  186. // If the target already exists in TargetData, return the index as a
  187. //  negative number. That way, the caller knows it already existed, but
  188. //  doesn't need to do another call to find it.
  189. //
  190. // This doesn't actually change any +FRIENDLY/-FRIENDLY flags: that is
  191. //  handled elsewhere.
  192. //
  193. // Special case: TID 0 returns T_ROWS as the index, since it's guaranteed
  194. //  to be out-of-bounds and no you're not messing with TID 0 seriously stop.
  195.  
  196. function int TGT_Add(int tid)
  197. {
  198.     if (tid == 0) { return T_ROWS; }
  199.  
  200.     int curIndex = TGT_Find(tid);
  201.     if (curIndex != -1) { return -curIndex; }
  202.  
  203.     // Guess what? This might not actually grab the right actor!
  204.     //  GetActorProperty for TIDs with multiple actors assigned to them is
  205.     //  *completely undefined*!
  206.     //
  207.     // Yes, something as *checking friendliness* can cause bugs to appear.
  208.     int isFriend = GetActorProperty(tid, APROP_Friendly);
  209.  
  210.     curIndex = TargetCount;
  211.  
  212.     TargetData[curIndex][T_TID]            = tid;
  213.     TargetData[curIndex][T_ORIGTID]        = tid;
  214.     TargetData[curIndex][T_CURSTATE]       = false;
  215.     TargetData[curIndex][T_ALREADYFRIEND]  = isFriend;
  216.    
  217.     int i;
  218.  
  219.     for (i = 0; i < TARGETSLOTS; i++)
  220.     {
  221.         TargetData[curIndex][T_SLOTSTART + i] = false;
  222.     }
  223.  
  224.     TargetCount += 1;
  225.  
  226.     return curIndex;
  227. }
  228.  
  229.  
  230.  
  231. // Clears a target by row, and pulls the top row down to the deleted slot to
  232. //  preserve contiguity.
  233. //
  234. // Note that we don't actually clear out the top row, we just copy its contents
  235. // over, since TGT_Add clears it anyway when it gets back to it.
  236. //
  237. // Return values:
  238. //
  239. // - 0: Success, yay.
  240. //
  241. // - 1: Row given was out of bounds, and therefore nothing was done.
  242.  
  243. function int TGT_Del(int row)
  244. {
  245.     if (row < 0 || row >= TargetCount) { return 1; }
  246.  
  247.     TargetCount -= 1;
  248.  
  249.     int i;
  250.  
  251.     for (i = 0; i < T_COLS; i++)
  252.     {
  253.         TargetData[row][i] = TargetData[TargetCount][i];
  254.     }
  255.  
  256.     return 0;
  257. }
  258.  
  259.  
  260.  
  261. // Clears a target by TID. Uses TGT_Del to do it.
  262. //
  263. // Return values:
  264. //
  265. // - 0: TID was found and deleted.
  266. //
  267. // - 1: The TID was not found, and nothing was deleted.
  268. //
  269. // - 2: The TID was 0.
  270. //
  271. // - 3: Something went horribly wrong: somehow, the TID was found, and it
  272. //      was out of bounds despite TGT_Find only looking within the bounds.
  273. //      If this happens, be scared.
  274.  
  275. function int TGT_DelTID(int tid)
  276. {
  277.     if (tid == 0) { return 2; }
  278.  
  279.     int curIndex = TGT_Find(tid);
  280.     if (curIndex == -1) { return 1; }
  281.  
  282.     int result = TGT_Del(curIndex);
  283.  
  284.     // This should never happen.
  285.     if (result == 1) { return 3; }
  286.  
  287.     return 0;
  288. }
  289.  
  290.  
  291.  
  292. // Sets the given column of data for a TID to the given value.
  293. //  This doesn't do any auto-pruning, nor does it apply anything.
  294. //  Setting T_TID is not allowed, because this could create duplicates.
  295. //
  296. // Return values:
  297. //
  298. // - 0: Column was set properly.
  299. //
  300. // - 1: TID was not foumd.
  301. //
  302. // - 2: TID was 0.
  303. //
  304. // - 3: Column was out of range.
  305. //
  306. // - 4: Column was T_TID, which is expliclty disallowed.
  307.  
  308. function int TGT_SetData(int tid, int slot, int val)
  309. {
  310.     if (slot == T_TID) { return 4; }
  311.     if (slot < 0 || slot >= T_COLS) { return 3; }
  312.     if (tid == 0) { return 2; }
  313.  
  314.     int curIndex = TGT_Find(tid);
  315.     if (curIndex == -1) { return 1; }
  316.  
  317.     TargetData[curIndex][slot] = val;
  318.  
  319.     return 0;
  320. }
  321.  
  322.  
  323.  
  324. // Sets data for a given row of data, given a slot mask. See the TS_* constants
  325. //  at the top of the file for the slot mask constants you should use.
  326. //
  327. // To use this function, you set the appropriate values in TGT_DataArray, then
  328. //  call the function with the proper slot mask.
  329. //
  330. // For example, to set T_ORIGTID and T_CHECKED, you'd do something like this:
  331. //
  332. //      TGT_DataArray[T_ORIGTID] = 12345;
  333. //      TGT_DataArray[T_CHECKED] = true;
  334. //      TGT_SetDataArray(tid, TS_ORIGTID | TS_CHECKED);
  335. //
  336. // Again, you aren't allowed to change T_TID, to guarantee each TID is only found
  337. //  once in the target data.
  338. //
  339. // You *could* set index T_TID of TGT_DataArray, but it just gets ignored.
  340. //
  341. // Return values:
  342. //
  343. // - 0: Columns were set properly.
  344. //
  345. // - 1: TID was not found.
  346. //
  347. // - 2: TID was 0.
  348.  
  349. int TGT_DataArray[T_COLS];
  350.  
  351. function int TGT_SetDataArray(int tid, int slotmask)
  352. {
  353.     if (tid == 0) { return 2; }
  354.  
  355.     int curIndex = TGT_Find(tid);
  356.     if (curIndex == -1) { return 1; }
  357.  
  358.     int i, checkmask;
  359.     for (i = 0; i < T_COLS; i++)
  360.     {
  361.         // preserve target data integrity
  362.         if (i == T_TID) { continue; }
  363.  
  364.         // check if setting this column
  365.         checkmask = 1 << i;
  366.         if (!(slotmask & checkmask)) { continue; }
  367.  
  368.         TargetData[curIndex][i] = TGT_DataArray[i];
  369.     }
  370.  
  371.     return 0;
  372. }
  373.  
  374.        
  375.  
  376. // Checks the values of all the slots set on a TID, and if any of them are on, flips
  377. //  its friendliness.
  378. //
  379. // Return values:
  380. //
  381. // - -1: TID was not found.
  382. //
  383. // -  0 (false): Target is set to original friendliness.
  384. //
  385. // -  1 (true):  Target is set to opposite friendliness.
  386. //
  387. // -  2: TID is 0 *stop it*
  388.  
  389. function int TGT_ApplySlots(int tid)
  390. {
  391.     if (tid == 0) { return 2; }
  392.  
  393.     int curIndex = TGT_Find(tid);
  394.     if (curIndex == -1) { return -1; }
  395.  
  396.     int flipFriendliness = false;
  397.     int i;
  398.  
  399.     for (i = T_SLOTSTART; i < T_COLS; i++)
  400.     {
  401.         if (TargetData[curIndex][i])
  402.         {
  403.             flipFriendliness = true;
  404.             break;
  405.         }
  406.     }
  407.  
  408.     int curState = TargetData[curIndex][T_CURSTATE];
  409.  
  410.     // remember, only apply friendliness changes if it actually changed
  411.     if (curState != flipFriendliness)
  412.     {
  413.         int endState = flipFriendliness;
  414.  
  415.         // flip end state if started as friend
  416.         //  this doesn't affect the internal flipped-or-not stuff,
  417.         //  just the item given
  418.         if (TargetData[curIndex][T_ALREADYFRIEND])
  419.         {
  420.             endState = !endState;
  421.         }
  422.  
  423.         if (endState) { GiveActorInventory(tid, "ArcFriendly",   1); }
  424.         else          { GiveActorInventory(tid, "ArcUnfriendly", 1); }
  425.     }
  426.  
  427.     return flipFriendliness;
  428. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement