Duke4.net Forums: EDuke32 Scripting - Duke4.net Forums

Jump to content

  • 115 Pages +
  • « First
  • 86
  • 87
  • 88
  • 89
  • 90
  • Last »
  • You cannot start a new topic
  • You cannot reply to this topic

EDuke32 Scripting  "CON coding help"

User is offline   Jimmy 

  • Let's go Brandon!

#2611

Try having the game check to see if the gib is in an invalid sector, and if so, break and killit.
0

#2612

View PostJimmy, on 28 October 2020 - 12:08 PM, said:

Try having the game check to see if the gib is in an invalid sector, and if so, break and killit.


The issue is that I'm not sure how to do that.
0

User is offline   jimbob 

#2613

hey, havent been to this site in ages, but i had the urge to make some duke mods and was wondering about a few things.

1, i want to add new reload animations to a custom weapon wich replaces the chaingun. it behaves like the chaingun/ripper except it needs a 30 round magazine, and some reload animations
i have all the artwork in place, might need some tweaking, but i cant for the life of me figure out how to tell the game when to reload, where the artfiles are and how long the animation needs to last, tried looking at the wiki and use the 'manual reload' tutorial, but it just jiggles the gun infinetly.
i have the new reload animation, 7 frames long at tile 2582, and basically it is an oscillation of pulling out a mag, and sticking it back in.
for the weapon i use these gamevars.
// thompson
gamevar WEAPON3_WORKSLIKE 3 0
gamevar WEAPON3_CLIP 30 0
gamevar WEAPON3_RELOAD 60 0
// gamevar WEAPON3_FIREDELAY 1 0
gamevar WEAPON3_TOTALTIME 10 0 // was 10
// gamevar WEAPON3_HOLDDELAY 0 0
gamevar WEAPON3_FLAGS 73813 // 85
gamevar WEAPON3_SHOOTS CHAINGUN
// gamevar WEAPON3_SPAWNTIME 0 0
gamevar WEAPON3_SHOTSPERBURST 0 0
gamevar WEAPON3_INITIALSOUND 0
gamevar WEAPON3_FIRESOUND CHAINGUN_FIRE
gamevar WEAPON3_SOUND2TIME 0
gamevar WEAPON3_SOUND2SOUND 0
gamevar WEAPON3_SPAWN SHELL

2, i have an actor wich spawns at a certain point, goes through an AI routine, but i want this actor to litteraly keel over and die after X seconds, after wich i want the corpse to be removed after a while.
i have the routines down, and even the corpse cleanup code but the game refuses to use 'count' if it is going through other routines, or if it moves. i have a a cleanup state as follows
state cleanup
cstat 2
ifcount 330
{
cstat 514
}
ifcount 360
{
killit
}
ends

this kicks in after the actor has been shot and is dead on the floor ( aparently if movement is 0 it starts counting )

i trier adding something like
ifcount 1000 action GIDROPDEAD ( the actors falling dead animation )
strength 0
state GIDYING ( check the DYING state of the actor for ifhitweapon etc )

but because it keeps going through its routines and keeps moving it never reaches the count number, or, when it dies it keeps looping its dying animation.
0

User is offline   jimbob 

#2614

i thought about it for a bit, and perhaps substracting health every other state will eventually drain the actors health, causing it to quite litterally die, this would give some random amount of time before this happens, and wil definatly cause the actor to die eventually.

another thing, how do i change the offset for the ejecting brass, right now it spawns in an incorrect location.

and since where on the topic of editing existing things, the muscle flashes used with the chaingun have three different offsets so they animate in front of each 'barrel' of the gun, i'd like to change this to one location for my new gun.
0

User is offline   Reaper_Man 

  • Once and Future King

#2615

I have a bunch of questions about performance. How "expensive" are the following commands?

sqrt
updatesector
cansee
setarray
setvarvar (specifically pulling data from an array)


I'm trying to improve performance on my A* pathfinding, and I'm trying to identify which operations are very "expensive" that I should avoid or limit my usage of. I am calling these potentially thousands of times for every enemy on a given frame. There's not frequently frame drops and I am doing what I can to limit the frequency for these calls, but I'm curious which of these are the most heavy on CPU.

I am using "sqrt" for a simple Euclidian distance calculation, as dist / ldist takes actors and not X/Y positions:

