Line data Source code
1 0 : /*
2 :
3 : OOShipGroup.m
4 :
5 :
6 : Oolite
7 : Copyright (C) 2004-2013 Giles C Williams and contributors
8 :
9 : This program is free software; you can redistribute it and/or
10 : modify it under the terms of the GNU General Public License
11 : as published by the Free Software Foundation; either version 2
12 : of the License, or (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 : MA 02110-1301, USA.
23 :
24 : */
25 :
26 : #import "OOShipGroup.h"
27 : #import "OOJavaScriptEngine.h"
28 : #import "OOShipGroup.h"
29 : #import "Universe.h"
30 :
31 :
32 0 : static JSObject *sShipGroupPrototype;
33 :
34 :
35 : static JSBool ShipGroupGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
36 : static JSBool ShipGroupSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
37 : static JSBool ShipGroupConstruct(JSContext *context, uintN argc, jsval *vp);
38 :
39 : // Methods
40 : static JSBool ShipGroupAddShip(JSContext *context, uintN argc, jsval *vp);
41 : static JSBool ShipGroupRemoveShip(JSContext *context, uintN argc, jsval *vp);
42 : static JSBool ShipGroupContainsShip(JSContext *context, uintN argc, jsval *vp);
43 :
44 :
45 0 : static JSClass sShipGroupClass =
46 : {
47 : "ShipGroup",
48 : JSCLASS_HAS_PRIVATE,
49 :
50 : JS_PropertyStub, // addProperty
51 : JS_PropertyStub, // delProperty
52 : ShipGroupGetProperty, // getProperty
53 : ShipGroupSetProperty, // setProperty
54 : JS_EnumerateStub, // enumerate
55 : JS_ResolveStub, // resolve
56 : JS_ConvertStub, // convert
57 : OOJSObjectWrapperFinalize,// finalize
58 : JSCLASS_NO_OPTIONAL_MEMBERS
59 : };
60 :
61 :
62 0 : enum
63 : {
64 : // Property IDs
65 : kShipGroup_ships, // array of ships, double, read-only
66 : kShipGroup_leader, // leader, Ship, read/write
67 : kShipGroup_name, // name, string, read/write
68 : kShipGroup_count, // number of ships, integer, read-only
69 : };
70 :
71 :
72 0 : static JSPropertySpec sShipGroupProperties[] =
73 : {
74 : // JS name ID flags
75 : { "count", kShipGroup_count, OOJS_PROP_READONLY_CB },
76 : { "leader", kShipGroup_leader, OOJS_PROP_READWRITE_CB },
77 : { "name", kShipGroup_name, OOJS_PROP_READWRITE_CB },
78 : { "ships", kShipGroup_ships, OOJS_PROP_READONLY_CB },
79 : { 0 }
80 : };
81 :
82 :
83 0 : static JSFunctionSpec sShipGroupMethods[] =
84 : {
85 : // JS name Function min args
86 : { "toString", OOJSObjectWrapperToString, 0 },
87 : { "addShip", ShipGroupAddShip, 1 },
88 : { "containsShip", ShipGroupContainsShip, 1 },
89 : { "removeShip", ShipGroupRemoveShip, 1 },
90 : { 0 }
91 : };
92 :
93 :
94 0 : DEFINE_JS_OBJECT_GETTER(JSShipGroupGetShipGroup, &sShipGroupClass, sShipGroupPrototype, OOShipGroup);
95 :
96 :
97 0 : void InitOOJSShipGroup(JSContext *context, JSObject *global)
98 : {
99 : sShipGroupPrototype = JS_InitClass(context, global, NULL, &sShipGroupClass, ShipGroupConstruct, 0, sShipGroupProperties, sShipGroupMethods, NULL, NULL);
100 : OOJSRegisterObjectConverter(&sShipGroupClass, OOJSBasicPrivateObjectConverter);
101 : }
102 :
103 :
104 0 : static JSBool ShipGroupGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
105 : {
106 : if (!JSID_IS_INT(propID)) return YES;
107 :
108 : OOJS_NATIVE_ENTER(context)
109 :
110 : OOShipGroup *group = nil;
111 : id result = nil;
112 :
113 : if (EXPECT_NOT(!JSShipGroupGetShipGroup(context, this, &group))) return NO;
114 :
115 : switch (JSID_TO_INT(propID))
116 : {
117 : case kShipGroup_ships:
118 : result = [group memberArray];
119 : if (result == nil) result = [NSArray array];
120 : break;
121 :
122 : case kShipGroup_leader:
123 : result = [group leader];
124 : break;
125 :
126 : case kShipGroup_name:
127 : result = [group name];
128 : if (result == nil) result = [NSNull null];
129 : break;
130 :
131 : case kShipGroup_count:
132 : return JS_NewNumberValue(context, [group count], value);
133 :
134 : default:
135 : OOJSReportBadPropertySelector(context, this, propID, sShipGroupProperties);
136 : return NO;
137 : }
138 :
139 : *value = OOJSValueFromNativeObject(context, result);
140 : return YES;
141 :
142 : OOJS_NATIVE_EXIT
143 : }
144 :
145 :
146 0 : static JSBool ShipGroupSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
147 : {
148 : if (!JSID_IS_INT(propID)) return YES;
149 :
150 : OOJS_NATIVE_ENTER(context)
151 :
152 : OOShipGroup *group = nil;
153 : ShipEntity *shipValue = nil;
154 :
155 : if (EXPECT_NOT(!JSShipGroupGetShipGroup(context, this, &group))) return NO;
156 :
157 : switch (JSID_TO_INT(propID))
158 : {
159 : case kShipGroup_leader:
160 : shipValue = OOJSNativeObjectOfClassFromJSValue(context, *value, [ShipEntity class]);
161 : if (shipValue != nil || JSVAL_IS_NULL(*value))
162 : {
163 : [group setLeader:shipValue];
164 : return YES;
165 : }
166 : break;
167 :
168 : case kShipGroup_name:
169 : [group setName:OOStringFromJSValueEvenIfNull(context, *value)];
170 : return YES;
171 : break;
172 :
173 : default:
174 : OOJSReportBadPropertySelector(context, this, propID, sShipGroupProperties);
175 : return NO;
176 : }
177 :
178 : OOJSReportBadPropertyValue(context, this, propID, sShipGroupProperties, *value);
179 : return NO;
180 :
181 : OOJS_NATIVE_EXIT
182 : }
183 :
184 :
185 : // new ShipGroup([name : String [, leader : Ship]]) : ShipGroup
186 0 : static JSBool ShipGroupConstruct(JSContext *context, uintN argc, jsval *vp)
187 : {
188 : OOJS_NATIVE_ENTER(context)
189 :
190 : if (EXPECT_NOT(!JS_IsConstructing(context, vp)))
191 : {
192 : OOJSReportError(context, @"ShipGroup() cannot be called as a function, it must be used as a constructor (as in new ShipGroup(...)).");
193 : return NO;
194 : }
195 :
196 : NSString *name = nil;
197 : ShipEntity *leader = nil;
198 :
199 : if (argc >= 1)
200 : {
201 : if (!JSVAL_IS_STRING(OOJS_ARGV[0]))
202 : {
203 : OOJSReportBadArguments(context, nil, @"ShipGroup()", 1, OOJS_ARGV, @"Could not create ShipGroup", @"group name");
204 : return NO;
205 : }
206 : name = OOStringFromJSValue(context, OOJS_ARGV[0]);
207 : }
208 :
209 : if (argc >= 2)
210 : {
211 : leader = OOJSNativeObjectOfClassFromJSValue(context, OOJS_ARGV[1], [ShipEntity class]);
212 : if (leader == nil && !JSVAL_IS_NULL(OOJS_ARGV[1]))
213 : {
214 : OOJSReportBadArguments(context, nil, @"ShipGroup()", 1, OOJS_ARGV + 1, @"Could not create ShipGroup", @"ship");
215 : return NO;
216 : }
217 : }
218 :
219 : OOJS_RETURN_OBJECT([OOShipGroup groupWithName:name leader:leader]);
220 :
221 : OOJS_NATIVE_EXIT
222 : }
223 :
224 :
225 : @implementation OOShipGroup (OOJavaScriptExtensions)
226 :
227 0 : - (jsval) oo_jsValueInContext:(JSContext *)context
228 : {
229 : jsval result = JSVAL_NULL;
230 :
231 : if (_jsSelf == NULL)
232 : {
233 : _jsSelf = JS_NewObject(context, &sShipGroupClass, sShipGroupPrototype, NULL);
234 : if (_jsSelf != NULL)
235 : {
236 : if (!JS_SetPrivate(context, _jsSelf, [self retain])) _jsSelf = NULL;
237 : }
238 : }
239 :
240 : if (_jsSelf != NULL) result = OBJECT_TO_JSVAL(_jsSelf);
241 :
242 : return result;
243 : }
244 :
245 :
246 0 : - (void) oo_clearJSSelf:(JSObject *)selfVal
247 : {
248 : if (_jsSelf == selfVal) _jsSelf = NULL;
249 : }
250 :
251 : @end
252 :
253 :
254 :
255 : // *** Methods ***
256 :
257 : // addShip(ship : Ship)
258 0 : static JSBool ShipGroupAddShip(JSContext *context, uintN argc, jsval *vp)
259 : {
260 : OOJS_NATIVE_ENTER(context)
261 :
262 : OOShipGroup *thisGroup = nil;
263 : ShipEntity *ship = nil;
264 : BOOL OK = YES;
265 :
266 : if (EXPECT_NOT(!JSShipGroupGetShipGroup(context, OOJS_THIS, &thisGroup))) return NO;
267 :
268 : if (argc > 0) ship = OOJSNativeObjectOfClassFromJSValue(context, OOJS_ARGV[0], [ShipEntity class]);
269 : if (ship == nil)
270 : {
271 : if (argc > 0 && JSVAL_IS_NULL(OOJS_ARGV[0])) OOJS_RETURN_VOID; // OK, do nothing for null ship.
272 :
273 : OOJSReportBadArguments(context, @"ShipGroup", @"addShip", MIN(argc, 1U), OOJS_ARGV, nil, @"ship");
274 : return NO;
275 : }
276 :
277 : if ([thisGroup containsShip:ship])
278 : {
279 : // nothing to do...
280 : OOJS_RETURN_VOID;
281 : }
282 : else
283 : {
284 : ShipEntity *thisGroupLeader = [thisGroup leader];
285 :
286 : if ([thisGroupLeader escortGroup] == thisGroup) // escort group!
287 : {
288 : if ([thisGroup count] > 1) // already with some escorts
289 : {
290 : OOShipGroup *thatGroup = [ship group];
291 : if ([thatGroup count] > 1 && [[thatGroup leader] escortGroup] == thatGroup) // new escort already escorting!
292 : {
293 : OOJSReportWarningForCaller(context, @"ShipGroup", @"addShip", @"Ship %@ cannot be assigned to two escort groups, ignoring.", ship);
294 : OK = NO;
295 : }
296 : else
297 : {
298 : OK = [thisGroupLeader acceptAsEscort:ship];
299 : }
300 : }
301 : else // [thisGroup count] == 1, default unescorted ship?
302 : {
303 : if ([thisGroupLeader escortGroup] == [thisGroupLeader group])
304 : {
305 : // Default unescorted, unescortable, ship. Create new group and use that instead.
306 : [thisGroupLeader setGroup:[[OOShipGroup alloc] initWithName:@"ship group"]];
307 : thisGroup = [thisGroupLeader group];
308 : }
309 : else
310 : {
311 : // Unescorted ship with custom group. See if it accepts escorts.
312 : OK = [thisGroupLeader acceptAsEscort:ship];
313 : }
314 : }
315 : }
316 : if (OK)
317 : {
318 : OOJS_RETURN_BOOL([thisGroup addShip:ship]); // if ship is there already, noop & YES
319 : }
320 : else OOJS_RETURN_BOOL(NO);
321 : }
322 :
323 : OOJS_NATIVE_EXIT
324 : }
325 :
326 :
327 : // removeShip(ship : Ship)
328 0 : static JSBool ShipGroupRemoveShip(JSContext *context, uintN argc, jsval *vp)
329 : {
330 : OOJS_NATIVE_ENTER(context)
331 :
332 : OOShipGroup *thisGroup = nil;
333 : ShipEntity *ship = nil;
334 :
335 : if (EXPECT_NOT(!JSShipGroupGetShipGroup(context, OOJS_THIS, &thisGroup))) return NO;
336 :
337 : if (argc > 0) ship = OOJSNativeObjectOfClassFromJSValue(context, OOJS_ARGV[0], [ShipEntity class]);
338 : if (ship == nil)
339 : {
340 : if (argc > 0 && JSVAL_IS_NULL(OOJS_ARGV[0])) OOJS_RETURN_VOID; // OK, do nothing for null ship.
341 :
342 : OOJSReportBadArguments(context, @"ShipGroup", @"removeShip", MIN(argc, 1U), OOJS_ARGV, nil, @"ship");
343 : return NO;
344 : }
345 :
346 : OOJS_RETURN_BOOL([thisGroup removeShip:ship]);
347 :
348 : OOJS_NATIVE_EXIT
349 : }
350 :
351 :
352 : // containsShip(ship : Ship) : Boolean
353 0 : static JSBool ShipGroupContainsShip(JSContext *context, uintN argc, jsval *vp)
354 : {
355 : OOJS_NATIVE_ENTER(context)
356 :
357 : OOShipGroup *thisGroup = nil;
358 : ShipEntity *ship = nil;
359 :
360 : if (EXPECT_NOT(!JSShipGroupGetShipGroup(context, OOJS_THIS, &thisGroup))) return NO;
361 :
362 : if (argc > 0) ship = OOJSNativeObjectOfClassFromJSValue(context, OOJS_ARGV[0], [ShipEntity class]);
363 : if (ship == nil)
364 : {
365 : if (argc > 0 && JSVAL_IS_NULL(OOJS_ARGV[0])) OOJS_RETURN_BOOL(NO); // OK, return false for null ship.
366 :
367 : OOJSReportBadArguments(context, @"ShipGroup", @"containsShip", MIN(argc, 1U), OOJS_ARGV, nil, @"ship");
368 : return NO;
369 : }
370 :
371 : OOJS_RETURN_BOOL([thisGroup containsShip:ship]);
372 :
373 : OOJS_NATIVE_EXIT
374 : }
|