News:

One Minute Game Review by The Happy Friar: https://ugetube.com/@OneMinteGameReviews
Also on Rumble: https://rumble.com/c/c-1115371

idTech 4 (aka Doom 3 tech) Discord Server! https://discord.gg/9wtCGHa

Main Menu
Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - solarsplace

#1
Hi

Is your ship a single model?

To make the physics work properly so your player or other AI does not end up falling through the model when it moves and or the player jumps when its moving you need to make your ship a func_mover and bind your ship which is now a func_mover but no itself set to move to a controlling bobbing or pendulum which handles the movement ( bobbing ).

I have had sucess with this technique.

Good luck!

Cheers
#2
Hi

No, this is not possible.

The only way to do this is import the model into a suitable modelling program and scale the model and export as a new model.

Have a look at the Kats Bits site for all sorts of modeling tutorials and import / export scripts.

http://www.katsbits.com/tools/

Cheers
#3
Hi

Nothing ready made, but this is the script 'overview' of what I do in the SDK to 'toss' an item.

This should work:

Spawn your moveable item with "nodrop" "1" keyval set.

Set its origin where you want it to be - just in front of player?

Ideally you want to test whether you can spawn a bounding box in front of the player with no collision to make sure you don't spawn into a wall! could be a pain in script! or just do a trace out say 128 units and make sure you don't hit anything before you spawn it.

Then create a vector variable pointing forward of the player.

Then:

// Sets the current linear velocity of this entity in units per second. The linear velocity of
// a physics object is a vector that defines the translation of the center of mass in units per second.
scriptEvent   void    setLinearVelocity( vector velocity );

Have a look in one of the Doom3 AI scripts like 'ai_monster_flying_lostsoul.script' for an example of how to use this.

Sorry not at a comp where I can create a script right now.

Thanks
#4
Hi

Thanks for the feed back, and we are glad you are getting positive results :)

I have passed this on the Nemyax who is the creator of the tool. I think he is going to change the documentation to say only the 2.7+ versions are now supported.

Thanks
#5
Quote from: motorsep on June 19, 2015, 09:07:45 AM
Have you ever adjusted workflow by chance? Last time I recall (when this add-on showed up at KatsBits) the workflow was pretty convoluted and people were complaining.

Hello