defstate astardist
{
	setvarvar ASTARDELTAX ASTARPOSX
	subvarvar ASTARDELTAX NODEPOSX
	abs ASTARDELTAX

	setvarvar ASTARDELTAY ASTARPOSY
	subvarvar ASTARDELTAY NODEPOSY
	abs ASTARDELTAY

	mulvarvar ASTARDELTAX ASTARDELTAX
	mulvarvar ASTARDELTAY ASTARDELTAY

	addvarvar ASTARDELTAX ASTARDELTAY

	sqrt ASTARDELTAX ASTARDIST
}
ends


Is there a cheaper method of getting the distance between 2 arbitrary points in space?

I'm using "updatesector" in conjunction with "cansee" to validate if 2 points in space are valid (IE not in the void):

// Ignore any point we don't have line of sight to
getactor[THISACTOR].sectnum ASTARSECT
updatesector ASTARPOSX ASTARPOSY ASTARSECT
getsector[ASTARSECT].floorz ASTARPOSZ
subvar ASTARPOSZ 6144

getactor[THISACTOR].sectnum NODESECT
updatesector NODEPOSX NODEPOSY NODESECT
getsector[NODESECT].floorz NODEPOSZ
subvar NODEPOSZ 6144

cansee ASTARPOSX ASTARPOSY ASTARPOSZ ASTARSECT NODEPOSX NODEPOSY NODEPOSZ NODESECT ASTARCANSEE


I need to validate line-of-sight between 2 points, is there a less expensive method than this?

I don't have concise examples of using "setarray" and "setvarvar" for pulling values from an array, but suffice it to say that 2 separate arrays have their values checked and/or set potentially thousands of times during each loop. I know that this sucks, and I try to use a reference to the array value (rather than comparing it directly, IE ifvarvarl VAR ARRAY[INDEX]), but I am not sure I can improve things further. How much of a CPU hit could this be causing?
0

User is offline   Danukem 

  • Duke Plus Developer

#2616

View PostReaper_Man, on 10 December 2020 - 09:33 AM, said:

I'm trying to improve performance on my A* pathfinding, and I'm trying to identify which operations are very "expensive" that I should avoid or limit my usage of. I am calling these potentially thousands of times for every enemy on a given frame.


Those calculations aren't super expensive but you are sure doing them a lot. It sounds like you are making your actors re-evauluate the path every single tic, which is excessive in my opinion. You can give each actor an interval and then have them do it every 10 tics or so. Stagger it so that only certain actors are doing it on certain tics (for example you could use the actors sprite ID to offset player_par and then mod 10 on the result to determine when to calcaulte). A lag of up to 10 tics on their reaction speed to changes in the maze won't be very noticeable but will reduce the calculations per second by nearly 90%
0

User is offline   Salvation 

#2617

A noobish question - i just can't figure this one out:

I would like to increase chaingun rate of fire by decreasing it's TOTALTIME. Like this:

gamevar WEAPON3_TOTALTIME 6 0

Original TOTALTIME was 12

After inserting this it wont display anymore chaingun firing tiles (the firing tiles contained cool muzzle blast) and it only "shakes" when shooting. Only main tile, which is nr 2537 appears but firing tiles 2538, 2539 and 2540 does not.

Any simple ideas how to fix this?
0

User is offline   Danukem 

  • Duke Plus Developer

#2618

The chaingun fires multiple times during the 12 tics and animates, so simply cutting that in half is not the right approach. Leave TOTALTIME alone, and instead try changing the weapon's flags:

gamevar WEAPON3_FLAGS 73820 0

That will add the "fire every other" flag which I think should make it fire on almost every tic now (because it also has the fire on every third flag). You could also try removing the fire on every third flag and just have fire on every other which would give you flags 73804

But it's been a while since I messed with it so I could be mistaken about how these flags will affect things -- it's not always straightforward. These days I code the animation so I can change things more drastically.
0

User is offline   Reaper_Man 

  • Once and Future King

#2619

View PostDanukem, on 10 December 2020 - 11:27 AM, said:

Those calculations aren't super expensive but you are sure doing them a lot. It sounds like you are making your actors re-evauluate the path every single tic, which is excessive in my opinion. You can give each actor an interval and then have them do it every 10 tics or so. Stagger it so that only certain actors are doing it on certain tics (for example you could use the actors sprite ID to offset player_par and then mod 10 on the result to determine when to calcaulte). A lag of up to 10 tics on their reaction speed to changes in the maze won't be very noticeable but will reduce the calculations per second by nearly 90%


