]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/assault-circuit-board-creator.pl
add the ACBC Assault Circuit Board Creator
[divverent/nexuiz.git] / misc / 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                 push @l, Entity
108                         classname => "info_player_attacker",
109                         target => $target,
110                         origin => "$xx $yy $z";
111
112                 $xx = $x + 32;
113                 push @l, Entity
114                         classname => "info_player_defender",
115                         target => $target,
116                         origin => "$xx $yy $z";
117         }
118
119         return @l;
120 }
121
122 my @assault_entities = ();
123
124 my $obj_prev = undef;
125 my $des_prev = undef;
126
127 my @prevorigin = (-256, 0, 0);
128
129 for my $i(0..@objectives - 1)
130 {
131         my @origin =
132         (
133                 $ofs[0] + $i * 256,
134                 $ofs[1] + 0,
135                 $ofs[2] + 0
136         );
137
138         my $count = $objectives[$i];
139         $count =~ /^(\d+)(?:,(\d+))?$/s
140                 or die "Invalid count spec: must be number or number,number";
141         my $count_destroy = $1;
142         my $count_push = $2 || 0;
143         $count = $count_destroy + $count_push;
144
145         my $obj = "obj$i";
146         my $des = "obj$i\_destructible";
147         my $dec = "obj$i\_decrease";
148
149         if($i == 0)
150         {
151                 push @assault_entities, Entity
152                         classname => "target_assault_roundstart",
153                         target => $obj,
154                         target2 => $des,
155                         origin => "@prevorigin";
156         }
157         else
158         {
159                 push @assault_entities, Entity
160                         classname => "target_objective",
161                         targetname => $obj_prev,
162                         target => $obj,
163                         target2 => $des,
164                         origin => "@prevorigin";
165
166                 push @assault_entities, ObjectiveSpawns $obj_prev, @prevorigin;
167
168                 push @assault_entities, Entity
169                         classname => "func_assault_wall",
170                         target => $obj_prev,
171                         model => [
172                                 BrushRectangle
173                                         "dsi/dsiglass",
174                                         $origin[0] - 128 - 16,
175                                         $origin[1] - 512,
176                                         $origin[2] - 512,
177                                         $origin[0] - 128 + 16,
178                                         $origin[1] + 512,
179                                         $origin[2] + 512
180                         ];
181         }
182
183         @prevorigin = @origin;
184
185         $origin[2] += 64;
186
187         my $dmg = FindDamage($count);
188
189         push @assault_entities, Entity
190                 classname => "target_objective_decrease",
191                 targetname => $dec,
192                 target => $obj,
193                 dmg => $dmg,
194                 origin => "@origin";
195
196         $origin[2] += 64;
197
198         for(1..$count_destroy)
199         {
200                 push @assault_entities, Entity
201                         classname => "func_assault_destructible",
202                         targetname => $des,
203                         target => $dec,
204                         health => 1000,
205                         mdl => "rocket_explode",
206                         count => 1,
207                         noise => "weapons/rocket_impact.wav",
208                         dmg => 50,
209                         dmg_edge => 0,
210                         dmg_radius => 150,
211                         dmg_force => 200,
212                         model => [
213                                 BrushRectangle
214                                         "dsi/cretebase",
215                                         $origin[0] - 16,
216                                         $origin[1] - 16,
217                                         $origin[2] - 16,
218                                         $origin[0] + 16,
219                                         $origin[1] + 16,
220                                         $origin[2] + 16
221                         ];
222
223                 $origin[2] += 64;
224         }
225
226         for(1..$count_push)
227         {
228                 push @assault_entities, Entity
229                         classname => "func_button",
230                         target => $dec,
231                         angle => -2,
232                         model => [
233                                 BrushRectangle
234                                         "dsi/dablue",
235                                         $origin[0] - 16,
236                                         $origin[1] - 16,
237                                         $origin[2] - 16,
238                                         $origin[0] + 16,
239                                         $origin[1] + 16,
240                                         $origin[2] + 16
241                         ];
242
243                 $origin[2] += 64;
244         }
245
246         $obj_prev = $obj;
247         $des_prev = $des;
248 }
249
250 my $obj = "roundend";
251 my @origin =
252 (
253         $ofs[0] + @objectives * 256,
254         $ofs[1] + 0,
255         $ofs[2] + 0
256 );
257
258 push @assault_entities, Entity
259         classname => "target_objective",
260         targetname => $obj_prev,
261         target => $obj,
262         origin => "@prevorigin";
263
264 push @assault_entities, ObjectiveSpawns $obj_prev, @prevorigin;
265
266 push @assault_entities, Entity
267         classname => "target_assault_roundend",
268         targetname => $obj,
269         origin => "@origin";
270
271 my $map = join "",
272 (
273         Entity(classname => "worldspawn"),
274         @assault_entities
275 );
276
277 print $map;