With all due respect, it seemed to be just yourself that was complaining ( http://www.katsbits.com/smforum/index.php?topic=404.0 ).

AFAIK the tool has not been updated with an enhanced GUI etc, so your still not going to like it i'm afraid.

Please take any constructive criticism up with the author of the tool.

Thanks
#6
Hi

This is post to let you all know about an update to the Arx End Of Sun - MD5 tool for Blender 2.66+

The tool has now been updated to support both import and export of meshes and animations.

Please find full discussion and download details of the tool here: http://www.katsbits.com/smforum/index.php?topic=520.msg3977#new

Thanks
#7
Hi

I tested the monster in a big empty box map. I spent a good couple of hours on him that I really should have spend on Arx as there is still so much to complete.

I took him from totally broken to now chasing me and shooting me. I did not test what happens if I hide from him, perhaps there is something else broken in their script. I didn't change script logic as such that is all still what they wrote, I just added fixes to get what was already there to function in a rudimentary way.

Did you rebuild a new AAS for the map using his AAS file? you should have a "mapname.aas_mastermind" file of several KB / MB in size?

If you don't have a valid AAS file the AI path-finding and route to player plotting falls back to a less than optimal state.

I probably won't be able to do any further work on this for about a week now.

Can you put sys.print statements in all the methods and see if you can see where it gets stuck?

Thanks

#8
Quote from: BielBdeLuna on June 10, 2015, 01:23:51 PM
for Arx end if Sun how do you guys do the AI?

Hi

In Arx I use basically just the standard Doom3 AI SDK code and scripts for the enemy AI. I have fiddled with the code and scripts in many places for game specific tweaks, but its basically working just like standard. I have spent many hours working with the AI scripts and they are a bloody nightmare!

However for friendly AI that can help the player attack the monster AI - I use a highly modified version of Ivan The B's "Smart AI" code / mod ( Can't find a download :( - http://planetdoom.gamespy.com/View993a.html?view=POTD.Detail&id=616 ).

Smart AI really is very awesome :) - I will PM Ivan tomorrow and hope he can provide a new download link...

Hope that answered the question.

Thanks
#9
id Tech 4 Scripting / Re: GPL AI
June 10, 2015, 12:31:27 PM
Quote from: motorsep on June 10, 2015, 12:13:09 PM
Quote from: solarsplace on October 17, 2014, 09:40:01 AM
The origin bone should remain stationary for the flying monsters. Their speed is controlled by parameters such as "fly_speed" and the code moves them based on this speed rather than by animation.

It doesn't - any moving monster has to have moving origin bone. Load up Cacodemon into Blender and see the animation - origin bone moves with any linear motion.

Hi

Perhaps there is more to the flying monster type then, as I have monster fish in Arx that are "MOVETYPE_FLY" and their origin position remains permanently rooted to 0,0,0 and they zoom around the map with no problems!

Perhaps the "fly_speed" is a speed in addition to the translation of the animation... I will have a look if I remember later... I notice actually that the Cacodemon does indeed translate and also does some funky bobbing about and tentacle wafting in the process, I suspect the effects are additive.

Cheers
#10
Hi

Not to cast aspersions on the people that made the mod you downloaded, but the Spider Mastermind is broken in that download. It would never have worked. However, I know nothing about that mod, and perhaps they never even stated it was present and working?

Anyway, I fixed it for you :) - I copied the spiders .DEF, .script and MD5 files into a standalone mod and added a reference to the spider's script into the "doom_main.script". I also copied the default aas.def and added the  spiders .aas definition. The sounds seem to work for me too, make sure to copy over the sound shader file and the audio files. Plus you will need to root out the material files, textures, particles etc.

Anyway here are the fixes so you don't need the rest of that mod to use it apart from all the spider assets.

In "monster_boss_asmodeus.def" change "channel legs" to "channel torso"

I personally find that the Doom3 AI setup is a bloody confusing mess of a system....

Fixed script below. Search for "SOLARSPLACE" to see the changes.

/***********************************************************************

ai_monster_boss_asmodeus.script

monster_boss_spidermastermind

***********************************************************************/

#define ASMODEUS_RANGE_ATTACK_RANGE 3000
#define ASMODEUS_NEXTATTACK_DELAY 3
#define ASMODEUS_NOFOVATTACK_DELAY 3
#define ASMODEUS_NUM_PROJECTILES 70
#define ASMODEUS_ATTACK_RATE .1

// anim blend times
#define ASMODEUS_PAIN_TO_PAIN 7
#define ASMODEUS_PAIN_DELAY 2
#define ASMODEUS_PAIN_TO_IDLE 2
#define ASMODEUS_IDLE_TO_PAIN 2
#define ASMODEUS_SIGHT_TO_SIGHT 3
#define ASMODEUS_SIGHT_TO_IDLE 2
#define ASMODEUS_BLAST_TO_IDLE 3
#define ASMODEUS_IDLE_TO_BLAST 3
#define ASMODEUS_WALK_TO_IDLE 3
#define ASMODEUS_IDLE_TO_WALK 1
#define ASMODEUS_RANGE_TO_IDLE 1
#define ASMODEUS_IDLE_TO_RANGE 3
#define ASMODEUS_BLAST_DELAY 3.5

//SOLARSPLACE - Changed all ANIMCHANNEL_LEGS to ANIMCHANNEL_TORSO

//SOLARSPLACE
#define RIGHT_ANGLE 90.0