No, the routine only runs basically once every animation cycle. It essentially looks like this:

ifactioncount 5
	resetactioncount
else
ifactioncount 4
{
	state astar
	state facetarget

	action A_ASTAR
	move M_ASTAR geth getv
	break
}


The reason there's so many calls is because of how the navigation nodes are built, which is basically just valid points on the grid. So if a hypothetical map takes up a 32768 x 32768 square, and if the nodes are built at 512 intervals, that's still 4096 potentially valid points. It's also possible that some points are evaluated multiple times by looking at a node's neighbors, so 4096 is actually the best case scenario because it assumes essentially a straight unobstructed line from corner to corner. Theoretically this count could go up to 28,672 in very bad scenarios, where nearly every node is re-evaluted for each of it's neighbors. (Of course the real-world execution will be much lower, outside of particularly bad maze-y designs, but I digress.)

Decreasing the navigation node density obviously improves things (512 to 768 for example), but then it becomes less useful in areas with tight navigation. It is possible to have areas of varying node density, but that is outside the scope of solving the core algorithm performance.

I've found a way to reduce the sqrt calls for checking distance, but they are still called up to 8 times per each neighbor, and the nature of the algorithm requires the rest of the culprits are all called if the distance check succeeds.
0

User is offline   Danukem 

  • Duke Plus Developer

#2620

Ok, so it's not done the way I suspected, but it still seems to me that you could break up the workload and spread it over time more. EDIT: Also you have your nodes very close together if I understand correctly. This could also create a potential for too many sprites in the map, once you get a big map with a log ot effects going on.

EDIT2: I'm guessing you are spawning in the nodes via code, which would explain why you have them so dense. If you hand place them in maps you can reduce the density a lot. That does mean that maps have to be hand edited to use the system but otherwise you need some very smart code for analyzing the map structure and placing nodes with the minimal density required in a particular area of a map.

This post has been edited by Danukem: 10 December 2020 - 02:11 PM

0

User is offline   Reaper_Man 

  • Once and Future King

#2621

View PostDanukem, on 10 December 2020 - 01:51 PM, said:

Ok, so it's not done the way I suspected, but it still seems to me that you could break up the workload and spread it over time more. EDIT: Also you have your nodes very close together if I understand correctly. This could also create a potential for too many sprites in the map, once you get a big map with a log ot effects going on.

EDIT2: I'm guessing you are spawning in the nodes via code, which would explain why you have them so dense. If you hand place them in maps you can reduce the density a lot. That does mean that maps have to be hand edited to use the system but otherwise you need some very smart code for analyzing the map structure and placing nodes with the minimal density required in a particular area of a map.

To clarify, the nodes aren't actors, they are X and Y positions recorded in an array. The system actually doesn't spawn anything, which is why dist / ldist aren't useful and I have to use sqrt to do the distance calculation manually. This is also why manually placing waypoints isn't a viable solution. As I mentioned I do have some actors that can generate nodes in the X/Y arrays with a variable density in their vicinity, but that's more for things like doorways and other tight areas where mappers need granular control, rather than manually creating a navigation mesh for the entire map.
0

User is offline   Danukem 

  • Duke Plus Developer

#2622

That sounds good. Well, I don't have anything to contribute as far as optimizing the calculations. In my experiences with dealing with similar problems in CON, my guess is that fiddling with the code that does the calculations will only give you micro-optimizations and most of your gains will come from reducing the number of (virtual) nodes and/or spacing out the workload more.
1

User is offline   Reaper_Man 

  • Once and Future King

#2623

View PostDanukem, on 10 December 2020 - 03:03 PM, said:

That sounds good. Well, I don't have anything to contribute as far as optimizing the calculations. In my experiences with dealing with similar problems in CON, my guess is that fiddling with the code that does the calculations will only give you micro-optimizations and most of your gains will come from reducing the number of (virtual) nodes and/or spacing out the workload more.

Right, I feel like I'm probably up against the wall with what I can do from CON. I can do away with the sqrt calls and use a more simplistic distance guesstimate, but it's the cansee calls I worry are the culprit. I don't know how updatesector works under the hood, and if I'm going overkill to validate the X/Y positions.

Thanks for your input as always, Dan!
0

User is offline   Reaper_Man 

  • Once and Future King

#2624

For anyone who comes across this later, I wound up using a square root approximation, which works because my node points are on a grid.

