Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
OOCharacter.m
Go to the documentation of this file.
1/*
2
3OOCharacter.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "OOCharacter.h"
26
27#import "Universe.h"
28#import "OOStringExpander.h"
29#import "OOStringParsing.h"
31#import "OOJSScript.h"
32
33
34@interface OOCharacter (Private)
35
36- (id) initWithGenSeed:(Random_Seed)characterSeed andOriginalSystem:(OOSystemID)systemSeed;
37- (void) setCharacterFromDictionary:(NSDictionary *)dict;
38
39- (void)setOriginSystem:(OOSystemID)value;
41
42@end
43
44
45@implementation OOCharacter
46
47- (NSString *) descriptionComponents
48{
49 return [NSString stringWithFormat:@"%@, %@. bounty: %i insurance: %llu", [self name], [self shortDescription], [self legalStatus], [self insuranceCredits]];
50}
51
52
53- (NSString *) oo_jsClassName
54{
55 return @"Character";
56}
57
58
59- (void) dealloc
60{
61 [_name release];
62 [_shortDescription release];
63 [_scriptActions release];
64 DESTROY(_script);
65
66 [super dealloc];
67}
68
69
70- (id) initWithGenSeed:(Random_Seed)characterSeed andOriginalSystem:(OOSystemID)system
71{
72 if ((self = [super init]))
73 {
74 // do character set-up
75 _genSeed = characterSeed;
76 _originSystem = system;
77
78 [self basicSetUp];
79 }
80 return self;
81}
82
83
84- (id) initWithRole:(NSString *)role andOriginalSystem:(OOSystemID)system
85{
86 Random_Seed seed;
88
89 if ((self = [self initWithGenSeed:seed andOriginalSystem:system]))
90 {
91 [self castInRole:role];
92 }
93
94 return self;
95}
96
97+ (OOCharacter *) characterWithRole:(NSString *)role andOriginalSystem:(OOSystemID)system
98{
99 return [[[self alloc] initWithRole:role andOriginalSystem:system] autorelease];
100}
101
102
103+ (OOCharacter *) randomCharacterWithRole:(NSString *)role andOriginalSystem:(OOSystemID)system
104{
105 Random_Seed seed;
106
107 seed.a = (Ranrot() & 0xff);
108 seed.b = (Ranrot() & 0xff);
109 seed.c = (Ranrot() & 0xff);
110 seed.d = (Ranrot() & 0xff);
111 seed.e = (Ranrot() & 0xff);
112 seed.f = (Ranrot() & 0xff);
113
114 OOCharacter *character = [[[OOCharacter alloc] initWithGenSeed:seed andOriginalSystem:system] autorelease];
115 [character castInRole:role];
116
117 return character;
118}
119
120
121+ (OOCharacter *) characterWithDictionary:(NSDictionary *)dict
122{
123 OOCharacter *character = [[[OOCharacter alloc] init] autorelease];
124 [character setCharacterFromDictionary:dict];
125
126 return character;
127}
128
129
130- (NSString *) planetOfOrigin
131{
132 // determine the planet of origin
133 NSDictionary *originInfo = [UNIVERSE generateSystemData:[self planetIDOfOrigin]];
134 return [originInfo objectForKey:KEY_NAME];
135}
136
137
138- (OOSystemID) planetIDOfOrigin
139{
140 // determine the planet of origin
141 return _originSystem;
142}
143
144
145- (NSString *) species
146{
147 // determine the character's species
148 int species = [self genSeed].f & 0x03; // 0-1 native to home system, 2 human colonial, 3 other
149 NSString* speciesString = nil;
150 if (species == 3) speciesString = [UNIVERSE getSystemInhabitants:[self genSeed].e plural:NO];
151 else speciesString = [UNIVERSE getSystemInhabitants:[self planetIDOfOrigin] plural:NO];
152
153 if (![[UNIVERSE descriptions] oo_boolForKey:@"lowercase_ignore"])
154 {
155 speciesString = [speciesString lowercaseString];
156 }
157
158 return [speciesString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
159}
160
161
162- (void) basicSetUp
163{
164 // save random seeds for restoration later
165 RNG_Seed savedRNGSeed = currentRandomSeed();
166 RANROTSeed savedRANROTSeed = RANROTGetFullSeed();
167 // set RNG to character seed
168 Random_Seed genSeed = [self genSeed];
170
171 // determine the planet of origin
172 NSDictionary *originInfo = [UNIVERSE generateSystemData:[self planetIDOfOrigin]];
173 NSString *planet = [originInfo oo_stringForKey:KEY_NAME];
174 OOGovernmentID government = [originInfo oo_intForKey:KEY_GOVERNMENT]; // 0 .. 7 (0 anarchic .. 7 most stable)
175 int criminalTendency = government ^ 0x07;
176
177 // determine the character's species
178 NSString *species = [self species];
179
180 // determine the character's name
182 NSString *genName = nil;
183 if ([species hasPrefix:@"human"])
184 {
185 genName = [NSString stringWithFormat:@"%@ %@", OOExpandWithSeed(genSeed, @"%R"), OOExpandKeyWithSeed(genSeed, @"nom")];
186 } else {
187 /* NOTE: we can't use "%R %R" because that will produce the same string
188 twice. TODO: is there a reason not to use %N and kOOExpandGoodRNG
189 here? Is there some context where we rely on being able to get the
190 same name for a given genSeed?
191 */
192 genName = [NSString stringWithFormat:@"%@ %@", OOExpandWithSeed(genSeed, @"%R"), OOExpandWithSeed(genSeed, @"%R")];
193 }
194 [self setName:genName];
195
196 [self setShortDescription:OOExpandKeyWithSeed(genSeed, @"character-generic-description", species, planet)];
197
198 // determine _legalStatus for a completely random character
199 [self setLegalStatus:0]; // clean
200 int legalIndex = gen_rnd_number() & gen_rnd_number() & 0x03;
201 while (((gen_rnd_number() & 0xf) < criminalTendency) && (legalIndex < 3))
202 {
203 legalIndex++;
204 }
205 if (legalIndex == 3)
206 {
207 // criminal
208 [self setLegalStatus:criminalTendency + criminalTendency * (gen_rnd_number() & 0x03) + (gen_rnd_number() & gen_rnd_number() & 0x7f)];
209 }
210 legalIndex = 0;
211 if (_legalStatus > 0) legalIndex = (_legalStatus <= 50) ? 1 : 2;
212
213 // if clean - determine insurance level (if any)
214 [self setInsuranceCredits:0];
215 if (legalIndex == 0)
216 {
217 int insuranceIndex = gen_rnd_number() & gen_rnd_number() & 0x03;
218 switch (insuranceIndex)
219 {
220 case 1:
221 [self setInsuranceCredits:125];
222 break;
223 case 2:
224 [self setInsuranceCredits:250];
225 break;
226 case 3:
227 [self setInsuranceCredits:500];
228 }
229 }
230
231 // restore random seed
232 setRandomSeed( savedRNGSeed);
233 RANROTSetFullSeed(savedRANROTSeed);
234}
235
236
237- (BOOL) castInRole:(NSString *)role
238{
239 BOOL specialSetUpDone = NO;
240
241 role = [role lowercaseString];
242 if ([role hasPrefix:@"pirate"])
243 {
244 // determine _legalStatus for a completely random character
245 Random_Seed genSeed = [self genSeed];
246 int sins = 0x08 | (genSeed.a & genSeed.b);
247 [self setLegalStatus:sins & 0x7f];
248
249 specialSetUpDone = YES;
250 }
251 else if ([role hasPrefix:@"trader"])
252 {
253 [self setLegalStatus:0]; // clean
254
255 int insuranceIndex = gen_rnd_number() & 0x03;
256 switch (insuranceIndex)
257 {
258 case 0:
259 [self setInsuranceCredits:0];
260 break;
261 case 1:
262 [self setInsuranceCredits:125];
263 break;
264 case 2:
265 [self setInsuranceCredits:250];
266 break;
267 case 3:
268 [self setInsuranceCredits:500];
269 }
270 specialSetUpDone = YES;
271 }
272 else if ([role hasPrefix:@"hunter"])
273 {
274 [self setLegalStatus:0]; // clean
275 int insuranceIndex = gen_rnd_number() & 0x03;
276 if (insuranceIndex == 3)
277 [self setInsuranceCredits:500];
278 specialSetUpDone = YES;
279 }
280 else if ([role hasPrefix:@"police"])
281 {
282 [self setLegalStatus:0]; // clean
283 [self setInsuranceCredits:125];
284 specialSetUpDone = YES;
285 }
286 else if ([role isEqual:@"miner"])
287 {
288 [self setLegalStatus:0]; // clean
289 [self setInsuranceCredits:25];
290 specialSetUpDone = YES;
291 }
292 else if ([role isEqual:@"passenger"])
293 {
294 [self setLegalStatus:0]; // clean
295 int insuranceIndex = gen_rnd_number() & 0x03;
296 switch (insuranceIndex)
297 {
298 case 0:
299 [self setInsuranceCredits:25];
300 break;
301 case 1:
302 [self setInsuranceCredits:125];
303 break;
304 case 2:
305 [self setInsuranceCredits:250];
306 break;
307 case 3:
308 [self setInsuranceCredits:500];
309 }
310 specialSetUpDone = YES;
311 }
312 else if ([role isEqual:@"slave"])
313 {
314 [self setLegalStatus:0]; // clean
315 [self setInsuranceCredits:0];
316 specialSetUpDone = YES;
317 }
318 else if ([role isEqual:@"thargoid"])
319 {
320 [self setLegalStatus:100];
321 [self setInsuranceCredits:0];
322 [self setName:DESC(@"character-thargoid-name")];
323 [self setShortDescription:DESC(@"character-a-thargoid")];
324 specialSetUpDone = YES;
325 }
326
327 // do long description here
328
329 return specialSetUpDone;
330}
331
332
333- (NSString *)name
334{
335 return _name;
336}
337
338
339- (NSString *)shortDescription
340{
341 return _shortDescription;
342}
343
344
346{
347 return _genSeed;
348}
349
350
351- (int)legalStatus
352{
353 return _legalStatus;
354}
355
356
357- (OOCreditsQuantity)insuranceCredits
358{
359 return _insuranceCredits;
360}
361
362
363- (NSArray *)legacyScript
364{
365 return _scriptActions;
366}
367
368
369- (NSDictionary *) infoForScripting
370{
371 return [NSDictionary dictionaryWithObjectsAndKeys:
372 [self name], @"name",
373 [self shortDescription], @"description",
374 [self species], @"species",
375 [NSNumber numberWithInt:[self legalStatus]], @"legalStatus",
376 [NSNumber numberWithUnsignedLongLong:[self insuranceCredits]], @"insuranceCredits",
377 [NSNumber numberWithInt:[self planetIDOfOrigin]], @"homeSystem",
378 nil];
379}
380
381
382- (void)setName:(NSString *)value
383{
384 [_name autorelease];
385 _name = [value copy];
386}
387
388
389- (void)setShortDescription:(NSString *)value
390{
391 [_shortDescription autorelease];
392 _shortDescription = [value copy];
393}
394
395
396- (void)setOriginSystem:(OOSystemID)value
397{
398 _originSystem = value;
399}
400
401
402- (void)setGenSeed:(Random_Seed)value
403{
404 _genSeed = value;
405}
406
407
408- (void)setLegalStatus:(int)value
409{
410 _legalStatus = value;
411}
412
413
414- (void)setInsuranceCredits:(OOCreditsQuantity)value
415{
416 _insuranceCredits = value;
417}
418
419
420- (void)setLegacyScript:(NSArray *)some_actions
421{
422 [_scriptActions autorelease];
423 _scriptActions = [some_actions copy];
424}
425
426
427- (OOJSScript *)script
428{
429 return _script;
430}
431
432
433- (void) setCharacterScript:(NSString *)scriptName
434{
435 [_script autorelease];
436 _script = [OOScript jsScriptFromFileNamed:scriptName
437 properties:[NSDictionary dictionaryWithObject:self forKey:@"character"]];
438 [_script retain];
439}
440
441
442- (void) doScriptEvent:(jsid)message
443{
444 JSContext *context = OOJSAcquireContext();
445 [_script callMethod:message inContext:context withArguments:NULL count:0 result:NULL];
446 OOJSRelinquishContext(context);
447}
448
449
450- (void) setCharacterFromDictionary:(NSDictionary *)dict
451{
452 id origin = nil;
453 Random_Seed seed;
454
455 origin = [dict objectForKey:@"origin"];
456 if ([origin isKindOfClass:[NSNumber class]] ||
457 ([origin respondsToSelector:@selector(intValue)] && ([origin intValue] != 0 || [origin isEqual:@"0"])))
458 {
459 // Number or numerical string
460 [self setOriginSystem:[origin intValue]];
461 }
462 else if ([origin isKindOfClass:[NSString class]])
463 {
464 OOSystemID sys = [UNIVERSE findSystemFromName:origin];
465 if (sys < 0)
466 {
467 OOLogERR(@"character.load.unknownSystem", @"could not find a system named '%@' in this galaxy.", origin);
468 [self setOriginSystem:(ranrot_rand() & 0xff)];
469 }
470 else
471 {
472 [self setOriginSystem:sys];
473 }
474 }
475 else
476 {
477 // no origin defined, select one at random.
478 [self setOriginSystem:(ranrot_rand() & 0xff)];
479 }
480
481 if ([dict objectForKey:@"random_seed"])
482 {
483 seed = RandomSeedFromString([dict oo_stringForKey:@"random_seed"]); // returns kNilRandomSeed on failure
484 }
485 else
486 {
487 seed.a = (ranrot_rand() & 0xff);
488 seed.b = (ranrot_rand() & 0xff);
489 seed.c = (ranrot_rand() & 0xff);
490 seed.d = (ranrot_rand() & 0xff);
491 seed.e = (ranrot_rand() & 0xff);
492 seed.f = (ranrot_rand() & 0xff);
493 }
494 [self setGenSeed:seed];
495 [self basicSetUp];
496
497 if ([dict oo_stringForKey:@"role"]) [self castInRole:[dict oo_stringForKey:@"role"]];
498 if ([dict oo_stringForKey:@"name"]) [self setName:[dict oo_stringForKey:@"name"]];
499 if ([dict oo_stringForKey:@"short_description"]) [self setShortDescription:[dict oo_stringForKey:@"short_description"]];
500 if ([dict objectForKey:@"legal_status"]) [self setLegalStatus:[dict oo_intForKey:@"legal_status"]];
501 if ([dict objectForKey:@"bounty"]) [self setLegalStatus:[dict oo_intForKey:@"bounty"]];
502 if ([dict objectForKey:@"insurance"]) [self setInsuranceCredits:[dict oo_unsignedLongLongForKey:@"insurance"]];
503 if ([dict oo_stringForKey:@"script"]) [self setCharacterScript:[dict oo_stringForKey:@"script"]];
504 if ([dict oo_arrayForKey:@"script_actions"]) [self setLegacyScript:[dict oo_arrayForKey:@"script_actions"]];
505
506}
507
508@end
#define DESTROY(x)
Definition OOCocoa.h:77
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
return nil
Random_Seed RandomSeedFromString(NSString *abcdefString)
uint64_t OOCreditsQuantity
Definition OOTypes.h:182
int16_t OOSystemID
Definition OOTypes.h:211
uint8_t OOGovernmentID
Definition OOTypes.h:206
#define UNIVERSE
Definition Universe.h:833
Random_Seed genSeed()
BOOL castInRole:(NSString *role)
OOCreditsQuantity insuranceCredits()
NSString * name()
void setCharacterFromDictionary:(NSDictionary *dict)
NSString * shortDescription()
id jsScriptFromFileNamed:properties:(NSString *fileName,[properties] NSDictionary *properties)
Definition OOScript.m:192
voidpf uLong int origin
Definition ioapi.h:140
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void make_pseudo_random_seed(Random_Seed *seed_ptr)
RANROTSeed RANROTGetFullSeed(void)
void seed_RNG_only_for_planet_description(Random_Seed s_seed)
void setRandomSeed(RNG_Seed a_seed)
RNG_Seed currentRandomSeed(void)
void RANROTSetFullSeed(RANROTSeed seed)
int gen_rnd_number(void)
void seed_for_planet_description(Random_Seed s_seed)
unsigned Ranrot(void)
#define ranrot_rand()