object monster_boss_asmodeus : monster_base {
float nextAttack;
float nextBlast;
float nextNoFOVAttack;
entity combat_node;
entity blast_entity;
float nextpain;

//SOLARSPLACE - Changed Legs_ to Torso_
void Torso_RangeAttack();
void Torso_Walk();
void Torso_Idle();
void Torso_Pain();
void Torso_Sight();
void Torso_Death();

void init();
void state_Begin();
void state_Idle();
void do_attack(float attack_flags);
float check_attacks();
void combat_range();
void combat_blast();
void fire_shot();

//SOLARSPLACE
float arcsinTwo(float sine, float result, float power);
float arcsin(float oppHypRatio);
float removeMe;
};

//SOLARSPLACE
float monster_boss_asmodeus::arcsinTwo(float sine, float result, float power)
{
float higher_result = result + power;
if (result == higher_result)
{   
return result;   
}
 
if ( (higher_result <= RIGHT_ANGLE) && (sys.sin(higher_result) <= sine) )
{
result = higher_result;
}
return arcsinTwo(sine, result, power / 2);
}

//SOLARSPLACE
float monster_boss_asmodeus::arcsin( float oppHypRatio )
{
if (oppHypRatio < 0.0)
{
float a = -1 * arcsinTwo(-oppHypRatio, 0.0, RIGHT_ANGLE);
return a;
}
return arcsinTwo(oppHypRatio, 0.0, RIGHT_ANGLE);
}

/***********************************************************************

animation control

***********************************************************************/

void monster_boss_asmodeus::Torso_Sight() {
playAnim( ANIMCHANNEL_TORSO, "sight" );

while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_SIGHT_TO_SIGHT ) ) {
waitFrame();
}

//SOLARSPLACE
finishAction( "sight" );

animState( ANIMCHANNEL_TORSO, "Torso_Idle", ASMODEUS_SIGHT_TO_IDLE );
}

void monster_boss_asmodeus::Torso_Idle() {
idleAnim( ANIMCHANNEL_TORSO, "idle" );

eachFrame {
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_TORSO, "Torso_Walk", ASMODEUS_IDLE_TO_WALK );
}
}
}

void monster_boss_asmodeus::Torso_Pain() {
float currenttime;

stopSound( 1, 1 );
currenttime = sys.getTime();

if ( currenttime > nextpain ) {
playAnim( ANIMCHANNEL_TORSO, "pain" );
nextpain = sys.getTime() + ASMODEUS_PAIN_TO_PAIN;
while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_PAIN_DELAY ) ) {
waitFrame();
}
animState( ANIMCHANNEL_TORSO, "Torso_Idle", ASMODEUS_PAIN_TO_IDLE );
}
}

void monster_boss_asmodeus::Torso_RangeAttack() {
playAnim( ANIMCHANNEL_TORSO, "ranged_attack" );

while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_RANGE_TO_IDLE ) ) {
waitFrame();
}

//SOLARSPLACE
finishAction( "range_attack" );

animState( ANIMCHANNEL_TORSO, "Torso_Idle", ASMODEUS_RANGE_TO_IDLE );
}

void monster_boss_asmodeus::Torso_Walk() {
playAnim( ANIMCHANNEL_TORSO, "walk" );
startSound( "snd_walk", 1, 1 );

while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_WALK_TO_IDLE ) ) {
waitFrame();
}

animState( ANIMCHANNEL_TORSO, "Torso_Idle", ASMODEUS_WALK_TO_IDLE );
}

void monster_boss_asmodeus::Torso_Death() {
playAnim( ANIMCHANNEL_TORSO, "death" );

while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_WALK_TO_IDLE ) ) {
waitFrame();
}
}

/***********************************************************************

AI

***********************************************************************/


/*
=====================
monster_boss_asmodeus::state_Dead
=====================
*/
void monster_boss_asmodeus::state_Dead() {
becomeNonSolid();
clearEnemy();

playAnim( ANIMCHANNEL_TORSO, "death" );
sys.wait(7);

remove();
}

