Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // How functions in here fit together:
- //
- // TGT_FindTID
- // - Given a TID, find the target data row it occupies.
- //
- // TGT_Add
- // - Add a given TID to the target data table.
- //
- // TGT_Del
- // - Delete a given row in the target data table.
- //
- // TGT_DelTID
- // - Delete a given TID from the target data table.
- //
- // TGT_SetData
- // - Set a column in the target data table to a given value for the given TID.
- //
- // TGT_SetDataArray
- // - Sets an entire row of target data, save TID, for the given TID. This exists
- // because setting an entire row at once is quicker than using TGT_SetData
- // repeatedly when you need it.
- //
- // TGT_ApplySlots
- // - Give out friendliness/unfriendliness items based off slot status
- // in the target data. Only gives them if status changed.
- //
- // TARGETSLOTS defines how many slots are defined for targeting purposes.
- //
- // Target slots are used to determine whether an enemy should be marked +FRIENDLY
- // or -FRIENDLY. If even one of them is set, the target's friendliness is flipped.
- // If all of them are unset, it's flipped back to what it was normally.
- //
- // The reason this is necessary is so that the arc won't pick up unwanted targets
- // multiple times with A_LookEx.
- //
- // The reason why this complicated system is necessary is because the last time I
- // tried this, friendliness tended to break. A lot. It probably still will, since
- // dead actors don't show up on ThingCount and TIDs can be shared with actors,
- // but there really isn't much of anything I can do about that.
- //
- // I hate TIDs. I hate juggling them around. I hate what they do to my code.
- // I hate the unexplainable bugs that arise from them, the inconsistencies in
- // how they're handled, how in the 17 years that ZDoom has had ACS there has been
- // no better solution made, how I can't even be goddamn sure that the TID I assign
- // to an actor will be *unique* or even *be there* next tic. I hate the fact that
- // by changing a TID on *anything*, I am breaking multiple maps out there. I hate
- // the dipshit developers who have refused to put in anything better for the past
- // 17 years. The whole goddamn system can go to hell.
- //
- // Just once - just fucking once - I want my code to not fall apart into a pile
- // of special cases and incomprehensible gibberish the moment it runs into them.
- // I want to be sure that I'm working with the right actor, that I'm not
- // accidentally moving some random demon or teleporter halfway across the map.
- //
- // Is that seriously so much to ask for?
- //
- // Anyway, enough ranting. Here's what the slots are for.
- //
- // HITALREADY - used when a target's been hit by an arc
- // can be unset automatically or manually, but always gets cleared
- // every tic, at some point during the tic
- //
- // CHECKED - used when looking for targets - this makes them untargetable so
- // A_LookEx doesn't get stuck on them during an arc cycle
- #define TARGETSLOTS 2
- #define TSLOT_HITALREADY 0
- #define TSLOT_CHECKED 1
- // Columns for TargetData!
- //
- // T_ROWS is how many targets can be stored. It's high so things don't go bad.
- //
- // T_COLS just defines how many columns there are.
- //
- // T_TID corresponds to the TID of the actor being looked at.
- //
- // T_ORIGTID corresponds to the original TID of the actor being looked at. It's
- // normally equal to T_TID, since it's set to the same value as T_TID in TGT_Add,
- // but it can be set elsewhere, presumably to avoid breaking maps horribly by
- // changing a demon's TID from, say, 5 to 26001. Did I mention I hate TIDs?
- //
- // T_CURSTATE is there to mark whether the enemy's friendliness is currently flipped
- // or not. Friendliness works in mysterious ways; apparently, making a monster
- // -FRIENDLY multiple times adds to the monster counter every time.
- // False means "original" and true means "flipped".
- //
- // T_ALREADYFRIEND marks whether the target started friendly or not. This is to
- // reverse friendliness behaviour.
- //
- // T_SLOTSTART is the column at which the target slots above start at.
- // From that column on, everything is a target slot.
- #define T_ROWS 65536
- #define T_COLS (4 + TARGETSLOTS)
- #define T_TID 0
- #define T_ORIGTID 1
- #define T_CURSTATE 2
- #define T_ALREADYFRIEND 3
- #define T_SLOTSTART 4
- // These are for easier access to the slot columns.
- #define T_HITALREADY (T_SLOTSTART + TSLOT_HITALREADY)
- #define T_CHECKED (T_SLOTSTART + TSLOT_CHECKED)
- // These are the slot mask constants for TGT_SetDataArray. Combine these with
- // bitwise OR "|" to create the slot mask you want to use to set data with.
- // These correspond with the above columns directly.
- //
- // TS_ALL specifies all of the columns.
- //
- // TS_TID isn't included because T_TID should not be changed, only read. The
- // only two functions that should alter T_TID are TGT_Add and TGT_Del. If
- // anything else alters them, duplicate entries could be made, with undefined
- // behaviour.
- //
- // Alternately, just use the constants directly (1 << colIndex), but that's
- // less readable.
- #define TS_ALL ((1 << T_COLS) - 1)
- #define TS_ORIGTID (1 << T_ORIGTID)
- #define TS_CURSTATE (1 << T_CURSTATE)
- #define TS_ALREADYFRIEND (1 << T_ALREADYFRIEND)
- #define TS_HITALREADY (1 << T_HITALREADY)
- #define TS_CHECKED (1 << T_CHECKED)
- // How many targets are currently stored in TargetData. This is used not
- // just to keep track of how many targets there are, but also to keep
- // TargetData contiguous - when a target is removed, the topmost target
- // gets moved down into the now-empty slot. This way, when adding a target
- // we can just slap it on the end without looking for an empty slot.
- //
- // The less time spent traversing the array, the better.
- int TargetCount;
- // This stores the states of enemies that have been set +FRIENDLY as a result
- // of the arc code. Don't touch it manually; down that road lies madness.
- //
- // Trust me on that one. I'm rewriting this for a reason.
- int TargetData[T_ROWS][T_COLS];
- // Find the index of a given TID in TargetData. If it doesn't exist,
- // return -1.
- //
- // Used for many things, like making sure no duplicate TIDs end up in the
- // array. +FRIENDLY is very fragile, so I'm taking precautions.
- //
- // Special case: TID 0 always returns -1, because messing with TID 0 is horrible.
- function int TGT_Find(int tid)
- {
- if (tid == 0) { return -1; }
- int i;
- int checkTID;
- for (i = 0; i < TargetCount; i++)
- {
- checkTID = TargetData[i][T_TID];
- if (tid == checkTID) { return i; }
- }
- return -1;
- }
- // Add a target to TargetData, with no slots set yet, and return the
- // index of the target. All other columns are set to appropriate values.
- //
- // If the target already exists in TargetData, return the index as a
- // negative number. That way, the caller knows it already existed, but
- // doesn't need to do another call to find it.
- //
- // This doesn't actually change any +FRIENDLY/-FRIENDLY flags: that is
- // handled elsewhere.
- //
- // Special case: TID 0 returns T_ROWS as the index, since it's guaranteed
- // to be out-of-bounds and no you're not messing with TID 0 seriously stop.
- function int TGT_Add(int tid)
- {
- if (tid == 0) { return T_ROWS; }
- int curIndex = TGT_Find(tid);
- if (curIndex != -1) { return -curIndex; }
- // Guess what? This might not actually grab the right actor!
- // GetActorProperty for TIDs with multiple actors assigned to them is
- // *completely undefined*!
- //
- // Yes, something as *checking friendliness* can cause bugs to appear.
- int isFriend = GetActorProperty(tid, APROP_Friendly);
- curIndex = TargetCount;
- TargetData[curIndex][T_TID] = tid;
- TargetData[curIndex][T_ORIGTID] = tid;
- TargetData[curIndex][T_CURSTATE] = false;
- TargetData[curIndex][T_ALREADYFRIEND] = isFriend;
- int i;
- for (i = 0; i < TARGETSLOTS; i++)
- {
- TargetData[curIndex][T_SLOTSTART + i] = false;
- }
- TargetCount += 1;
- return curIndex;
- }
- // Clears a target by row, and pulls the top row down to the deleted slot to
- // preserve contiguity.
- //
- // Note that we don't actually clear out the top row, we just copy its contents
- // over, since TGT_Add clears it anyway when it gets back to it.
- //
- // Return values:
- //
- // - 0: Success, yay.
- //
- // - 1: Row given was out of bounds, and therefore nothing was done.
- function int TGT_Del(int row)
- {
- if (row < 0 || row >= TargetCount) { return 1; }
- TargetCount -= 1;
- int i;
- for (i = 0; i < T_COLS; i++)
- {
- TargetData[row][i] = TargetData[TargetCount][i];
- }
- return 0;
- }
- // Clears a target by TID. Uses TGT_Del to do it.
- //
- // Return values:
- //
- // - 0: TID was found and deleted.
- //
- // - 1: The TID was not found, and nothing was deleted.
- //
- // - 2: The TID was 0.
- //
- // - 3: Something went horribly wrong: somehow, the TID was found, and it
- // was out of bounds despite TGT_Find only looking within the bounds.
- // If this happens, be scared.
- function int TGT_DelTID(int tid)
- {
- if (tid == 0) { return 2; }
- int curIndex = TGT_Find(tid);
- if (curIndex == -1) { return 1; }
- int result = TGT_Del(curIndex);
- // This should never happen.
- if (result == 1) { return 3; }
- return 0;
- }
- // Sets the given column of data for a TID to the given value.
- // This doesn't do any auto-pruning, nor does it apply anything.
- // Setting T_TID is not allowed, because this could create duplicates.
- //
- // Return values:
- //
- // - 0: Column was set properly.
- //
- // - 1: TID was not foumd.
- //
- // - 2: TID was 0.
- //
- // - 3: Column was out of range.
- //
- // - 4: Column was T_TID, which is expliclty disallowed.
- function int TGT_SetData(int tid, int slot, int val)
- {
- if (slot == T_TID) { return 4; }
- if (slot < 0 || slot >= T_COLS) { return 3; }
- if (tid == 0) { return 2; }
- int curIndex = TGT_Find(tid);
- if (curIndex == -1) { return 1; }
- TargetData[curIndex][slot] = val;
- return 0;
- }
- // Sets data for a given row of data, given a slot mask. See the TS_* constants
- // at the top of the file for the slot mask constants you should use.
- //
- // To use this function, you set the appropriate values in TGT_DataArray, then
- // call the function with the proper slot mask.
- //
- // For example, to set T_ORIGTID and T_CHECKED, you'd do something like this:
- //
- // TGT_DataArray[T_ORIGTID] = 12345;
- // TGT_DataArray[T_CHECKED] = true;
- // TGT_SetDataArray(tid, TS_ORIGTID | TS_CHECKED);
- //
- // Again, you aren't allowed to change T_TID, to guarantee each TID is only found
- // once in the target data.
- //
- // You *could* set index T_TID of TGT_DataArray, but it just gets ignored.
- //
- // Return values:
- //
- // - 0: Columns were set properly.
- //
- // - 1: TID was not found.
- //
- // - 2: TID was 0.
- int TGT_DataArray[T_COLS];
- function int TGT_SetDataArray(int tid, int slotmask)
- {
- if (tid == 0) { return 2; }
- int curIndex = TGT_Find(tid);
- if (curIndex == -1) { return 1; }
- int i, checkmask;
- for (i = 0; i < T_COLS; i++)
- {
- // preserve target data integrity
- if (i == T_TID) { continue; }
- // check if setting this column
- checkmask = 1 << i;
- if (!(slotmask & checkmask)) { continue; }
- TargetData[curIndex][i] = TGT_DataArray[i];
- }
- return 0;
- }
- // Checks the values of all the slots set on a TID, and if any of them are on, flips
- // its friendliness.
- //
- // Return values:
- //
- // - -1: TID was not found.
- //
- // - 0 (false): Target is set to original friendliness.
- //
- // - 1 (true): Target is set to opposite friendliness.
- //
- // - 2: TID is 0 *stop it*
- function int TGT_ApplySlots(int tid)
- {
- if (tid == 0) { return 2; }
- int curIndex = TGT_Find(tid);
- if (curIndex == -1) { return -1; }
- int flipFriendliness = false;
- int i;
- for (i = T_SLOTSTART; i < T_COLS; i++)
- {
- if (TargetData[curIndex][i])
- {
- flipFriendliness = true;
- break;
- }
- }
- int curState = TargetData[curIndex][T_CURSTATE];
- // remember, only apply friendliness changes if it actually changed
- if (curState != flipFriendliness)
- {
- int endState = flipFriendliness;
- // flip end state if started as friend
- // this doesn't affect the internal flipped-or-not stuff,
- // just the item given
- if (TargetData[curIndex][T_ALREADYFRIEND])
- {
- endState = !endState;
- }
- if (endState) { GiveActorInventory(tid, "ArcFriendly", 1); }
- else { GiveActorInventory(tid, "ArcUnfriendly", 1); }
- }
- return flipFriendliness;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement