Initial checkout of Vore Tournament 0.1.alpha.
[voretournament/voretournament.git] / misc / tools / assault-circuit-board-creator.pl
1 #!/usr/bin/perl
2
3 # script that creates an "assault circuit"
4
5 use strict;
6 use warnings;
7
8 my @objectives = @ARGV;
9
10 if(!@objectives)
11 {
12         print STDERR <<EOF;
13 Assault Circuit Board Creator
14
15 Usage: 
16   [brushprimit=1 \\]
17   [ofs_x=offset \\]
18   [ofs_y=offset \\]
19   [ofs_z=offset \\]
20   perl $0 breakables1[,buttons1] breakables2[,buttons2] breakables3[,buttons3] ... \\
21   > file.map
22
23 Example:
24   ofs_z=1024 perl $0 1 1 3,2 1 > assault.map
25 EOF
26         exit 1;
27 }
28
29 my $bp = $ENV{brushprimit};
30 my @ofs = ($ENV{ofs_x} || 0, $ENV{ofs_y} || 0, $ENV{ofs_z} || 0);
31
32 my $BRUSHDEF_START = $bp ? "{\nbrushDef\n{" : "{";
33 my $BRUSHDEF_END   = $bp ? "}\n}" : "}";
34 my $BRUSHDEF_PRE   = $bp ? "( ( 0.03125 0 -0 ) ( -0 0.03125 0 ) ) " : "";
35 my $BRUSHDEF_POST  = $bp ? " 0 0 0" : " 0 0 0 0.500000 0.500000 0 0 0";
36
37 sub BrushRectangle($@@)
38 {
39     my ($shader, $x0, $y0, $z0, $x1, $y1, $z1) = @_;
40     return <<EOF;
41 $BRUSHDEF_START
42 ( $x1 $y1 $z1 ) ( $x1 $y0 $z1 ) ( $x0 $y1 $z1 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
43 ( $x1 $y1 $z1 ) ( $x0 $y1 $z1 ) ( $x1 $y1 $z0 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
44 ( $x1 $y1 $z1 ) ( $x1 $y1 $z0 ) ( $x1 $y0 $z1 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
45 ( $x0 $y0 $z0 ) ( $x1 $y0 $z0 ) ( $x0 $y1 $z0 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
46 ( $x0 $y0 $z0 ) ( $x0 $y0 $z1 ) ( $x1 $y0 $z0 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
47 ( $x0 $y0 $z0 ) ( $x0 $y1 $z0 ) ( $x0 $y0 $z1 ) $BRUSHDEF_PRE$shader$BRUSHDEF_POST
48 $BRUSHDEF_END
49 EOF
50 }
51
52 sub Entity(%)
53 {
54         my (%h) = @_;
55         my @brushes = ();
56         if(ref $h{model} eq 'ARRAY')
57         {
58                 @brushes = @{$h{model}};
59                 delete $h{model};
60         }
61         return join "", ("{\n", (map { qq{"$_" "$h{$_}"\n} } keys %h), @brushes, "}\n");
62         # "
63 }
64
65 sub FindDamage($)
66 {
67         my ($cnt) = @_;
68
69         my $dmg;
70
71         # 1. divisible by 10?
72         $dmg = (1 + int(10 / $cnt)) * 10;
73         return $dmg
74                 if $dmg * ($cnt - 1) < 100;
75
76         # 2. divisible by 5?
77         $dmg = (1 + int(20 / $cnt)) * 5;
78         return $dmg
79                 if $dmg * ($cnt - 1) < 100;
80
81         # 3. divisible by 2?
82         $dmg = (1 + int(50 / $cnt)) * 2;
83         return $dmg
84                 if $dmg * ($cnt - 1) < 100;
85
86         # 4. divisible by 1?
87         $dmg = (1 + int(100 / $cnt));
88         return $dmg
89                 if $dmg * ($cnt - 1) < 100;
90
91         # 5. give up
92         return (100 / $cnt + 100 / ($cnt + 1)) / 2;
93 }
94
95 sub ObjectiveSpawns($@)
96 {
97         my ($target, $x, $y, $z) = @_;
98
99         my @l = ();
100
101         $z -= 64;
102
103         for(1..6)
104         {
105                 my $xx = $x - 32;
106                 my $yy = $y + ($_ - 3.5) * 64;
107                 my $zz = $z - 8 - 32; # align feet to 64-grid
108                 push @l, Entity
109                         classname => "info_player_attacker",
110                         target => $target,
111                         origin => "$xx $yy $zz";
112
113                 $xx = $x + 32;
114                 push @l, Entity
115                         classname => "info_player_defender",
116                         target => $target,
117                         origin => "$xx $yy $zz";
118         }
119
120         return @l;
121 }
122
123 my @assault_entities = ();
124
125 my $obj_prev = undef;
126 my $des_prev = undef;
127
128 my @prevorigin = @ofs;
129
130 for my $i(0..@objectives - 1)
131 {
132         my @origin =
133         (
134                 $ofs[0] + ($i + 1) * 256,
135                 $ofs[1] + 0,
136                 $ofs[2] + 0
137         );
138
139         my $count = $objectives[$i];
140         $count =~ /^(\d+)(?:,(\d+))?$/s
141                 or die "Invalid count spec: must be number or number,number";
142         my $count_destroy = $1;
143         my $count_push = $2 || 0;
144         $count = $count_destroy + $count_push;
145
146         my $obj = "obj$i";
147         my $des = "obj$i\_destructible";
148         my $dec = "obj$i\_decrease";
149
150         if($i == 0)
151         {
152                 push @assault_entities, Entity
153                         classname => "target_assault_roundstart",
154                         target => $obj,
155                         target2 => $des,
156                         origin => "@prevorigin";
157         }
158         else
159         {
160                 push @assault_entities, Entity
161                         classname => "target_objective",
162                         targetname => $obj_prev,
163                         target => $obj,
164                         target2 => $des,
165                         origin => "@prevorigin";
166
167                 push @assault_entities, ObjectiveSpawns $obj_prev, @prevorigin;
168
169                 push @assault_entities, Entity
170                         classname => "func_assault_wall",
171                         target => $obj_prev,
172                         model => [
173                                 BrushRectangle
174                                         "dsi/dsiglass",
175                                         $origin[0] - 128 - 32,
176                                         $origin[1] - 512,
177                                         $origin[2] - 512,
178                                         $origin[0] - 128 + 32,
179                                         $origin[1] + 512,
180                                         $origin[2] + 512
181                         ];
182         }
183
184         @prevorigin = @origin;
185
186         $origin[2] += 64;
187
188         my $dmg = FindDamage($count);
189
190         push @assault_entities, Entity
191                 classname => "target_objective_decrease",
192                 targetname => $dec,
193                 target => $obj,
194                 dmg => $dmg,
195                 origin => "@origin";
196
197         $origin[2] += 64;
198
199         for(1..$count_destroy)
200         {
201                 push @assault_entities, Entity
202                         classname => "func_assault_destructible",
203                         targetname => $des,
204                         target => $dec,
205                         health => 1000,
206                         mdl => "rocket_explode",
207                         count => 1,
208                         noise => "weapons/rocket_impact.wav",
209                         dmg => 50,
210                         dmg_edge => 0,
211                         dmg_radius => 150,
212                         dmg_force => 200,
213                         model => [
214                                 BrushRectangle
215                                         "dsi/cretebase",
216                                         $origin[0] - 16,
217                                         $origin[1] - 16,
218                                         $origin[2] - 16,
219                                         $origin[0] + 16,
220                                         $origin[1] + 16,
221                                         $origin[2] + 16
222                         ];
223
224                 $origin[2] += 64;
225         }
226
227         for(1..$count_push)
228         {
229                 push @assault_entities, Entity
230                         classname => "func_button",
231                         target => $dec,
232                         angle => -2,
233                         model => [
234                                 BrushRectangle
235                                         "dsi/dablue",
236                                         $origin[0] - 16,
237                                         $origin[1] - 16,
238                                         $origin[2] - 16,
239                                         $origin[0] + 16,
240                                         $origin[1] + 16,
241                                         $origin[2] + 16
242                         ];
243
244                 $origin[2] += 64;
245         }
246
247         $obj_prev = $obj;
248         $des_prev = $des;
249 }
250
251 my $obj = "roundend";
252 my @origin =
253 (
254         $ofs[0] + (@objectives + 1) * 256,
255         $ofs[1] + 0,
256         $ofs[2] + 0
257 );
258
259 push @assault_entities, Entity
260         classname => "target_objective",
261         targetname => $obj_prev,
262         target => $obj,
263         origin => "@prevorigin";
264
265 push @assault_entities, ObjectiveSpawns $obj_prev, @prevorigin;
266
267 push @assault_entities, Entity
268         classname => "target_assault_roundend",
269         targetname => $obj,
270         origin => "@origin";
271
272 my $map = join "",
273 (
274         Entity(classname => "worldspawn"),
275         @assault_entities
276 );
277
278 print $map;