/*
=====================
monster_boss_asmodeus::init
=====================
*/
void monster_boss_asmodeus::init() {
setSmokeVisibility( 0, 0 );
nextpain = 0;
nextBlast = 0;
nextAttack = 0;

setState( "state_Begin" );
}

/*
=====================
monster_boss_asmodeus::state_Begin
=====================
*/
void monster_boss_asmodeus::state_Begin() {
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
monster_begin();
setMoveType( MOVETYPE_ANIM );
setState( "state_Idle" );
}

/************************

Combat

************************/

/*
=====================
monster_boss_asmodeus::state_Idle
=====================
*/
void monster_boss_asmodeus::state_Idle() {

//SOLARSPLACE
/*
if (stayOnMission) {
if (!attackMission) {
m_mission = getMission();

if ( m_mission ) {
m_mission_vec = m_mission.getOrigin();
faceEntity( m_mission );
if ( testMoveToPosition( m_mission_vec ) ) {
moveToPosition( m_mission_vec );
waitMove();
}
}
}
} else {
*/
wait_for_enemy();
//}

nextAttack = 0;

setState( "state_Combat" );
}

/*
=====================
monster_boss_asmodeus::do_attack
=====================
*/
void monster_boss_asmodeus::do_attack( float attack_flags ) {
nextNoFOVAttack = sys.getTime() + ASMODEUS_NOFOVATTACK_DELAY;
if ( attack_flags & ATTACK_MISSILE ) {
combat_range();
} else if ( attack_flags & ATTACK_MELEE ) {
combat_blast();
} else if ( attack_flags & ATTACK_COMBAT_NODE ) {
combat_ainode( combat_node );
}
}

/*
=====================
monster_boss_asmodeus::check_attacks
=====================
*/
float monster_boss_asmodeus::check_attacks() {
float currentTime;
float attack_flags;
vector org;

attack_flags = 0;
currentTime = sys.getTime();

org = getOrigin();
blast_entity = findActorsInBounds( org + '-295 -295 0', org + '295 295 295' );
if ( blast_entity ) {
if(  sys.getTime() > nextBlast ) {
attack_flags |= ATTACK_MELEE;
}
}

if ( !blast_entity ) {
combat_node = getCombatNode();
if ( combat_node ) {
attack_flags |= ATTACK_COMBAT_NODE;
}
}

if ( ( ( sys.getTime() > nextNoFOVAttack ) && AI_ENEMY_VISIBLE ) || AI_ENEMY_IN_FOV ) {
if ( !canReachEnemy() || ( currentTime >= nextAttack ) ) {
if ( canHitEnemyFromJoint( "Turret" ) ) {
attack_flags |= ATTACK_MISSILE;
}
}
}

if ( AI_PAIN ) {
animState( ANIMCHANNEL_TORSO, "Torso_Pain", ASMODEUS_IDLE_TO_PAIN );
}

return attack_flags;
}

/*
=====================
monster_boss_asmodeus::combat_blast
=====================
*/
void monster_boss_asmodeus::combat_blast() {

startFx( getKey( "blast_fx" ) );
sys.radiusDamage( getOrigin(), self, self, self, "blastWave", 1.0 );

nextBlast = sys.getTime() + ASMODEUS_BLAST_DELAY;
}

/*
=====================
monster_boss_asmodeus::combat_range
=====================
*/
void monster_boss_asmodeus::combat_range() {

stopSound( 1, 1 );
fire_shot();

while( !animDone( ANIMCHANNEL_TORSO, ASMODEUS_RANGE_TO_IDLE ) ) {
waitFrame();
}

nextAttack = sys.getTime() + ASMODEUS_NEXTATTACK_DELAY;
nextNoFOVAttack = sys.getTime() + ASMODEUS_NOFOVATTACK_DELAY;
animState( ANIMCHANNEL_TORSO, "Torso_Idle", ASMODEUS_RANGE_TO_IDLE );
}

