void G2API_CopySpecificG2Model(CGhoul2Info_v &ghoul2From, int modelFrom, CGhoul2Info_v &ghoul2To, int modelTo) { qboolean forceReconstruct = qfalse; // have we real ghoul2 models yet? if (((int)&ghoul2From) && ((int)&ghoul2To)) { // assume we actually have a model to copy from if (ghoul2From.size() > modelFrom) { // if we don't have enough models on the to side, resize us so we do if (ghoul2To.size() <= modelTo) { ghoul2To.resize(modelTo + 1); forceReconstruct = qtrue; } // do the copy ghoul2To[modelTo] = ghoul2From[modelFrom]; if (forceReconstruct) { //rww - we should really do this shouldn't we? If we don't mark a reconstruct after this, //and we do a GetBoltMatrix in the same frame, it doesn't reconstruct the skeleton and returns //a completely invalid matrix ghoul2To[0].mSkelFrameNum = 0; } } } }
// copy a model from one ghoul2 instance to another, and reset the root surface on the new model if need be // NOTE if modelIndex = -1 then copy all the models // returns the last model index in destination. -1 equals nothing copied. int G2API_CopyGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v &g2To, int modelIndex) { int returnval=-1; int i, model; int from = 0; int to = g2From.size(); /* assert(g2To); if (!g2From) { assert(g2From); return(returnval); } */ // determing if we are only copying one model or not if (modelIndex != -1) { from = modelIndex; to = modelIndex + 1; } model = 0; // now copy the models for (i=from; i<to; i++) { // find a free spot in the list for (; model< g2To.size(); model++) { if (g2To[model].mModelindex == -1) { // Copy model to clear position g2To[model] = g2From[i]; break; } } if (model >= g2To.size()) { // didn't find a spare slot, so new ones to add break; } } if (i < to) { // add in any other ones to the end model = g2To.size(); g2To.resize(model + to - i); for(;i<to;i++) { g2To[model] = g2From[i]; model++; } } return returnval; }
qboolean G2API_GetBoltMatrix_SPMethod(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, const vec3_t scale ) { assert(ghoul2.size() > modelIndex); if ((int)&ghoul2 && (ghoul2.size() > modelIndex)) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; //assert(boltIndex < ghlInfo->mBltlist.size()); if (ghlInfo && (boltIndex < ghlInfo->mBltlist.size()) && boltIndex >= 0 ) { // make sure we have transformed the skeleton if (!gG2_GBMNoReconstruct) { G2_ConstructGhoulSkeleton(ghoul2, frameNum, modelList, true, angles, position, scale, false); } gG2_GBMNoReconstruct = qfalse; mdxaBone_t scaled; mdxaBone_t *use; use=&ghlInfo->mBltlist[boltIndex].position; if (scale[0]||scale[1]||scale[2]) { scaled=*use; use=&scaled; // scale the bolt position by the scale factor for this model since at this point its still in model space if (scale[0]) { scaled.matrix[0][3] *= scale[0]; } if (scale[1]) { scaled.matrix[1][3] *= scale[1]; } if (scale[2]) { scaled.matrix[2][3] *= scale[2]; } } // pre generate the world matrix G2_GenerateWorldMatrix(angles, position); VectorNormalize((float*)use->matrix[0]); VectorNormalize((float*)use->matrix[1]); VectorNormalize((float*)use->matrix[2]); Multiply_3x4Matrix(matrix, &worldMatrix, use); return qtrue; } } return qfalse; }
int G2API_AddBolt(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName) { assert(ghoul2.size()>modelIndex); if ((int)&ghoul2 && ghoul2.size()>modelIndex) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; if (ghlInfo) { return G2_Add_Bolt(ghlInfo->mFileName, ghlInfo->mBltlist, ghlInfo->mSlist, boneName); } } return -1; }
void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius) { int i, lod; skin_t *skin; shader_t *cust_shader; // walk each possible model for this entity and try tracing against it for (i=0; i<ghoul2.size(); i++) { // don't bother with models that we don't care about. if (!ghoul2[i].mValid) { continue; } assert(G2_MODEL_OK(&ghoul2[i])); // do we really want to collide with this object? if (ghoul2[i].mFlags & GHOUL2_NOCOLLIDE) { continue; } if (ghoul2[i].mCustomShader) { cust_shader = R_GetShaderByHandle(ghoul2[i].mCustomShader ); } else { cust_shader = NULL; } // figure out the custom skin thing if ( ghoul2[i].mSkin > 0 && ghoul2[i].mSkin < tr.numSkins ) { skin = R_GetSkinByHandle( ghoul2[i].mSkin ); } else { skin = NULL; } lod = G2_DecideTraceLod(ghoul2[i],useLod); //reset the quick surface override lookup G2_FindOverrideSurface(-1, ghoul2[i].mSlist); CTraceSurface TS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, ghoul2[i].currentModel, lod, rayStart, rayEnd, collRecMap, entNum, i, skin, cust_shader, ghoul2[i].mTransformedVertsArray, eG2TraceType, fRadius); // start the surface recursion loop G2_TraceSurfaces(TS); // if we've hit one surface on one model, don't bother doing the rest if (TS.hitOne) { break; } } }
void G2API_SetBoltInfo(CGhoul2Info_v &ghoul2, int modelIndex, int boltInfo) { if ((int)&ghoul2) { if (ghoul2.size() > modelIndex) { ghoul2[modelIndex].mModelBoltLink = boltInfo; } } }
// main calling point for the model transform for collision detection. At this point all of the skeleton has been transformed. void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod) { int i, lod; vec3_t correctScale; VectorCopy(scale, correctScale); // check for scales of 0 - that's the default I believe if (!scale[0]) { correctScale[0] = 1.0; } if (!scale[1]) { correctScale[1] = 1.0; } if (!scale[2]) { correctScale[2] = 1.0; } // walk each possible model for this entity and try rendering it out for (i=0; i<ghoul2.size(); i++) { CGhoul2Info &g=ghoul2[i]; // don't bother with models that we don't care about. if (!g.mValid) { continue; } assert(g.mBoneCache); assert(G2_MODEL_OK(&g)); // stop us building this model more than once per frame g.mMeshFrameNum = frameNum; // decide the LOD lod = G2_DecideTraceLod(g, useLod); // give us space for the transformed vertex array to be put in ghoul2[i].mTransformedVertsArray = (int*)G2VertSpace->MiniHeapAlloc(g.currentModel->mdxm->numSurfaces * 4); if (!g.mTransformedVertsArray) { Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust MiniHeapSize in SV_SpawnServer.\n"); } memset(g.mTransformedVertsArray, 0,(g.currentModel->mdxm->numSurfaces * 4)); G2_FindOverrideSurface(-1,g.mSlist); //reset the quick surface override lookup; // recursively call the model surface transform G2_TransformSurfaces(g.mSurfaceRoot, g.mSlist, g.mBoneCache, g.currentModel, lod, correctScale, G2VertSpace, g.mTransformedVertsArray, false); } }
qboolean G2API_AttachG2Model(CGhoul2Info_v &ghoul2From, int modelFrom, CGhoul2Info_v &ghoul2To, int toBoltIndex, int toModel) { assert( toBoltIndex >= 0 ); if ( toBoltIndex < 0 ) { return qfalse; } // make sure we have a model to attach, a model to attach to, and a bolt on that model if (((int)&ghoul2From) && ((int)&ghoul2To) && (ghoul2From.size() > modelFrom) && (ghoul2To.size() > toModel) && ((ghoul2To[toModel].mBltlist[toBoltIndex].boneNumber != -1) || (ghoul2To[toModel].mBltlist[toBoltIndex].surfaceNumber != -1))) { // encode the bolt address into the model bolt link toModel &= MODEL_AND; toBoltIndex &= BOLT_AND; ghoul2From[modelFrom].mModelBoltLink = (toModel << MODEL_SHIFT) | (toBoltIndex << BOLT_SHIFT); return qtrue; } return qfalse; }
void G2API_AnimateG2Models(CGhoul2Info_v &ghoul2, float speedVar) { int model; // Walk the list and find all models that are active for (model=0; model< ghoul2.size(); model++) { if (ghoul2[model].mModel) { G2_Animate_Bone_List(ghoul2, speedVar, model); } } }
int AnimTest(CGhoul2Info_v &ghoul2,const char *m,const char *, int line) { if (G2_SetupModelPointers(ghoul2)) { int i; for (i=0; i<ghoul2.size(); i++) { AnimTest(&ghoul2[i],m,0,line); } return i; } return 666; //these return values are to saisfy the optimizer }
// decide if we have Ghoul2 models associated with this ghoul list or not qboolean G2API_HaveWeGhoul2Models(CGhoul2Info_v &ghoul2) { int i; if ((int)&ghoul2) { for (i=0; i<ghoul2.size();i++) { if (ghoul2[i].mModelindex != -1) { return qtrue; } } } return qfalse; }
qboolean G2API_SetBoneAngles(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const vec3_t angles, const int flags, const Eorientations up, const Eorientations left, const Eorientations forward, qhandle_t *modelList, int blendTime, int currentTime ) { if ((int)&ghoul2 && ghoul2.size()>modelIndex) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; if (ghlInfo) { // ensure we flush the cache ghlInfo->mSkelFrameNum = 0; return G2_Set_Bone_Angles(ghlInfo->mFileName, ghlInfo->mBlist, boneName, angles, flags, up, left, forward, modelList, ghlInfo->mModelindex, blendTime, currentTime); } } return qfalse; }
qboolean G2API_SetBoneAnim(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const int AstartFrame, const int AendFrame, const int flags, const float animSpeed, const int currentTime, const float AsetFrame, const int blendTime) { int endFrame=AendFrame; int startFrame=AstartFrame; float setFrame=AsetFrame; assert(endFrame>0); assert(startFrame>=0); assert(endFrame<100000); assert(startFrame<100000); assert(setFrame>=0.0f||setFrame==-1.0f); assert(setFrame<=100000.0f); if (endFrame<=0) { endFrame=1; } if (endFrame>=100000) { endFrame=1; } if (startFrame<0) { startFrame=0; } if (startFrame>=100000) { startFrame=0; } if (setFrame<0.0f&&setFrame!=-1.0f) { setFrame=0.0f; } if (setFrame>100000.0f) { setFrame=0.0f; } if ((int)&ghoul2 && ghoul2.size()>modelIndex) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; if (ghlInfo) { // ensure we flush the cache ghlInfo->mSkelFrameNum = 0; return G2_Set_Bone_Anim(ghlInfo->mFileName, ghlInfo->mBlist, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime); } } return qfalse; }
qboolean G2API_SetSurfaceOnOff(CGhoul2Info_v &ghoul2, const char *surfaceName, const int flags) { CGhoul2Info *ghlInfo = NULL; if ((int)&ghoul2 && ghoul2.size()>0) { ghlInfo = &ghoul2[0]; } if (ghlInfo) { // ensure we flush the cache ghlInfo->mMeshFrameNum = 0; return G2_SetSurfaceOnOff(ghlInfo->mFileName, ghlInfo->mSlist, surfaceName, flags); } return qfalse; }
qboolean G2API_SetNewOrigin(CGhoul2Info_v &ghoul2, const int boltIndex) { CGhoul2Info *ghlInfo = NULL; if ((int)&ghoul2 && ghoul2.size()>0) { ghlInfo = &ghoul2[0]; } if (ghlInfo) { ghlInfo->mNewOrigin = boltIndex; ghlInfo->mFlags |= GHOUL2_NEWORIGIN; return qtrue; } return qfalse; }
qboolean G2_SetRootSurface( CGhoul2Info_v &ghoul2, const int modelIndex, const char *surfaceName) { int surf; int flags; assert(modelIndex>=0&&modelIndex<ghoul2.size()); assert(ghoul2[modelIndex].currentModel); assert(ghoul2[modelIndex].currentModel->mdxm); // first find if we already have this surface in the list surf = G2_IsSurfaceLegal(ghoul2[modelIndex].currentModel, surfaceName, &flags); if (surf != -1) { ghoul2[modelIndex].mSurfaceRoot = surf; return qtrue; } assert(0); return qfalse; }
// run through the Ghoul2 models and set each of the mModel values to the correct one from the cgs.gameModel offset lsit void G2API_SetGhoul2ModelIndexes(CGhoul2Info_v &ghoul2, qhandle_t *modelList, qhandle_t *skinList) { return; #if 0 int i; if ((int)&ghoul2) { for (i=0; i<ghoul2.size(); i++) { if (ghoul2[i].mModelindex != -1) { // broken into 3 lines for debugging, STL is a pain to view... // int iModelIndex = ghoul2[i].mModelindex; qhandle_t mModel = modelList[iModelIndex]; ghoul2[i].mModel = mModel; ghoul2[i].mSkin = skinList[ghoul2[i].mCustomSkin]; } } } #endif }
qboolean G2_SetRootSurface(CGhoul2Info_v &ghoul2, const int modelIndex, const char *surfaceName) { int surf; int flags; int *activeSurfaces, *activeBones; assert(ghoul2[modelIndex].currentModel && ghoul2[modelIndex].animModel); model_t *mod_m = (model_t *)ghoul2[modelIndex].currentModel; model_t *mod_a = (model_t *)ghoul2[modelIndex].animModel; // did we find a ghoul 2 model or not? if (!mod_m->mdxm) { return qfalse; } // first find if we already have this surface in the list surf = G2_IsSurfaceLegal(mod_m, surfaceName, &flags); if (surf != -1) { // first see if this ghoul2 model already has this as a root surface if (ghoul2[modelIndex].mSurfaceRoot == surf) { return qtrue; } // set the root surface ghoul2[modelIndex].mSurfaceRoot = surf; // ok, now the tricky bits. // firstly, generate a list of active / on surfaces below the root point // gimme some space to put this list into activeSurfaces = (int *)Z_Malloc(mod_m->mdxm->numSurfaces * 4, TAG_GHOUL2, qtrue); memset(activeSurfaces, 0, (mod_m->mdxm->numSurfaces * 4)); activeBones = (int *)Z_Malloc(mod_a->mdxa->numBones * 4, TAG_GHOUL2, qtrue); memset(activeBones, 0, (mod_a->mdxa->numBones * 4)); G2_FindRecursiveSurface(mod_m, surf, ghoul2[modelIndex].mSlist, activeSurfaces); // now generate the used bone list CConstructBoneList CBL(ghoul2[modelIndex].mSurfaceRoot, activeBones, ghoul2[modelIndex].mSlist, mod_m, ghoul2[modelIndex].mBlist); G2_ConstructUsedBoneList(CBL); // now remove all procedural or override surfaces that refer to surfaces that arent on this list G2_RemoveRedundantGeneratedSurfaces(ghoul2[modelIndex].mSlist, activeSurfaces); // now remove all bones that are pointing at bones that aren't active G2_RemoveRedundantBoneOverrides(ghoul2[modelIndex].mBlist, activeBones); // then remove all bolts that point at surfaces or bones that *arent* active. G2_RemoveRedundantBolts(ghoul2[modelIndex].mBltlist, ghoul2[modelIndex].mSlist, activeSurfaces, activeBones); // then remove all models on this ghoul2 instance that use those bolts that are being removed. for (int i=0; i<ghoul2.size(); i++) { // are we even bolted to anything? if (ghoul2[i].mModelBoltLink != -1) { int boltMod = (ghoul2[i].mModelBoltLink >> MODEL_SHIFT) & MODEL_AND; int boltNum = (ghoul2[i].mModelBoltLink >> BOLT_SHIFT) & BOLT_AND; // if either the bolt list is too small, or the bolt we are pointing at references nothing, remove this model if (((int)ghoul2[boltMod].mBltlist.size() <= boltNum) || ((ghoul2[boltMod].mBltlist[boltNum].boneNumber == -1) && (ghoul2[boltMod].mBltlist[boltNum].surfaceNumber == -1))) { CGhoul2Info_v *g2i = &ghoul2; G2API_RemoveGhoul2Model((CGhoul2Info_v **)&g2i, i); } } } //No support for this, for now. // remember to free what we used Z_Free(activeSurfaces); Z_Free(activeBones); return (qtrue); }
qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles, const vec3_t position, const int frameNum, qhandle_t *modelList, vec3_t scale ) { assert(ghoul2.size() > modelIndex); if (gG2_GBMUseSPMethod) { gG2_GBMUseSPMethod = qfalse; return G2API_GetBoltMatrix_SPMethod(ghoul2, modelIndex, boltIndex, matrix, angles, position, frameNum, modelList, scale); } if ((int)&ghoul2 && (ghoul2.size() > modelIndex)) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; //assert(boltIndex < ghlInfo->mBltlist.size()); if (ghlInfo && (boltIndex < ghlInfo->mBltlist.size()) && boltIndex >= 0 ) { // make sure we have transformed the skeleton if (!gG2_GBMNoReconstruct) { G2_ConstructGhoulSkeleton(ghoul2, frameNum, modelList, true, angles, position, scale, false); } gG2_GBMNoReconstruct = qfalse; mdxaBone_t scaled; mdxaBone_t *use; use=&ghlInfo->mBltlist[boltIndex].position; if (scale[0]||scale[1]||scale[2]) { scaled=*use; use=&scaled; // scale the bolt position by the scale factor for this model since at this point its still in model space if (scale[0]) { scaled.matrix[0][3] *= scale[0]; } if (scale[1]) { scaled.matrix[1][3] *= scale[1]; } if (scale[2]) { scaled.matrix[2][3] *= scale[2]; } } // pre generate the world matrix G2_GenerateWorldMatrix(angles, position); // for some reason we get the end matrix rotated by 90 degrees mdxaBone_t rotMat, tempMatrix; vec3_t newangles = {0,270,0}; Create_Matrix(newangles, &rotMat); // make the model space matrix we have for this bolt into a world matrix // Multiply_3x4Matrix(matrix, &worldMatrix,use); Multiply_3x4Matrix(&tempMatrix, &worldMatrix,use); vec3_t origin; origin[0] = tempMatrix.matrix[0][3]; origin[1] = tempMatrix.matrix[1][3]; origin[2] = tempMatrix.matrix[2][3]; tempMatrix.matrix[0][3] = tempMatrix.matrix[1][3] = tempMatrix.matrix[2][3] = 0; Multiply_3x4Matrix(matrix, &tempMatrix, &rotMat); matrix->matrix[0][3] = origin[0]; matrix->matrix[1][3] = origin[1]; matrix->matrix[2][3] = origin[2]; return qtrue; } } return qfalse; }
void G2_LoadGhoul2Model(CGhoul2Info_v &ghoul2, char *buffer) { int i,x; // first thing, lets see how many ghoul2 models we have, and resize our buffers accordingly int newSize = *(int*)buffer; ghoul2.resize(newSize); buffer += 4; // did we actually resize to a value? if (!newSize) { // no, ok, well, done then. return; } // this one isn't a define since I couldn't work out how to figure it out at compile time int ghoul2BlockSize = (int)&ghoul2[0].mTransformedVertsArray - (int)&ghoul2[0].mModelindex; // now we have enough instances, lets go through each one and load up the relevant details for (i=0; i<ghoul2.size(); i++) { ghoul2[i].mSkelFrameNum = 0; ghoul2[i].mModelindex=-1; ghoul2[i].mFileName[0]=0; ghoul2[i].mValid=false; // load the ghoul2 info from the buffer memcpy(&ghoul2[i].mModelindex, buffer, ghoul2BlockSize); buffer +=ghoul2BlockSize; if (ghoul2[i].mModelindex!=-1&&ghoul2[i].mFileName[0]) { ghoul2[i].mModelindex = i; G2_SetupModelPointers(&ghoul2[i]); } // give us enough surfaces to load up the data ghoul2[i].mSlist.resize(*(int*)buffer); buffer +=4; // now load all the surfaces for (x=0; x<ghoul2[i].mSlist.size(); x++) { memcpy(&ghoul2[i].mSlist[x], buffer, SURFACE_SAVE_BLOCK_SIZE); buffer += SURFACE_SAVE_BLOCK_SIZE; } // give us enough bones to load up the data ghoul2[i].mBlist.resize(*(int*)buffer); buffer +=4; // now load all the bones for (x=0; x<ghoul2[i].mBlist.size(); x++) { memcpy(&ghoul2[i].mBlist[x], buffer, BONE_SAVE_BLOCK_SIZE); buffer += BONE_SAVE_BLOCK_SIZE; } // give us enough bolts to load up the data ghoul2[i].mBltlist.resize(*(int*)buffer); buffer +=4; // now load all the bolts for (x=0; x<ghoul2[i].mBltlist.size(); x++) { memcpy(&ghoul2[i].mBltlist[x], buffer, BOLT_SAVE_BLOCK_SIZE); buffer += BOLT_SAVE_BLOCK_SIZE; } } }
qboolean G2_SaveGhoul2Models(CGhoul2Info_v &ghoul2, char **buffer, int *size) { int i, x; // is there anything to save? if (!ghoul2.IsValid()||!ghoul2.size()) { *buffer = (char *)Z_Malloc(4, TAG_GHOUL2, qfalse); int *tempBuffer = (int *)*buffer; *tempBuffer = 0; *size = 4; return qtrue; } // yeah, lets get busy *size = 0; // this one isn't a define since I couldn't work out how to figure it out at compile time int ghoul2BlockSize = (int)&ghoul2[0].mTransformedVertsArray - (int)&ghoul2[0].mModelindex; // add in count for number of ghoul2 models *size += 4; // start out working out the total size of the buffer we need to allocate for (i=0; i<ghoul2.size();i++) { *size += ghoul2BlockSize; // add in count for number of surfaces *size += 4; *size += (ghoul2[i].mSlist.size() * SURFACE_SAVE_BLOCK_SIZE); // add in count for number of bones *size += 4; *size += (ghoul2[i].mBlist.size() * BONE_SAVE_BLOCK_SIZE); // add in count for number of bolts *size += 4; *size += (ghoul2[i].mBltlist.size() * BOLT_SAVE_BLOCK_SIZE); } // ok, we should know how much space we need now *buffer = (char*)Z_Malloc(*size, TAG_GHOUL2, qfalse); // now lets start putting the data we care about into the buffer char *tempBuffer = *buffer; // save out how many ghoul2 models we have *(int *)tempBuffer = ghoul2.size(); tempBuffer +=4; for (i=0; i<ghoul2.size();i++) { // first save out the ghoul2 details themselves // OutputDebugString(va("G2_SaveGhoul2Models(): ghoul2[%d].mModelindex = %d\n",i,ghoul2[i].mModelindex)); memcpy(tempBuffer, &ghoul2[i].mModelindex, ghoul2BlockSize); tempBuffer += ghoul2BlockSize; // save out how many surfaces we have *(int*)tempBuffer = ghoul2[i].mSlist.size(); tempBuffer +=4; // now save the all the surface list info for (x=0; x<ghoul2[i].mSlist.size(); x++) { memcpy(tempBuffer, &ghoul2[i].mSlist[x], SURFACE_SAVE_BLOCK_SIZE); tempBuffer += SURFACE_SAVE_BLOCK_SIZE; } // save out how many bones we have *(int*)tempBuffer = ghoul2[i].mBlist.size(); tempBuffer +=4; // now save the all the bone list info for (x=0; x<ghoul2[i].mBlist.size(); x++) { memcpy(tempBuffer, &ghoul2[i].mBlist[x], BONE_SAVE_BLOCK_SIZE); tempBuffer += BONE_SAVE_BLOCK_SIZE; } // save out how many bolts we have *(int*)tempBuffer = ghoul2[i].mBltlist.size(); tempBuffer +=4; // lastly save the all the bolt list info for (x=0; x<ghoul2[i].mBltlist.size(); x++) { memcpy(tempBuffer, &ghoul2[i].mBltlist[x], BOLT_SAVE_BLOCK_SIZE); tempBuffer += BOLT_SAVE_BLOCK_SIZE; } } return qtrue; }