// Search distance 1.5 times node graph size, cheap method of accounting for diagonal distance
setvarvar ASTARMAXDIST NODEGRAPHSIZE
mulvar ASTARMAXDIST 15
divvar ASTARMAXDIST 10

// Estimated square root distance for diagonal movement
setvarvar ASTARSQRT NODEGRAPHSIZE
mulvar ASTARSQRT 1414
divvar ASTARSQRT 1000

[ . . .]

// ASTARPOSX/Y and NODEPOSX/Y are the X/Y position of the start and end points, respectively
setvarvar ASTARDELTAX ASTARPOSX
setvarvar ASTARDELTAY ASTARPOSY

subvarvar ASTARDELTAX NODEPOSX
abs ASTARDELTAX

subvarvar ASTARDELTAY NODEPOSY
abs ASTARDELTAY

// If node within range
ifvarvarl ASTARDELTAX ASTARMAXDIST
	ifvarvarl ASTARDELTAY ASTARMAXDIST
{
	// Cheap square root approximation
	ifvare ASTARDELTAX 0
		setvarvar ASTARDISTANCE NODEGRAPHSIZE
	else
	ifvare ASTARDELTAY 0
		setvarvar ASTARDISTANCE NODEGRAPHSIZE
	else
		setvarvar ASTARDISTANCE ASTARSQRT


In this specific case, NODEGRAPHSIZE is 700 units, so ASTARMAXDIST becomes 1050 and ASTARSQRT becomes 989. Subtracting the start X or Y position from the ending X or Y position gives you the distance on one axis, and if both are less than the ASTARMAXDIST, then that means the distance is either going to be 700 or 989.

Anyway, my next question:

I am using several for loops, but often run into cases where I can/should exit out of them early. Is it possible to end a for loop early? The wiki makes it seem like you can't, and "break" doesn't seem to do anything either. Should I use while loops instead of for loops for cases where I know I will need to break them early? Is it faster to use a while loop in situations where I might break out of early, and for loops where I know I will need to iterate through every item?

This post has been edited by Reaper_Man: 12 December 2020 - 07:17 PM

0

User is offline   jimbob 

#2625

If i understand your idea, it scans for valid player spaces every X and decides that is a valid point for the actor to move in, in order to speed up efficiëncy is there something like a pre-calculated mesh of nodes? In certain older games you could 'render' pathfinding and it would create a waypoint system, and would calculate movement off of that instead of doing it realtime, wich sounds much more CPU efficiënt than checking the entire build grid every X.
0

User is offline   Reaper_Man 

  • Once and Future King

#2626

View Postjimbob, on 13 December 2020 - 11:33 AM, said:

If i understand your idea, it scans for valid player spaces every X and decides that is a valid point for the actor to move in, in order to speed up efficiëncy is there something like a pre-calculated mesh of nodes? In certain older games you could 'render' pathfinding and it would create a waypoint system, and would calculate movement off of that instead of doing it realtime, wich sounds much more CPU efficiënt than checking the entire build grid every X.

Yes, the node graph is precalculated only once at map load, and I have a system to store and load the node graph on the disk and use that instead of generating it every map load, to speed things up further. But the node generation isn't a bottleneck, it's the various checks and iterations through the node graph. Consider a map that is 65536 units square, and the node graph density is 700 units, or 94 grid points per axis. That creates an array of only 8800 items. Searching through 8800 items is pretty fast. Searching for 8800 items 8799 separate times - or 77 million searches - is what is slow. Reducing that number, and reducing any other expensive calls within each of those iterations, is the goal.

The square root approximation method here works because every point is on a grid. Neighboring nodes are either straight or diagonal, and the distance is precalculated using the square root approximation for the diagonal points. Using the sqrt function isn't necessary because the distance is only ever going to be one length or the other.

I've been playing around with multiple search densities and I think I've come up with a system that balances speed/performance and search accuracy. It does 2 searches - a coarse grid search to find the nearest point, and then a fine local search to the nearest point. Think of this as searching for the path based on rooms and hallways, and then a second search to navigate the room you're in to get to the doorway. This cuts down the hypothetical 77 million searches down to only a few thousand.
0

User is offline   Sangman 

#2627

View PostReaper_Man, on 12 December 2020 - 05:55 PM, said:

I am using several for loops, but often run into cases where I can/should exit out of them early. Is it possible to end a for loop early? The wiki makes it seem like you can't, and "break" doesn't seem to do anything either. Should I use while loops instead of for loops for cases where I know I will need to break them early? Is it faster to use a while loop in situations where I might break out of early, and for loops where I know I will need to iterate through every item?


In situations where a while loop isn't appropriate I use a control variable that I set to a certain value, and only execute the code in the loop if the variable is not set to that value... Not quite the same as breaking the for loop but it works :P

eg

set variable -1

for yadda yadda
{
      ifn variable 1
     {
           // some code that sets variable to 1
     }
}


View PostDanukem, on 10 December 2020 - 03:03 PM, said:

most of your gains will come from reducing the number of (virtual) nodes and/or spacing out the workload more.


Yup, I had a similar situation a while ago and I spread the workload out by giving each actor a random chance to execute its code depending on a tic count (that I reset back to 0 after calculating). Like first 30 tics have a 10% chance of calculating, next 30 have a 20% chance etc until finally at 120 tics the calculation is forced.

You could also account for player distance/visibility.. An easy performance improvement is to restrict the amount of times calculations are run against/by things that the player can't see.

But I don't know how compatible all of that would be with the A* stuff.

This post has been edited by Sangman: 13 December 2020 - 04:01 PM

0

User is offline   Reaper_Man 

  • Once and Future King

#2628

View PostSangman, on 13 December 2020 - 03:53 PM, said:

In situations where a while loop isn't appropriate I use a control variable that I set to a certain value, and only execute the code in the loop if the variable is not set to that value... Not quite the same as breaking the for loop but it works :P

eg

Spoiler


Thanks. I was doing basically this as well. I decided to swap them out for while loops, since I wanted to remove as many loop iterations as possible when possible. Even if the for loop is doing nothing, it's still using a non-zero amount of CPU time. Each node only has 8 neighbors, so after all 8 neighbors have been found, I know I can safely exit the loop. Under normal, sane conditions this wouldn't matter, but when I'm trying to reduce hundreds of thousands of total iterations on a given game tic, every CPU cycle counts.

View PostSangman, on 13 December 2020 - 03:53 PM, said:

Yup, I had a similar situation a while ago and I spread the workload out by giving each actor a random chance to execute its code depending on a tic count (that I reset back to 0 after calculating). Like first 30 tics have a 10% chance of calculating, next 30 have a 20% chance etc until finally at 120 tics the calculation is forced.

You could also account for player distance/visibility.. An easy performance improvement is to restrict the amount of times calculations are run against/by things that the player can't see.

But I don't know how compatible all of that would be with the A* stuff.

The A* system is locked to a single actor each tic, partially for performance reasons, but also because gamearrays are global only and actors can't share the path data that is stored in the arrays. Also as mentioned previously, they aren't trying to run A* on every single tic, they only do it once every "occasionally", and they store their path data locally as well to reduce the number of calls they need to make to the expensive A* functions.

There's also a lot of other AI considerations and A* is just one part of their overall behavior - an AI doesn't need to pathfind if they have direct line-of-sight with the player, for example. It's not a magic bullet, it's just one tool in the toolbox, and is meant to replace any instance of "seekplayer" to keep them from getting stuck in rooms or running into walls and sprites more than anything else.

So anyway, after working on this the past few days, I've been able to drastically improve the performance of the search. I've cut the number of iterations down from 500k to 11k, and the number of expensive operations down from 258k to just over 1000. There's still some minor things I want to try and improve, and of course there's lots of real-world testing that needs to be done, but I think I've found just about all of the shortcuts that can reasonably be found. Thank you everyone for the feedback and suggestions!

This post has been edited by Reaper_Man: 13 December 2020 - 06:15 PM

0

User is offline   Reaper_Man 

  • Once and Future King

#2629

Not sure where else to post this, but wanted to share some findings of mine digging into AI and pathfinding.

You can theoretically hack "seekplayer" to navigate towards any other actor, due to how it interacts with HoloDuke. From VM_AlterAng:

int const spriteAngle    = vm.pSprite->ang;
int const holoDukeSprite = vm.pPlayer->holoduke_on;

// NOTE: looks like 'owner' is set to target sprite ID...

vm.pSprite->owner = (holoDukeSprite >= 0
					 && cansee(sprite[holoDukeSprite].x, sprite[holoDukeSprite].y, sprite[holoDukeSprite].z, sprite[holoDukeSprite].sectnum,
							   vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum))
  ? holoDukeSprite
  : vm.pPlayer->i;

int const goalAng = (sprite[vm.pSprite->owner].picnum == APLAYER)
		  ? getangle(vm.pActor->lastv.x - vm.pSprite->x, vm.pActor->lastv.y - vm.pSprite->y)
		  : getangle(sprite[vm.pSprite->owner].x - vm.pSprite->x, sprite[vm.pSprite->owner].y - vm.pSprite->y);

This bit of code sets goalAng to the angle to face the target, where the target is either the player or the HoloDuke, specifically the actor stored on "holoduke_on" player member. Meaning you can do this:

// holoduke_on resets to -1 when holoduke_amount hits 0, so always keep the holoduke_amount at full
setplayer[THISACTOR].holoduke_amount 2400

ifaction 0
{
	findnearsprite 100 32768 ACTOR_TARGET
	
	ifvare ACTOR_TARGET -1
		killit

	setplayer[THISACTOR].holoduke_on ACTOR_TARGET

	action A_ACTOR
	move M_ACTOR seekplayer
	break
}


This actor now is using "seekplayer" to seek out something other than the player.

Unfortunately, the catch is the "cansee" check, meaning that this only works if there's already line of sight between the actor calling this and the faked HoloDuke, rendering this mostly useless.
2

User is offline   Reaper_Man 

  • Once and Future King

#2630

Another question I'm sure has a simple answer... How do I draw into widescreen screen space using screentext? By that I mean, how do I properly use screentext (and rotatesprite) to draw an element the full width of the screen, regardless of the aspect ratio?

For example, I have a text element that I want to take up 70% of the screen width. In 4:3 this would be ~716 pixels, but widescreen this would be ~896 pixels. What am I looking for to run that math?

Or a more simple example, I have some HUD icons that I want to appear at the left or right edge of the screen. A value of 0 for x in screentext/rotatesprite will properly draw it at the edge of the screen in 4:3 aspect ratios, but in widescreen it's floating in the middle of the screen (where the edge of the 4:3 space would be).

What am I missing?
0

User is offline   Hendricks266 

  • Weaponized Autism

  #2631

Use orientation flag 1024.
1

User is offline   jimbob 

#2632

How do i set an owner to an actor, basically i want an actor do go through its routine but only if an enemy is nearby and alive, concrete i want an enemy to be alive and closeby a stationary machinegun wich should obvious stop shooting if the enemy has died.
0

User is offline   Danukem 

  • Duke Plus Developer

#2633

That was confusing. I'm not sure if you are asking about the machinegun itself or some other actor. If I was going to code a friendly turret AI but didn't have any of the AI infrastructure that I have added for my mods... I would probably have it loop through statnum 1 sprites of the enemy picnums, then target only ones with .extra > 0 and in line of sight.
0

User is offline   Sangman 

#2634

View PostReaper_Man, on 18 December 2020 - 11:17 AM, said:

Not sure where else to post this, but wanted to share some findings of mine digging into AI and pathfinding.

You can theoretically hack "seekplayer" to navigate towards any other actor, due to how it interacts with HoloDuke. From VM_AlterAng:

int const spriteAngle    = vm.pSprite->ang;
int const holoDukeSprite = vm.pPlayer->holoduke_on;

// NOTE: looks like 'owner' is set to target sprite ID...

vm.pSprite->owner = (holoDukeSprite >= 0
					 && cansee(sprite[holoDukeSprite].x, sprite[holoDukeSprite].y, sprite[holoDukeSprite].z, sprite[holoDukeSprite].sectnum,
							   vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum))
  ? holoDukeSprite
  : vm.pPlayer->i;

int const goalAng = (sprite[vm.pSprite->owner].picnum == APLAYER)
		  ? getangle(vm.pActor->lastv.x - vm.pSprite->x, vm.pActor->lastv.y - vm.pSprite->y)
		  : getangle(sprite[vm.pSprite->owner].x - vm.pSprite->x, sprite[vm.pSprite->owner].y - vm.pSprite->y);

This bit of code sets goalAng to the angle to face the target, where the target is either the player or the HoloDuke, specifically the actor stored on "holoduke_on" player member. Meaning you can do this:

// holoduke_on resets to -1 when holoduke_amount hits 0, so always keep the holoduke_amount at full
setplayer[THISACTOR].holoduke_amount 2400

ifaction 0
{
	findnearsprite 100 32768 ACTOR_TARGET
	
	ifvare ACTOR_TARGET -1
		killit

	setplayer[THISACTOR].holoduke_on ACTOR_TARGET

	action A_ACTOR
	move M_ACTOR seekplayer
	break
}


This actor now is using "seekplayer" to seek out something other than the player.

Unfortunately, the catch is the "cansee" check, meaning that this only works if there's already line of sight between the actor calling this and the faked HoloDuke, rendering this mostly useless.



lol that's cool - but it also sounds like something unintended that's definitely going to break in some future eduke32 version :D
0

User is offline   Danukem 

  • Duke Plus Developer

#2635

View PostSangman, on 20 December 2020 - 03:18 PM, said:

that's definitely going to break in some future eduke32 version :D


Why wait, it's already pre-broken because seekplayer is garbage and the hack also depends on line of sight.
1

User is offline   Reaper_Man 

  • Once and Future King

#2636

I'm actually not sure if it would break in future versions of EDuke, unless how the HoloDuke item works changes. I believe the philosophy for EDuke is to not make changes that affect the gameplay of the original game, even if IMO the fact that the HoloDuke only works with line-of-sight at all seems like a design oversight. It would be one thing if this was a typo or some other human error, but the way it works is pretty clear, even if kinda useless.

View PostDanukem, on 20 December 2020 - 03:23 PM, said:

Why wait, it's already pre-broken because seekplayer is garbage and the hack also depends on line of sight.

seekplayer is garbage. For anyone who has never looked in the source code, all it essentially does is change the angle of the actor by a random value between -128 and +128 degrees to the nearest direction of the target every few tics. That's it. Doom's target search was even more advanced than this, where enemies would walk until they hit a wall, and then trace the walls in the direction nearest the target. This is why Doom's enemies can manage to get themselves out of rooms that Duke's can't. I highly recommend a custom approach for target search when writing your own enemy AI, and use seekplayer only as a worst case fallback.

This post has been edited by Reaper_Man: 20 December 2020 - 06:27 PM

1

User is offline   jimbob 

#2637

View PostDanukem, on 20 December 2020 - 02:48 PM, said:

That was confusing. I'm not sure if you are asking about the machinegun itself or some other actor. If I was going to code a friendly turret AI but didn't have any of the AI infrastructure that I have added for my mods... I would probably have it loop through statnum 1 sprites of the enemy picnums, then target only ones with .extra > 0 and in line of sight.

I have a machinegun, wich is stationary that shoots bursts if the player is close and in its line of sight, but this works on its own and looks silly as a result, so i want an enemy to 'operate' it meaning that the machinegun only fires if the enemy is close and alive. If it was the player i could use ifpdistl and ifpalive or something but afaik there is no such command for enemies.

I could make it into one large sprite and cactor enemy if the machinegun is destroyed but that would make the sprite very large and cause clipping issues
0

User is offline   Sangman 

#2638

In that case you still have to do the loop Dan mentioned but instead use dist or ldist for the distance check. However that will cause the gun to start shooting even if the enemy is in front of it, so you'd also need to account for the proper angle somehow.
0

User is offline   jimbob 

#2639

I can look at the code for the tank actor in the atomic edition and see how they programmed the button on the back of the tank, and use that. Ill look into that loop of danukem and see if i can get that to work
0

User is offline   Mark 

#2640

Wait a minute...After all these years I never knew there was a usable button on the back of a pigtank. :blink:

Make a small sector behind the machine gun and put a stayput version of the enemy in that sector. Then use the findnearactor feature in the gun actor so that if the enemy gets killed first it is no longer found and the gun stops shooting. And if the gun gets "killed" first have that cactor the enemy into the non-stayput version. The only problem is if you need the gun to fire in any direction and not just mostly forward. It would still work but the enemy won't follow the gun direction. Also you would have to tag this enemy somehow different from the rest so they don't all get affected. Maybe a different pal.

This post has been edited by Mark: 21 December 2020 - 06:50 AM

0

Share this topic:


  • 115 Pages +
  • « First
  • 86
  • 87
  • 88
  • 89
  • 90
  • Last »
  • You cannot start a new topic
  • You cannot reply to this topic


All copyrights and trademarks not owned by Voidpoint, LLC are the sole property of their respective owners. Play Ion Fury! ;) © Voidpoint, LLC

Enter your sign in name and password


Sign in options