From 1386f9edd579e08e30a1512ca0dcb62233ea2667 Mon Sep 17 00:00:00 2001 From: Hu1night <2506405864@qq.com> Date: Sun, 21 Apr 2024 17:35:14 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=99=E4=B8=80=E5=91=A8=E6=88=90=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 + autoexec.cfg | 2 + datasrc/network.py | 1 + src/game/server/gamecontroller.cpp | 4 +- src/game/server/gamemodes.h | 2 + src/game/server/gamemodes/hunterc.cpp | 120 ++++++++++++++++++++++++++ src/game/server/gamemodes/hunterc.h | 20 +++++ src/game/server/gamemodes/huntern.cpp | 80 +++++++++-------- src/game/server/gamemodes/huntern.h | 10 +-- 9 files changed, 193 insertions(+), 48 deletions(-) create mode 100644 src/game/server/gamemodes/hunterc.cpp create mode 100644 src/game/server/gamemodes/hunterc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 056831bf1d..4997e2ca29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -977,6 +977,8 @@ set_src(GAME_SERVER GLOB_RECURSE src/game/server gamemodes/ctf.h gamemodes/dm.cpp gamemodes/dm.h + gamemodes/hunterc.cpp + gamemodes/hunterc.h gamemodes/huntern.cpp gamemodes/huntern.h gamemodes/instagib.cpp diff --git a/autoexec.cfg b/autoexec.cfg index d62467464c..b316fa4ff9 100644 --- a/autoexec.cfg +++ b/autoexec.cfg @@ -167,6 +167,7 @@ add_gametypefile "gtdm" "itdm" "room_config/modes/gtdm.rcfg" add_gametypefile "gctf" "ictf" "room_config/modes/gctf.rcfg" add_gametypefile "catch" "catch" "room_config/modes/catch.rcfg" add_gametypefile "zcatch" "zcatch" "room_config/modes/zcatch.rcfg" +add_gametypefile "hunterc" "hunterc" "room_config/modes/hunterc.rcfg" # Lobby override config, room 0 will be have this config applied after room config sv_lobby_override_config "room_config/lobby.rcfg" @@ -179,6 +180,7 @@ sv_roomlist_vote_title "=== ROOM LIST ===" add_vote " " "info" add_vote "=== CREATE NEW ROOM ===" "info" add_vote "HunterN" "create huntern" +add_vote "HunterC" "create hunterc" add_vote "Deathmatch" "create dm" add_vote "Team Deathmatch" "create tdm" add_vote "Capture the Flag" "create ctf" diff --git a/datasrc/network.py b/datasrc/network.py index 3b8b2899ba..781ff2d902 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -52,6 +52,7 @@ TEAM_SPECTATORS=-1, TEAM_RED, TEAM_BLUE, + NUM_TEAMS, FLAG_MISSING=-3, FLAG_ATSTAND, diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index ebdadf010f..8023caa68c 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -1871,8 +1871,8 @@ void IGameController::Snap(int SnappingClient) } else { - pGameDataObj->m_FlagCarrierRed = 0; - pGameDataObj->m_FlagCarrierBlue = 0; + pGameDataObj->m_FlagCarrierRed = FLAG_ATSTAND; + pGameDataObj->m_FlagCarrierBlue = FLAG_ATSTAND; } } else diff --git a/src/game/server/gamemodes.h b/src/game/server/gamemodes.h index 4053c6b42b..e96aaa5b0f 100644 --- a/src/game/server/gamemodes.h +++ b/src/game/server/gamemodes.h @@ -11,6 +11,7 @@ #include "gamemodes/instagib.h" #include "gamemodes/huntern.h" +#include "gamemodes/hunterc.h" #endif @@ -26,4 +27,5 @@ REGISTER_GAME_TYPE(ictf, CGameControllerICTF) REGISTER_GAME_TYPE(catch, CGameControllerCatch) REGISTER_GAME_TYPE(zcatch, CGameControllerZCatch) REGISTER_GAME_TYPE(huntern, CGameControllerHunterN) +REGISTER_GAME_TYPE(hunterc, CGameControllerHunterC) #endif \ No newline at end of file diff --git a/src/game/server/gamemodes/hunterc.cpp b/src/game/server/gamemodes/hunterc.cpp new file mode 100644 index 0000000000..ba1e3a3e54 --- /dev/null +++ b/src/game/server/gamemodes/hunterc.cpp @@ -0,0 +1,120 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include "hunterc.h" + +#include +#include +#include +//#include +#include + +CGameControllerHunterC::CGameControllerHunterC() : + CGameControllerHunterN() +{ + m_pGameType = "hunterC"; + + m_apClassSpawnMsg[4] = "这局你是平民Civic! 消灭敌方队伍胜利! \n猎人双倍伤害 有瞬杀锤子和破片榴"; + m_pFlag = nullptr; +} + +void CGameControllerHunterC::OnGameStart(bool IsRound) +{ + m_GameFlags = HUNTERN_GAMEFLAGS; + m_DoWinchenkClassTick = -1; + + int PreselectPlayerCount = 0; // 最近没当过猎人的玩家的计数 + int rHunter = 0; // 猎人选择随机数 + + for(int i = 0; i < MAX_CLIENTS; ++i) // 重置并计数玩家 + { + CPlayer *pPlayer = GetPlayerIfInRoom(i); + if(!pPlayer || pPlayer->GetTeam() == TEAM_SPECTATORS + || (pPlayer->m_RespawnDisabled && (!pPlayer->GetCharacter() || !pPlayer->GetCharacter()->IsAlive()))) + continue; + + pPlayer->m_AmongUsTeam = TEAM_RED; // 重置队伍 + pPlayer->m_HiddenScore = 0; // 重置隐藏分 + pPlayer->m_UseHunterWeapon = false; // 默认武器 + pPlayer->m_Class = CLASS_CIVIC; // 重置玩家为平民 + if(pPlayer->m_Preselect) // 猎人选择伪随机!我们要在m_Preselect的玩家里面选择猎人 + ++PreselectPlayerCount; // 计数有PreselectPlayerCount个玩家 + } + + if(m_aTeamSize[TEAM_RED] < 2) // m_aTeamSize[TEAM_RED] = 非队伍模式的人数量 + return; + + m_NumHunter = (m_aTeamSize[TEAM_RED] - 2) / m_HunterRatio + 1; // 我们要多少个猎人 + str_format(m_HunterList, sizeof(m_HunterList), "本回合的 %d 个Hunter是: ", m_NumHunter); // Generate Hunter info message 生成猎人列表消息头 + + SendChatTarget(-1, "——————欢迎来到HunterN猎人杀——————"); + //MatchFlag = -1; // 要成为Jug的玩家不存在 撤了 + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "本回合有 %d 个猎人Hunter has been selected.", m_NumHunter); + SendChatTarget(-1, aBuf); + SendChatTarget(-1, "规则:每回合秘密抽选猎人 猎人对战平民 活人看不到死人消息"); + SendChatTarget(-1, " 猎人双倍伤害 有瞬杀锤子(平民无锤)和破片榴弹(对自己无伤)"); + SendChatTarget(-1, "分辨队友并消灭敌人来取得胜利!Be warned! Sudden Death."); + + for(int iHunter = m_NumHunter; iHunter > 0; --iHunter) // 需要选择m_NumHunter个猎人 + { + if(PreselectPlayerCount <= 0) // 先检查m_Preselect的玩家够不够(即所有玩家是不是最近都当过猎人了) 如果不够就重置所有玩家的m_Preselect + { + for(int i = 0; i < MAX_CLIENTS; ++i) // 重置所有玩家的m_Preselect + { + CPlayer *pPlayer = GetPlayerIfInRoom(i); + if(!pPlayer || pPlayer->GetTeam() == TEAM_SPECTATORS + || (pPlayer->m_RespawnDisabled && (!pPlayer->GetCharacter() || !pPlayer->GetCharacter()->IsAlive()))) + continue; + + pPlayer->m_Preselect = true; // 设置m_Preselect为真(包括猎人 主要是为了随机性) + if(pPlayer->m_Class == CLASS_CIVIC) // 只有平民才可以被计数 + ++PreselectPlayerCount; // 重置PreselectPlayerCount + } + } + + rHunter = rand() % PreselectPlayerCount; // 在PreselectPlayerCount个玩家里选择第rHunter个猎人 + + for(int i = 0; i < MAX_CLIENTS; ++i) // 在PreselectPlayerCount个玩家里选择第rHunter个玩家为猎人 + { + CPlayer *pPlayer = GetPlayerIfInRoom(i); + if(!pPlayer || pPlayer->GetTeam() == TEAM_SPECTATORS + || (pPlayer->m_RespawnDisabled && (!pPlayer->GetCharacter() || !pPlayer->GetCharacter()->IsAlive())) + || !pPlayer->m_Preselect || pPlayer->m_Class != CLASS_CIVIC) // 在平民职业的玩家里面选择猎人 + continue; // 首先剔除不在选择队列里的玩家 + + if(rHunter != 0) // 计数玩家 + { + rHunter--; + continue; + } + + pPlayer->m_Class = CLASS_HUNTER; // 设置猎人Flag + //pPlayer->m_UseHunterWeapon = true; // 使用猎人武器 // 在OnCharachar里面设置 + pPlayer->m_AmongUsTeam = TEAM_BLUE; // 设置队伍 + pPlayer->m_Preselect = false; // 把m_Preselect设为否 即最近当过猎人 + --PreselectPlayerCount; + + // Generate Hunter info message 生成猎人列表消息 + str_append(m_HunterList, Server()->ClientName(i), sizeof(m_HunterList)); + str_append(m_HunterList, ", ", sizeof(m_HunterList)); + + m_pFlag = new CFlag(GameWorld(), 0, pPlayer->GetCharacter()->m_Pos); + + break; + } + } + + for(int i = 0; i < MAX_CLIENTS; ++i) // 循环所有旁观者 把猎人列表告诉他们 + { + CPlayer *pPlayer = GetPlayerIfInRoom(i); + if(!pPlayer) + continue; + + if(pPlayer->GetTeam() == TEAM_SPECTATORS) + SendChatTarget(pPlayer->GetCID(), m_HunterList); // 给膀胱者发 + else if(pPlayer->GetCharacter() && pPlayer->GetCharacter()->IsAlive()) // 这个玩家出生了 所以OnCharacterSpawn已经过了 + OnResetClass(pPlayer->GetCharacter()); // 在这里给他们Class提示和武器 + } + + InstanceConsole()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "huntern", m_HunterList); +} diff --git a/src/game/server/gamemodes/hunterc.h b/src/game/server/gamemodes/hunterc.h new file mode 100644 index 0000000000..9fcc8a922d --- /dev/null +++ b/src/game/server/gamemodes/hunterc.h @@ -0,0 +1,20 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#ifndef GAME_SERVER_GAMEMODES_HUNTERC_H +#define GAME_SERVER_GAMEMODES_HUNTERC_H +#include + +class CGameControllerHunterC : public CGameControllerHunterN +{ +public: + CGameControllerHunterC(); + + // event + //virtual void OnCharacterSpawn(class CCharacter *pChr) override; + + void OnGameStart(bool IsRound) override; + + CFlag *m_pFlag; +}; + +#endif // GAME_SERVER_GAMEMODES_HUNTERC_H diff --git a/src/game/server/gamemodes/huntern.cpp b/src/game/server/gamemodes/huntern.cpp index 637a1b2f4d..c35280d7bd 100644 --- a/src/game/server/gamemodes/huntern.cpp +++ b/src/game/server/gamemodes/huntern.cpp @@ -1,7 +1,5 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include - #include "huntern.h" #include #include @@ -177,10 +175,11 @@ static void ConRevive(IConsole::IResult *pResult, void *pUserData) CGameControllerHunterN::CGameControllerHunterN() : IGameController() { - m_pGameType = "HunterN"; + m_pGameType = "hunterN"; m_GameFlags = HUNTERN_GAMEFLAGS; // 生存模式,回合模式,SUDDENDEATH,回合终局显示游戏结束,游戏结束/旁观Snap队伍模式 + m_DoWinchenkClassTick = -1; mem_zero(m_aMaprotation, sizeof(m_aMaprotation)); INSTANCE_CONFIG_INT(&m_HunterRatio, "htn_hunt_ratio", 4, 2, MAX_CLIENTS, CFGFLAG_CHAT | CFGFLAG_INSTANCE, "几个玩家里选取一个猎人(整数,默认4,限制2~64)"); @@ -246,6 +245,11 @@ void CGameControllerHunterN::CycleMap() // 循环地图 } // Event +void CGameControllerHunterN::OnInit() +{ + SetGameState(IGS_END_MATCH, m_GameoverTime); // EndMatch(); +} + void CGameControllerHunterN::OnWorldReset() // 重置部分值和职业选择 { m_GameFlags = HUNTERN_GAMEFLAGS; @@ -385,36 +389,31 @@ void CGameControllerHunterN::DoWincheckRound() // check for time based win return; } - int PlayerCount = 0; - int TeamRedCount = 0; - int TeamBlueCount = 0; + int TeamPlayerCount[NUM_TEAMS] = {0}; + int AliveTeamPlayerCount[NUM_TEAMS] = {0}; for(int i = 0; i < MAX_CLIENTS; ++i) // 计数玩家 { CPlayer *pPlayer = GetPlayerIfInRoom(i); - if(!pPlayer || pPlayer->GetTeam() == TEAM_SPECTATORS - || (pPlayer->m_RespawnDisabled - && (!pPlayer->GetCharacter() || !pPlayer->GetCharacter()->IsAlive()))) + if(!pPlayer || pPlayer->GetTeam() == TEAM_SPECTATORS) continue; - ++PlayerCount; - if(pPlayer->m_AmongUsTeam == TEAM_RED) - ++TeamRedCount; - else //if(pPlayer->m_AmongUsTeam == TEAM_BLUE) - ++TeamBlueCount; + TeamPlayerCount[pPlayer->m_AmongUsTeam]++; // 计数双方队伍人数 + if(!pPlayer->m_RespawnDisabled || (pPlayer->GetCharacter() && pPlayer->GetCharacter()->IsAlive())) + AliveTeamPlayerCount[pPlayer->m_AmongUsTeam]++; // 计数活着的玩家 } - if(!IsTimeEnd && (TeamBlueCount && TeamRedCount)) // 如果不是回合限时结束则需某队死光 + if(!IsTimeEnd && (AliveTeamPlayerCount[TEAM_RED] && AliveTeamPlayerCount[TEAM_BLUE])) // 如果不是回合限时结束则需某队死光 { - m_DoWinchenkClassTick = 0; + m_DoWinchenkClassTick = -1; return; } // 游戏结束 - m_aTeamscore[TEAM_RED] = 0; // 重置 - m_aTeamscore[TEAM_BLUE] = 0; + m_aTeamscore[TEAM_RED] = TeamPlayerCount[TEAM_RED]; // 队伍分数形式显示双方人数 + m_aTeamscore[TEAM_BLUE] = TeamPlayerCount[TEAM_BLUE]; - for(int i = 0; i < MAX_CLIENTS; ++i) // 进行队伍分数 玩家分数和隐藏分操作 + for(int i = 0; i < MAX_CLIENTS; ++i) // 进行玩家分数和隐藏分操作 { CPlayer *pPlayer = GetPlayerIfInRoom(i); if(!pPlayer) @@ -425,29 +424,24 @@ void CGameControllerHunterN::DoWincheckRound() // check for time based win if(pPlayer->m_HiddenScore) // 玩家拥有隐藏分 pPlayer->m_Score += pPlayer->m_HiddenScore; // 添加隐藏分 - - if(pPlayer->m_AmongUsTeam == TEAM_RED) // 队伍分数显示双方人数 - m_aTeamscore[TEAM_RED] += 1; // 累加队伍分数 用队伍分数显示有几个民 - else //if(pPlayer->m_AmongUsTeam == TEAM_BLUE) - m_aTeamscore[TEAM_BLUE] += 1; // 累加队伍分数 用队伍分数显示有几个猎 } - if(!PlayerCount) + if(!AliveTeamPlayerCount[TEAM_RED] && !AliveTeamPlayerCount[TEAM_BLUE]) { SendChatTarget(-1, "两人幸终!"); } - else if(!TeamBlueCount) // no blue + else if(!AliveTeamPlayerCount[TEAM_BLUE]) // no blue { SendChatTarget(-1, m_HunterList); - SendChatTarget(-1, "红队胜利!"); // 平民为红队 + SendChatTarget(-1, "平民胜利!"); //GameWorld()->CreateSoundGlobal(SOUND_CTF_CAPTURE); // 猎人死的时候够吵了 m_aTeamscore[TEAM_BLUE] = -m_aTeamscore[TEAM_BLUE]; // 反转蓝队分数 显示"红队胜利" } - else if(!TeamRedCount) // no red + else if(!AliveTeamPlayerCount[TEAM_RED]) // no red { //SendChatTarget(-1, m_HunterList); // 猎人胜利不显示列表(因为平民被打死的时候已经显示过了) - SendChatTarget(-1, "蓝队胜利!"); // 猎人为蓝队 + SendChatTarget(-1, "猎人胜利!"); GameWorld()->CreateSoundGlobal(SOUND_CTF_CAPTURE); m_aTeamscore[TEAM_RED] = -m_aTeamscore[TEAM_RED]; // 反转红队分数 就会显示"蓝队胜利" @@ -552,15 +546,18 @@ int CGameControllerHunterN::OnCharacterDeath(class CCharacter *pVictim, class CP if(m_GameState != IGS_GAME_RUNNING) // 如果游戏在正常运行 return DEATH_SKIP_SCORE; // 跳过内置分数逻辑 - if(pVictim->GetPlayer()->m_Class == CLASS_HUNTER) // 猎人死亡 进行计数和猎人死亡报告 + int VictimCID = pVictim->GetPlayer()->GetCID(); + + switch(pVictim->GetPlayer()->m_Class) // 猎人死亡 进行计数和猎人死亡报告 { + case CLASS_HUNTER: --m_NumHunter; // 计数猎人死亡 if(m_EffectHunterDeath) GameWorld()->CreatePlayerSpawn(pVictim->m_Pos); // 死亡给个出生烟 char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "Hunter '%s' was defeated! ", Server()->ClientName(pVictim->GetPlayer()->GetCID())); + str_format(aBuf, sizeof(aBuf), "Hunter '%s' was defeated! ", Server()->ClientName(VictimCID)); if(m_BroadcastHunterDeath == 1 || !m_NumHunter) // 如果是最后一个Hunter @@ -589,16 +586,17 @@ int CGameControllerHunterN::OnCharacterDeath(class CCharacter *pVictim, class CP GameWorld()->CreateSoundGlobal(SOUND_CTF_DROP, CmaskOne(pPlayer->GetCID())); } } - } - else if(pVictim->GetPlayer()->m_Class == CLASS_CIVIC) // 平民死亡 - { + break; + case CLASS_JUGGERNAUT: + //char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "Juggernaut '%s' was defeated! ", Server()->ClientName(VictimCID)); + SendChatTarget(-1, aBuf); + GameWorld()->CreateSoundGlobal(SOUND_CTF_CAPTURE); + break; + default://case CLASS_CIVIC: // 平民死亡 GameWorld()->CreateSoundGlobal(SOUND_CTF_DROP); + break; } - /*else if(pVictim->GetPlayer()->m_Class == CLASS_JUGGERNAUT) - { - SendChatTarget(-1, "Juggernaut was defeated!"); - GameWorld()->CreateSoundGlobal(SOUND_CTF_CAPTURE); - }*/ if(pKiller != pVictim->GetPlayer()) // 不是自杀 { @@ -611,12 +609,12 @@ int CGameControllerHunterN::OnCharacterDeath(class CCharacter *pVictim, class CP char aBuf[64]; str_format(aBuf, sizeof(aBuf), "你被 '%s' 的%s所杀", Server()->ClientName(pKiller->GetCID()), m_apWeaponName[Weapon + 1]); - SendChatTarget(pVictim->GetPlayer()->GetCID(), aBuf); // 给被弄死的人发 + SendChatTarget(VictimCID, aBuf); // 给被弄死的人发 } } if(m_NumHunter) // 如果没有猎人(当然是全死光啦) 就不要发猎人列表 等EndMatch - SendChatTarget(pVictim->GetPlayer()->GetCID(), m_HunterList); // 给被弄死的人发猎人列表 + SendChatTarget(VictimCID, m_HunterList); // 给被弄死的人发猎人列表 m_DoWinchenkClassTick = ((Server()->TickSpeed() * m_Wincheckdeley) / 1000); // 延时终局 diff --git a/src/game/server/gamemodes/huntern.h b/src/game/server/gamemodes/huntern.h index 5f1d4d550d..f1a576ed2e 100644 --- a/src/game/server/gamemodes/huntern.h +++ b/src/game/server/gamemodes/huntern.h @@ -7,7 +7,7 @@ class CGameControllerHunterN : public IGameController { -private: // config +protected: // config int m_HunterRatio; //int m_BroadcastHunterList; int m_BroadcastHunterDeath; @@ -28,6 +28,7 @@ class CGameControllerHunterN : public IGameController void CycleMap(); // game event + void OnInit() override; void OnWorldReset() override; void OnPreEntitySnap(int SnappingClient, int OtherMode) override; // per tick void DoWincheckMatch() override; @@ -42,7 +43,7 @@ class CGameControllerHunterN : public IGameController //int OnPickup(CPickup *pPickup, CCharacter *pChar, SPickupSound *pSound) override; int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon) override; -private: // Intelnal function and value +protected: // Intelnal function and value int m_NumHunter; // 有多少个猎人 int m_DoWinchenkClassTick; // 终局判断延迟的Tick char m_HunterList[256]; // 猎人列表 @@ -50,7 +51,6 @@ class CGameControllerHunterN : public IGameController //int TeamClass[1]; //int MatchFlag = -1; -protected: enum { HUNTERN_GAMEFLAGS = IGF_SURVIVAL | IGF_ROUND_TIMER_ROUND | IGF_SUDDENDEATH | IGF_MARK_MATCH | IGF_MARK_AMONGUS, }; enum HUNTERN_WINFLAG { @@ -61,8 +61,8 @@ class CGameControllerHunterN : public IGameController }; const char* m_apClassSpawnMsg[4] = { - {"这局你是平民Civic! 消灭敌方队伍胜利! \n猎人双倍伤害 有瞬杀锤子和破片榴弹"}, - {" 这局你是猎人Hunter! 消灭敌方队伍胜利!\n 猎人双倍伤害 有瞬杀锤子和破片榴弹"}, + {"这局你是平民Civic! 找出并消灭猎人以胜利! \n猎人双倍伤害 有瞬杀锤子和破片榴弹"}, + {" 这局你是猎人Hunter! 与其他猎人消灭平民以胜利!\n 猎人双倍伤害 有瞬杀锤子和破片榴弹"}, {" 这局你是剑圣Juggernaut! 消灭敌方队伍胜利!\n 剑圣40心20盾 有盾反锤子且能斩杀"}, {" 这局你是傀儡师Puppetee! 消灭敌方队伍胜利!\n 猎人双倍伤害 有瞬杀锤子和破片榴弹"},};