本页主题: “猫有n条命”规则第四版 Execl VBA版本(开发中) 打印 | 加为IE收藏 | 复制链接 | 收藏主题 | 上一主题 | 下一主题

bbsriver
杀人游戏MVP勋章I 杀人游戏MVP勋章II
级别: 管理员


精华: 52
发帖: 17391
威望: 8729 点
金钱: 7064 静电币
支持度: 19801 点
在线时间:13725(小时)
注册时间:2002-11-21
最后登录:2016-12-22

 “猫有n条命”规则第四版 Execl VBA版本(开发中)

今年年初我对游戏发展有两个设想,其中之一是把复杂规则的计算交给电脑来处理,以减轻天神的工作量并减少错误。在游戏20作了一次尝试,写了一个execl表格,用函数计算投标情况和中标者。成功之后,接下来我准备把猫命规则也做成execl表格。但开始设计之后才知道excel函数功能有限,很难演算出猫命的游戏进程。非用VBA不可。所以我开始学VBA编程。

昨晚完成了程序的第一部分:发牌

按7人、每人5张牌的游戏模式写的程序。这部分代码的设计是:

  • 划定一个7*5的表格区域,每行对应1个玩家,每格对应1张牌。
  • 区域中的每个单元格都有下拉框,其中列出本格可以选择的牌型供天神安放。
  • 已经被分派光了的牌自动从下拉框中消去。
  • 一个玩家已经有了的特权牌自动从这个玩家的单元格的下拉框中消去,但庶民牌不受影响。
  • 杀手牌和狼人牌分配给同一个玩家的话将会提示错误。
  • 如果一个玩家已经被分配了4张特权牌,程序自动把最后一张填充为庶民牌。
  • 每分配了一张牌程序都会自动计算最新的情况。

    Copy code
    Function KW(PlayerACards As Range) As Integer
        '检查杀手牌和狼人牌是否发给了该玩家
        KW = Application.WorksheetFunction.CountIf(PlayerACards, "杀手") + Application.WorksheetFunction.CountIf(PlayerACards, "狼人")
    End Function

    Sub AutoWriteCivilian(PlayerACards As Range)
        '如果已经分配给该玩家4张牌且没有庶民牌,则自动分配给玩家1张庶民牌
        If Application.WorksheetFunction.CountIf(PlayerACards, "") = 1 And Application.WorksheetFunction.CountIf(PlayerACards, "庶民") = 0 Then
            '查找最后一个空白单元格并写入“庶民”
            For Each cell In PlayerACards.Cells
                If cell.Value = "" Then
                    cell.Select
                    ActiveCell.Value = "庶民"
                    Exit For
                End If
            Next cell
        End If
    End Sub

    Private Sub Worksheet_Change(ByVal Target As Range)

        '声明变量StartRow、CurrentPlayer和UndealCol,用于指定可分配牌型列表所在区域的位置
        Dim StartRow As Integer
        Dim CurrentPlayer As Integer
        Dim UndealCol As Integer
       
        '给StartRow赋值
        StartRow = 30
       
        '声明7位玩家各自的持牌情况区域
        Dim Player1Cards As Range
        Dim Player2Cards As Range
        Dim Player3Cards As Range
        Dim Player4Cards As Range
        Dim Player5Cards As Range
        Dim Player6Cards As Range
        Dim Player7Cards As Range
       
        Set Player1Cards = Worksheets("日程").Range("$D$30:$H$30")
        Set Player2Cards = Worksheets("日程").Range("$D$31:$H$31")
        Set Player3Cards = Worksheets("日程").Range("$D$32:$H$32")
        Set Player4Cards = Worksheets("日程").Range("$D$33:$H$33")
        Set Player5Cards = Worksheets("日程").Range("$D$34:$H$34")
        Set Player6Cards = Worksheets("日程").Range("$D$35:$H$35")
        Set Player7Cards = Worksheets("日程").Range("$D$36:$H$36")
           
        '声明对象DealtCards,指定表格中用于记录玩家的持牌情况的区域
        Dim DealtCards As Range
        Set DealtCards = Union(Player1Cards, Player2Cards, Player3Cards, Player4Cards, Player5Cards, Player6Cards, Player7Cards)
       
        '声明对象UndealCards,指定表格中用于记录可分配牌型的区域
        Dim UndealCards As Range
        Set UndealCards = Worksheets("日程").Range("$CW$30:$DI$36")
       
        '指定触发本过程的单元格范围
        If Target.column <= 8 And Target.column >= 4 And Target.row <= 36 And Target.row >= 30 Then
         
            '清空记录可分配牌型的区域
            UndealCards.Select
            Selection.ClearContents
           
            '声明变量CardCount,记录这一牌型被分配了几张
            Dim CardCount As Integer
            '声明变量CardName,记录这一牌型的名称
            Dim CardName As String
         
            '循环检查7位玩家的可分配牌型
            For CurrentPlayer = StartRow To StartRow + 6
           
                '初始化undealcol
                UndealCol = 101
           
                '循环检查13种牌型
                For i = 2 To 14
               
                    '给cardname变量赋值
                    CardName = Worksheets("常量").Cells(i, 1).Value
                   
                    '调用Excel内置函数countif,统计该牌型已经一共被分配了几张
                    CardCount = Application.WorksheetFunction.CountIf(DealtCards, CardName)
                   
                        '声明对象mycards,指定表格中记录该玩家已分到的牌型的区域
                        Dim mycards As Range
                        Set mycards = Rows(CurrentPlayer)
                       
                        '声明变量MyCardCount,记录这一牌型是否已分配给该玩家
                        Dim MyCardCount As Integer
                                       
                        '调用Excel内置函数countif,统计该牌型是否曾被分配给该玩家
                        MyCardCount = Application.WorksheetFunction.CountIf(mycards, CardName)
                       
                        '庶民牌不管是否已经分配给该玩家,都不统计(庶民牌可以重复分配)
                        If CardName = "庶民" Then
                            MyCardCount = 0
                        End If
                                       
                    '循环查找可分配牌型列表所在区域的第一个空白单元格
                    Do While Worksheets("日程").Cells(CurrentPlayer, UndealCol).Value <> ""
                        UndealCol = UndealCol + 1
                    Loop
                   
                    '如果该牌型还没有被分配光,而且还没有被分配给该玩家过,就把该牌型写入可分配的牌型列表之中第一个空白单元格
                    If CardCount < Worksheets("常量").Cells(i, 2).Value And MyCardCount = 0 Then
                        Debug.Print CardName
                        Worksheets("日程").Cells(CurrentPlayer, UndealCol).Value = CardName
                    End If
               
                Next i
       
            Next CurrentPlayer
       
            '循环查找记录玩家的持牌情况的区域的下一个空白单元格并把光标移动到该单元格以供下一次输入
            For Each cell In DealtCards.Cells
                If cell.Value = "" Then
                    cell.Select
                    Exit For
                End If
            Next cell
           
            '声明变量KWError,记录指定区域中的杀手牌和狼人牌共有几张
            Dim KWError As Integer
           
            '调用KW函数检查是否把杀手牌和狼人牌分配给了同一个玩家
            KWError = KW(Player1Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player2Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player3Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player4Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player5Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player6Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            KWError = KW(Player7Cards)
            If KWError = 2 Then
                MsgBox ("杀手牌和狼人牌不能分配给同一个玩家!请修改!")
            End If
           
            '分配了4张特权牌后,调用AutoWriteCivilian过程自动分配给该玩家一张庶民牌
            Call AutoWriteCivilian(Player1Cards)
            Call AutoWriteCivilian(Player2Cards)
            Call AutoWriteCivilian(Player3Cards)
            Call AutoWriteCivilian(Player4Cards)
            Call AutoWriteCivilian(Player5Cards)
            Call AutoWriteCivilian(Player6Cards)
            Call AutoWriteCivilian(Player7Cards)
           
            '声明变量EmptyCells,记录一个区域中空格单元格的数目
            Dim EmptyCells As Integer
           
            '检查记录玩家的持牌情况的区域中是否还有空格
            EmptyCells = Application.WorksheetFunction.CountIf(DealtCards, "")
           
            '选中记录玩家的持牌情况的区域并提示所有牌已经分配完毕
            If EmptyCells = 0 Then
                DealtCards.Select
                MsgBox ("所有牌都已经被分配")
            End If
       
        End If

    End Sub
  • Posted: 2007-07-07 13:49 | [楼 主]
    bbsriver
    杀人游戏MVP勋章I 杀人游戏MVP勋章II
    级别: 管理员


    精华: 52
    发帖: 17391
    威望: 8729 点
    金钱: 7064 静电币
    支持度: 19801 点
    在线时间:13725(小时)
    注册时间:2002-11-21
    最后登录:2016-12-22

     

    我也发现这个错误了,已经改了
    Posted: 2007-07-08 10:43 | 1 楼
    bbsriver
    杀人游戏MVP勋章I 杀人游戏MVP勋章II
    级别: 管理员


    精华: 52
    发帖: 17391
    威望: 8729 点
    金钱: 7064 静电币
    支持度: 19801 点
    在线时间:13725(小时)
    注册时间:2002-11-21
    最后登录:2016-12-22

     

    程序的第二部分是供天神输入第一夜的玩家行动。代码设计是:

  • 提供7*n的表格,供天神输入每位玩家的第一夜行动。每行对应1个玩家。
  • 表格分为“行动”、“消耗点数”、“作用对象”,例表之中只为每个玩家留了4次行动的表格,正式表格可以扩展到10次以上。
  • “行动”区域提供下拉框,框中自动列出该玩家当夜可用的特权供天神选择。
  • 程序根据每个玩家手中持有的牌,计算生成该玩家当夜可使用的特权列表,列入下拉框选项(需要手工执行这个宏)。
  • 已经被丢掉的牌所对应的特权不会被列入下拉框中。
  • 天神选择玩家的行动后,程序自动计算该行动消耗的行动点数,并检查该玩家的行动点数是否够用。如果不够,将提示报错。

    行动点数的计算模块和行动的作用对象选择模块还没有完成,3rd的时候再补。



    1、生成特权下拉框供天神选择
    Copy code
    Sub ListMyPrivileges(PlayerCards As Range, Player As Integer)

        '声明变量CardName和PrivilegeName,记录牌型名称和特权名称
        Dim CardName As String
        Dim PrivilegeName As String
       
        '声明变量CurrentPlayer和PrivilegeCol,记录可使用特权区域的起始和起始列
        Dim PrivilegeCol As Integer
        Dim CurrentPlayer As Integer
        CurrentPlayer = PlayerCards.row
       
        '清空记录可使用特权的区域以准备写入
        For i = 101 To 111
            Worksheets("日程").Cells(CurrentPlayer, i).Select
            Selection.ClearContents
        Next i
       
        '循环把玩家持牌区域中的每一张牌的名字记录到CardName
        For c = 4 To 8
            CardName = Worksheets("日程").Cells(CurrentPlayer, c).Value
           
            '声明变量CardLife,记录这张牌是否已经被丢掉
            Dim CardLife As Integer
           
            '到"变量2"表中检查这张牌是否已经被丢掉
            CardLife = Worksheets("变量2").Cells(Player + 1, c - 2).Value
                   
            '如果这张牌还没有被丢掉,则循环查找这张牌所对应的特权,并记录在PrivilegeName(保镖牌自动生效,不必列出)
            For i = 2 To 23
               
                If CardLife = 1 And CardName = Worksheets("常量").Cells(i, 3) Then
                    PrivilegeName = Worksheets("常量").Cells(i, 4)
                    'Debug.Assert PrivilegeName = "狙击"
                   
                    '初始化PrivilegeCol
                    PrivilegeCol = 101
       
                    '循环查找可使用特权列表所在区域的第一个空白单元格
                    Do While Worksheets("日程").Cells(CurrentPlayer, PrivilegeCol).Value <> ""
                        PrivilegeCol = PrivilegeCol + 1
                    Loop
                   
                    '把PrivilegeName中的特权名称写入可使用特权列表的第一个单元格
                    Worksheets("日程").Cells(CurrentPlayer, PrivilegeCol).Value = PrivilegeName
                End If
               
            Next i
           
        Next c

    End Sub

    Sub 列出每个玩家第一夜可用的特权()

        '声明7位玩家各自的持牌情况区域
        Dim Player1Cards As Range
        Dim Player2Cards As Range
        Dim Player3Cards As Range
        Dim Player4Cards As Range
        Dim Player5Cards As Range
        Dim Player6Cards As Range
        Dim Player7Cards As Range
       
        Set Player1Cards = Worksheets("日程").Range("$D$46:$H$46")
        Set Player2Cards = Worksheets("日程").Range("$D$47:$H$47")
        Set Player3Cards = Worksheets("日程").Range("$D$48:$H$48")
        Set Player4Cards = Worksheets("日程").Range("$D$49:$H$49")
        Set Player5Cards = Worksheets("日程").Range("$D$50:$H$50")
        Set Player6Cards = Worksheets("日程").Range("$D$51:$H$51")
        Set Player7Cards = Worksheets("日程").Range("$D$52:$H$52")
       
        '调用ListMyPrivileges子过程列出每个玩家的可用特权
        Call ListMyPrivileges(Player1Cards, 1)
        Call ListMyPrivileges(Player2Cards, 2)
        Call ListMyPrivileges(Player3Cards, 3)
        Call ListMyPrivileges(Player4Cards, 4)
        Call ListMyPrivileges(Player5Cards, 5)
        Call ListMyPrivileges(Player6Cards, 6)
        Call ListMyPrivileges(Player7Cards, 7)
       
        '返回表头界面
        Range("J46").Select
           
    End Sub



    2、选择行动后自动填充行动点数,并检查点数是否够用
    Copy code
    Private Sub Worksheet_Change(ByVal Target As Range)
        '如果玩家使用了特权,在下一列自动填充该特权的行动点数
        '如果天神在“行动一”和“行动二”当中输入了特权,则
        If Target.column = 10 Or Target.column = 13 Or Target.column = 16 Or Target.column = 19 Then
            If Target.Count = 1 Then
           
            '声明变量PrivilegeName和PrivilegeAP,分别代表行使的特权的名称和行驶的特权对应的行动点数
            Dim PrivilegeName As String
            Dim PrivilegeAP
            PrivilegeName = Target.Value
           
                '循环查找该特权对应的行动点数并写入下一列单元格中
                For i = 2 To 22
                   
                    If PrivilegeName = Worksheets("常量").Cells(i, 4).Value Then
                        If PrivilegeName <> "法医" And PrivilegeName <> "纵火犯" Then
                            PrivilegeAP = Worksheets("常量").Cells(i, 5).Value
                            Target.Offset(0, 1).Value = PrivilegeAP
                        End If
                       
                        '计算“法医”特权的行动点数
                        If PrivilegeName = "法医" Then
                            '调用WhichPlayer确定玩家代号
                            PlayerNo = WhichPlayer(Worksheets("日程").Cells(Target.row, 2).Value)
                            '从“变量2”表中取得该玩家法医特权的使用次数记录,计算本次所需行动点数
                            PrivilegeAP = Application.WorksheetFunction.RoundUp((Worksheets("变量2").Cells(PlayerNo + 1, 8) + 1) / 2, 0)
                            Target.Offset(0, 1).Value = PrivilegeAP
                        End If
                       
                        '如果是“纵火犯”特权(纵火犯特权是扣除下一夜的行动点数,今夜计为0点)
                        If PrivilegeName = "纵火犯" Then
                            PrivilegeAP = 0
                            Target.Offset(0, 1).Value = PrivilegeAP
                        End If
                       
                    End If
                       
                    '如果是删除输入的特权,则相应的行动点数也清零
                    If PrivilegeName = "" Then
                        PrivilegeAP = ""
                        Target.Offset(0, 1).Value = PrivilegeAP
                    End If

                Next i
           
            End If
     
            '如果一次删除多个单元格的内容,则把对应的行动点数都清零
            If Target.Count > 1 Then
                Target.Offset(0, 1).Value = ""
            End If
       
        End If
       


        '检查行动点数是否够用
        '声明变量UsableAP和UsedAP,记录该玩家可用的行动点数和已用的行动点数
        Dim UsableAP, UsedAP As Integer
        UsedAP = Application.WorksheetFunction.Sum(Worksheets("日程").Cells(Target.row, 11).Value, Worksheets("日程").Cells(Target.row, 14).Value, Worksheets("日程").Cells(Target.row, 17).Value, Worksheets("日程").Cells(Target.row, 20).Value)
        UsableAP = Worksheets("日程").Cells(Target.row, 3).Value - UsedAP
       
        '输入特权后自动计算行动点数是否够用,如果不够,提示并清空输入的特权
        If Target.column = 11 Or Target.column = 14 Or Target.column = 17 Or Target.column = 20 Then
            If Target.Count = 1 Then
                If Target.Value > UsableAP + Target.Value Then
                    MsgBox ("行动点数不足,不能使用这项特权!")
                    Target.Value = ""
                    Target.Offset(0, -1).Value = ""
                End If
            End If
        End If
    End Sub


    3、将玩家名称和序号对应起来的函数
    Copy code
    Function WhichPlayer(PlayerName As String) As Integer
       
        '根据输入的玩家名字,确定玩家在游戏中的序号,以供在索引表格中查找时确定Range之用
        Select Case PlayerName
            Case Worksheets("日程").Cells(30, 2).Value
            WhichPlayer = 1
            Case Worksheets("日程").Cells(31, 2).Value
            WhichPlayer = 2
            Case Worksheets("日程").Cells(32, 2).Value
            WhichPlayer = 3
            Case Worksheets("日程").Cells(33, 2).Value
            WhichPlayer = 4
            Case Worksheets("日程").Cells(34, 2).Value
            WhichPlayer = 5
            Case Worksheets("日程").Cells(35, 2).Value
            WhichPlayer = 6
            Case Worksheets("日程").Cells(36, 2).Value
            WhichPlayer = 7
        End Select
       
    End Function
  • Posted: 2007-07-08 12:46 | 2 楼
    bbsriver
    杀人游戏MVP勋章I 杀人游戏MVP勋章II
    级别: 管理员


    精华: 52
    发帖: 17391
    威望: 8729 点
    金钱: 7064 静电币
    支持度: 19801 点
    在线时间:13725(小时)
    注册时间:2002-11-21
    最后登录:2016-12-22

     

    这部分代码用于自动生成每种特权的可作用对象列表。代码设计是:

  • 天神输入每个玩家的“行动”之后,程序自动判断这个行动可以作用的对象,并生成下拉框列表供天神选择,或者自动填充。
  • 程序将自动检查每个玩家的生死状态,将死者排除在可作用对象之外。
  • 使用“瞄准狙击”特权后,程序将弹出对话框,要求输入瞄准的牌的顺位,并自动判断这张牌是不是底牌,有没有没丢掉。如果不符合规则将报错。
  • 使用“变形”特权后,程序将自动列出所有可以变成的牌型。排除玩家在游戏开始时已经持有的牌,(还应该排除已经变过的牌,这部分代码到第一天的模块中再加入)。

    法医特权的对象是每夜的牺牲者,特赦特权的对象每天的被处决者。因为牺牲者计算模块和被处决者计算模块还没有写,这两部分暂缺。

    另外优化了前几部分代码,改进了循环的效率。
    每多写一点,对VBA的认识就深一点。

    Copy code
       
    Private Sub Worksheet_Change(ByVal Target As Range)

        '第四部分:如果玩家使用了特权,自动设定该特权对应的作用对象下拉框选项
        '如果天神在“行动”当中输入了特权,则
        If Target.Column = 10 Or Target.Column = 13 Or Target.Column = 16 Or Target.Column = 19 Then
       
            If Target.Count = 1 Then
           
                Select Case Target.Value
                   
                    '如果删除了某次行动,则清除对应的“作用对象”单元格
                    Case ""
                        Target.Offset(0, 2) = ""
                        Target.Offset(0, 2).Validation.Delete
                   
                    '列出瞄准狙击特权的作用对象:手上至少还有两张牌的玩家
                    Case "瞄准狙击"
                        Call ShootPrivilege(Target)
                   
                    '直接写入圣人、防弹衣、狼毒特权的作用对象:使用者自己
                    Case "圣人", "防弹衣", "狼毒"
                        Call Myself(Target)
                   
                    '列出禁锢和纵火犯特权的作用对象:除了自己以外其他还活着的玩家
                    Case "禁锢", "纵火犯"
                        Call AllExceptMe(Target)
                   
                    '直接写入反狙击特权的作用对象:全体玩家
                    Case "反狙击"
                        Call AllPlayers(Target)
                   
                    Case "特赦"
                   
                    Case "法医"
                                       
                    '列出变形特权的作用对象:自己没拿到的任一特权牌牌型
                    Case "变形"
                        Call Transform(Target)
                                       
                    '列出一般特权作用对象:全体还活着的玩家
                    Case Else
                        Call GenlPrivileges(Target)
                End Select
               
            End If
     
            '如果一次删除多个单元格的内容,则把对应的作用对象都清零
            If Target.Count > 1 Then
                Target.Offset(0, 2).Value = ""
                Target.Offset(0, 2).Validation.Delete
            End If
       
        End If
       
       
       
       
        '第四部分之二:要求天神手工输入瞄准狙击哪张牌
        '如果天神选择了“瞄准狙击”特权的作用对象,且只改动了一个单元格,而且不是删除单元格中的内容,则
        If Target.Column = 12 Or Target.Column = 15 Or Target.Column = 18 Or Target.Column = 21 Then
            If Target.Count = 1 Then
                If Target.Offset(0, -2).Value = "瞄准狙击" And Target.Value <> "" Then
               
                    '声明变量WhichCard,记录被瞄准的牌的倒数序号
                    Dim WhichCard As Integer
                   
                    '要求手工输入被瞄准的牌的倒数序号
                    WhichCard = Application.InputBox("要瞄准" & Target.Value & "的倒数第几张牌?" + _
                                  " (例如:要瞄准狙击倒数第二张牌就输入“2”)", Title:="指定要瞄准的牌", Type:=1)
                    '将序号写到瞄准狙击可作用对象列表区域的末尾
                    Worksheets("日程").Cells(Target.Row, 158).Value = WhichCard

                    '声明变量AimPlayer,调用WhichPlayer函数记录被瞄准的玩家的代号
                    Dim AimPlayer As Integer
                    AimPlayer = WhichPlayer(Target.Value)
                   
                    '声明变量AimCards,到“变量2”表格中检查这张牌是否被丢掉
                    Dim AimCards As Integer
                    AimCard = Worksheets("变量2").Cells(AimPlayer + 1, WhichCard + 1).Value

                    '如果瞄准的是底牌,报错并要求重新输入
                    If WhichCard = 1 Then
                        aaa = MsgBox("不能瞄准狙击底牌!请重新选择目标!", Buttons:=vbCritical)
                        Target.Value = ""
                    End If
                   
                    '如果瞄准的是已经被丢掉的牌,报错并要求重新输入
                    If AimCard <> 1 And WhichCard <= 5 And WhichCard > 1 Then
                        aaa = MsgBox(Target.Value & "的倒数第" & CStr(WhichCard) & "张牌已经被丢掉了。不能瞄准被丢掉的牌!请重新选择目标!", Buttons:=vbCritical)
                        Target.Value = "'"
                    End If
                       
                    '如果瞄准的是不存在的牌,报错并要求重新输入
                    If WhichCard > 5 Then
                        aaa = MsgBox("每个玩家最多只有5张牌。倒数第" & CStr(WhichCard) & "张牌不存在!请重新选择目标!", Buttons:=vbCritical)
                        Target.Value = "'"
                    End If
               
                End If
            End If
        End If
       
    End Sub


    Copy code
    Option Explicit
    Sub GenlPrivileges(Target As Range)

        '清空一般特权可作用对象列表区域以准备写入
        Dim d As Integer
        For d = 151 To 157
            Worksheets("日程").Cells(Target.Row, d).Select
            Selection.Clear
        Next d
       
        '在“变量2”表格中循环检查7位玩家的底牌是否还在(在就表示这个玩家还活着)
        Dim genl As Integer
        For genl = 2 To 8
       
            '声明变量LivePlayer,记录玩家的名字
            Dim LivePlayer As String
            LivePlayer = Worksheets("变量2").Cells(genl, 1).Value
           
            If Worksheets("变量2").Cells(genl, 2).Value = 1 Then
           
                '循环查找一般特权可作用对象列表区域的第一个空白单元格
                Dim PrivilegesCol As Integer
                PrivilegesCol = 151
               
                Do While Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value <> ""
                    PrivilegesCol = PrivilegesCol + 1
                Loop
               
                '将玩家的名字写到第一个空白单元格中
                Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value = LivePlayer
           
            End If
           
        Next genl
       
        '调用RangeAddress函数,生成记录一般特权可作用对象列表区域的A1格式地址
        Dim privilegeAim As String
        privilegeAim = RangeAddress(Target.Row, 151, Target.Row, 157)
                               
        '指定“作用对象”单元格的下拉框列表地址
        With Target.Offset(0, 2).Validation
            .Delete
            .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
            xlBetween, Formula1:="=" & privilegeAim
            .IgnoreBlank = True
            .InCellDropdown = True
            .IMEMode = xlIMEModeNoControl
            .ShowInput = True
            .ShowError = True
        End With
        '清空并选中“作用对象”单元格,以供天神选择新的作用对象
        Target.Offset(0, 2).Value = ""
        Target.Offset(0, 2).Select

    End Sub

    Sub ShootPrivilege(Target As Range)

        '清空瞄准狙击可作用对象列表区域以准备写入
        Dim s As Integer
        For s = 161 To 167
            Worksheets("日程").Cells(Target.Row, s).Select
            Selection.Clear
        Next s
           
        '在“变量2”表格中循环检查7位玩家的倒数第二张牌是否还在(瞄准狙击不能打底牌)
        Dim shot As Integer
        For shot = 2 To 8
       
            '声明变量ShotPlayer,记录玩家的名字
            Dim ShotPlayer As String
            ShotPlayer = Worksheets("变量2").Cells(shot, 1).Value
           
            If Worksheets("变量2").Cells(shot, 3).Value = 1 Then
                '循环查找瞄准狙击可作用对象列表区域的第一个空白单元格
                Dim PrivilegesCol As Integer
                PrivilegesCol = 161
               
                Do While Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value <> ""
                    PrivilegesCol = PrivilegesCol + 1
                Loop
               
                '将玩家的名字写到第一个空白单元格中
                Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value = ShotPlayer
            End If
           
        Next shot
       
        '调用RangeAddress函数,生成记录瞄准狙击特权可作用对象列表区域的A1格式地址
        Dim privilegeAim As String
        privilegeAim = RangeAddress(Target.Row, 161, Target.Row, 167)
                               
        '指定“作用对象”单元格的下拉框列表地址
        With Target.Offset(0, 2).Validation
            .Delete
            .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
            xlBetween, Formula1:="=" & privilegeAim
            .IgnoreBlank = True
            .InCellDropdown = True
            .IMEMode = xlIMEModeNoControl
            .ShowInput = True
            .ShowError = True
        End With
        '清空并选中“作用对象”单元格,以供天神选择新的作用对象
        Target.Offset(0, 2).Value = ""
        Target.Offset(0, 2).Select
    End Sub

    Sub Myself(Target As Range)
       
        '将行使特权者本人写入“作用对象”单元格(用于圣人、防弹衣、狼毒特权)
        Dim privilegeAim As String
        privilegeAim = Worksheets("日程").Cells(Target.Row, 2).Value
        Target.Offset(0, 2).Value = privilegeAim
        Target.Offset(0, 2).Validation.Delete
       
    End Sub

    Sub AllExceptMe(Target As Range)

        '清空禁锢特权可作用对象列表区域以准备写入(也用于纵火犯特权)
        Dim f As Integer
        For f = 171 To 176
            Worksheets("日程").Cells(Target.Row, f).Select
            Selection.Clear
        Next f
       
        '在“变量2”表格中循环检查7位玩家的底牌是否还在(在就表示这个玩家还活着)
        Dim forb As Integer
        For forb = 2 To 8
       
            '声明变量LivePlayer,记录玩家的名字
            Dim LivePlayer As String
            LivePlayer = Worksheets("变量2").Cells(forb, 1).Value
           
            '循环检查该玩家的底牌是否还在,并把自己排除在外
            If Worksheets("变量2").Cells(forb, 2).Value = 1 And LivePlayer <> Worksheets("日程").Cells(Target.Row, 2).Value Then
               
                '循环查找一般特权可作用对象列表区域的第一个空白单元格
                Dim PrivilegesCol As Integer
                PrivilegesCol = 171
               
                Do While Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value <> ""
                    PrivilegesCol = PrivilegesCol + 1
                Loop
               
                '将玩家的名字写到第一个空白单元格中
                Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value = LivePlayer
           
            End If
           
        Next forb
       
        '调用RangeAddress函数,生成记录禁锢特权可作用对象列表区域的A1格式地址
        Dim privilegeAim As String
        privilegeAim = RangeAddress(Target.Row, 171, Target.Row, 176)
                               
        '指定“作用对象”单元格的下拉框列表地址
        With Target.Offset(0, 2).Validation
            .Delete
            .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
            xlBetween, Formula1:="=" & privilegeAim
            .IgnoreBlank = True
            .InCellDropdown = True
            .IMEMode = xlIMEModeNoControl
            .ShowInput = True
            .ShowError = True
        End With
        '清空并选中“作用对象”单元格,以供天神选择新的作用对象
        Target.Offset(0, 2).Value = ""
        Target.Offset(0, 2).Select

    End Sub

    Sub Transform(Target As Range)

        '清空变形特权可作用对象列表区域以准备写入
        Dim d As Integer
        For d = 201 To 209
            Worksheets("日程").Cells(Target.Row, d).Select
            Selection.Clear
        Next d
       
        '在“常量”表格中循环检查11种牌型
        Dim trans As Integer
        For trans = 2 To 12
       
            '声明变量CardName,记录牌型的名字
            Dim CardName As String
            CardName = Worksheets("常量").Cells(trans, 1).Value
           
            '声明变量PlayerNo以确定该玩家的代号
            Dim PlayerNo As Integer
            PlayerNo = WhichPlayer(Worksheets("日程").Cells(Target.Row, 2).Value)
           
            '声明变量DoMeHave,记录是否该玩家是否已持有这张牌(默认为没有)
            Dim DoMeHave As Integer
            DoMeHave = 0
           
            '循环检查该玩家自己手中的5张牌是否有和CardName重复的牌型
            Dim mc As Integer
            For mc = 4 To 8
                If CardName = Worksheets("日程").Cells(PlayerNo + 29, mc).Value Then
                    DoMeHave = 1
                    Exit For
                End If
            Next mc
           
            '如果没有重复,将牌型名称写入变形特权可作用对象列表区域
            If DoMeHave = 0 Then
           
                '循环查找变形特权可作用对象列表区域的第一个空白单元格
                Dim PrivilegesCol As Integer
                PrivilegesCol = 201
               
                Do While Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value <> ""
                    PrivilegesCol = PrivilegesCol + 1
                Loop
               
                '将牌型写到第一个空白单元格中
                Worksheets("日程").Cells(Target.Row, PrivilegesCol).Value = CardName
           
            End If
           
        Next trans
       
        '调用RangeAddress函数,生成记录变形特权可作用对象列表区域的A1格式地址
        Dim privilegeAim As String
        privilegeAim = RangeAddress(Target.Row, 201, Target.Row, 209)
                               
        '指定“作用对象”单元格的下拉框列表地址
        With Target.Offset(0, 2).Validation
            .Delete
            .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
            xlBetween, Formula1:="=" & privilegeAim
            .IgnoreBlank = True
            .InCellDropdown = True
            .IMEMode = xlIMEModeNoControl
            .ShowInput = True
            .ShowError = True
        End With
        '清空并选中“作用对象”单元格,以供天神选择新的作用对象
        Target.Offset(0, 2).Value = ""
        Target.Offset(0, 2).Select

    End Sub

    Sub AllPlayers(Target As Range)
       
        '将"全体玩家"写入“作用对象”单元格(用于反狙击特权)
        Dim privilegeAim As String
        privilegeAim = "全体玩家"
        Target.Offset(0, 2).Value = privilegeAim
        Target.Offset(0, 2).Validation.Delete

    End Sub


    Copy code
    Function Address(r As Integer, c As Integer) As String
       
        'Address函数,通过调用“函数”表格中的Excel函数,将Cell地址格式转化为A1地址格式
        '输入行的数字
        Worksheets("函数").Range("B2").Value = r
        '输入列的数字
        Worksheets("函数").Range("D2").Value = c
        Address = Worksheets("函数").Range("F2").Value
       
    End Function

    Function RangeAddress(StartRow As Integer, StartCol As Integer, LastRow As Integer, LastCol As Integer) As String
        Dim Start, Last As String
        Start = Address(StartRow, StartCol)
        Last = Address(LastRow, LastCol)
        RangeAddress = Start & ":" & Last
    End Function
  • Posted: 2007-07-10 06:41 | 3 楼
    bbsriver
    杀人游戏MVP勋章I 杀人游戏MVP勋章II
    级别: 管理员


    精华: 52
    发帖: 17391
    威望: 8729 点
    金钱: 7064 静电币
    支持度: 19801 点
    在线时间:13725(小时)
    注册时间:2002-11-21
    最后登录:2016-12-22

     

    Quote:
    引用第7楼香香睡美人于2007-07-09 23:12发表的  :
    为什么中间要隔这么多列,分这么开?

    看起来比较舒服。挤在一起看不清楚
    Posted: 2007-07-10 07:06 | 4 楼
    帖子浏览记录 版块浏览记录
    狗狗静电BBS - wwW.DoGGiEhoMe.CoM » 「天黑请闭眼」游戏 Mafia Game

    沪ICP备05008186号
    Powered by PHPWind Styled by MagiColor