Skip to content

Commit

Permalink
成年韩梅、成年小九、哑炮、秦无命、SP白菲菲技能调整
Browse files Browse the repository at this point in the history
  • Loading branch information
CuteReimu committed Nov 13, 2023
1 parent 06e9b7c commit b9f9956
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 46 deletions.
23 changes: 23 additions & 0 deletions src/main/kotlin/handler/skill_pin_ming_san_lang_tos.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.fengsheng.handler

import com.fengsheng.HumanPlayer
import com.fengsheng.protos.Role
import com.fengsheng.skill.ActiveSkill
import com.fengsheng.skill.SkillId
import org.apache.log4j.Logger

class skill_pin_ming_san_lang_tos : AbstractProtoHandler<Role.skill_pin_ming_san_lang_tos>() {
override fun handle0(r: HumanPlayer, pb: Role.skill_pin_ming_san_lang_tos) {
val skill = r.findSkill(SkillId.PIN_MING_SAN_LANG) as? ActiveSkill
if (skill == null) {
log.error("你没有这个技能")
r.sendErrorMessage("你没有这个技能")
return
}
skill.executeProtocol(r.game!!, r, pb)
}

companion object {
private val log = Logger.getLogger(skill_pin_ming_san_lang_tos::class.java)
}
}
5 changes: 0 additions & 5 deletions src/main/kotlin/handler/skill_yu_si_wang_po_a_tos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ class skill_yu_si_wang_po_a_tos : AbstractProtoHandler<Role.skill_yu_si_wang_po_
r.sendErrorMessage("你没有这个技能")
return
}
if (HashSet(pb.cardIdsList).size != pb.cardIdsCount) {
log.error("卡牌重复${pb.cardIdsList.toTypedArray().contentToString()}")
r.sendErrorMessage("卡牌重复${pb.cardIdsList.toTypedArray().contentToString()}")
return
}
skill.executeProtocol(r.game!!, r, pb)
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/skill/LianXin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.apache.log4j.Logger
import java.util.concurrent.TimeUnit

/**
* 成年小九技能【联信】:接收其他角色情报后,可以翻开此角色,摸两张牌,然后将一张含该情报不同颜色的手牌置入传出者的情报区
* 成年小九技能【联信】:接收其他角色情报后,可以翻开此角色,摸两张牌,然后将一张含该情报相同颜色的手牌置入传出者的情报区
*/
class LianXin : InitialSkill, TriggeredSkill {
override val skillId = SkillId.LIAN_XIN
Expand All @@ -22,7 +22,7 @@ class LianXin : InitialSkill, TriggeredSkill {
!askWhom.roleFaceUp
} ?: return null
val color = event.messageCard.colors
return ResolveResult(executeLianXinA(g.fsm!!, event) { card -> card.colors.any { it !in color } }, true)
return ResolveResult(executeLianXinA(g.fsm!!, event) { card -> card.colors.any { it in color } }, true)
}

private data class executeLianXinA(val fsm: Fsm, val event: ReceiveCardEvent, val checkCard: (Card) -> Boolean) :
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/skill/MiXin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.apache.log4j.Logger
import java.util.concurrent.TimeUnit

/**
* 成年韩梅技能【密信】:接收其他角色情报后,可以翻开此角色,摸两张牌,然后将一张含该情报相同颜色的手牌置入传出者的情报区
* 成年韩梅技能【密信】:接收其他角色情报后,可以翻开此角色,摸两张牌,然后将一张含该情报不同颜色的手牌置入传出者的情报区
*/
class MiXin : InitialSkill, TriggeredSkill {
override val skillId = SkillId.MI_XIN
Expand All @@ -22,7 +22,7 @@ class MiXin : InitialSkill, TriggeredSkill {
!askWhom.roleFaceUp
} ?: return null
val color = event.messageCard.colors
return ResolveResult(executeMiXinA(g.fsm!!, event) { card -> card.colors.any { it in color } }, true)
return ResolveResult(executeMiXinA(g.fsm!!, event) { card -> card.colors.any { it !in color } }, true)
}