/*
=====================
monster_boss_asmodeus::fire_shot
=====================
*/
void monster_boss_asmodeus::fire_shot() {
vector orgOne;
vector orgTwo;
float turretJoint;
vector ang;
float x;
entity enemy;
vector enemyPos;
float spread;
float directAccuracy;
float hypotenuse;
float opposite;

turretJoint = getJointHandle( "Turret" );
spread = getIntKey( "spread" );
directAccuracy = getIntKey( "direct_accuracy" );

startSound( "snd_attack", 1, 1 );
setSmokeVisibility( 0, 1 );

for ( x = 0; x < ASMODEUS_NUM_PROJECTILES; x++ ) {
enemy = getEnemy();
orgOne = getOrigin();
if( !canHitEnemyFromJoint( "Turret" ) ) {
break;
}

if( AI_ENEMY_DEAD ) {
break;
}

blast_entity = findActorsInBounds( orgOne + '-295 -295 0', orgOne + '295 295 295' );
if ( blast_entity ) {
if(  sys.getTime() > nextBlast ) {
combat_blast();
}
}

faceEnemy();
orgTwo = getJointPos( turretJoint );
ang = getAngles();

playAnim( ANIMCHANNEL_TORSO, "ranged_attack" );
startFx( getKey( "gunLight" ) );

if( sys.random( spread ) <= spread/directAccuracy ) {
directDamage( enemy, "damage_asmodeus_bullet" );
} else {
if ( int( sys.random( 2 ) ) + 1 == 1 ) {
ang_y -= sys.random( spread );
} else {
ang_y += sys.random( spread );
}

enemyPos = enemy.getJointPos( getJointHandle( "Body" ) );

opposite = enemyRange2D();
hypotenuse = sys.sqrt( enemyRange2D()*enemyRange2D() + (orgTwo_z - enemyPos_z)*(orgTwo_z - enemyPos_z) );

if( hypotenuse == 0 ) {
break;
}

if( orgTwo_z > enemyPos_z ) {
ang_x = 90 - arcsin( opposite/hypotenuse );
} else {
ang_x = arcsin( opposite/hypotenuse ) - 90;
}

launchMissile( orgTwo, ang );
}
sys.wait( ASMODEUS_ATTACK_RATE );
}
stopSound( 1, 1 );
setSmokeVisibility( 0, 0 );
}
#11
Hi

Try this... I can't test it as at work ATM, but it should work. That monster only uses 1 animation channel 'channel legs ( *origin )' so don't try to play animations on torso or its going to fail.

In the AI script file:

About line 41 add:

void Torso_Idle();

About line 80 add:

void monster_boss_asmodeus::Torso_Idle() {
idleAnim( ANIMCHANNEL_LEGS, "idle" );

eachFrame {
if ( AI_FORWARD ) {
animState( ANIMCHANNEL_LEGS, "Legs_Walk", ASMODEUS_IDLE_TO_WALK );
}
}
}


You may well find that there are further errors as the script gets past various points, but they can be tackled one at a time...

Cheers
#12
Hi

An idea to potentially save you lots of time could be to use Ivan_the_B's Smart AI mod: http://planetdoom.gamespy.com/View993a.html?view=POTD.Detail&id=616

The Smart AI mod lets you have one or more friendly AI squad mates to fight along side you. All the work you need is already done. They have follow and wait modes and their own set of special path entities to let you configure special behaviors for them.

Trouble is, I can't find a download for it online now, and I don't have the original source, only a highly modified version incorporated into the Arx code that would not work for you.

Perhaps you could PM Ivan and see if he could re-up or send you the files? - http://idtechforums.fuzzylogicinc.com/index.php?action=profile;u=91

