KillerBots

Check-in [11179945c5]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Game now feature complete!!
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:11179945c5156e861df6c74f95bc6c60e021f537
User & Date: gerald 2013-08-16 21:41:25
Context
2013-08-16
22:01
List to not walk into walls. check-in: bc575faeae user: gerald tags: trunk
21:41
Game now feature complete!! check-in: 11179945c5 user: gerald tags: trunk
2013-08-12
20:28
Added base pieces. check-in: 8d591e05b7 user: gerald tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to KillerBots.tcl.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
namespace eval ::gui::help:: {}


##
## Load the GUI and library files
##
foreach dir [list gui lib] {
    foreach file [] {
        source $file
    }
}

##
## Load the message files
##
foreach dir [list [file join $baseDir msgs] ~/KillerBots/msgs] {
    if {[file exists]} {
        ::msgcat::mcload $dir
    }
}

##
## Load Perferences
##
loadPerferences

##
## Invoke the main procedure
##
main {*}$argv







|







|
|













17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
namespace eval ::gui::help:: {}


##
## Load the GUI and library files
##
foreach dir [list gui lib] {
    foreach file [glob [file join $baseDir $dir *.tcl]] {
        source $file
    }
}

##
## Load the message files
##
foreach dir [list [file join $baseDir msgs] ~/.KillerBots/msgs] {
    if {[file exists $dir]} {
        ::msgcat::mcload $dir
    }
}

##
## Load Perferences
##
loadPerferences

##
## Invoke the main procedure
##
main {*}$argv

Changes to gui/CreatePerferencesGui.tcl.

1
2
3
4
5
6
7
8

9
10
11
12
13
14
























































15
16
17
18




















































proc ::gui::CreatePerferencesGui {} {
    variable windows
    variable ::perferences

    set main windows(main)
    set w [toplevel $main.perferences]
    wm withdraw $w
    set windows(perferences) $w

    wm transient $w $main
    wm title $w [::msgcat::mc perferences.title]
    wm protocol $w WM_DELETE_WINDOW ::gui::perferencesDismiss

    set f $w.frame
    ttk::frame $f
























































    grid configure $f -sticky nsew
    grid columnconfigure $w $f -weight 1
    grid rowconfigure $w $f -weight 1
}






















































|

|



>


|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
proc ::gui::CreatePerferencesGui {} {
    variable windows
    variable tempSettings

    set main $windows(main)
    set w [toplevel $main.perferences]
    wm withdraw $w
    set windows(perferences) $w
    set windows(perferences,displayCommand) ::gui::DisplayPerferencesGui
    wm transient $w $main
    wm title $w [::msgcat::mc perferences.title]
    wm protocol $w WM_DELETE_WINDOW {set ::gui::windows(Perference,status) -1}

    set f $w.frame
    ttk::frame $f
    set itemList {
        Robots menubutton {ROBOT_*} {}
        Player menubutton {PERSON_*} {}
        RefreshRate scale 10 120
        Speed scale 15 60
        Level scale 1 10
        RobotsPerLevel scale 5 50
        SecondsPerLevel scale 60 300
    }
    set imageList [image names]
    foreach {item type min max} $itemList {
        ::tk::label $f.label$item -text [::msgcat::mc label,$item]
        switch -exact -- $type {
            menubutton {
                ::ttk::menubutton $f.entry$item -menu $f.entry$item.menu
                menu $f.entry$item.menu
                grid configure $f.label$item - $f.entry$item -sticky ew
                foreach image [lsort -dictionary [lsearch -all -inline $imageList $min]] {
                    $f.entry$item.menu add radiobutton \
                        -value $image \
                        -variable ::gui::tempSettings($item) \
                        -image $image
                }
            }
            scale {
                ::ttk::entry $f.value$item \
                    -state readonly \
                    -textvariable ::gui::tempSettings($item)
                ::ttk::scale $f.entry$item \
                    -from $min \
                    -to $max \
                    -variable ::gui::tempSettings($item)
                    grid configure $f.label$item $f.value$item $f.entry$item -sticky ew
            }
            default {
                ##
                ## should never get here
                ##
            }
        }
    }
    grid columnconfigure $f $f.entry$item -weight 1

    set b $f.buttons
    ::ttk::frame $b
    ::ttk::button $b.save \
        -text [::msgcat::mc Save] \
        -command {set ::gui::windows(Perference,status) 1}
    ::ttk::button $b.cancel \
        -text [::msgcat::mc Cancel] \
        -command {set ::gui::windows(Perference,status) -1}
    grid configure x $b.save x $b.cancel x
    grid columnconfigure $b {0 2 4} -weight 1

    grid configure $b -columnspan 3 -sticky ew

    grid configure $f -sticky nsew
    grid columnconfigure $w $f -weight 1
    grid rowconfigure $w $f -weight 1

    ##
    ## Set up the two menubuttons
    ##
    set buttonDict [list \
        Robots  $f.entryRobots \
        Player  $f.entryPlayer \
    ]
    trace add variable ::gui::tempSettings write [list updateMenuButton $buttonDict ::gui::tempSettings]

}

proc updateMenuButton {buttonDict nsVarName varName index ops} {
    upvar #0 $nsVarName arrayVar

    if {![info exists arrayVar($index)]} {
        after 1 [info level 0]
    }
    if {[dict exists $buttonDict $index]} {
        [dict get $buttonDict $index] configure -image $arrayVar($index)
    } else {
        set arrayVar($index) [expr {int($arrayVar($index))}]
    }
}

proc ::gui::DisplayPerferencesGui {w} {
    variable windows
    variable tempSettings
    variable ::settings

    set simulationActive [expr {[info exists calculated(timeLeft)] && ($calculated(timeLeft) > 0.0)}]
    if {$simulationActive} {
        pauseSimulation
    }

    set w $windows(perferences)
    array set tempSettings [array get settings]
    set windows(Perference,status) 0
    after idle [list grab set $w]
    vwait ::gui::windows(Perference,status)
    grab release $w
    wm withdraw $w

    if {$windows(Perference,status) == 1} {
        array set settings [array get tempSettings]
        savePerferences
    }

    if {$simulationActive} {
        doSimulationStep
    }

}

Changes to gui/createMainWindow.tcl.



1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
..
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53














54
55
56

57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75













76
77
78
79
80



81
82
83
84




85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
121
122
123
124
125
126
127


























































