private data class executeMiXinA(
Expand Down
88 changes: 88 additions & 0 deletions src/main/kotlin/skill/PinMingSanLang.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.fengsheng.skill

import com.fengsheng.*
import com.fengsheng.card.count
import com.fengsheng.phase.MainPhaseIdle
import com.fengsheng.protos.Common.color.Black
import com.fengsheng.protos.Role.skill_pin_ming_san_lang_toc
import com.fengsheng.protos.Role.skill_pin_ming_san_lang_tos
import com.google.protobuf.GeneratedMessageV3
import org.apache.log4j.Logger
import java.util.concurrent.TimeUnit

/**
* 秦无命技能【拼命三郎】:出牌阶段限一次,你可以将一张纯黑色手牌置入自己的情报区,然后摸三张牌。你不能以此法令自己有三张或更多的黑情报。
*/
class PinMingSanLang : MainPhaseSkill(), InitialSkill {
override val skillId = SkillId.PIN_MING_SAN_LANG

override fun mainPhaseNeedNotify(r: Player): Boolean =
super.mainPhaseNeedNotify(r) && r.cards.any { it.isPureBlack() }

override fun executeProtocol(g: Game, r: Player, message: GeneratedMessageV3) {
if (r !== (g.fsm as? MainPhaseIdle)?.whoseTurn) {
log.error("现在不是出牌阶段空闲时点")
(r as? HumanPlayer)?.sendErrorMessage("现在不是出牌阶段空闲时点")
return
}
if (r.getSkillUseCount(skillId) > 0) {
log.error("[拼命三郎]一回合只能发动一次")
(r as? HumanPlayer)?.sendErrorMessage("[拼命三郎]一回合只能发动一次")
return
}
val pb = message as skill_pin_ming_san_lang_tos
if (r is HumanPlayer && !r.checkSeq(pb.seq)) {
log.error("操作太晚了, required Seq: ${r.seq}, actual Seq: ${pb.seq}")
r.sendErrorMessage("操作太晚了")
return
}
val card = r.findCard(pb.cardId)
if (card == null) {
log.error("没有这张卡")
(r as? HumanPlayer)?.sendErrorMessage("没有这张卡")
return
}
if (!card.isPureBlack()) {
log.error("这张牌不是纯黑色")
(r as? HumanPlayer)?.sendErrorMessage("这张牌不是纯黑色")
return
}
if (r.messageCards.count(Black) >= 2) {
log.error("你不能以此法令自己有三张或更多的黑情报")
(r as? HumanPlayer)?.sendErrorMessage("你不能以此法令自己有三张或更多的黑情报")
return
}
r.incrSeq()
r.addSkillUseCount(skillId)
log.info("${r}发动了[拼命三郎],将手牌中的${card}置入自己的情报区")
r.deleteCard(card.id)
r.messageCards.add(card)
for (p in g.players) {
if (p is HumanPlayer) {
val builder = skill_pin_ming_san_lang_toc.newBuilder()
builder.playerId = p.getAlternativeLocation(r.location)
builder.card = card.toPbCard()
p.send(builder.build())
}
}
r.draw(3)
g.addEvent(AddMessageCardEvent(r))
g.continueResolve()
}

companion object {
private val log = Logger.getLogger(PinMingSanLang::class.java)
fun ai(e: MainPhaseIdle, skill: ActiveSkill): Boolean {
e.whoseTurn.getSkillUseCount(SkillId.PIN_MING_SAN_LANG) == 0 || return false
e.whoseTurn.messageCards.count(Black) < 2 || return false
val card = e.whoseTurn.cards.filter { it.isPureBlack() }.randomOrNull() ?: return false
val cardId = card.id
GameExecutor.post(e.whoseTurn.game!!, {
val builder = skill_pin_ming_san_lang_tos.newBuilder()
builder.cardId = cardId
skill.executeProtocol(e.whoseTurn.game!!, e.whoseTurn, builder.build())
}, 2, TimeUnit.SECONDS)
return true
}
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/skill/RoleCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ object RoleCache {
RoleSkillsData("金自来", role.jin_zi_lai, false, true, DuMing()),
RoleSkillsData("成年小九", role.adult_xiao_jiu, false, false, LianXin(), ShunShiErWei()),
RoleSkillsData("成年韩梅", role.adult_han_mei, true, false, MiXin(), JiangJiJiuJi()),
RoleSkillsData("秦无命", role.qin_wu_ming, false, true, YuSiWangPo()),
RoleSkillsData("秦无命", role.qin_wu_ming, false, true, PinMingSanLang(), YuSiWangPo()),
RoleSkillsData("李书云", role.li_shu_yun, true, false, DingLun(), ZhenLi()),
RoleSkillsData("SP阿芙罗拉", role.sp_a_fu_luo_la, true, false, YingBianZiRu(), HunShuiMoYu()),
RoleSkillsData("SP白菲菲", role.sp_bai_fei_fei, true, true, TaoQu()),
Expand Down
6 changes: 4 additions & 2 deletions src/main/kotlin/skill/ShouKouRuPing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.fengsheng.protos.Role.skill_shou_kou_ru_ping_toc
import org.apache.log4j.Logger

/**
* 哑炮技能【守口如瓶】:你对其他角色使用、其他角色对你使用【试探】和【威逼】时,取消原效果,改为双方各摸一张牌
* 哑炮技能【守口如瓶】:你对其他角色使用、其他角色对你使用【试探】和【威逼】时,这张牌无效。如果这是本回合首次触发此技能,双方各摸一张牌
*/
class ShouKouRuPing : InitialSkill, TriggeredSkill {
override val skillId = SkillId.SHOU_KOU_RU_PING
Expand All @@ -20,6 +20,7 @@ class ShouKouRuPing : InitialSkill, TriggeredSkill {
val targetPlayer = event.targetPlayer!!
(askWhom === event.player || askWhom === targetPlayer) && event.player !== targetPlayer
} ?: return null
askWhom.addSkillUseCount(skillId)
log.info("${askWhom}发动了[守口如瓶]")
for (p in askWhom.game!!.players) {
if (p is HumanPlayer) {
Expand All @@ -37,7 +38,8 @@ class ShouKouRuPing : InitialSkill, TriggeredSkill {
p.send(builder.build())
}
}
g.sortedFrom(listOf(event.player, event.targetPlayer!!), event.whoseTurn.location).forEach { it.draw(1) }
if (askWhom.getSkillUseCount(skillId) == 1)
g.sortedFrom(listOf(event.player, event.targetPlayer!!), event.whoseTurn.location).forEach { it.draw(1) }
event.valid = false
return null
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/skill/SkillId.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ enum class SkillId(private val cName: String) {
CONG_RONG_YING_DUI("从容应对"), CHI_ZI_ZHI_XIN("赤子之心"), YUN_CHOU_WEI_WO("运筹帷幄"), HOU_LAI_REN("后来人"),
ZI_ZHENG_QING_BAI("自证清白"), SHOU_KOU_RU_PING("守口如瓶"), DU_MING("赌命"), LIAN_XIN("联信"), SHUN_SHI_ER_WEI("顺势而为"),
MI_XIN("密信"), JIANG_JI_JIU_JI("将计就计"), HAN_HOU_LAO_SHI("憨厚老实"), YI_WEN_AN_HAO("译文暗号"),
YU_SI_WANG_PO("鱼死网破"), DING_LUN("定论"), ZHEN_LI("真理"), YING_BIAN_ZI_RU("应变自如"), HUN_SHUI_MO_YU("浑水摸鱼"),
TAO_QU("套取"), TAN_XU_BIAN_SHI("探虚辨实"), CUN_BU_BU_RANG("寸步不让"), XIN_GE_LIAN_LUO("信鸽联络"),
HOU_ZI_QIE_XIN("猴子窃信"), BIAN_ZE_TONG("变则通"), YOU_DI_SHEN_RU("诱敌深入"), JIAN_DI_FENG_XING("歼敌风行"),
XIANG_JIN_SI_SUO("详尽思索"), QIANG_YING_XIA_LING("强硬下令"), JIE_CHE_YUN_HUO("借车运货"),
PIN_MING_SAN_LANG("拼命三郎"), YU_SI_WANG_PO("鱼死网破"), DING_LUN("定论"), ZHEN_LI("真理"), YING_BIAN_ZI_RU("应变自如"),
HUN_SHUI_MO_YU("浑水摸鱼"), TAO_QU("套取"), TAN_XU_BIAN_SHI("探虚辨实"), CUN_BU_BU_RANG("寸步不让"),
XIN_GE_LIAN_LUO("信鸽联络"), HOU_ZI_QIE_XIN("猴子窃信"), BIAN_ZE_TONG("变则通"), YOU_DI_SHEN_RU("诱敌深入"),
JIAN_DI_FENG_XING("歼敌风行"), XIANG_JIN_SI_SUO("详尽思索"), QIANG_YING_XIA_LING("强硬下令"), JIE_CHE_YUN_HUO("借车运货"),
WORKERS_ARE_KNOWLEDGABLE("咱们工人有知识");


Expand Down
3 changes: 1 addition & 2 deletions src/main/kotlin/skill/TaoQu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.apache.log4j.Logger
import java.util.concurrent.TimeUnit

/**
* SP白菲菲技能【套取】:出牌阶段限一次,你可以弃置两张含含相同颜色的牌,将一名其他角色情报区的一张同色情报加入手牌,该角色摸一张牌
* SP白菲菲技能【套取】:出牌阶段限一次,你可以弃置两张含含相同颜色的牌,将一名其他角色情报区的一张同色情报加入手牌。
*/
class TaoQu : MainPhaseSkill(), InitialSkill {
override val skillId = SkillId.TAO_QU
Expand Down Expand Up @@ -186,7 +186,6 @@ class TaoQu : MainPhaseSkill(), InitialSkill {
p.send(builder.build())
}
}
target.draw(1)
g.addEvent(DiscardCardEvent(fsm.whoseTurn, player))
return ResolveResult(fsm, true)
}
Expand Down
33 changes: 14 additions & 19 deletions src/main/kotlin/skill/YuSiWangPo.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.fengsheng.skill

import com.fengsheng.*
import com.fengsheng.card.count
import com.fengsheng.phase.MainPhaseIdle
import com.fengsheng.protos.Common.color.Black
import com.fengsheng.protos.Role.*
import com.google.protobuf.GeneratedMessageV3
import org.apache.log4j.Logger
import java.util.concurrent.TimeUnit

/**
* 秦无命技能【鱼死网破】:出牌阶段限一次,你可以弃掉任意张数手牌(至少1),让一名其他玩家弃置对应数量+1的手牌(不足则全弃),然后你们各摸一张牌
* 秦无命技能【鱼死网破】:出牌阶段限一次,你可以弃置一张手牌,令一名其他角色弃置(你的黑情报数量+1)的手牌(不足则全弃)。
*/
class YuSiWangPo : MainPhaseSkill(), InitialSkill {
override val skillId = SkillId.YU_SI_WANG_PO
Expand Down Expand Up @@ -49,16 +51,14 @@ class YuSiWangPo : MainPhaseSkill(), InitialSkill {
(r as? HumanPlayer)?.sendErrorMessage("目标已死亡")
return
}
val cards = pb.cardIdsList.map {
val card = r.findCard(it)
if (card == null) {
log.error("没有这张卡")
(r as? HumanPlayer)?.sendErrorMessage("没有这张卡")
return
}
card
val card = r.findCard(pb.cardId)
if (card == null) {
log.error("没有这张卡")
(r as? HumanPlayer)?.sendErrorMessage("没有这张卡")
return
}
val discardAll = cards.size + 1 >= target.cards.size
val discardCount = r.messageCards.count(Black)
val discardAll = discardCount >= target.cards.size
r.incrSeq()
r.addSkillUseCount(skillId)
log.info("${r}${target}发动了[鱼死网破]")
Expand All @@ -68,15 +68,14 @@ class YuSiWangPo : MainPhaseSkill(), InitialSkill {
val builder = skill_yu_si_wang_po_a_toc.newBuilder()
builder.playerId = p.getAlternativeLocation(r.location)
builder.targetPlayerId = p.getAlternativeLocation(target.location)
builder.cardCount = cards.size + 1
if (!discardAll) {
builder.waitingSecond = timeout
if (p === target) builder.seq = p.seq
}
p.send(builder.build())
}
}
g.playerDiscardCard(r, *cards.toTypedArray())
g.playerDiscardCard(r, card)
g.addEvent(DiscardCardEvent(r, r))
if (target.cards.isNotEmpty()) g.addEvent(DiscardCardEvent(r, target))
if (discardAll) {
Expand All @@ -89,11 +88,9 @@ class YuSiWangPo : MainPhaseSkill(), InitialSkill {
}
}
g.playerDiscardCard(target, *target.cards.toTypedArray())
r.draw(1)
target.draw(1)
g.continueResolve()
} else {
g.resolve(executeYuSiWangPo(g.fsm!!, r, target, cards.size + 1, timeout))
g.resolve(executeYuSiWangPo(g.fsm!!, r, target, discardCount, timeout))
}
}

Expand Down Expand Up @@ -180,16 +177,14 @@ class YuSiWangPo : MainPhaseSkill(), InitialSkill {
private val log = Logger.getLogger(YuSiWangPo::class.java)
fun ai(e: MainPhaseIdle, skill: ActiveSkill): Boolean {
e.whoseTurn.getSkillUseCount(SkillId.YU_SI_WANG_PO) == 0 || return false
e.whoseTurn.cards.isNotEmpty() || return false
val card = e.whoseTurn.cards.randomOrNull() ?: return false
val target =
e.whoseTurn.game!!.players.filter { it!!.alive && it.isEnemy(e.whoseTurn) && it.cards.size >= 2 }
.randomOrNull() ?: return false
val count = (1..minOf(e.whoseTurn.cards.size, target.cards.size - 1)).random()
val cardIds = e.whoseTurn.cards.shuffled().subList(0, count).map { it.id }
GameExecutor.post(e.whoseTurn.game!!, {
val builder = skill_yu_si_wang_po_a_tos.newBuilder()
builder.targetPlayerId = e.whoseTurn.getAlternativeLocation(target.location)
builder.addAllCardIds(cardIds)
builder.cardId = card.id
skill.executeProtocol(e.whoseTurn.game!!, e.whoseTurn, builder.build())
}, 2, TimeUnit.SECONDS)
return true
Expand Down
29 changes: 20 additions & 9 deletions src/main/proto/role.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ message skill_yi_wen_an_hao_toc {
uint32 player_id = 1;
}

// 广播使用【守口如瓶】:你对其他角色使用、其他角色对你使用【试探】和【威逼】时,取消原效果,改为双方各摸一张牌。(摸牌走摸牌协议)
// 广播使用【守口如瓶】:你对其他角色使用、其他角色对你使用【试探】和【威逼】时,这张牌无效。如果这是本回合首次触发此技能,双方各摸一张牌。(摸牌走摸牌协议)
message skill_shou_kou_ru_ping_toc {
uint32 player_id = 1;
uint32 card_player_id = 2; // 使用牌的角色
Expand Down Expand Up @@ -1267,7 +1267,7 @@ message skill_lian_xin_a_toc {
uint32 seq = 5;
}

// 成年小九【联信】B:然后将一张含该情报不同颜色的手牌置入传出者的情报区
// 成年小九【联信】B:然后将一张含该情报相同颜色的手牌置入传出者的情报区
message skill_lian_xin_b_tos {
uint32 card_id = 1;
uint32 seq = 2;
Expand Down Expand Up @@ -1299,7 +1299,7 @@ message skill_mi_xin_a_toc {
uint32 seq = 5;
}

// 成年韩梅【密信】B:然后将一张含该情报相同颜色的手牌置入传出者的情报区
// 成年韩梅【密信】B:然后将一张含该情报不同颜色的手牌置入传出者的情报区
message skill_mi_xin_b_tos {
uint32 card_id = 1;
uint32 seq = 2;
Expand All @@ -1317,20 +1317,31 @@ message skill_jiang_ji_jiu_ji_toc {
uint32 player_id = 1;
}

// 秦无命【鱼死网破】A:出牌阶段限一次,你可以弃掉任意张数手牌(至少1),让一名其他玩家弃置(对应数量+1)的手牌(不足则全弃),然后你们各摸一张牌。
// 秦无命【拼命三郎】:出牌阶段限一次,你可以将一张纯黑色手牌置入自己的情报区,然后摸三张牌。你不能以此法令自己有三张或更多的黑情报。
message skill_pin_ming_san_lang_tos {
uint32 card_id = 1;
uint32 seq = 2;
}

// 广播使用【拼命三郎】
message skill_pin_ming_san_lang_toc {
uint32 player_id = 1; // 秦无命的ID
card card = 2;
}

// 秦无命【鱼死网破】A:出牌阶段限一次,你可以弃置一张手牌,令一名其他角色弃置(你的黑情报数量+1)的手牌(不足则全弃)。
message skill_yu_si_wang_po_a_tos {
uint32 target_player_id = 1;
repeated uint32 card_ids = 2;
uint32 card_id = 2;
uint32 seq = 3;
}

// 广播使用【鱼死网破】A
message skill_yu_si_wang_po_a_toc {
uint32 player_id = 1; // 秦无命的ID
uint32 target_player_id = 2;
uint32 card_count = 3; // 秦无命弃牌的数量+1,弃牌走弃牌协议
uint32 waiting_second = 4; // 如果全弃,则这个字段为0
uint32 seq = 5;
uint32 waiting_second = 3; // 如果全弃,则这个字段为0
uint32 seq = 4;
}

// 秦无命【鱼死网破】B:对方弃牌(如果全弃,不用客户端请求)
Expand Down Expand Up @@ -1409,7 +1420,7 @@ message skill_tao_qu_a_toc {
uint32 seq = 4;
}

// SP白菲菲【套取】B:将一名其他角色情报区的一张同色情报加入手牌,该角色摸一张牌
// SP白菲菲【套取】B:将一名其他角色情报区的一张同色情报加入手牌
message skill_tao_qu_b_tos {
uint32 target_player_id = 1;
uint32 card_id = 2;
Expand Down

0 comments on commit b9f9956

Please sign in to comment.