Cheers
#13
id Tech 4 Scripting / Re: Tutorial: FX System
June 05, 2015, 11:09:49 AM
Quote from: motorsep on June 05, 2015, 10:52:20 AM
Why couldn't you bind particle emitter and light to the hand right in the Radiant ?

Hi

You can bind an entity to another entity relative to the parents origin in the map editor, but that will not help VG have a particle effect glued to his monsters hand thoughout the monsters animations.

I am pretty certain thats what VG is after?

Cheers
#14
id Tech 4 Scripting / Re: Tutorial: FX System
June 05, 2015, 06:25:09 AM
Hi

I here is some code that is working in Arx End Of Sun. It is in the AI script for a Goblin that carries a flaming torch with torch flame particles and a light entity. I decided to do this the old fashioned way with individual script statements rather than a helper function such as startfx so I have greater control to switch the particle off and on when I need to. This will do what you want and it does work.

FYI startfx does work the way you want it to. I know this because I am using it this way elsewhere in my code. It has supporting code in the SDK to automatically bind to joints specified in the .fx file. However, when it does not work, it is hard to debug because there are no discrete steps that you can easily trace through. This is why I am showing you the method below.

What you must always do with things like this, is to break them down into small discrete solvable and provable steps otherwise you have several systems at work and potentially each has a problem and you keep changing things in thing all over the place in the hope of stumbling upon the fix.

#1 find a stock Doom3 particle that runs for a long time. Check this in your map in a func_emitter to prove that it does work and run for a good length of time. Do not proceed until you have proven your test particle works.

#2 Put a light with your light shader you want to use into a map and make sure the light works.  Do not proceed until you have proven your test particle works.

#3 Please open the xyz.md5mesh file for your Barron monster, make absolutely sure you have the joint name 100% correct "rhand" and put it into the "lampBone" variable in the script below. If you got the wrong joint name then it will absolutely not track the AI position.

#4 Put your light shader in the script below in the place of "lights/arx_flame_torch4"

#5 Put the script below into the init() section of your AI before any other commands - just for now. Move it later if you want / need to.

#6 Don't be scared to put in loads of sys.print statements in the scripts to help test your AI

Good luck

entity torchFlames;
entity torchLight;

string lampBone = "torch_tip";
vector lightOrigin;

// Flames
sys.setSpawnArg( "model", "arx_fire_torch.prt" );
torchFlames = sys.spawn( "func_emitter" );
torchFlames.setOrigin( self.getJointPos( self.getJointHandle( lampBone ) ) );
torchFlames.bindToJoint( self, lampBone, 0 );

// Light
sys.setSpawnArg( "_color", "1 0.84 0.44" );
sys.setSpawnArg( "falloff", "0" );
sys.setSpawnArg( "light_radius", "146 146 224" );
sys.setSpawnArg( "nodiffuse", "0" );
sys.setSpawnArg( "noshadows", "0" );
sys.setSpawnArg( "nospecular", "0" );
sys.setSpawnArg( "texture", "lights/arx_flame_torch4" );
torchLight = sys.spawn( "light" );
lightOrigin = self.getJointPos( self.getJointHandle( lampBone ) );
lightOrigin_z = lightOrigin_z + 6; // Solarsplace - Need to get the light outside the torch mesh.
torchLight.setOrigin( lightOrigin );
torchLight.bindToJoint( self, lampBone, 0 );
#15
id Tech 4 Scripting / Re: Tutorial: FX System
June 01, 2015, 09:15:03 AM
Hi

I think the game code / syntax is case sensitive. Not at a suitable comp to check right now. But your code is not the same case as what is in the code.

if ( !token.Icmp( "fadeIn" ) ) {
FXAction.fadeInTime = src.ParseFloat();
continue;
}


Look here ( http://www.iddevnet.com/doom3/fx.php ) and copy / paste the "FX decl keywords" in place of yours to make sure they are 100% correct.

Give that a try, the rest looks ok from a quick look over.

Cheers