diff --git a/CMakeLists.txt b/CMakeLists.txt index b70473f2ce..f6a0b75b14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1014,6 +1014,8 @@ set_src(GAME_SERVER GLOB_RECURSE src/game/server weapons/ninja.h weapons/pistol.cpp weapons/pistol.h + weapons/puppeteehammer.cpp + weapons/puppeteehammer.h weapons/shotgun.cpp weapons/shotgun.h ) diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 42021ef931..8e464d827c 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -94,6 +94,7 @@ class CCharacter : public CEntity void ForceSetWeapon(int Slot, int Type, int Ammo = -1); void SetOverrideWeapon(int Slot, int Type, int Ammo = -1); void SetPowerUpWeapon(int Type, int Ammo = -1); + void SetPowerUpWeaponPointer(CWeapon *Weapon) { m_pPowerupWeapon = Weapon; } void SetEndlessHook(bool Enable); @@ -291,6 +292,10 @@ class CCharacter : public CEntity int m_MaxArmor; // Hunter vec2 GetDirection() { return normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); } // Hunter + vec2 GetAimPos() { return vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY); } // Hunter + CNetObj_PlayerInput GetLatestInput() { return m_LatestInput; } // Hunter + CNetObj_PlayerInput GetLatestPrevPrevInput() { return m_LatestPrevPrevInput; } // Hunter + void SetQueuedWeaponSlot(int WeaponSlot) { m_QueuedWeaponSlot = WeaponSlot; } }; enum diff --git a/src/game/server/weapons.h b/src/game/server/weapons.h index 72c564b8b8..438c26642f 100644 --- a/src/game/server/weapons.h +++ b/src/game/server/weapons.h @@ -11,6 +11,7 @@ REGISTER_WEAPON(WEAPON_ID_EXPLODINGLASER, CExplodingLaser) REGISTER_WEAPON(WEAPON_ID_HUNTHAMMER, CHuntHammer) // Hunter //REGISTER_WEAPON(WEAPON_ID_JUGNINJA, CJugNinja) // Hunter +REGISTER_WEAPON(WEAPON_ID_PUPPETEEHAMMER, CPuppeteeHammer) // Hunter #else @@ -28,6 +29,7 @@ REGISTER_WEAPON(WEAPON_ID_HUNTHAMMER, CHuntHammer) // Hunter #include "weapons/hunthammer.h" // Hunter //#include "weapons/jugninja.h" // Hunter +#include "weapons/puppeteehammer.h" enum { diff --git a/src/game/server/weapons/hunthammer.cpp b/src/game/server/weapons/hunthammer.cpp index 9e6690cbc6..46b7fb2fe1 100644 --- a/src/game/server/weapons/hunthammer.cpp +++ b/src/game/server/weapons/hunthammer.cpp @@ -17,7 +17,7 @@ void CHuntHammer::Snap(int SnappingClient, int OtherMode) if(Character()->GetPlayer()->GetCID() != SnappingClient) return; - if(!Character()->m_IsFiring || m_ReloadTimer > 1) + if(!(Character()->GetLatestInput().m_Fire & 1) || m_ReloadTimer > 1) return; CNetObj_Laser *pObj = static_cast(Server()->SnapNewItem(NETOBJTYPE_LASER, IndicatorSnapID, sizeof(CNetObj_Laser))); diff --git a/src/game/server/weapons/puppeteehammer.cpp b/src/game/server/weapons/puppeteehammer.cpp new file mode 100644 index 0000000000..bf97643c77 --- /dev/null +++ b/src/game/server/weapons/puppeteehammer.cpp @@ -0,0 +1,159 @@ +#include "puppeteehammer.h" +#include +#include + +CPuppeteeHammer::CPuppeteeHammer(CCharacter *pOwnerChar) : + CWeapon(pOwnerChar) +{ + m_MaxAmmo = 10; + m_AmmoRegenTime = 1; + m_FireDelay = 500; + m_IsKeepFiring = false; + m_PrevTickPuppets = 0; + mem_zero(m_aPuppetCID, sizeof(m_aPuppetCID)); + mem_zero(m_aPuppetsDirPos, sizeof(m_aPuppetsDirPos)); +} + +void CPuppeteeHammer::Tick() +{ + CWeapon::Tick(); + + int CharCount = 0; + CCharacter *apChar[MAX_PUPPETS] = {0}; + + for(int i = 0; i < MAX_PUPPETS; i++) + { + if(!m_aPuppetCID[i]) + continue; + + apChar[i] = GameServer()->GetPlayerChar(m_aPuppetCID[i] - 1); + if(apChar[i]) + CharCount++; + else + m_aPuppetCID[i] = 0; + } + + if(!CharCount) // Just do nothing + {} + else if((Character()->GetLatestPrevPrevInput().m_Fire & 1) && !(Character()->GetLatestInput().m_Fire & 1) && IsReloading()) // 松发让傀儡开火 + { + vec2 AimPos = Pos() + Character()->GetAimPos(); + + for(int i = 0; i < MAX_PUPPETS; i++) + { + CCharacter *pChr = apChar[i]; + if(!pChr) + continue; + + CWeapon *pChrWeapon = pChr->CurrentWeapon(); + if(!pChrWeapon) + continue; + + vec2 AimDir = normalize(AimPos - pChr->m_Pos); + + pChrWeapon->HandleFire(AimDir); + } + } + else if((m_IsKeepFiring && !IsReloading()) // Pressing + || (m_PrevTickPuppets != CharCount)) // Update + { + vec2 OwnerDir = Character()->GetDirection(); + vec2 PuppetsDir = OwnerDir * clamp(length(Character()->GetAimPos()), 48.f, 128.f); + int a = 0; + + for(int i = 0; i < MAX_PUPPETS; i++) + { + if(!m_aPuppetCID[i]) + continue; + + a++; + m_aPuppetsDirPos[i] = PuppetsDir + (vec2(-OwnerDir.y, OwnerDir.x) * ((a / 2) * 32.f * (a % 2 ? 1 : -1) + ((CharCount % 2) * 16.f))); + } + } + + if(CharCount) + { + //SetPowerUpWeaponPointer(this); + + int OwnerQueuedWeaponSlot = Character()->GetLatestInput().m_WantedWeapon - 1; + + for(int i = 0; i < MAX_PUPPETS; i++) + { + CCharacter *pChr = apChar[i]; + if(!pChr) + continue; + + //pChr->Freeze(5, true); + + pChr->SetQueuedWeaponSlot(OwnerQueuedWeaponSlot); + + // TODO: replace MoveBox + pChr->Core()->m_Vel = Pos() + m_aPuppetsDirPos[i] - pChr->Core()->m_Pos; + GameServer()->Collision()->MoveBox(&pChr->Core()->m_Pos, &pChr->Core()->m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), 0.f); + pChr->Core()->m_Vel = vec2(0.f, 0.f); + } + } + + m_IsKeepFiring = m_IsKeepFiring ? (Character()->GetLatestInput().m_Fire & 1) : false; + m_PrevTickPuppets = CharCount; +} + +void CPuppeteeHammer::Fire(vec2 Direction) +{ + int ClientID = Character()->GetPlayer()->GetCID(); + GameWorld()->CreateSound(Pos(), SOUND_HAMMER_FIRE); + + GameServer()->Antibot()->OnHammerFire(ClientID); + + m_IsKeepFiring = true; + + if(Character()->IsSolo() || Character()->m_Hit & CCharacter::DISABLE_HIT_HAMMER) + return; + + vec2 HammerHitPos = Pos() + Direction * GetProximityRadius() * 0.75f; + + CCharacter *apEnts[MAX_CLIENTS]; + int Num = GameWorld()->FindEntities(HammerHitPos, GetProximityRadius() * 0.5f, (CEntity **)apEnts, + MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER); + + for(int i = 0; i < Num; ++i) + { + CCharacter *pTarget = apEnts[i]; + + //if ((pTarget == this) || GameServer()->Collision()->IntersectLine(ProjStartPos, pTarget->m_Pos, NULL, NULL)) + if((pTarget == Character() || (pTarget->IsAlive() && pTarget->IsSolo()))) + continue; + + bool IsPuppet = false; + int TargetCID = pTarget->GetPlayer()->GetCID(); + for(int i = 0; i < MAX_PUPPETS; i++) // Check Puppet + { + if(TargetCID != m_aPuppetCID[i] - 1) + continue; + + IsPuppet = true; + break; + } + if(IsPuppet) + continue; + + for(int i = 0; i < MAX_PUPPETS; i++) // Set Puppet + { + if(m_aPuppetCID[i]) + continue; + + m_aPuppetCID[i] = TargetCID + 1; + break; + } + + // set his velocity to fast upward (for now) + if(length(pTarget->m_Pos - HammerHitPos) > 0.0f) + GameWorld()->CreateHammerHit(pTarget->m_Pos - normalize(pTarget->m_Pos - HammerHitPos) * GetProximityRadius() * 0.5f); + else + GameWorld()->CreateHammerHit(HammerHitPos); + + pTarget->TakeDamage(vec2(0.f, -0.5f), 0, ClientID, WEAPON_HAMMER, GetWeaponID(), false); // 法师近战 + + GameServer()->Antibot()->OnHammerHit(ClientID); + } +} \ No newline at end of file diff --git a/src/game/server/weapons/puppeteehammer.h b/src/game/server/weapons/puppeteehammer.h new file mode 100644 index 0000000000..8d77e9faa9 --- /dev/null +++ b/src/game/server/weapons/puppeteehammer.h @@ -0,0 +1,23 @@ +#ifndef GAME_SERVER_WEAPONS_PUPPETEEHAMMER_H +#define GAME_SERVER_WEAPONS_PUPPETEEHAMMER_H + +#include + +class CPuppeteeHammer : public CWeapon +{ +public: + CPuppeteeHammer(CCharacter *pOwnerChar); + + void Tick() override; + void Fire(vec2 Direction) override; + int GetType() override { return WEAPON_HAMMER; } + bool IsPowerupOver() { return false; } +private: + enum { MAX_PUPPETS = 4, }; + int m_aPuppetCID[MAX_PUPPETS]; + vec2 m_aPuppetsDirPos[MAX_PUPPETS]; + bool m_IsKeepFiring; + int m_PrevTickPuppets; +}; + +#endif // GAME_SERVER_WEAPONS_PUPPETEEHAMMER_H