Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //video: http://www.youtube.com/watch?v=0aZBceWVXz8
- #define KATSTATUS_INHAND 0
- #define KATSTATUS_INAIR 1
- #define KATSTATUS_INTARGET 2
- struct KatanaInfo {
- RpAtomic* pKat;
- float fAcc;
- float fSpeed;
- CQuaternion qtStatus;
- CPedVC* pTarget;
- RwMatrix matFinal;
- DWORD dwStatus;
- };
- KatanaInfo pKatInfos[100];
- void KatanaAttack_AcquireSlot(int nSlot) {
- if(!pKatInfos[nSlot].pKat) {
- //if this slot has not been initialized, create the atomic
- UtilMakeSureModelIsLoaded(CWeaponModelInfo_KATANA, 0);
- pKatInfos[nSlot].pKat = CBaseModelInfoMethod_CreateInstance(lpModelList.x[CWeaponModelInfo_KATANA]);
- CBaseModelInfo_AddRef(lpModelList.x[CWeaponModelInfo_KATANA]);
- }
- else {
- if(pKatInfos[nSlot].pTarget) {
- //if target is already specified, remove the reference
- CEntity_RemoveReference(ENT(pKatInfos[nSlot].pTarget), (CEntity**)&pKatInfos[nSlot].pTarget);
- }
- }
- //initialize new slot
- pKatInfos[nSlot].pTarget = NULL;
- pKatInfos[nSlot].dwStatus = KATSTATUS_INHAND;
- pKatInfos[nSlot].fAcc = 0.3f;
- pKatInfos[nSlot].fSpeed = 0.3f;
- }
- void KatanaAttack_Process(CPedVC* pPed) {
- static int nUsed = -1;
- static DWORD dwLastThrow = 0;
- int nNew = -1;
- CVector vecPos, vecDistance;
- RwMatrix matInvert;
- matInvert.dwFlags=0;
- CMatrix stMatrix;
- RwMatrix *pRwMatrix;
- RwMatrix matReal;
- if(nUsed == -1) {
- //initialize first katana
- KatanaAttack_AcquireSlot(++nUsed);
- }
- //iterate through all katana slots
- for(int m=0; m<100; m++) {
- //unused slot, ignore
- if(!pKatInfos[m].pKat) continue;
- //freshly created slot, ignore
- if(m == nNew) continue;
- if(pKatInfos[m].dwStatus == KATSTATUS_INHAND) {
- //katana is still in player's hand
- //only process for the player
- if(pPed != stPlInf.pPlayerPed) continue;
- //check if the player is pressing SHIFT+4 and that there is no target assigned to this slot already
- if(!(GetKeyState('4') & 0x80) || !(GetKeyState(VK_SHIFT) & 0x80) || pKatInfos[m].pTarget != NULL) continue;
- //make sure the player is wielding a katana
- if(pPed->dwWepModelID != CWeaponModelInfo_KATANA) continue;
- //do not allow throwing katanas more often than once per 100ms
- if(dwLastThrow + 100 >= dwGameCount) continue;
- //get katana's atomic's matrix
- pRwMatrix = &RpAtomicGetFrame(pKatInfos[m].pKat)->matFrameRelative;
- //find a suitable target from near peds list
- for(int i=0; i<10; i++) {
- if(pPed->pNearPeds[i] && pPed->pNearPeds[i]->fCurHealth > 0.0f && pPed->pNearPeds[i]->byteIsInVehicle == 0) {
- pKatInfos[m].pTarget = pPed->pNearPeds[i];
- break;
- }
- }
- //target was not found, aborting
- if(pKatInfos[m].pTarget == NULL) continue;
- //register a reference, so that it is NULLed when the target ped is destroyed
- CEntity_RegisterReference(ENT(pKatInfos[m].pTarget), (CEntity**)&pKatInfos[m].pTarget);
- //initialize matrix
- stMatrix.pAttached = NULL;
- stMatrix.dwDeleteOnDetach = false;
- CMatrix_Attach(&stMatrix, pRwMatrix, false);
- CMatrix_SetScale(&stMatrix, 1.0f);
- CMatrix_SetRotate(&stMatrix, 0.0f, 0.0f, 0.0f);
- CMatrix_UpdateRW(&stMatrix);
- CMatrix_DCMatrix(&stMatrix);
- RwMatrix* pRwBase;
- DWORD dwIndex;
- //find the matrix for player's right hand
- RpHAnimHierarchy* pAnimHierarchy = RpClumpGetSkinHAnimHierarchy(ENT(pPed)->pModel);
- RwMatrix* pRwMatrixArray = RpHAnimHierarchyGetMatrixArray(pAnimHierarchy);
- dwIndex = RpHAnimIDGetIndex(pAnimHierarchy, pPed->pFrames[AFRAMEID_RHAND]->dwFrameNodeId);
- pRwBase = &pRwMatrixArray[dwIndex];
- //initialize katana's matrix
- RwMatrixTransform(pRwMatrix, pRwBase, rwCOMBINEPOSTCONCAT);
- //get katana's current rotation as a quaternion (for easier interpolation)
- QtMatrixToQuaternion(&pKatInfos[m].qtStatus, pRwMatrix);
- pKatInfos[m].dwStatus = KATSTATUS_INAIR;
- //initialize new slot for the katana in hand, recycle slots
- nUsed = (nUsed+1) % 100;
- KatanaAttack_AcquireSlot(nUsed);
- nNew = nUsed;
- dwLastThrow = dwGameCount;
- }
- else if(pKatInfos[m].dwStatus == KATSTATUS_INAIR) {
- //katana is in air
- //only process for player's render function, also check if the target is still active (might have been destroyed)
- if(pPed != stPlInf.pPlayerPed || pKatInfos[m].pTarget == NULL || ENT(pKatInfos[m].pTarget)->pModel == NULL) continue;
- //get katana's atomic's matrix
- pRwMatrix = &RpAtomicGetFrame(pKatInfos[m].pKat)->matFrameRelative;
- RwMatrix* pRwBase;
- DWORD dwIndex;
- //get the matrix for the spine of the target ped
- RpHAnimHierarchy* pAnimHierarchy = RpClumpGetSkinHAnimHierarchy(ENT(pKatInfos[m].pTarget)->pModel);
- RwMatrix* pRwMatrixArray = RpHAnimHierarchyGetMatrixArray(pAnimHierarchy);
- dwIndex = RpHAnimIDGetIndex(pAnimHierarchy, pPed->pFrames[AFRAMEID_SPINE1]->dwFrameNodeId);
- pRwBase = &pRwMatrixArray[dwIndex];
- //initialize matrix
- stMatrix.pAttached = NULL;
- stMatrix.dwDeleteOnDetach = false;
- //save katana's position (matrix functions tend to reset position)
- VecCopy(&vecPos, &pRwMatrix->vPos);
- //calculate heading matrix from current position to target
- CMatrix_Attach(&stMatrix, &matReal, false);
- CMatrix_SetScale(&stMatrix, 1.0f);
- CMatrix_SetRotate(&stMatrix, 0.0f, 0.0f, 0.0f);
- CVector *v1 = &vecPos, *v2 = &pRwBase->vPos;
- float XY = atan2(v2->Y-v1->Y,v2->X-v1->X);
- float XYZ = atan2(sqrt((v2->X-v1->X)*(v2->X-v1->X) + (v2->Y-v1->Y)*(v2->Y-v1->Y)), v2->Z-v1->Z);
- CMatrix_Rotate(&stMatrix, 0.0f, XYZ, XY);
- CMatrix_UpdateRW(&stMatrix);
- CMatrix_DCMatrix(&stMatrix);
- CQuaternion qtExa, qtRes;
- //interpolate between current rotation and desired rotation
- QtMatrixToQuaternion(&qtExa, &matReal);
- QtSlerp(&qtRes, &pKatInfos[m].qtStatus, &qtExa, pKatInfos[m].fAcc);
- //increase the interpolation degree for next frames
- pKatInfos[m].fAcc = min(pKatInfos[m].fAcc+0.03f, 1.0f);
- //store the new rotation
- QtQuaternionToMatrix(&qtRes, pRwMatrix);
- //calculate distance from katana to target
- VecCopy(&vecDistance, &vecPos);
- VecSubVec(&vecDistance, &pRwBase->vPos);
- float fLen = CVector_GetLength(&vecDistance);
- //only really necessary if there is some extra rotation applied here...
- memcpy(&matReal, pRwMatrix, sizeof(RwMatrix));
- CMatrix_Attach(&stMatrix, &matReal, false);
- CMatrix_Rotate(&stMatrix, 0.0f, 0.0f, 0.0f);
- CMatrix_UpdateRW(&stMatrix);
- CMatrix_DCMatrix(&stMatrix);
- if(fLen > pKatInfos[m].fSpeed) {
- //katana is on its way
- //move according to the rotation
- vecPos.X += matReal.vLookUp.X * pKatInfos[m].fSpeed;
- vecPos.Y += matReal.vLookUp.Y * pKatInfos[m].fSpeed;
- vecPos.Z += matReal.vLookUp.Z * pKatInfos[m].fSpeed;
- VecCopy(&pRwMatrix->vPos, &vecPos);
- //gradually increase movement speed
- pKatInfos[m].fSpeed += 0.001f;
- }
- else {
- //katana arrived at target
- //move according to the rotation
- vecPos.X += matReal.vLookUp.X * fLen;
- vecPos.Y += matReal.vLookUp.Y * fLen;
- vecPos.Z += matReal.vLookUp.Z * fLen;
- VecCopy(&pRwMatrix->vPos, &vecPos);
- //get the inverted matrix of target's spine
- RwMatrixInvert(&matInvert, pRwBase);
- //store katana's current rotation
- memcpy(&pKatInfos[m].matFinal, pRwMatrix, sizeof(RwMatrix));
- //transform rotation to local space of target
- RwMatrixTransform(&pKatInfos[m].matFinal, &matInvert, rwCOMBINEPOSTCONCAT);
- VecSetFloat(&pKatInfos[m].matFinal.vPos, 0.0f);
- //kill target and do some blood effects
- CPed_SpawnFlyingComponent(pKatInfos[m].pTarget, 1, 0);
- pKatInfos[m].pTarget->fCurHealth = 0.0f;
- //choose a death animation for the target
- DWORD dwAnimID = 16;
- if(rand() & 0x1000) {
- dwAnimID = 18;
- }
- //start death animation
- CPed_SetDie(pKatInfos[m].pTarget, dwAnimID, 4.0f, 0.0f);
- pKatInfos[m].dwStatus = KATSTATUS_INTARGET;
- }
- //make the RW engine aware of the rotation/position changes
- RwMatrixUpdate(pRwMatrix);
- RwFrameUpdateObjects(RpAtomicGetFrame(pKatInfos[m].pKat));
- //render katana's atomic
- pKatInfos[m].pKat->pRenderCallback(pKatInfos[m].pKat);
- }
- else if(pKatInfos[m].dwStatus == KATSTATUS_INTARGET) {
- //katana is in the target
- //only process this when rendering the target
- if(pPed != pKatInfos[m].pTarget) continue;
- DWORD dwIndex;
- RwMatrix* pRwBase;
- //get the matrix for the spine of the target ped
- RpHAnimHierarchy* pAnimHierarchy = RpClumpGetSkinHAnimHierarchy(ENT(pKatInfos[m].pTarget)->pModel);
- RwMatrix* pRwMatrixArray = RpHAnimHierarchyGetMatrixArray(pAnimHierarchy);
- dwIndex = RpHAnimIDGetIndex(pAnimHierarchy, pPed->pFrames[AFRAMEID_SPINE1]->dwFrameNodeId);
- pRwBase = &pRwMatrixArray[dwIndex];
- //get katana's atomic's matrix
- pRwMatrix = &RpAtomicGetFrame(pKatInfos[m].pKat)->matFrameRelative;
- memcpy(pRwMatrix, &pKatInfos[m].matFinal, sizeof(RwMatrix));
- //calculate world coords and rotation of the katana atomic
- RwMatrixTransform(pRwMatrix, pRwBase, rwCOMBINEPOSTCONCAT);
- //make the RW engine aware of the rotation/position changes
- RwMatrixUpdate(pRwMatrix);
- RwFrameUpdateObjects(RpAtomicGetFrame(pKatInfos[m].pKat));
- //render katana's atomic
- pKatInfos[m].pKat->pRenderCallback(pKatInfos[m].pKat);
- }
- }
- }
- CPedVC* _pHookPed;
- void _declspec(naked) Hook_CPed_Render() {
- _asm mov _pHookPed,ecx
- _asm pushad
- KatanaAttack_Process(_pHookPed);
- _asm popad
- _asm push ebx
- _asm push esi
- _asm mov ebx,ecx
- _asm push ebp
- _asm sub esp,0D8h
- _asm mov eax,4FE0FBh
- _asm jmp eax
- }
- void InstallHook(DWORD dwInstallAddress, DWORD dwHookFunction, DWORD dwHookStorage) {
- *(PDWORD)dwHookStorage = (DWORD)dwHookFunction;
- *((PWORD)dwInstallAddress) = 0x25FF;
- *((PDWORD)(dwInstallAddress+2)) = dwHookStorage;
- }
- InstallHook(0x4FE0F0, (DWORD)Hook_CPed_Render, 0x4FE4B4);
Add Comment
Please, Sign In to add comment