Jump to content

MGummelt

Members
  • Posts

    116
  • Joined

  • Last visited

Profile Information

  • Modding Interests
    Coder
  • Gaming Specialty
    Dueling
    Competitive Play
    Capture the Flag
    Siege
    FFA
    TFFA
    Full Force
    Speedrunning
    Singleplayer
  • Operating System
    Windows

Recent Profile Visitors

1,025 profile views

MGummelt's Achievements

Collaborator

Collaborator (3/10)

  • Very Popular Rare

Recent Badges

  1. Full Video: https://www.twitch.tv/videos/486308187 For those who missed it live!
  2. Full Video: https://www.twitch.tv/videos/486308187 For those who missed it live!
  3. Hey everyone, 3-4 of us original Jedi Outcast developers are going to be on a Twitch livestream with Gamasutra today answering questions about the game. 3PM EST Join us! https://twitter.com/Official_GDC/status/1176884282054168576 https://twitter.com/RavenSoftware/status/1176886571976581120?s=20 https://gamasutra.com/view/news/351066/Chat_with_the_developers_of_Jedi_Knight_II_Jedi_Outcast_at_3PM_EST.php
  4. Hey everyone, 3-4 of us original Jedi Outcast developers are going to be on a Twitch livestream with Gamasutra today answering questions about the game. 3PM EST Join us! https://twitter.com/Official_GDC/status/1176884282054168576 https://twitter.com/RavenSoftware/status/1176886571976581120?s=20 https://gamasutra.com/view/news/351066/Chat_with_the_developers_of_Jedi_Knight_II_Jedi_Outcast_at_3PM_EST.php
  5. Looks like the fix has been submitted to OpenJK. The next build should have it working properly!
  6. Hmm, not sure what that would have done for you - my OpenJK didn't come with any .cfg files.
  7. FYI, the correct cvars to set are: These are cheats, so you need to set helpUsObi to 1 first - best way to do this is in an autoexec.cfg in the base folder (it gets automatically executed). I'm not sure if OpenJK runs autoexec_sp.cfg in SP instead, but if so put these in there instead. This enables cheats:seta helpUsObi 1 The first cvar enables more kinds of dismemberment (0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head)seta g_dismemberment 3 The second one makes the saber do more damage (1) and in all parts of the animation (2)seta g_saberMoreRealistic 2 The third one allows a character to be dismembered more than once - and even when already deadseta debug_subdivision 1 The last one ignores the dismemberment probabilities defined in the NPC ext_data .npc files and just always allows all kinds of dismemberment. 0 = ignore probabilities, 1 = use probabilitiesseta g_dismemberProbabilities 0 Of course, with the bug still in OpenJK, these won't enable super-dismemberment, but once it's fixed, they will.
  8. Totally reviving this thread to say I found the bug in OpenJK that is making dismemberment not work.
  9. That‘s why I showed you the RocketThink() function above. That will point the fighter at the target and chase it, like a homing/tracking rocket. I only showed that function for the math/logic in it. I don’t think you could call that on an NPC as you probably want to set the velocity directly on the NPC, not the pos.trDelta (which is for networked general entities). I would copy that function and make the new one work for vehicle NPCs by storing the resultant velocity in the correct field on the NPC.
  10. fabs() is just a function to turn a negative number into a positive number (f = float, abs = "absolute value). Dif is the difference in height between the top of the enemy and the bottom of me (remember, this was written for NPCs, not vehicles - so this is keeping the height of the flying NPC above the head of the enemy, which it assumes is on the ground - the flying NPCs were never programmed to be able to fight other flying NPCs). The obvious issue, here, is that both of them are trying to fly just above the head of the other, so they both just keep going up and up in a feedback loop. You could make it so that the fighters are just trying to stay at about the same level as each other (same Z-height, within some reasonable tolerance, like +/- 64 units or so). But, really, if they're fighting in 3D space and able to pitch up/down to track their enemy, you shouldn't need this at all. Just angle them towards their enemy and make them chase them. No height matching is needed.
  11. Hmm, I'm not sure what this is, I wasn't a map designer or tech programmer. Are they passing through the "front" side of the patch mesh or the back? Does playerclipping the patch mesh fix it?
  12. Awesome, glad to hear it! Yeah, direct control over velocity is probably best for what you're trying to do. If you want to see an example of how we make objects head to a target using velocity, looking at any homing missile code in Jedi. And example is rocketThink() in g_weapon.cpp. I pasted below, removing some stuff to simplify it to the important parts: //--------------------------------------------------------- void rocketThink( gentity_t *ent ) //--------------------------------------------------------- { vec3_t newdir, targetdir, up={0,0,1}, right; vec3_t org; float dot, dot2; if ( ent->enemy && ent->enemy->inuse ) { >>Here we get the old velocity of the rocket - if it's got spawnflag 1, we use its custom specified speed, otherwise we use the standard constant rocket speed float vel = (ent->spawnflags&1)?ent->speed:ROCKET_VELOCITY; >>This is how much it "homes" or tracks the target - I think we used the "angle" field as a multiplier on how tightly the rocket could turn. float newDirMult = ent->angle?ent->angle*2.0f:1.0f; float oldDirMult = ent->angle?(1.0f-ent->angle)*2.0f:1.0f; >>Important part: >>Get the center of the target - some things have origins at their "feet", not their center VectorCopy( ent->enemy->currentOrigin, org ); org[2] += (ent->enemy->mins[2] + ent->enemy->maxs[2]) * 0.5f; >>This gets the direction from from the current position of the rocket to the target VectorSubtract( org, ent->currentOrigin, targetdir ); >>Turns the full vector above to a direction (normalized to a scale of 1) VectorNormalize( targetdir ); >>Here we need to figure out how much we need to turn from our current direction (ent->movedir) to our desired direction (that we just calculated above) // Now the rocket can't do a 180 in space, so we'll limit the turn to about 45 degrees. dot = DotProduct( targetdir, ent->movedir ); // a dot of 1.0 means right-on-target. >>Dot product is a normalized measure of the difference in angle between two directions - 1.0 is they both are going in the same direction, 0.0 is they're perpendicular, -1.0 means they're opposite directions. >>Here we're checking to see if the target is "behind us" (more then 90 degrees off to the side) if ( dot < 0.0f ) { >>Start turning us around - to the right or left, depending on which side the enemy is on // Go in the direction opposite, start a 180. CrossProduct( ent->movedir, up, right ); dot2 = DotProduct( targetdir, right ); if ( dot2 > 0 ) { // Turn 45 degrees right. VectorMA( ent->movedir, 0.3f*newDirMult, right, newdir ); } else { // Turn 45 degrees left. VectorMA(ent->movedir, -0.3f*newDirMult, right, newdir); } // Yeah we've adjusted horizontally, but let's split the difference vertically, so we kinda try to move towards it. newdir[2] = ( (targetdir[2]*newDirMult) + (ent->movedir[2]*oldDirMult) ) * 0.5; // slowing down coupled with fairly tight turns can lead us to orbit an enemy..looks bad so don't do it! //vel *= 0.5f; } >>These handle if it's more in front of us - turning harder the more in front of us it is else if ( dot < 0.70f ) { // Still a bit off, so we turn a bit softer VectorMA( ent->movedir, 0.5f*newDirMult, targetdir, newdir ); } else { // getting close, so turn a bit harder VectorMA( ent->movedir, 0.9f*newDirMult, targetdir, newdir ); } >>This adds some randomness - the higher the ent->random, the more randomness ("drunkenness") there will be in the velocity - this could be done only every certain interval if desired, instead of every think/update // add crazy drunkenness for ( int i = 0; i < 3; i++ ) { newdir[i] += crandom() * ent->random * 0.25f; } >>This makes the randomness go away after a while - so the rocket will start "drunken", but then straighten itself out after a while // decay the randomness ent->random *= 0.9f; >>This makes the homing rocket less likely to miss and pass the target - using an old Quake multiplayer trick - don't shoot the rocket at the player's center, shoot at their feet so that even if you miss them, you'll hit the floor and blow up close enough to damage them if ( ent->enemy->client && ent->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//tracking a client who's on the ground, aim at the floor...? // Try to crash into the ground if we get close enough to do splash damage float dis = Distance( ent->currentOrigin, org ); if ( dis < 128 ) { // the closer we get, the more we push the rocket down, heh heh. newdir[2] -= (1.0f - (dis / 128.0f)) * 0.6f; } } >>Back to the important stuff - now that we've got our new direction (calculated from our old direction and target direction and how much we can actually turn this think/update), normalize it to a scale of 1 so it's a direction, not a velocity VectorNormalize( newdir ); >>Take the new direction, scale it up to half our full speed and use that as our new velocity (I think we used half speed because otherwise it could miss targets too easily) VectorScale( newdir, vel * 0.5f, ent->s.pos.trDelta ); VectorCopy( newdir, ent->movedir ); SnapVector( ent->s.pos.trDelta ); // save net bandwidth VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; } >>Set the time of the next update ent->nextthink = level.time + ROCKET_ALT_THINK_TIME; // Nothing at all spectacular happened, continue. return; }
×
×
  • Create New...