proc ::gui::createMainWindow {} {
    variable windows

    set w [toplevel .main]
    wm withdraw $w
    set windows(main) $w
    wm transient $w .
    wm title $w [::msgcat::mc main.title]
    wm protocol $w WM_DELETE_WINDOW ::gui::createMainWindowDismiss


    set menu $w.menubar
    menu $menu
    if {[string equal $::tcl_platform(os) Darwin]} {
        set appleMenu $menu.apple
        menu $appleMenu
        $menu add cascade -menu $appleMenu
................................................................................

    ::ttk::frame $w.frame
    grid configure $w.frame -sticky nsew
    grid columnconfigure $w $w.frame -weight 1
    grid rowconfigure $w $w.frame -weight 1

    set f $w.frame
    ::ttk::treeview $f.data \
        -xscrollcommand [list $f.hsb set] \
        -yscrollcommand [list $f.hsb set] \
        -columns {id type name value} \
        -displaycolumns {type value} \
        -show {tree headings} \
        -selectmode browse
    scrollbar $f.hsb \
        -orient horizontal \
        -command [list $f.data xview]
    scrollbar $f.vsb \
        -orient vertical \
        -command [list $f.data yview]
    foreach column {id type name value} {
        $f.data heading $column -text [::msgcat::mc ColumnLabel,$column]
    }
    set windows(dataWidget) $f.data















    grid configure $f.data $f.vsb -sticky nsew
    grid configure $f.hsb -sticky nsew

    grid columnconfigure $f $f.data -weight 1
    grid rowconfigure $f $f.data -weight 1

    ::autoscroll::autoscroll $f.vsb
    ::autoscroll::autoscroll $f.hsb

    ::gui::createAboutWindow $w

    return;
}

proc ::gui::createMainWindowDismiss {} {
    destroy .
}

proc ::gui::createMainWindowFileMenu {menu} {
    variable windows

    set ::fileInfo(saveNeeded) 0














    $menu add separator
    $menu add command \
        -label [::msgcat::mc FileMenu.Install] \
        -command {installLocalization}
    if {![string equal $::tcl_platform(os) Darwin]} {



        $menu add command \
            -label [::msgcat::mc Menu.Perferences] \
            -command {displayWindow perferences}
    } else {




}

proc ::gui::createMainWindowHelpMenu {menu} {
    if {[string equal $::tcl_platform(os) Darwin]} {
        set parent [winfo parent $menu]
        set appleMenu $parent
        append appleMenu {.apple}
        $appleMenu add command \
            -label [::msgcat::mc HelpMenu.About] \
            -command {displayWindow helpAbout}
        $appleMenu add command \
            -label [::msgcat::mc Menu.Perferences] \
            -command {displayWindow perferences}
    } else {
        $menu add command \
            -label [::msgcat::mc HelpMenu.About] \
            -command {displayWindow helpAbout}
    }
    $menu add command \
        -label [::msgcat::mc HelpMenu.Help] \
................................................................................
        -icon info \
        -message [::msgcat::mc helpAbout.details] \
        -parent $windows(main) \
        -title [::msgcat::mc helpAbout.title] \
        -type ok
    return;
}
























































































>
>









>







 







|


|
|
|
<






|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>


|
>







>










|

>
>
>
>
>
>
>
>
>
>
>
>
>




|
>
>
>
|



>
>
>
>










<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
33
34
35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132



133
134
135
136
137
138
139
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
package require math

proc ::gui::createMainWindow {} {
    variable windows

    set w [toplevel .main]
    wm withdraw $w
    set windows(main) $w
    wm transient $w .
    wm title $w [::msgcat::mc main.title]
    wm protocol $w WM_DELETE_WINDOW ::gui::createMainWindowDismiss
    #wm resizable window ?width height?

    set menu $w.menubar
    menu $menu
    if {[string equal $::tcl_platform(os) Darwin]} {
        set appleMenu $menu.apple
        menu $appleMenu
        $menu add cascade -menu $appleMenu
................................................................................

    ::ttk::frame $w.frame
    grid configure $w.frame -sticky nsew
    grid columnconfigure $w $w.frame -weight 1
    grid rowconfigure $w $w.frame -weight 1

    set f $w.frame
    canvas $f.data \
        -xscrollcommand [list $f.hsb set] \
        -yscrollcommand [list $f.hsb set] \
        -width 640 \
        -height 640 \
        -scrollregion [list 0 0 640 640]

    scrollbar $f.hsb \
        -orient horizontal \
        -command [list $f.data xview]
    scrollbar $f.vsb \
        -orient vertical \
        -command [list $f.data yview]
    bind $f.data <Button-1> {::gui::placeTarget %x %y}
    set windows(dataWidget) $f.data

    ::ttk::frame $f.status
    ::ttk::label $f.status.levelLabel \
        -text [::msgcat::mc LevelLabel]
    ::ttk::entry $f.status.level \
        -state readonly \
        -textvariable ::settings(Level) \
        -width 3
    ::ttk::label $f.status.timeLeftLabel \
        -text [::msgcat::mc TimeLeftLabel]
    ::ttk::entry $f.status.timeLeft \
        -state readonly \
        -textvariable ::timeLeft \
        -width 8
    grid configure x $f.status.levelLabel $f.status.level x $f.status.timeLeftLabel $f.status.timeLeft x -sticky ew
    grid columnconfigure $f.status {0 3 6} -weight 1

    grid configure $f.data $f.vsb -sticky nsew
    grid configure $f.hsb -sticky ew
    grid configure $f.status -columnspan 2 -sticky ew
    grid columnconfigure $f $f.data -weight 1
    grid rowconfigure $f $f.data -weight 1

    ::autoscroll::autoscroll $f.vsb
    ::autoscroll::autoscroll $f.hsb

    ::gui::createAboutWindow $w
    ::gui::drawEnclosure $w
    return;
}

proc ::gui::createMainWindowDismiss {} {
    destroy .
}

proc ::gui::createMainWindowFileMenu {menu} {
    variable windows

    set windows(main,fileMenu) $menu

    $menu add command \
        -label [::msgcat::mc FileMenu,NewGame] \
        -command [list initializeSimulation]
    $menu add command \
        -label [::msgcat::mc FileMenu,PauseGame] \
        -command [list doPauseSimulation] \
        -state disabled
    set windows(main,fileMenu,pauseGame) [$menu index [::msgcat::mc FileMenu,PauseGame]]
    $menu add command \
        -label [::msgcat::mc FileMenu,RunGame] \
        -command [list doResumeSimulation] \
        -state disabled
    set windows(main,fileMenu,resumeGame) [$menu index [::msgcat::mc FileMenu,RunGame]]
    $menu add separator
    $menu add command \
        -label [::msgcat::mc FileMenu.Install] \
        -command {installLocalization}
    if {[string equal $::tcl_platform(os) Darwin]} {
        set parent [winfo parent $menu]
        set appleMenu $parent
        append appleMenu {.apple}
        $appleMenu add command \
            -label [::msgcat::mc Menu.Perferences] \
            -command {displayWindow perferences}
    } else {
       $menu add command \
            -label [::msgcat::mc Menu.Perferences] \
            -command {displayWindow perferences}
    }
}

proc ::gui::createMainWindowHelpMenu {menu} {
    if {[string equal $::tcl_platform(os) Darwin]} {
        set parent [winfo parent $menu]
        set appleMenu $parent
        append appleMenu {.apple}
        $appleMenu add command \
            -label [::msgcat::mc HelpMenu.About] \
            -command {displayWindow helpAbout}



    } else {
        $menu add command \
            -label [::msgcat::mc HelpMenu.About] \
            -command {displayWindow helpAbout}
    }
    $menu add command \
        -label [::msgcat::mc HelpMenu.Help] \
................................................................................
        -icon info \
        -message [::msgcat::mc helpAbout.details] \
        -parent $windows(main) \
        -title [::msgcat::mc helpAbout.title] \
        -type ok
    return;
}

proc ::gui::drawEnclosure {main} {
    variable windows

    ##
    ## Get the canvas widget
    ##
    set c $windows(dataWidget)

    ##
    ## Put the walls in
    ##
    for {set i 0} {$i < 640} {incr i 32} {
        $c create image 0 $i -image stone -anchor w -tags stone
        $c create image 640 $i -image stone -anchor e -tags stone
        $c create image $i 0  -image stone -anchor nw -tags stone
        $c create image $i 640 -image stone -anchor sw -tags stone
    }

    ##
    ## Put the water in
    ##
    $c create oval {300 300 340 340} -tags water -fill blue -outline blue
    $c create oval {140 120 170 160} -tags water -fill blue -outline blue
    $c create oval {440 520 470 560} -tags water -fill blue -outline blue
    $c create oval {440 120 470 160} -tags water -fill blue -outline blue
    $c create oval {140 520 170 560} -tags water -fill blue -outline blue

    ##
    ## Generate holes in the north wall
    ##
    set numHoles [::math::random 1 5]
    for {set i 1} {$i <= $numHoles} {incr i} {
        set x [::math::random 40 600]
        $c create polygon [list [expr {$x - 10}] 31 $x 20 [expr {$x + 10}] 31 $x 31] \
            -fill black -outline black -smooth true -splinesteps 20 \
            -tags [list hole popOut_$x,50]
    }

    ##
    ## Generate holes in the west wall
    ##
    set numHoles [::math::random 1 5]
    for {set i 1} {$i <= $numHoles} {incr i} {
        set x [::math::random 40 600]
        $c create polygon [list 31 [expr {$x - 10}] 20 $x 31 [expr {$x + 10}] 31 $x] \
            -fill black -outline black -smooth true -splinesteps 20 \
            -tags [list hole popOut_50,$x]
    }

    ##
    ## Generate holes in the south wall
    ##
    set numHoles [::math::random 1 5]
    for {set i 1} {$i <= $numHoles} {incr i} {
        set x [::math::random 40 600]
        $c create polygon [list [expr {$x - 10}] 608 $x 620 [expr {$x + 10}] 608 $x 608] \
            -fill black -outline black -smooth true -splinesteps 20 \
            -tags [list hole popOut_$x,588]
    }

    ##
    ## Generate holes in the east wall
    ##
    set numHoles [::math::random 1 5]
    for {set i 1} {$i <= $numHoles} {incr i} {
        set x [::math::random 40 600]
        $c create polygon [list 608 [expr {$x - 10}] 620 $x 608 [expr {$x + 10}] 608 $x] \
            -fill black -outline black -smooth true -splinesteps 20 \
            -tags [list hole popOut_588,$x]
    }
}

proc ::gui::placeTarget {x y} {
    variable windows

    set c $windows(dataWidget)

    if {[llength [$c gettags target]]} {
        $c coords target $x $y
    } elseif {[llength [$c gettags player]]} {
        $c create image [list $x $y] -anchor c -tags target -image target
        $c lower target player
        if {![llength [after info]] && ($::calculated(timeLeft) > 0.0)} {
            doResumeSimulation
        }
    }
}

Added gui/icons/KillerBots.png.

cannot compute difference between binary files

Added gui/icons/stone.png.

cannot compute difference between binary files

Added gui/icons/target.png.

cannot compute difference between binary files

Changes to helpFiles/index.html.

48
49
50
51
52
53
54
55
56
57











58
59
60
61
    </p>

    <h2>Game Play</h2>

    <p>
        Simply click on spot and you will attempt to move there. Both you and
        the robots move at the same speed, but the refesh rate can be controlled
        via the Perferences screen. To kill a robot have them run into each
        other. There may be other ways to kill robots, experiment -- if you
        dare. Also, remember, that these robots can learn.











    </p>

</body>
</html>







|
|
|
>
>
>
>
>
>
>
>
>
>
>




48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    </p>

    <h2>Game Play</h2>

    <p>
        Simply click on spot and you will attempt to move there. Both you and
        the robots move at the same speed, but the refesh rate can be controlled
        via the Perferences screen. To kill a robot have them run into
        something, other than yoruself. There may be other ways to kill robots,
        experiment -- if you dare. Also, remember, that these robots can learn.
    </p>

    <p>
        <b>Note:</b> If a robot "dies" in a pool of water, it "electrifies" the
        water -- which can kill you.
    </p>

    <p>
        <b>Note:</b> If you enter a hole, you will "pop" out of another hole
        within 5 seconds. However, there is no guarentee what hole or that you
        might not pop out on top of a robot!
    </p>

</body>
</html>

Changes to lib/loadPerferences.tcl.



1

2








3

































proc loadPerferences {} {

    








}































>
>

>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package require inifile

proc loadPerferences {} {
    variable settings

    if {[file exists ~/.KillerBots/perferences.ini]} {
        set ifd [::ini::open ~/.KillerBots/perferences.ini r]
        array set settings [::ini::get $ifd Settings]
        ::ini::close $ifd
        calculateSimulationConstants
    } else {
        intializePerferences
        savePerferences
    }

}

proc savePerferences {} {
    variable settings

    if {![file exists ~/.KillerBots]} {
        file mkdir ~/.KillerBots
    }
     set ifd [::ini::open ~/.KillerBots/perferences.ini w]
    foreach {key value} [array get settings] {
        ::ini::set $ifd Settings $key $value
    }
    array set settings [::ini::get $ifd Settings]
    ::ini::commit $ifd
    ::ini::close $ifd
    calculateSimulationConstants
}

proc intializePerferences {} {
    variable settings

    set images [lsort -dictionary [image names]]
    set settings(Robots) [lsearch -inline -glob $images {ROBOT_*}]
    set settings(Player) [lsearch -inline -glob $images {PERSON_*}]
    set settings(RefreshRate) 100
    set settings(Speed) 15.0
    set settings(Level) 1
    set settings(RobotsPerLevel) 5
    set settings(SecondsPerLevel) 120.0
}

Changes to lib/main.tcl.



































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
##
## Main procedure of XmlFileBrowser
##
proc main {args} {
    ::tcl::mathfunc::srand [clock clicks]

    ##
    ## Create the gui
    ##
    createGui

    ##
    ## Display teh main window
    ##
    displayWindow main
    
}

Changes to lib/simulation.tcl.

1
2





















































































































































































































































































package require math::geometry
























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
package require math::geometry

proc doSimulationStep {} {
    variable settings
    variable calculated
    variable ::gui::windows

    set calculated(timeLeft) [expr {max($calculated(timeLeft) - $calculated(deltaSecondsPerStep), 0.0)}]
    if {$calculated(timeLeft) <= 0.0} {
        set fileMenu $windows(main,fileMenu)
        $fileMenu entryconfigure $windows(main,fileMenu,pauseGame) -state disabled
        $fileMenu entryconfigure $windows(main,fileMenu,resumeGame) -state disabled
        set msg [::msgcat::mc Survived]
        tk_messageBox \
            -default ok \
            -detail $msg \
            -icon info \
            -parent $::gui::windows(main) \
            -title [::msgcat::mc GameOver,Title] \
            -type ok
        incr settings(Level)
    } else {
        after $calculated(afterDelay) [list doSimulationStep]
    }

    set status [catch {
        movePlayer
        moveRobots
    } msg]

    set ::timeLeft [format %6.1f $calculated(timeLeft)]

    ##
    ## On error, terminate the simulation
    ##
    if {$status} {
        pauseSimulation
        set fileMenu $windows(main,fileMenu)
        $fileMenu entryconfigure $windows(main,fileMenu,pauseGame) -state disabled
        $fileMenu entryconfigure $windows(main,fileMenu,resumeGame) -state disabled
        set calculated(timeLeft) 0.0
        tk_messageBox \
            -default ok \
            -detail $msg \
            -icon info \
            -parent $::gui::windows(main) \
            -title [::msgcat::mc GameOver,Title] \
            -type ok
    }
}

proc pauseSimulation {} {
    foreach id [after info] {
        after cancel $id
    }
}

proc initializeSimulation {} {
    variable settings
    variable ::gui::windows
    variable calculated

    set c $windows(dataWidget)

    set calculated(timeLeft) [expr {$settings(Level) * $settings(SecondsPerLevel)}]
    set ::timeLeft [format %6.1f $calculated(timeLeft)]

    ##
    ## Clean up play area
    ##
    $c delete target
    $c delete robot
    $c delete rubble
    $c delete player

    ##
    ## Create and place the player
    ##
    $c create image 0 0 -image $settings(Player) -tag player -anchor c
    while {1} {
        set x [::math::random 40 600]
        set y [::math::random 40 600]
        $c coords player $x $y
        if {![overlaps player]} {
            break
        }
    }
    set playerAt [$c coords player]

    ##
    ## Generated the robots, make sure they are at least a distance of 60 away
    ## from the player and not on top of anything else
    ##
    set maxRobots [expr {$settings(Level) * $settings(RobotsPerLevel)}]
    for {set i 1} {$i <= $maxRobots} {incr i} {
        set id [$c create image 0 0 -image $settings(Robots) -tag robot -anchor c]
        while {1} {
            set x [::math::random 40 600]
            set y [::math::random 40 600]
            $c coords $id $x $y
            if {[::math::geometry::distance $playerAt [list $x $y]] < 60} {
                continue
            } elseif {![overlaps $id]} {
                break
            }
        }
    }

    ##
    ## Set the calculated information so we do not have to do so every simulation step
    ##
    calculateSimulationConstants

    return;
}

proc calculateSimulationConstants {} {
    variable settings
    variable calculated

    set calculated(distancePerStep) [expr {(1.0* $settings(Speed)) / $settings(RefreshRate)}]
    set calculated(afterDelay) [expr {int(1000.0 / $settings(RefreshRate))}]
    set calculated(deltaSecondsPerStep) [expr {1.0 / $settings(RefreshRate)}]

    return;
}

proc overlaps {item} {
    variable ::gui::windows

    set c $windows(dataWidget)

    return [expr {[llength [$c find overlapping {*}[$c bbox $item]]] != 1}]
}

proc getOverlaps {item} {
    variable ::gui::windows

    set c $windows(dataWidget)
    set returnDict [dict create]

    set itemId [$c find withtag $item]
    set overlapList [$c find overlapping {*}[$c bbox $item]]
    foreach overlapId $overlapList {
        if {$itemId == $overlapId} {
            continue
        }
        set propertyDict [getItemDict $overlapId]
        set type [dict get $propertyDict type]
        dict lappend returnDict $type $propertyDict
    }

    return $returnDict
}

proc getItemDict {item} {
    variable ::gui::windows

    set c $windows(dataWidget)

    set itemId [$c find withtag $item]
    set propertyDict [dict create id $itemId]
    set type {}
    foreach tag [$c gettags $itemId] {
        if {[string match {*_*} $tag]} {
            dict set propertyDict {*}[split $tag {_}]
        } else {
            set type $tag
        }
    }
    dict set propertyDict type $type
    return $propertyDict
}

proc movePlayer {} {
    variable settings
    variable calculated
    variable ::gui::windows

    set c $windows(dataWidget)
    if {[info exists calculated(inTunnels)]} {
        if {![incr calculated(inTunnels) -1]} {
            set holeList [$c find withtag hole]
            set maxHole [llength $holeList]
            set hole [lindex $holeList [::math::random 0 $maxHole]]
            set popOut [split [dict get [getItemDict $hole] popOut] {,}]
            $c coords player {*}$popOut
            unset calculated(inTunnels)
        }
    } elseif {[llength [$c find withtag target]]} {
        set playerCoords [$c coords player]
        set vector [concat $playerCoords [$c coords target]]
        set angle [::math::geometry::angle $vector]
        set playerCoords [::math::geometry::movePointInDirection $playerCoords $angle $calculated(distancePerStep)]
        $c coords player {*}$playerCoords
    }
    set overlapList [getOverlaps player]
    if {[dict exists $overlapList robot] || [dict exists $overlapList junk]} {
        return -code error [::msgcat::mc DeathByRobot]
    } elseif {[dict exists $overlapList charged]} {
        return -code error [::msgcat::mc DeathByElectrocution]
    } elseif {[dict exists $overlapList hole]} {
        set calculated(lastPosition) [$c coords player]
        set calculated(inTunnels) [::math::random $settings(RefreshRate) [expr {5 * $settings(RefreshRate)}]]
        $c coords player -5000 -5000
        catch {$c delete target}
    }
}

proc moveRobots {} {
    variable settings
    variable calculated
    variable ::gui::windows

    set c $windows(dataWidget)

    set robotList [$c find withtag robot]
    if {![llength $robotList]} {
        incr settings(Level)
        return -code error  [::msgcat::mc Survived]
    }
    foreach id $robotList {
        moveRobot $id
    }
}

proc moveRobot {id} {
    variable settings
    variable calculated
    variable ::gui::windows

    set c $windows(dataWidget)
    if {[info exists calculated(inTunnels)]} {
        set target $calculated(lastPosition)
    } else {
        set target [$c coords player]
    }
    set playerCoords [$c coords $id]
    set vector [concat $playerCoords $target]
    set angle [::math::geometry::angle $vector]
    set playerCoords [::math::geometry::movePointInDirection $playerCoords $angle $calculated(distancePerStep)]
    $c coords $id {*}$playerCoords
    set overlapList [getOverlaps $id]
    if {[dict exists $overlapList player]} {
        return -code error [::msgcat::mc DeathByRobot]
    } elseif {[dict exists $overlapList robot] ||
              [dict exists $overlapList junk] ||
              [dict exists $overlapList hole] ||
              [dict exists $overlapList charged]} {
        $c addtag junk withtag $id
        $c dtag $id robot
    } elseif {[dict exists $overlapList water]} {
        $c addtag junk withtag $id
        $c dtag $id robot
        foreach waterDict [dict get $overlapList water] {
            set waterId [dict get $waterDict id]
            $c addtag charged withtag $waterId
        }
    }
}

proc doPauseSimulation {} {
    variable ::gui::windows

    set fileMenu $windows(main,fileMenu)
    $fileMenu entryconfigure $windows(main,fileMenu,pauseGame) -state disabled
    $fileMenu entryconfigure $windows(main,fileMenu,resumeGame) -state normal
    pauseSimulation

}

proc doResumeSimulation {} {
    variable ::gui::windows

    set fileMenu $windows(main,fileMenu)
    $fileMenu entryconfigure $windows(main,fileMenu,pauseGame) -state normal
    $fileMenu entryconfigure $windows(main,fileMenu,resumeGame) -state disabled
    doSimulationStep
}

Changes to msgs/C.msg.

14
15
16
17
18
19
20
21

























::msgcat::mcset C helpViewer.title     {Help for XML File Exporer}

::msgcat::mcset C index.html           {index.html}

::msgcat::mcset C FileMenu.Install     {Install Localization Files...}

::msgcat::mcset C Menu.Perferences     {Perferences...}































|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

::msgcat::mcset C helpViewer.title     {Help for XML File Exporer}

::msgcat::mcset C index.html           {index.html}

::msgcat::mcset C FileMenu.Install     {Install Localization Files...}

::msgcat::mcset C Menu.Perferences     {KillerBotPerferences...}

::msgcat::mcset C GameOver,Title       {Game Over}

::msgcat::mcset C FileMenu,NewGame     {New Game}
::msgcat::mcset C FileMenu,PauseGame   {Pause Game}
::msgcat::mcset C FileMenu,RunGame     {Run Game}

::msgcat::mcset C LevelLabel           {Level}
::msgcat::mcset C TimeLeftLabel        {Seconds Left}

::msgcat::mcset C DeathByRobot         {A robot killed you!}
::msgcat::mcset C DeathByElectrocution {You die in an electified pool of water!}
::msgcat::mcset C Survived             {You live to fight another day!}

::msgcat::mcset C label,Robots         {Robot Icon}
::msgcat::mcset C label,Player         {Player Icon}
::msgcat::mcset C label,RefreshRate    {Refreshes per sec.}
::msgcat::mcset C label,Speed          {Movement Speed}
::msgcat::mcset C label,Level          {Play Level}
::msgcat::mcset C label,RobotsPerLevel {Robots per Level}
::msgcat::mcset C label,SecondsPerLevel {Second per Level}

::msgcat::mcset C Save                 {Save}
::msgcat::mcset C Cancel               {Cancel}

Changes to msgs/ROOT.msg.

14
15
16
17
18
19
20
21
22
























::msgcat::mcset {} helpViewer.title     {Help for Killer Robots}

::msgcat::mcset {} index.html           {index.html}

::msgcat::mcset {} FileMenu.Install     {Install Localization Files...}

::msgcat::mcset {} Menu.Perferences     {Perferences...}































|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

::msgcat::mcset {} helpViewer.title     {Help for Killer Robots}

::msgcat::mcset {} index.html           {index.html}

::msgcat::mcset {} FileMenu.Install     {Install Localization Files...}

::msgcat::mcset {} Menu.Perferences     {KillerBot Perferences...}

::msgcat::mcset {} GameOver,Title       {Game Over}

::msgcat::mcset {} FileMenu,NewGame     {New Game}
::msgcat::mcset {} FileMenu,PauseGame   {Pause Game}
::msgcat::mcset {} FileMenu,RunGame     {Run Game}

::msgcat::mcset {} LevelLabel           {Level}
::msgcat::mcset {} TimeLeftLabel        {Seconds Left}

::msgcat::mcset {} DeathByRobot         {A robot killed you!}
::msgcat::mcset {} DeathByElectrocution {You die in an electified pool of water!}
::msgcat::mcset {} Survived             {You live to fight another day!}

::msgcat::mcset {} label,Robots         {Robot Icon}
::msgcat::mcset {} label,Player         {Player Icon}
::msgcat::mcset {} label,RefreshRate    {Refreshes per sec.}
::msgcat::mcset {} label,Speed          {Movement Speed}
::msgcat::mcset {} label,Level          {Play Level}
::msgcat::mcset {} label,RobotsPerLevel {Robots per Level}
::msgcat::mcset {} label,SecondsPerLevel {Second per Level}

::msgcat::mcset {} Save                 {Save}
::msgcat::mcset {} Cancel               {Cancel}

Changes to msgs/en.msg.

14
15
16
17
18
19
20
21

























::msgcat::mcset en helpViewer.title     {Help for XML File Exporer}

::msgcat::mcset en index.html           {index.html}

::msgcat::mcset en FileMenu.Install     {Install Localization Files...}

::msgcat::mcset en Menu.Perferences     {Perferences...}































|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

::msgcat::mcset en helpViewer.title     {Help for XML File Exporer}

::msgcat::mcset en index.html           {index.html}

::msgcat::mcset en FileMenu.Install     {Install Localization Files...}

::msgcat::mcset en Menu.Perferences     {KillerBot Perferences...}

::msgcat::mcset en GameOver,Title       {Game Over}

::msgcat::mcset en FileMenu,NewGame     {New Game}
::msgcat::mcset en FileMenu,PauseGame   {Pause Game}
::msgcat::mcset en FileMenu,RunGame     {Run Game}

::msgcat::mcset en LevelLabel           {Level}
::msgcat::mcset en TimeLeftLabel        {Seconds Left}

::msgcat::mcset en DeathByRobot         {A robot killed you!}
::msgcat::mcset en DeathByElectrocution {You die in an electified pool of water!}
::msgcat::mcset en Survived             {You live to fight another day!}

::msgcat::mcset en label,Robots         {Robot Icon}
::msgcat::mcset en label,Player         {Player Icon}
::msgcat::mcset en label,RefreshRate    {Refreshes per sec.}
::msgcat::mcset en label,Speed          {Movement Speed}
::msgcat::mcset en label,Level          {Play Level}
::msgcat::mcset en label,RobotsPerLevel {Robots per Level}
::msgcat::mcset en label,SecondsPerLevel {Second per Level}

::msgcat::mcset en Save                 {Save}
::msgcat::mcset en Cancel               {Cancel}