Jump to content

MGummelt

Members
  • Posts

    120
  • Joined

  • Last visited

Everything posted by MGummelt

  1. What model are you using for the saber they use? Can you post your .npc file and the .saber file for the saber you're using? Are you sure that saber model is working properly and included in your assets?
  2. You may need to declare the WP_SaberParry() function above your function if the actual definition of the function is lower in the .cpp file. You can see some other examples of that at the top of the wp_saber.cpp file: void WP_SaberDrop( gentity_t *self, gentity_t *saber ); qboolean WP_SaberLose( gentity_t *self, vec3_t throwDir ); void WP_SaberReturn( gentity_t *self, gentity_t *saber ); void WP_SaberBlock( gentity_t *saber, vec3_t hitloc, qboolean missleBlock ); void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlock ); Just add this there, too: qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker ); Note: if your function is in a different file altogether, you need to extern it like so: extern qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker );
  3. Heh... maybe install Windows 98, NT, 2000 or XP on an old machine, install Visual Studio .NET or VS.NET 2003 (or was it VS 6.0?) and try compiling it on that?
  4. Hmm. You'd have to put something in the dismemberment code that checks for specific models. Kind of a hardcoded hack, but you don't really have much of a choice as there's no real external data set for player models in MP. Probably best to put it in G_CheckForDismemberment() in g_combat.c... Check the player's model there, maybe like so? (second section is the new bit, just included the stuff above it so you know where it goes) if (gGAvoidDismember != 2) { //this means do the dismemberment regardless of randomness and damage if (Q_irand(0, 100) > dismember) { return; } if (damage < 5) { return; } } if (ent->client && ent->s.clientNum > 0 && ent->s.clientNum < MAX_CLIENTS){ trap_GetUserinfo(clientNum, userinfo, sizeof(userinfo)); modelname = Info_ValueForKey(userinfo, "model"); if (modelname == "chewbacca") return; } Obviously, for that to work, you need to add this declaration to the top of the function: char userinfo[MAX_INFO_VALUE], *modelname;
  5. Sure, and no porting needed. When when you hit an enemy in WP_SaberDamageTrace(), check their NPC type and if it's a galak mech or shadowtrooper, call this: WP_SaberParry( hitOwner, ent ); Maybe something like this... down in the WP_SaberApplyDamage() function, when it's checking the victims hit by the lightsaber around line 719): for ( int i = 0; i < numVictims; i++ ) { dFlags = baseDFlags|DAMAGE_DEATH_KNOCKBACK|DAMAGE_NO_HIT_LOC; if ( victimEntityNum[i] != ENTITYNUM_NONE && &g_entities[victimEntityNum[i]] != NULL ) { // Don't bother with this damage if the fraction is higher than the saber's fraction if ( dmgFraction[i] < saberHitFraction || brokenParry ) { victim = &g_entities[victimEntityNum[i]]; if ( !victim ) { continue; } First check the victim's NPC_class, and if it's the type of NPC you want to make reflect the player's saber, parry and return. Something like this: victim = &g_entities[victimEntityNum[i]]; if ( !victim ) { continue; } if (victim->client && (victim->client->NPC_class == CLASS_GALAKMECH || victim->client->NPC_class == CLASS_SHADOWTROOPER)) { WP_SaberParry(victim, attacker); return didDamage; }I think that should make the saber bounce off those enemies and do no damage.
  6. Wow, sounds ambitious! Sounds like a total conversion! Good luck with it, man!
  7. So, if you take just the saber locking code from both WP_Saber.cpp files (the Outcast one and Academy one) and diff them in whatever diff program you like (Notepad++ is free and can diff fairly well), you'll see there were a *ton* of changes to saber locking between Outcast and Academy, especially in relation to animations since it had to support dual sabers and saber staffs. Now, this means you obviously could not port the Academy saberlocking code to Outcast, as the code would be referring to enums and anims and structs that don't exist in Outcast. But you might have better luck replacing the saberlocking chunk of code in Academy with that of Outcast. Best case scenario, it might work but dual sabers and saber staffs wouldn't work right. But I'm guessing the animation system changes might make this impossible. If you want to diff them yourself, here are the line ranges in WP_Saber.cpp to compare: Outcast: 1813-2404 Academy: 2454-3522 Good luck!
  8. Just look for anywhere forcePowerLevel[FP_SABER_DEFENSE] is used, especially in the WP_SaberDamageTrace() function in WP_Saber.cpp. For example: if ( entPowerLevel < FORCE_LEVEL_3 && activeDefense && (hitOwnerPowerLevel > FORCE_LEVEL_2||(hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_2&&Q_irand(0,hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE]))) ) {//knockaways can make fast-attacker go into a broken parry anim if the ent is using fast or med (but not Tavion) //make me parry WP_SaberParry( hitOwner, ent ); This means that if the attacker's power level is less than 3 (like, maybe doing a fast attack) and the defender's power level is at least 3 (like, say, doing a strong attack) OR the defender has a Saber Defense of 3, then it has a chance of parrying away the attacker's hit (knocking it away). The chance of the parry is higher if the defender's saber offense level is higher. I'm guessing what you mean by "shunting away" the enemy saber is parrying. I would look at anything that calls WP_SaberParry() and see what conditions allow it, then tweak to your tastes.
  9. Absolutely, this is done in the .npc file. For example, look at the dismemberProbabilities in a Stormtrooper (no decapitations, can't cut them in half, no leg dismemberment - last one because they didn't have caps for leg dismemberment): StormTrooper { playerModel stormtrooper weapon WP_BLASTER health 30 headPitchRangeDown 30 reactions 3 aim 1 move 3 aggression 3 evasion 1 intelligence 5 rank crewman playerTeam TEAM_ENEMY enemyTeam TEAM_PLAYER // race klingon class CLASS_STORMTROOPER height 64 crouchheight 38 walkSpeed 51 runSpeed 200 snd st1 sndcombat st1 sndextra st1 yawspeed 70 walkSpeed 55 runSpeed 200 dismemberProbHead 0 dismemberProbArms 10 dismemberProbLegs 0 dismemberProbHands 20 dismemberProbWaist 0 } vs those in the saber training droid (fully dismemberable): saber_droid_training { playerModel saber_droid saber droid weapon WP_SABER saberStyle 1 FP_SABER_DEFENSE 1 FP_SABER_OFFENSE 1 reactions 1 aim 1 move 1 aggression 1 evasion 1 intelligence 1 hfov 120 vfov 120 playerTeam TEAM_ENEMY enemyTeam TEAM_PLAYER class CLASS_SABER_DROID snd saber_droid sndcombat saber_droid sndjedi saber_droid yawSpeed 100 walkSpeed 60 runSpeed 200 health 50 dismemberProbHead 100 dismemberProbArms 100 dismemberProbLegs 100 dismemberProbHands 100 dismemberProbWaist 100 }Just set them all to 0 and they should not be dismemberable.
  10. Ah, then you should just be able to spawn him any time you want from the console like so: \NPC spawn <npc name> You'd just need to know what NPC it was. cultistcommando? saboteurcommando?
  11. Hmm, maybe. But I would expect it to just complete immediately. Unless maybe it fails to find a path because he's standing on it already? I'm not sure, but I think the system is smart enough to say "oh, I'm already there, complete the task right away". And that doesn't sound like it would cause the problems you were seeing where they would stop or change directions en route to another navgoal? Maybe, but I'm a bit skeptical. You could rewrite your script to follow the navgoals in a more linear fashion (always 1-2-3 order in a loop) and see if it works more reliably? My guess is still that something else is changing their goal (did you turn on the debug cvars that show what their current goal is? Try this on the console: \nav show nodes \nav show navgoals \nav show enemypath (I believe this will just show the path to your current goal, not just enemies) That last one, I think, changes color depending on what's going on (can move forward, is blocked, etc). Try it and see what it shows you.
  12. Good question. If we're talking about single player Jedi Academy, it's in wp_saber.cpp. Look at the function WP_SaberDamageTrace(). This is sort of one of my classic "megafunctions" I used to write (and, honestly, sometimes still do). I try to comment everything, but keep in mind I was working solo on this stuff and I never imagined the public would ever see this code. So the comments aren't super-extensive or explanatory, they were mostly there for my own personal benefit. Often I would write the comments in a function first, to get down the flow and logic and content of the function, then fill it in with code. Then add more comments as I went along adding new features. This function does a lot of stuff. But the part you're interested in comes after this part: Further down, it checks to see if the saber it hit was also in someone's hand: Below that it does a bunch of checks to see the relative power level of the two sabers, then decides if the attack is strong enough to break through the defense or if it gets parried. However, I suspect that's not what you meant, no? I'm assuming that you actually wanted sabers to block each other more? To actually have saber-vs-saber collision be a bit "larger"? If that's the case, look in WP_SaberUpdate(). Here it sets the "size" of the saber entity (its mins and maxs - the minimum and maximum bounds of the axis-aligned bounding box of the lightsaber... in x, y and z coordinates... z is up in the Quake engine, unlike most other 3D coordinate systems). Notice here how it checks to see what blocking type is being used (this is defined for each possible animation in the big saber animation data table, saberMoveData, in bg_animation.cpp): {//FIXME: keep bbox in front of player, even when wide?vec3_t saberOrg;if ( ( (self->s.number&&!Jedi_SaberBusy(self)&&!g_saberRealisticCombat->integer) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_saberAutoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) )&& self->client->ps.weaponTime <= 0 && !G_InCinematicSaberAnim( self ) ){//full-size blocking for non-attacking player with g_saberAutoBlocking onvec3_t saberang={0,0,0}, fwd, sabermins={-8,-8,-8}, sabermaxs={8,8,8}; Below that, there's an "else" that then calculates a smaller bbox (bounding box) for the saber entity (this is what is hit by the other lightsaber's damage traces). The size of the bbox is based on the number of blades, their length and orientation. So a short, single-blade saber is going to have a much smaller bbox than, say, a 6-bladed saber with blades sticking out at all angles. Now, something to note is that this is just used for the "rough" first check to see if 2 sabers have hit. It's what the damage trace uses. But that's just a big cuboid, it's not accurate at all. Consider that check the "I could have possibly hit the other lightsaber blade because my blade intersected the cubical space that the other blade is somewhere inside of" check... So, back in WP_SaberDamageTrace, after it does the trace, it does some fancy math to see if the two blades (just line segments really), came close enough to each other to have touched. To figure that out, it calls a function named WP_SabersDistance() (this is a bit higher in the function that the section I quoted above: So you can see, above, that the sabers aren't considered as hitting each other unless the sabersDist is less than the collisionDist. Note that collisionDist goes up by 4 for every skill level in single player (meaning blocks are more common on higher difficulty levels). If realistic combat is turned on, the collisionDist uses the default low value of SABER_COLLISION_DIST, which is the bare minimum distance 2 sabers can be from each other and look like they are barely touching. That default value is defined right above the WP_SaberDamageTrace() function: So on, say, medium difficulty, that distance will be 6 + 6 + 4, or 16. That's pretty generous. If you want to make sabers hit each other more, just raise that number. Hopefully that helps. BTW, I wish I could get this board to keep the full formatting of the text I'm pasting in (color, tabbing, etc.) The code snippets would be a bit more readable. Anyone have any tips for that?
  13. Yeah, that should make them not remove themselves until they're that far away, if I recall. See the NPC_RemoveBody() function in NPC.cpp for the full logic.
  14. No, but the relevant code could be ported from Academy to Outcast and it should work.
  15. Looks like it was implemented but commented out. Look in AI_Jedi.cpp:
  16. This should behave exactly as it sounds. If that's set to 1, the rider will not be visible or collidable. Fighter type vehicles automatically make the player not collidable on the server when they board, but they should still be visible on the client. I can't think of anything that should make Walkers different. There's no special exceptions I can see in the code for VH_WALKER that pertains to not drawing the player. There must be something doing it, but I don't see it. I'd probably have to debug it and see where the client earlies-out on trying to draw the player. Oh, wait. There is one quirk to AT-STs. There's two types of AT-STs - NPCs and vehicles. I think when you "boarded" an NPC AT-ST, you actually are not boarding it like other vehicles. You're changing your playermodel to the AT-ST (same as if you changed your playermodel to a stormtrooper or droid). So it *is* drawing your playermodel, it's just that your playermodel has changed to be an AT-ST. Heh. Still if this isn't an NPC AT-ST but an inert vehicle that can be boarded by the player, then I don't see why it wouldn't try to draw your playermodel assuming hideRider is not set to 1 in the .veh def...
  17. By hand. Fun fact: most of the Call of Duty games still used this awful .menu system, though most recent ones have finally abandoned it (though Call of Duty Online still uses it for some things).
  18. So I didn't write the navigation system - that was written by Chris Reed (also still at Raven). ICARUS was written by Josh Weier (who left for Valve and who's last job I remember he had before retiring from the industry was project lead on Portal 2). I don't recall if he patterned it on anything, he just wanted it to be a high-level scripting system. Hence the name ICARUS (for the old myth of the father and son who escaped a prison tower by making wax wings). I reminded him that Icarus was the son who flew *too* high, causing his wings to melt and he plummeted to his death. I suggested DAEDALUS would be a more confidence-inspiring acronym, but he just liked the way ICARUS sounded better. Your script looks fine to me, for the most part. However, there are some things that could be causing the issue you're seeing: One thing to note is that your "casualwalk" task is not guaranteed to make them do anything. It may pick the same goal the NPC is already at. In that case the NPC will just stand there for the duration of the random wait time (0-4 seconds). But, still, if everything is set up correctly, he should at least move the first time. Stopping in the middle or changing direction (to what? a different point?) could be him reacting to enemies? Did you try setting him to ignore enemies instead of looking for and chasing enemies? Those things would change his goal (from your navgoal to the enemy) if I recall. However, that won't interrupt the script, so the script will wait a few seconds then make him go to a goal again. So you'll see him start going for a goal, then diverge to go after an enemy, but then within 0-4 seconds (0 would seem like he's just aborting his original goal early and going to a different one), going back to another goal (possibly the same one, possibly not). The way to prevent that is for your loop to not do anything if he has an enemy. The other way is to SET_ANGERSCRIPT to a script that includes the flush() command - that will stop all other scripts. For example, this script is run on guards on the Hoth3 level the first time they're attacked (from scripts/hoth3/1st_troopers_attacked.icarus): It flushes whatever they were doing before, waits 200ms, then sets their behavior state back to default behavior and tells them it's okay to look for enemies now (they were having a conversation before). That was set up as below in the script that starts their conversation (scripts/hoth3/guards_talking1.icarus): As for the pathfinding system itself, I believe it worked pretty well. The map needs waypoints (the network of points used later for pathfinding) You lay down waypoints in your map (simple entities in Radiant), connect them by selecting the first one, then the second one and hitting K (that will automatically fill in the target field on the first one and, if need be, the targetname field on the second one). This may seem annoying, but it doesn't take too long. You don't need a whole lot of waypoints, just enough that you can see each area of the map from the point. And it gives you some control over how the NPCs path through your map (go straight down the hall, or traffic stays to the right, etc.) In regards to the navgoals, you place a waypoint_navgoal in the map, making sure it's got a clear path to a normal waypoint (the nav network). Like other waypoints, it will drop to the floor and autoconnect to the nav mesh. However, it will not be used as a "pass-through" node for other pathing tasks - it is always a goal, and endpoint of a path. Alternatively, you can tell it to not autoconnect, but then it won't be reachable. You will need to manually target it from your desired normal waypoint. Normally, it will autoconnect navgoals and combat nodes to regular waypoints up to 500 units away and not too far above or below it - I believe 60 is the max Z difference allowed). Autoconnections to *other* combat nodes and navgoals can only be 250 units away, max. And, obviously, there has to be a clear path between the goals and waypoints to autoconnect them. Note that it only has to do this the first time, then it saves those to a .nav or .navNEW file and just loads that for the next time. If I recall, we shipped the game with those .nav files already, at least for MP. Much of what I just described above is done in the function NAV::LoadFromEntitiesAndSaveToFile() in g_navigator.cpp. When an NPC gets a command to go to a goal, it will calculate a path dynamically, using the waypoint connectivity network processed on map load. I believe Chris Reed used the A* algorithm for this. He got a degree in programming at UW and pathinding and AI are his specialties, so he does a pretty good job of it (he knows a lot more about writing fast, efficient, effective pathfinding algorithms than I do). First, the pathfinding system will find the closest waypoint on the network for the desired goal. If it can't find one, the path will fail. See GetNearestNode(). The node must be withing 550 of the goal and no more than maybe 100 above or below (with exceptions for flying enemies maybe). Assuming the pathfinding system found a closest node for the goal, then the system will continue with trying to find a path (there is a limit of 100 simultaneous pathers on PC, 60 on X-Box). I'm not aware of there being limits on how long the path can be (I imagine there are some), but I've never had any trouble getting an NPC to path all the way through a map if I recall. ICARUS will wait for the NPC to reach their goal before continuing on from your SET_NAVGOAL command. If they never reach the goal, the script will not continue. The only reason you would need to set multiple path nodes is if you want them to walk a patrol or stop and do something at each point or if you wanted to force them to take a certain route. Hope this helps!
  19. Hmm, interesting. I was not aware of this difference. I'll have to ask James Monroe (the Lead Programmer on JKO/JKA) why that may be...
  20. Hmm, if it's the anim I'm looking at (BOTH_P1_S1_T_), the blend time is only 50ms, which is 1/20th of a second. He shouldn't be transitioning to that anim so slowly? I think your saber style skill will scale the speed of the transition to attack animations.. not sure about blocking ones. See PM_SaberStartTransAnim() in bg_panimate.cpp As for the playback speed of animations, I believe that's handled in PM_SetAnimFinal() in bg_panimate.cpp. That stuff was written by Chris Reed, I believe, not me. He's still at Raven, too btw (along with Lead Programmer James Monroe). Anyway, if any scaling of an anim speed or blendtime is happening, it's probably in that function.
  21. Never heard of it. Must have been an internal concept at LA.
  22. 1. Sorry, no idea what this means...? 2. Not that I'm aware of - not at Raven anyway.
  23. I was only involved in the very beginning in the creation of the combat node/fightstyle system. I wouldn't be able to answer detailed questions about the shipped code, sorry. We didn't do the ports, but I think at the time the PS2 was considered very difficult to port to from PC. I have no idea where the GameCube code is, I've never seen it in our depot.
  24. Hmm. I have a hard time believing the game shipped with such an obvious bug. Does the retail (patched or unpatched) version behave this way? Or just the JKA source code when compiled?
×
×
  • Create New...