|
Posted by metlslime on 2007/08/08 04:57:56 |
This is a counterpart to the "Mapping Help" thread. If you need help with QuakeC coding, or questions about how to do some engine modification, this is the place for you! We've got a few coders here on the forum and hopefully someone knows the answer. |
|
|
Proximity Mine Help (based Off SoA Prox Launcher Code)
#3526 posted by ranger on 2024/12/30 17:19:16
Basically it's overall working but
the key issues are
it never seems to stick on world (it otherwise behaves properly more or less), and thus the arming and stick sounds never play. Also even if it doesn't stick the arming sound never plays
besides that it properly triggers on enemies, bounces off doors & enemies etc, and works more or less...
I've been working on this for 9+h and can't figure it out!
void() ProximityBomb =
{
local entity head;
local float blowup;
if (vlen(self.spawnmaster.velocity)>0)
{
ProximityGrenadeExplode();
self.think();
return;
}
if (time > self.delay)
{
mine_disarm();
self.think();
return;
}
self.touch = SUB_Null; //new
self.owner = world;
self.takedamage = DAMAGE_YES;
head = findradius(self.origin, PROX_MINE_RADIUS); //sensor radius
blowup = 0;
while (head) //what to look for
{
// Don't detonate on players or other mines
if ((head != self) && (head.health > 0) && (head.flags & (FL_CLIENT|FL_MONSTER)) && (head.classname != self.classname) && (head != self.lastvictim)) //(head.classname != "player"))
{
blowup = 1;
}
traceline(self.origin,head.origin,TRUE,self);
if (trace_fraction != 1.0)
blowup = 0;
if (blowup==1)
{
ProximityGrenadeExplode();
self.nextthink = time + 0.5;
return;
}
head = head.chain;
}
self.nextthink = time + 0.25;
};
#3527 posted by ranger on 2024/12/30 17:19:52
void() ProximityArmed = //new
{
sound(self, CHAN_WEAPON, "weapons/proxarmed.wav", 1, ATTN_NORM);
self.think = ProximityBomb;
self.nextthink = time + 0.25;
};
void() ProximityGrenadeTouch =
{
if (other == self || other == self.owner) //|| other == self.owner
{
sound (self, CHAN_WEAPON, "weapons/proxbounce.wav", 1, ATTN_NORM); // bounce sound
return;
}
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
// Don't collide with other mines
if (other.classname == self.classname)
{
sound (self, CHAN_WEAPON, "weapons/proxbounce.wav", 1, ATTN_NORM); // bounce sound
self.movetype = MOVETYPE_BOUNCE; // Add this line
return;
}
// Check if it's a brush entity (like doors)
if (other.movetype == MOVETYPE_PUSH) //|| other.solid == SOLID_BSP
{
sound(self, CHAN_WEAPON, "weapons/proxbounce.wav", 1, ATTN_NORM); // bounce sound
self.movetype = MOVETYPE_BOUNCE; // Add this line
return;
}
if (other.flags & FL_CLIENT) //user disarm mine
{
//self.solid = SOLID_NOT;
mine_disarm();
//remove(self);
return;
}
if ((other.takedamage == DAMAGE_AIM || other.solid == SOLID_TRIGGER || other.flags & FL_MONSTER )) //don't det on monsters || other.flags & FL_CLIENT
{
sound(self, CHAN_WEAPON, "weapons/proxbounce.wav", 1, ATTN_NORM);
//self.movetype = MOVETYPE_BOUNCE;
T_Damage(other, self, self.owner, 1);
//self.think();
return;
}
self.movetype = MOVETYPE_TOSS;
if (self.state == 1)
return;
if (vlen(other.velocity) > 0)
{
ProximityGrenadeExplode();
self.think();
return;
}
else
{
sound (self, CHAN_WEAPON, "weapons/proxstick.wav", 1, ATTN_NORM); // bounce sound
self.movetype = MOVETYPE_NONE;
setsize (self, '-5 -5 -5', '5 5 5');
self.state = 1;
self.spawnmaster = other;
self.velocity = '0 0 0';
// Start arming sequence
self.think = ProximityArmed;
self.nextthink = time + 2;
self.touch = SUB_Null; //new
self.solid = SOLID_NOT; //new
}
};
#3528 posted by ranger on 2024/12/30 17:20:49
void() ThrowProxMine =
{
float x;
// Check if enough time has passed since last throw
if (self.last_mine_time > time - 1.5)
return;
// Check if player has enough ammo
if (self.ammo_rockets2 < 1)
local entity missile; //, mpuff;
self.currentammo = self.ammo_rockets2 = self.ammo_rockets2 - 1;
self.last_mine_time = time; // Update last throw time
sound (self, CHAN_BODY, "zombie/z_shot1.wav", 0.8, ATTN_STATIC);
self.punchangle_x = -2;
missile = spawn ();
missile.owner = self;
missile.lastvictim = self;
missile.movetype = MOVETYPE_TOSS;// MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
missile.classname = "proximity_mine";
missile.takedamage = DAMAGE_YES; //DAMAGE_NO;
missile.health = 2;
missile.state = 0; //not armed
// set missile speed
makevectors (self.v_angle);
if (self.v_angle_x)
missile.velocity = v_forward*400 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
else
{
missile.velocity = aim(self, 10000);
missile.velocity = missile.velocity * 400;
missile.velocity_z = 200;
}
missile.avelocity = '100 400 100';
missile.angles = vectoangles(missile.velocity);
missile.touch = ProximityGrenadeTouch;
// set missile duration
missile.nextthink = time + 2; //min time until mine can explode from enemy
missile.think = ProximityBomb; //arm
missile.th_die = ProximityGrenadeExplode;
missile.delay = time + 90; // time until mine auto disarms
setmodel (missile, "progs/proxmine.mdl");
setorigin (missile, (self.origin) + (v_forward * 0) + (v_right * -17) + '0 0 10');
setsize (missile, '-4 -4 -4', '4 4 4');
};
Debugging
#3529 posted by Preach on 2024/12/31 08:58:58
The difficult part with your ProximityGrenadeTouch function is there are so many return statements which MIGHT end the function, and the bit of code that makes it stick to the wall is at the very end.
I would recommend you add some dprint statements to the function after each "checkpoint" - each place where the function has avoided a branch that contains a return. Then you can check how far execution gets through the function when you throw one against a wall, and deduce which exit is being taken unexpectedly. Two tips
a) pull down the console as soon as the bomb hits a wall for the first time, as you'll get a huge pile of debug messages if you let it bounce all over the shop first
b) remove the debug statements once you have solved the mystery, or they will be a pain in future
I See, Thanks!
#3530 posted by ranger on 2025/01/03 08:49:34
Another issue is... is it possible to dynamically spawn monsters real time via impulse? (like half life's impulse 76)
I tried adding the monster's model precache to void () worldspawn, void () StartFrame , but i keep getting "host error pf precache can only be done in spawn functions?"
StartFrame Timing
#3531 posted by Preach on 2025/01/03 22:41:32
StartFrame runs every frame! If you put a precache in there, you will hit the error for a late precache just about as fast as it's possible to hit it. Stick to worldspawn and you'll have a better time.
But as long as you time the precaches correctly (always on frame 0, and never afterwards), you can spawn monsters dynamically, in essentially the same way as creating a rocket or grenade. One small catch is that you can't update the total_monsters count after the first frame - so your monster kills can go over 100% unless you ensure that dynamically spawned monsters don't count for the kill count.
Another tricky wrinkle to deal with is where to place the monster so that it isn't stuck. Usually that's the responsibility of the mapper! One thing's for sure, you'll have to come up a compromise, and here's the proof: imagine that we make a map that's just a box 8 units larger than the player. It's physically impossible to successfully spawn a monster into that map.
Fixed Precaches
#3532 posted by Preach on 2025/01/03 23:09:11
One other thing to warn you - don't ever randomise your precaches! Imagine you had some plan to randomly select one monster which your impulse spawns for the duration of the map, and you make the selection in frame 0 then precache just the assets for the selected monster. This exposes you to an interesting bug!
The bug arises when you save and load the game. In particular when you load the game, the engine:
1) Runs the first few frames of the map as if you had started from scratch
2) Reads the entity states from the save file and shuffles everything around to match it
The point of 1) is mainly to precache everything again. But second time round you might roll a different number on the random monster table and precache different models. Things may start showing up with the wrong models, or if you are less lucky the whole thing just crashes.
The only way to avoid this problem is to make the precache sequence entirely deterministic. If you're married to the random spawnable monster idea, you might have to precache the models for all the options, even if only one is ever used at a time.
And there are other more subtle ways to hit this error. Imagine you have an entity which you only allow a 50% chance of manifesting, randomised on each map load. Even if you have so many of this entity that one spawns every time, random variation might change the order in which models are first precached, as the first manifestation may occur before or after other fixed entities. Changing the order of precache messes up which models appear after a save is reloaded.
I'm Confused...
#3533 posted by ranger on 2025/01/05 15:27:24
can you give example code?
I keep getting the "host error pf precache can only be done in spawn functions?"
regardless of where I put the monster's precache ?
On A Side Note - For Dynamically Spawned Monster Placement We Can Try
#3534 posted by ranger on 2025/01/05 15:37:00
spawny.origin_x = (0.5 - random())* 2 * 5000; //It's origin is randomized
spawny.origin_y = (0.5 - random())* 2 * 5000;
spawny.origin_z = (0.5 - random())* 2 * 5000;
while((pointcontents(spawny.origin) != CONTENT_EMPTY) && (spawny.aflag < 75))
{
//If the pointcontents of the monster origin is not empty, reset it To a more suitable space. If no space can be found within 75 loops,
//Leave it where it last was placed.
spawny.origin_x = (0.5 - random())* 2 * 5000;
spawny.origin_y = (0.5 - random())* 2 * 5000;
spawny.origin_z = (0.5 - random())* 2 * 5000;
spawny.aflag = spawny.aflag + 1;
}
Jazz Is About All The Notes He's NOT Playing
#3535 posted by Preach on 2025/01/05 20:03:56
The important part is not where you put the precaches, but REMOVING them from everywhere except worldspawn. If you are really struggling, remove all the precaches of the model until you start getting a different error about a resource NOT being precached. Then add one precache to worldspawn and you should be set.
WOW Thanks! It's Almost Fixed!
#3536 posted by ranger on 2025/01/08 08:56:49
I didn't realize it was so simple! weird... i swore i did that before and it didn't work...
Ok so I can spawn the monster now and i can see the monster in front of me for a few sec, but then game crashes with "host error pr execute program null function"
Also
#3537 posted by ranger on 2025/01/08 11:05:33
what controls how high or low a monster can step up/down?
seems they have trouble with stairs & small ledges?
Units
#3538 posted by madfox on 2025/01/08 19:05:20
Best measure is 16 units,might be 15.
In a turnine stair it is better to keep the steplength more than 16, aproxemate 24.
Step Height
#3539 posted by Preach on 2025/01/09 00:46:54
Look up #define STEPSIZE here
https://github.com/id-Software/Quake/blob/master/WinQuake/sv_move.c
The height for climbing a step is applied equally for both players and monsters. But one of the differences is how smoothly the movement is applied. A player moving at 360 units per second on a modern computer would have that movement split up into 72 segments of length 5. Each movement can climb one step, so the player can comfortably manage many steps close together.
In contrast, a monster moving forwards at 360 units per second would move in just 10 segments of 36 units each. And the movement is all or nothing - if the monster would need to climb TWO steps to reach the end point, it will collide with the second step and the entire movement is aborted.
So putting more horizontal spaces between the steps will help a lot. Monsters will also never go off a ledge with drop a of more than 1 step using walkmove or movetogoal - you have to give them velocity movement if you want them to really fall. Be careful, it's easy to turn see that feature turn into an exploit as your monsters can now be lured into pit traps and completely bypassed.
Smoothing
#3540 posted by Preach on 2025/01/09 00:48:56
Another alternative is to split up the navigation into small segments within a frame, for example replacing movetogoal(20) with movetogoal(10); movetogoal(10); It's not always a 1 to 1 equivalence, like with lots of Quake AI it's a thing to experiment with and tune.
Host Error Pr Execute Program Null Function
#3541 posted by Preach on 2025/01/09 00:53:11
This error means that you've forgotten to set something, but the error message doesn't tell you which something it is. Some possibilities are
th_stand - the AI for an idle monster
th_run - the AI for a newly alerted monster
th_pain - the AI for a pain animation
th_die - the AI for a death animation
think - the next function to run after a timer.
To try and diagnose, add this line to the START of your monster spawn function
th_stand = SUB_Null;
If that fixes the error, you know that you've forgotten th_stand - and NOW you need to fix that by giving the monster the AI, this is a diagnostic tool only. If that doesn't help, add another line
th_run = SUB_Null;
Repeat until adding a line avoids the crash, then develop a fix.
Step Height
#3542 posted by ranger on 2025/01/09 06:03:49
soo... you're saying it cannot be changed via mod? it's engine based?
No Change
#3543 posted by Preach on 2025/01/09 09:48:49
Yeah, #define means it's hard-coded when the engine is compiled.
#3544 posted by ranger on 2025/01/09 17:12:05
ok i resolved the null bug - was missing the think/nextthink... i was using custom entity so walk monster start wasn't working
Monster AI (II)
#3545 posted by ranger on 2025/01/09 17:17:54
It's sorta working (thanks for the findNextMonster Preach!) (monsters sometimes attack other faction monsters) but very unreliable - vs the player whom they always attack instantly on sight?
the 2 main issues I'm still trying to solve is:
1 - monsters find a new enemy after killing the current hostile faction monster; (currently they just sit there, even if new enemy monster enters their LOS)
2 - monsters commonly do not fight enemy faction monsters on sight, only sometimes?
so how can i solve these 2? do you need to see my "FindTarget" again? or?
Hint
#3546 posted by Preach on 2025/01/11 00:46:41
Ask yourself this question: why do monsters stop attacking a target when it dies? Unless there's some code that checks whether the target dies, they ought to just continue attacking a dead target in the same way they attack a living one. Your first mission is to find that location.
After that, you need to add some code into that path to make sure that your monsters find an enemy. If you think you already have code there that does so, add some dprint statements to it, to check whether your code is not running, or if it's running but not detecting a viable monster target. Come back with that more precise intel on your problem.
I Figured It Out!
#3547 posted by ranger on 2025/01/11 06:16:37
it's to do with FindTarget in AI.qc and strangely ai_stand(); in the monster animations
FUCK this - man took 5h to fix thru line by line trial & error
makes me wanna stop coding/modding quake forever LOL............
#3548 posted by ranger on 2025/01/11 06:21:27
I am defo NOT a programmer LOL
dunno how you guys can do this professionally as careers
maybe cause i don't got any former training/edu in programming, but i cannot do this "back & forth" debugging for 40h a week, will 100% die lol
Need Help With Flickering Lighting Effects On The QSS Engine
#3549 posted by Andrew on 2025/01/11 07:35:45
Hello everyone!
I have a wonderful modification of "TribalFX" for «QuakeSpasm Spiked» engine. In this modification the author used additional light sources for monsters attack, grenades, rockets, objects, flashlight, etc. Tribal replaced all these effects with standard commands, for example, "EF_MUZZLEFLASH" with the commands "particleeffectnum" and added their description to the file "effectinfo.txt ". But when you turn on the game with a frame rate of more than 72 FPS, there is an unbearable flickering of these additional lighting effects. It's like a strobe light effect.
In early January 2025, @Tribalquake provided me with the source files and I saw that the whole point of the problem was in the file "effectinfo.txt ". I'm not a programmer and at first glance everything looks right. Where can this flicker bug hide depending on the frame rate? All his works are similar to the modification of "AD", but made from scratch.
All files are there, including "effectinfo.txt " and the source files"*.qc". I informed the author about this problem three years ago, but Tribal abandoned it for family reasons.
Can someone help fix this bug? I just don't understand what text command needs to be added to the file "effectinfo.txt " to synchronize with the frame rate of the game.
Here is a link to a video demonstrating this flickering effect (ver.01Ufix). Comparison at frame rates of 72 fps and 144 fps:
https://drive.google.com/file/d/1V8BQy3yWHYezQ98ie8UzX10iqKowQqTo/view?usp=sharing
Here is a link to versions 01T and 01U. They are very different from each other. Wonderful new effects have been added in version 01U, but the flickering of the light spoils everything:
https://drive.google.com/file/d/18wRTcNkRXpQVvrk8-s5WO4GXOiKEIRV5/view?usp=sharing
https://drive.google.com/file/d/1r2MDg_YzPSvBctJvLVP1_243NdJxQH0h/view?usp=sharing
My email: ashalunov1980@gmail.com
QC Code
#3550 posted by Preach on 2025/01/11 09:36:42
To narrow down the search, I took a look at how the flashlight was programmed in client.qc. It turns out that the flashlight uses different effects in the flash_on function between versions U and T.
In version T:
myflash.effects = EF_DIMLIGHT;
In version U:
//myflash.effects = EF_DIMLIGHT;
myflash.traileffectnum = particleeffectnum("flashlight"); //tribal glow
Presumably the fancy effects are not compatible with high frame rates in the engine, and changing back to EF_DIMLIGHT will fix the issue.
|
|
You must be logged in to post in this thread.
|
Website copyright © 2002-2025 John Fitzgibbons. All posts are copyright their respective authors.
|
|