5 * Created by Alyssa Milburn on Tue May 25 2004.
6 * Copyright (c) 2004-2006 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
21 #include "CreatureAgent.h"
23 #include "Catalogue.h"
24 #include <cmath> // powf
28 Creature::Creature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) {
33 genus
= 0; // TODO: really, we shouldn't do this, and should instead later assert that a genus was set
42 dreaming
= false; // ?
50 for (unsigned int i
= 0; i
< 5; i
++)
54 Creature::~Creature() {
57 void Creature::finishInit() {
61 bool Creature::shouldProcessGene(gene
*g
) {
62 geneFlags
&flags
= g
->header
.flags
;
64 // non-expressed genes are to be ignored
65 if (flags
.notexpressed
) return false;
67 // gender-specific genes are only to be processed if they are of this
68 if (flags
.femaleonly
&& !female
) return false;
69 if (flags
.maleonly
&& female
) return false;
71 // obviously we only switch on at the stage in question
72 if (g
->header
.switchontime
!= stage
) return false;
74 // TODO: header.variant?
79 void Creature::processGenes() {
80 for (vector
<gene
*>::iterator i
= genome
->genes
.begin(); i
!= genome
->genes
.end(); i
++) {
81 if (shouldProcessGene(*i
)) addGene(*i
);
85 void oldCreature::processGenes() {
86 brain
->processGenes();
87 Creature::processGenes();
90 void c2eCreature::processGenes() {
91 // brain must be processed first (to create loci etc)
92 // organs should be processed last, because new ones will be created by normal processGenes()
94 brain
->processGenes();
95 Creature::processGenes();
96 for (std::vector
<shared_ptr
<c2eOrgan
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
101 void Creature::addGene(gene
*g
) {
102 if (typeid(*g
) == typeid(creatureInstinctGene
)) {
103 unprocessedinstincts
.push_back((creatureInstinctGene
*)g
);
104 } else if (typeid(*g
) == typeid(creatureGenusGene
)) {
105 // TODO: mmh, genus changes after setup shouldn't be valid
106 genus
= ((creatureGenusGene
*)g
)->genus
;
107 parent
->genus
= genus
+ 1;
108 } else if (typeid(*g
) == typeid(creaturePigmentGene
)) {
109 creaturePigmentGene
&p
= *((creaturePigmentGene
*)g
);
110 // TODO: we don't sanity-check
111 tintinfo
[p
.color
] = p
.amount
;
112 } else if (typeid(*g
) == typeid(creaturePigmentGene
)) {
113 creaturePigmentBleedGene
&p
= *((creaturePigmentBleedGene
*)g
);
114 tintinfo
[3] = p
.rotation
;
115 tintinfo
[4] = p
.swap
;
119 void Creature::ageCreature() {
120 if (stage
>= senile
) return; // TODO
122 stage
= (lifestage
)((int)stage
+ 1);
126 parent
->creatureAged();
127 #ifndef _CREATURE_STANDALONE
128 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(4, "", ""); // aged event
132 void Creature::setAsleep(bool a
) {
133 // TODO: skeletalcreature might need to close eyes? or should that just be done during the skeletal update?
139 void Creature::setDreaming(bool d
) {
145 void Creature::born() {
146 parent
->creatureBorn();
149 #ifndef _CREATURE_STANDALONE
150 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).wasBorn();
151 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(3, "", ""); // born event, parents..
157 void Creature::die() {
158 parent
->creatureDied();
161 #ifndef _CREATURE_STANDALONE
162 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).hasDied();
163 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(7, "", ""); // died event
165 // TODO: disable brain/biochemistry updates
167 // TODO: TODO: TODO: this is c2e-specific
168 parent
->stopScript();
169 parent
->queueScript(72);
170 // skeletalcreature eyes, also? see setAsleep comment
174 void Creature::tick() {
183 * oldCreature contains the shared elements of C1 of C2 (creatures are mostly identical in both games)
185 oldCreature::oldCreature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : Creature(g
, is_female
, _variant
, a
) {
189 for (unsigned int i
= 0; i
< 8; i
++) floatingloci
[i
] = 0;
190 for (unsigned int i
= 0; i
< 7; i
++) lifestageloci
[i
] = 0;
191 for (unsigned int i
= 0; i
< 8; i
++) involaction
[i
] = 0;
192 for (unsigned int i
= 0; i
< 256; i
++) chemicals
[i
] = 0;
195 fertile
= pregnant
= receptive
= 0;
198 brain
= 0; // just in case
201 c1Creature::c1Creature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : oldCreature(g
, is_female
, _variant
, a
) {
202 assert(g
->getVersion() == 1);
204 for (unsigned int i
= 0; i
< 6; i
++) senses
[i
] = 0;
205 for (unsigned int i
= 0; i
< 8; i
++) gaitloci
[i
] = 0;
206 for (unsigned int i
= 0; i
< 16; i
++) drives
[i
] = 0;
208 // TODO: chosenagents size
210 brain
= new oldBrain(this);
215 c2Creature::c2Creature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : oldCreature(g
, is_female
, _variant
, a
) {
216 assert(g
->getVersion() == 2);
218 throw creaturesException("You can't create Creatures 2 creatures yet. Bug fuzzie."); // TODO
220 for (unsigned int i
= 0; i
< 14; i
++) senses
[i
] = 0;
221 for (unsigned int i
= 0; i
< 16; i
++) gaitloci
[i
] = 0;
222 for (unsigned int i
= 0; i
< 17; i
++) drives
[i
] = 0;
224 mutationchance
= 0; mutationdegree
= 0;
226 // TODO: chosenagents size
228 brain
= new oldBrain(this);
233 c2eCreature::c2eCreature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : Creature(g
, is_female
, _variant
, a
) {
234 assert(g
->getVersion() == 3);
236 for (unsigned int i
= 0; i
< 256; i
++) chemicals
[i
] = 0.0f
;
239 for (unsigned int i
= 0; i
< 7; i
++) lifestageloci
[i
] = 0.0f
;
241 for (unsigned int i
= 0; i
< 32; i
++) floatingloci
[i
] = 0.0f
;
242 fertile
= pregnant
= ovulate
= receptive
= chanceofmutation
= degreeofmutation
= 0.0f
;
244 for (unsigned int i
= 0; i
< 8; i
++) involaction
[i
] = 0.0f
;
245 for (unsigned int i
= 0; i
< 16; i
++) gaitloci
[i
] = 0.0f
;
246 for (unsigned int i
= 0; i
< 14; i
++) senses
[i
] = 0.0f
;
247 for (unsigned int i
= 0; i
< 20; i
++) drives
[i
] = 0.0f
;
249 for (unsigned int i
= 0; i
< 8; i
++) involactionlatency
[i
] = 0;
253 if (!catalogue
.hasTag("Action Script To Neuron Mappings"))
254 throw creaturesException("c2eCreature was unable to read the 'Action Script To Neuron Mappings' catalogue tag");
255 const std::vector
<std::string
> &mappinginfotag
= catalogue
.getTag("Action Script To Neuron Mappings");
256 for (std::vector
<std::string
>::const_iterator i
= mappinginfotag
.begin(); i
!= mappinginfotag
.end(); i
++)
257 mappinginfo
.push_back(atoi(i
->c_str()));
259 // TODO: should we really hard-code this?
260 chosenagents
.resize(40);
262 brain
= new c2eBrain(this);
267 unsigned int c1Creature::getGait() {
268 unsigned int gait
= 0;
270 for (unsigned int i
= 1; i
< 8; i
++)
271 if (gaitloci
[i
] > gaitloci
[gait
])
277 unsigned int c2Creature::getGait() {
281 void c1Creature::tick() {
282 // TODO: should we tick some things even if dead?
285 senses
[0] = 255; // always-on
286 senses
[1] = (asleep
? 255 : 0); // asleep
292 for (unsigned int i
= 0; i
< 7; i
++) {
293 if ((lifestageloci
[i
] != 0) && (stage
== (lifestage
)i
))
297 if (dead
!= 0) die();
302 void oldCreature::tickBrain() {
310 unsigned int c2eCreature::getGait() {
311 unsigned int gait
= 0;
313 for (unsigned int i
= 1; i
< 16; i
++)
314 if (gaitloci
[i
] > gaitloci
[gait
])
320 void c2eCreature::tick() {
321 // TODO: should we tick some things even if dead?
324 // TODO: update muscleenergy
326 senses
[0] = 1.0f
; // always-on
327 senses
[1] = (asleep
? 1.0f
: 0.0f
); // asleep
328 // space for old C2 senses: hotness, coldness, light level
329 senses
[5] = 0.0f
; // crowedness (TODO)
330 // space for old C2 senses: radiation, time of day, season
331 senses
[9] = 1.0f
; // air quality (TODO)
332 senses
[10] = 0.0f
; // steepness of upcoming slope (up) (TODO)
333 senses
[11] = 0.0f
; // steepness of upcoming slope (down) (TODO)
334 // space for old C2 senses: oncoming wind, wind from behind
340 for (unsigned int i
= 0; i
< 7; i
++) {
341 if ((lifestageloci
[i
] != 0.0f
) && (stage
== (lifestage
)i
))
345 if (dead
!= 0.0f
) die();
350 void c2eCreature::tickBrain() {
354 attention
.clear(); // TODO: doesn't belong here
355 if (!dreaming
) return; // TODO
358 // TODO: correct timing?
359 if ((ticks
% 4) != 0)
363 // TODO: this returns a bool (whether it did an instinct or not), shouldn't we do non-instinct dreaming or something if it's false?
364 // .. if not, make it a void ;p
369 c2eLobe
*drivlobe
= brain
->getLobeById("driv");
371 for (unsigned int i
= 0; i
< 20 && i
< drivlobe
->getNoNeurons(); i
++) {
372 drivlobe
->setNeuronInput(i
, drives
[i
]);
376 /*c2eLobe *verblobe = brain->getLobeById("verb");
378 for (unsigned int i = 0; i < verblobe->getNoNeurons(); i++) {
379 verblobe->setNeuronInput(i, 0.0f); // TODO
383 c2eLobe *nounlobe = brain->getLobeById("noun");
385 for (unsigned int i = 0; i < nounlobe->getNoNeurons(); i++) {
386 nounlobe->setNeuronInput(i, 0.0f); // TODO
390 #ifndef _CREATURE_STANDALONE
395 c2eLobe
*visnlobe
= brain
->getLobeById("visn");
397 for (unsigned int i
= 0; i
< visnlobe
->getNoNeurons() && i
< chosenagents
.size(); i
++) {
398 AgentRef a
= chosenagents
[i
];
401 // TODO: use eye position? see Creature::agentInSight
402 float ourxpos
= parent
->x
+ (parent
->getWidth() / 2.0f
);
403 float theirxpos
= a
->x
+ (a
->getWidth() / 2.0f
);
404 float distance
= theirxpos
- ourxpos
;
406 // TODO: squash result into appropriate range?
407 visnlobe
->setNeuronInput(i
, distance
/ parent
->range
.getFloat());
411 c2eLobe
*smellobe
= brain
->getLobeById("smel");
419 #ifndef _CREATURE_STANDALONE
420 AgentRef oldattn
= attention
;
423 c2eLobe
*attnlobe
= brain
->getLobeById("attn");
425 attn
= attnlobe
->getSpareNeuron();
428 c2eLobe
*decnlobe
= brain
->getLobeById("decn");
430 // TODO: check bounds of mappinginfo
431 decn
= mappinginfo
[decnlobe
->getSpareNeuron()];
434 // TODO: doesn't belong here
435 if (attn
>= 0 && attn
< (int)chosenagents
.size())
436 attention
= chosenagents
[attn
];
438 if (zombie
) return; // TODO: docs say zombies "don't process decision scripts", correct?
440 // fire scripts as needed
441 // TODO: doesn't belong here
442 // TODO: deal with decisions which don't have agents attached
443 // TODO: deal with moving between ATTNs which don't have a choseagent right now (eg, nothing in sight)
444 if (parent
->vmStopped() || oldattn
!= attention
|| olddecn
!= decn
) {
445 if (attention
&& dynamic_cast<CreatureAgent
*>(attention
.get())) {
446 parent
->queueScript(decn
+ 32); // 'on creatures'
448 parent
->queueScript(decn
+ 16); // 'on agents'
452 // involuntary actions
453 for (unsigned int i
= 0; i
< 8; i
++) {
454 if (involactionlatency
[i
] > 0) {
455 involactionlatency
[i
]--;
459 if (involaction
[i
] > 0.0f
) {
460 parent
->queueScript(i
+ 64);
466 bool c2eCreature::processInstinct() {
467 if (unprocessedinstincts
.empty()) return false;
469 creatureInstinctGene
*g
= unprocessedinstincts
.front();
470 unprocessedinstincts
.pop_front();
472 // *** work out which verb neuron to fire by reverse-mapping from the mapping table
473 int actualverb
= reverseMapVerbToNeuron(g
->action
);
474 // we have no idea which verb neuron to use, so no instinct processing
475 if (actualverb
== -1) return false;
479 /*std::cout << "*** processing instinct for verb #" << actualverb << std::endl;
480 std::cout << "reinforce using drive #" << (int)g->drive << " at level " << ((int)g->level - 128) / 128.0f << std::endl;
481 for (unsigned int i = 0; i < 3; i++) {
482 if (g->lobes[i] != 255) {
483 std::cout << "input: lobe tissue #" << (int)(g->lobes[i] - 1) << ", neuron #" << (int)g->neurons[i] << std::endl;
488 * instinct processing! a production by fuzzie in conjunction with coffee
490 * this is mostly guesswork because instincts seem to take place in a single tick in the engine,
491 * making them pretty difficult to observe
493 * we reset the brain by setting pre-REM chemical to full and ticking it once, then we set REM to full
494 * and perform two ticks: one with just the inputs set, and once with a response in the 'resp' lobe
497 // *** sanity checks/setup
499 c2eLobe
*resplobe
= brain
->getLobeById("resp");
500 c2eLobe
*verblobe
= brain
->getLobeById("verb");
501 // no response/verb lobe? no instincts for you, then..
502 if (!resplobe
|| !verblobe
) return false;
504 // if action/drive are beyond the size of the relevant lobe, can't process instinct
505 if ((unsigned int)actualverb
>= verblobe
->getNoNeurons()) return false;
506 if (g
->drive
>= resplobe
->getNoNeurons()) return false;
508 c2eLobe
*inputlobe
[3] = { 0, 0, 0 };
510 for (unsigned int i
= 0; i
< 3; i
++) {
511 // TODO: what about unused?
512 uint8 lobetissueid
= g
->lobes
[i
];
513 if (lobetissueid
== 255) continue;
514 /* fuzzie would like to take this opportunity to quote from the pygenes source:
515 * Apparently, someone decided that because the rows are 1 above the lobe IDs, they should write the ROW NUMBER into the file, instead. Someone, somewhere, needs SHOOTING. */
517 inputlobe
[i
] = brain
->getLobeByTissue(lobetissueid
);
518 // TODO: should we really barf out if this happens?
519 if (!inputlobe
[i
]) return false;
520 if (g
->neurons
[i
] >= inputlobe
[i
]->getNoNeurons()) return false;
525 // TODO: is this a sensible place to wipe the lobes?
526 for (std::map
<std::string
, c2eLobe
*>::iterator i
= brain
->lobes
.begin(); i
!= brain
->lobes
.end(); i
++)
529 // TODO: non-hardcode 212/213? they seem to be in "Brain Parameters" catalogue tag
530 // TODO: won't learning be sort of ruined by the repeated application of pre-REM?
531 chemicals
[212] = 1.0f
; // pre-REM to full
532 chemicals
[213] = 0.0f
; // REM to null
534 chemicals
[212] = 0.0f
; // pre-REM to null
535 chemicals
[213] = 1.0f
; // REM to full
537 // *** set inputs and tick
539 for (unsigned int i
= 0; i
< 3; i
++) {
540 // TODO: eeeevil hack - it looks like this is required, but is there no better way?
541 if (g
->lobes
[i
] == 3) {
543 * the visn lobe subtracts input from 1.0 to get distance of object, so 1.0 is no good
544 * we use 0.1, like c2e seems to feed it (the joys of hacked genetics and brain-in-a-vat!)
546 // TODO: shouldn't we check lobe size?
547 c2eLobe
*visnlobe
= brain
->getLobeById("visn");
549 visnlobe
->setNeuronInput(g
->neurons
[i
], 0.1f
);
553 inputlobe
[i
]->setNeuronInput(g
->neurons
[i
], 1.0f
);
555 verblobe
->setNeuronInput(actualverb
, 1.0f
);
558 // *** set response and tick
560 // TODO: shouldn't we make sure that decn/attn achieved the desired result?
561 // TODO: should we set the input neurons again here? (it seems to work without - fuzzie)
563 // TODO: TODO: TODO: check division of g->level!!
564 // g->drive seems to be a direct mapping
565 resplobe
->setNeuronInput(g
->drive
, ((int)g
->level
- 128) / 128.0f
);
568 // *** finish off and return
570 // TODO: shouldn't REM be present throughout sleep?
571 chemicals
[213] = 0.0f
; // REM to null
573 // wipe the lobes again, to stop any issues with neurons being set which shouldn't be at the end of an instinct run
574 // TODO: is wiping the lobes here truly what we should do?
575 for (std::map
<std::string
, c2eLobe
*>::iterator i
= brain
->lobes
.begin(); i
!= brain
->lobes
.end(); i
++)
578 //std::cout << "*** instinct done" << std::endl;
579 //std::cout << std::endl;
584 void oldCreature::addGene(gene
*g
) {
585 Creature::addGene(g
);
586 if (typeid(*g
) == typeid(bioInitialConcentrationGene
)) {
587 // initialise chemical levels
588 bioInitialConcentrationGene
*b
= (bioInitialConcentrationGene
*)(g
);
589 chemicals
[b
->chemical
] = b
->quantity
;
590 } else if (typeid(*g
) == typeid(bioHalfLivesGene
)) {
591 bioHalfLivesGene
*d
= dynamic_cast<bioHalfLivesGene
*>(g
);
597 void c1Creature::addGene(gene
*g
) {
598 oldCreature::addGene(g
);
600 if (typeid(*g
) == typeid(bioReactionGene
)) {
601 reactions
.push_back(shared_ptr
<c1Reaction
>(new c1Reaction()));
602 reactions
.back()->init((bioReactionGene
*)(g
));
603 } else if (typeid(*g
) == typeid(bioEmitterGene
)) {
604 emitters
.push_back(c1Emitter());
605 emitters
.back().init((bioEmitterGene
*)(g
), this);
606 } else if (typeid(*g
) == typeid(bioReceptorGene
)) {
607 receptors
.push_back(c1Receptor());
608 receptors
.back().init((bioReceptorGene
*)(g
), this);
612 void c2eCreature::addGene(gene
*g
) {
613 Creature::addGene(g
);
615 if (typeid(*g
) == typeid(bioInitialConcentrationGene
)) {
616 // initialise chemical levels
617 bioInitialConcentrationGene
*b
= (bioInitialConcentrationGene
*)(g
);
618 chemicals
[b
->chemical
] = b
->quantity
/ 255.0f
; // TODO: correctness unchecked
619 } else if (typeid(*g
) == typeid(organGene
)) {
621 organGene
*o
= dynamic_cast<organGene
*>(g
);
623 if (!o
->isBrain()) { // TODO: handle brain organ
624 organs
.push_back(shared_ptr
<c2eOrgan
>(new c2eOrgan(this, o
)));
626 } else if (typeid(*g
) == typeid(bioHalfLivesGene
)) {
627 bioHalfLivesGene
*d
= dynamic_cast<bioHalfLivesGene
*>(g
);
633 void oldCreature::addChemical(unsigned char id
, unsigned char val
) {
637 if ((int)chemicals
[id
] + val
> 255) chemicals
[id
] = 255;
638 else chemicals
[id
] += val
;
641 void oldCreature::subChemical(unsigned char id
, unsigned char val
) {
645 if ((int)chemicals
[id
] - val
< 0) chemicals
[id
] = 0;
646 else chemicals
[id
] -= val
;
649 void c2eCreature::adjustChemical(unsigned char id
, float value
) {
652 chemicals
[id
] += value
;
654 if (chemicals
[id
] < 0.0f
) chemicals
[id
] = 0.0f
;
655 else if (chemicals
[id
] > 1.0f
) chemicals
[id
] = 1.0f
;
658 void c2eCreature::adjustDrive(unsigned int id
, float value
) {
662 if (drives
[id
] < 0.0f
) drives
[id
] = 0.0f
;
663 else if (drives
[id
] > 1.0f
) drives
[id
] = 1.0f
;
666 // lookup table, snaffled from real creatures
667 // TODO: work out if these are meaningful values :)
668 unsigned int c1rates
[32] = {
669 0, 0x32A5, 0x71DD, 0xAABB, 0xD110, 0xE758, 0xF35C,
670 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
671 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
672 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
676 inline unsigned int oldCreature::calculateMultiplier(unsigned char rate
) {
677 return c1rates
[rate
];
680 inline unsigned int oldCreature::calculateTickMask(unsigned char rate
) {
681 if (rate
< 7) return 0;
682 else return (1 << ((unsigned int)rate
- 7)) - 1;
685 void c1Creature::tickBiochemistry() {
688 if ((ticks
% 5) != 0) return;
691 for (std::vector
<c1Emitter
>::iterator i
= emitters
.begin(); i
!= emitters
.end(); i
++) {
696 for (std::vector
<c1Receptor
>::iterator i
= receptors
.begin(); i
!= receptors
.end(); i
++) {
701 for (std::vector
<shared_ptr
<c1Reaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) {
702 processReaction(**i
);
705 oldCreature::tickBiochemistry();
708 void oldCreature::tickBiochemistry() {
709 // process half-lives
710 if (!halflives
) return; // TODO: correct?
711 for (unsigned int i
= 0; i
< 256; i
++) {
712 // TODO: this code hasn't been tested thoroughly, but seems to agree with basic testing
714 // work out which rate we're dealing with
715 unsigned char rate
= halflives
->halflives
[i
] / 8;
717 // if the tickmask doesn't want us to change things this tick, don't!
718 if ((biochemticks
& calculateTickMask(rate
)) != 0) continue;
720 // do the actual adjustment
721 chemicals
[i
] = (chemicals
[i
] * calculateMultiplier(rate
)) / 65536;
727 void c2eCreature::tickBiochemistry() {
728 // only process biochem every 4 ticks
729 // TODO: correct? should probably apply to brain too, at least
730 if ((ticks
% 4) != 0) return;
733 for (std::vector
<shared_ptr
<c2eOrgan
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
737 // process half-lives for chemicals
738 if (!halflives
) return; // TODO: correct?
739 for (unsigned int x
= 0; x
< 256; x
++) {
740 if (halflives
->halflives
[x
] == 0) {
741 // 0 is a special case for half-lives
744 // reaction rate = 1.0 - 0.5**(1.0 / 2.2**(rate * 32.0 / 255.0))
745 float rate
= 1.0 - powf(0.5, 1.0 / powf(2.2, (halflives
->halflives
[x
] * 32.0) / 255.0));
747 chemicals
[x
] -= chemicals
[x
] * rate
;
752 unsigned char *c1Creature::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
) {
762 return &lifestageloci
[l
];
763 } else if (l
== 0) return &muscleenergy
;
766 case 1: // circulatory
768 return &floatingloci
[l
];
770 case 2: // reproductive
772 if (l
== 0) return &fertile
;
773 else if (l
== 1) return &receptive
;
775 if (l
== 0) return &fertile
;
776 else if (l
== 1) return &pregnant
;
781 if (l
== 0) return &dead
;
784 case 4: // sensorimotor
786 if (l
< 8) return &involaction
[l
];
787 else if (l
< 16) return &gaitloci
[l
- 8];
789 if (l
< 6) return &senses
[l
];
791 break; // TODO: should this break be here? added it, but can't check, no internet
793 case 5: // drive levels
794 if (l
< 16) return &drives
[l
];
798 std::cout
<< "c1Creature::getLocusPointer failed to interpret locus (" << (int)o
<< ", "
799 << (int)t
<< ", " << (int)l
<< ") of " << (receptor
? "receptor" : "emitter")
805 float *c2eCreature::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
) {
809 c2eLobe
*lobe
= brain
->getLobeByTissue(t
);
812 unsigned int neuronid
= o
/3, stateno
= o
%3;
813 if (neuronid
>= lobe
->getNoNeurons()) break;
814 return &lobe
->getNeuron(neuronid
)->variables
[stateno
];
822 return &lifestageloci
[l
];
823 } else if (l
== 0) return &muscleenergy
;
826 case 1: // circulatory
828 return &floatingloci
[l
];
830 case 2: // reproductive
833 if (!receptor
) { // emitter
834 if (l
== 0) return &fertile
;
835 else if (l
== 1) return &pregnant
;
840 case 0: return &ovulate
;
841 case 1: return &receptive
;
842 case 2: return &chanceofmutation
;
843 case 3: return °reeofmutation
;
848 if (l
== 0) return &dead
;
851 case 4: // sensorimotor
854 if (!receptor
) { // emitter
855 if (val
< 14) return &senses
[val
];
858 if (val
< 8) return &involaction
[val
];
860 if (val
< 16) return &gaitloci
[val
];
865 if (l
< 20) return &drives
[l
];
871 std::cout
<< "c2eCreature::getLocusPointer failed to interpret locus (" << (int)o
<< ", "
872 << (int)t
<< ", " << (int)l
<< ") of " << (receptor
? "receptor" : "emitter")
877 /*****************************************************************************/
879 c2eOrgan::c2eOrgan(c2eCreature
*p
, organGene
*g
) {
880 parent
= p
; assert(parent
);
881 ourGene
= g
; assert(ourGene
);
882 lifeforce
= ourGene
->lifeforce
* (1000000.0f
/ 255.0f
);
883 longtermlifeforce
= shorttermlifeforce
= lifeforce
;
886 clockrate
= ourGene
->clockrate
/ 255.0f
;
887 injurytoapply
= 0.0f
;
888 damagerate
= ourGene
->damagerate
/ 255.0f
;
889 biotick
= ourGene
->biotickstart
/ 255.0f
;
890 atpdamagecoefficient
= ourGene
->atpdamagecoefficient
* (lifeforce
/ (255.0f
* 255.0f
));
892 // TODO: is genes.size() always the size we want?
893 energycost
= (1.0f
/ 128.0f
) + ourGene
->genes
.size() * (0.1f
/ 255.0f
);
896 void c2eOrgan::processGenes() {
897 shared_ptr
<c2eReaction
> r
; // we need to store the previous reaction for possible receptor use
898 // TODO: should this cope with receptors created at other lifestages? i doubt it.. - fuzzie
900 for (vector
<gene
*>::iterator i
= ourGene
->genes
.begin(); i
!= ourGene
->genes
.end(); i
++) {
901 if (!parent
->shouldProcessGene(*i
)) continue;
903 if (typeid(*(*i
)) == typeid(bioReactionGene
)) {
904 reactions
.push_back(shared_ptr
<c2eReaction
>(new c2eReaction()));
905 r
= reactions
.back();
906 reactions
.back()->init((bioReactionGene
*)(*i
));
907 } else if (typeid(*(*i
)) == typeid(bioEmitterGene
)) {
908 emitters
.push_back(c2eEmitter());
909 emitters
.back().init((bioEmitterGene
*)(*i
), this);
910 } else if (typeid(*(*i
)) == typeid(bioReceptorGene
)) {
911 receptors
.push_back(c2eReceptor());
912 receptors
.back().init((bioReceptorGene
*)(*i
), this, r
);
917 void c2eOrgan::tick() {
918 if (longtermlifeforce
<= 0.5f
) return; // We're dead!
920 biotick
+= clockrate
;
924 // if it's our turn to tick..
925 if (biotick
>= 1.0f
) {
927 // .. push the biotick back down
930 // *** energy consumption
931 // chem 35 = ATP, chem 36 = ADP (TODO: fix hardcoding)
932 float atplevel
= parent
->getChemical(35);
933 bool hadenergy
= false;
934 if (atplevel
>= energycost
) {
936 parent
->adjustChemical(35, -energycost
);
937 parent
->adjustChemical(36, energycost
);
940 for (vector
<c2eEmitter
>::iterator i
= emitters
.begin(); i
!= emitters
.end(); i
++)
943 // *** tick reactions
944 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++)
945 processReaction(**i
);
947 // *** out of energy damage
948 applyInjury(atpdamagecoefficient
);
951 // *** long-term damage
952 float diff
= longtermlifeforce
- shorttermlifeforce
;
953 longtermlifeforce
= longtermlifeforce
- (diff
* damagerate
); // damagerate always <= 1.0
955 // *** repair injuries
956 float repair
= diff
* repairrate
; // repairrate always <= 1.00
957 shorttermlifeforce
+= repair
;
958 // adjust Injury chemical (TODO: de-hardcode)
959 parent
->adjustChemical(127, -repair
/ lifeforce
);
962 applyInjury(injurytoapply
);
965 // *** tick receptors
966 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) (*i
)->receptors
= 0;
967 clockratereceptors
= 0; repairratereceptors
= 0; injuryreceptors
= 0;
969 for (vector
<c2eReceptor
>::iterator i
= receptors
.begin(); i
!= receptors
.end(); i
++)
970 processReceptor(*i
, ticked
);
972 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) if ((*i
)->receptors
> 0) (*i
)->rate
/= (*i
)->receptors
;
973 if (clockratereceptors
> 0) clockrate
/= clockratereceptors
;
974 if (repairratereceptors
> 0) repairrate
/= repairratereceptors
;
975 if (injuryreceptors
> 0) injurytoapply
/= injuryreceptors
;
977 // *** decay life force
978 shorttermlifeforce
-= shorttermlifeforce
* (1.0f
/ 1000000.0f
);
979 longtermlifeforce
-= longtermlifeforce
* (1.0f
/ 1000000.0f
);
982 void c2eOrgan::applyInjury(float value
) {
983 shorttermlifeforce
-= value
;
984 if (shorttermlifeforce
< 0.0f
)
985 shorttermlifeforce
= 0.0f
;
986 // adjust Injury chemical (TODO: de-hardcode)
987 parent
->adjustChemical(127, value
/ lifeforce
);
990 void c1Creature::processReaction(c1Reaction
&d
) {
993 bioReactionGene
&g
= *d
.data
;
995 // TODO: this might not all be correct
997 // work out which rate we're dealing with
998 unsigned char rate
= g
.rate
/ 8;
1000 // if the tickmask doesn't want us to change things this tick, don't!
1001 if ((biochemticks
& calculateTickMask(rate
)) != 0) return;
1003 unsigned char ratio
= 255, ratio2
= 255;
1004 if (g
.reactant
[0] != 0) {
1005 assert(g
.quantity
[0] != 0); // TODO
1006 ratio
= getChemical(g
.reactant
[0]) / g
.quantity
[0];
1008 if (g
.reactant
[1] != 0) {
1009 assert(g
.quantity
[1] != 0); // TODO
1010 ratio2
= getChemical(g
.reactant
[1]) / g
.quantity
[1];
1013 // pick lowest ratio, if zero then return
1014 if (ratio2
< ratio
) ratio
= ratio2
;
1015 if (ratio
== 0) return;
1017 // calculate the actual adjustment (can't go out of bounds)
1018 ratio
= ratio
- ((ratio
* calculateMultiplier(rate
)) / 65536);
1020 // change chemical levels
1021 subChemical(g
.reactant
[0], ratio
* g
.quantity
[0]);
1022 subChemical(g
.reactant
[1], ratio
* g
.quantity
[1]);
1023 addChemical(g
.reactant
[2], ratio
* g
.quantity
[2]);
1024 addChemical(g
.reactant
[3], ratio
* g
.quantity
[3]);
1027 void c2eOrgan::processReaction(c2eReaction
&d
) {
1028 bioReactionGene
&g
= *d
.data
;
1030 // TODO: this might not all be correct
1032 float ratio
= 1.0f
, ratio2
= 1.0f
;
1033 if (g
.reactant
[0] != 0) {
1034 assert(g
.quantity
[0] != 0); // TODO
1035 ratio
= parent
->getChemical(g
.reactant
[0]) / (float)g
.quantity
[0];
1037 if (g
.reactant
[1] != 0) {
1038 assert(g
.quantity
[1] != 0); // TODO
1039 ratio2
= parent
->getChemical(g
.reactant
[1]) / (float)g
.quantity
[1];
1042 // pick lowest ratio, if zero then return
1043 if (ratio2
< ratio
) ratio
= ratio2
;
1044 if (ratio
== 0.0f
) return;
1046 // calculate the actual adjustment
1047 float rate
= 1.0 - powf(0.5, 1.0 / powf(2.2, (1.0 - d
.rate
) * 32.0));
1048 ratio
= ratio
* rate
;
1050 // change chemical levels
1051 parent
->adjustChemical(g
.reactant
[0], -(ratio
* (float)g
.quantity
[0]));
1052 parent
->adjustChemical(g
.reactant
[1], -(ratio
* (float)g
.quantity
[1]));
1053 parent
->adjustChemical(g
.reactant
[2], ratio
* (float)g
.quantity
[2]);
1054 parent
->adjustChemical(g
.reactant
[3], ratio
* (float)g
.quantity
[3]);
1057 void c1Creature::processEmitter(c1Emitter
&d
) {
1060 bioEmitterGene
&g
= *d
.data
;
1062 if ((biochemticks
% g
.rate
) != 0) return;
1064 if (!d
.locus
) return;
1065 unsigned char f
= *d
.locus
;
1066 if (g
.clear
) *d
.locus
= 0;
1067 if (g
.invert
) f
= 255 - f
;
1070 if (f
< g
.threshold
) return;
1071 addChemical(g
.chemical
, g
.gain
);
1073 int r
= (((int)f
- g
.threshold
) * g
.gain
) / 255;
1075 // clip the result of the calculation to unsigned char, and reassign it
1076 if (r
< 0) r
= 0; else if (r
> 255) r
= 255;
1079 addChemical(g
.chemical
, f
);
1083 void c2eOrgan::processEmitter(c2eEmitter
&d
) {
1084 bioEmitterGene
&g
= *d
.data
;
1086 if (d
.sampletick
!= g
.rate
) {
1087 assert(d
.sampletick
< g
.rate
);
1094 if (!d
.locus
) return;
1096 if (g
.clear
) *d
.locus
= 0.0f
;
1097 if (g
.invert
) f
= 1.0f
- f
;
1100 if (f
< d
.threshold
) return;
1101 parent
->adjustChemical(g
.chemical
, d
.gain
);
1103 f
= (f
- d
.threshold
) * d
.gain
;
1104 if (f
> 0.0f
) // TODO: correct check?
1105 parent
->adjustChemical(g
.chemical
, f
);
1109 void c1Creature::processReceptor(c1Receptor
&d
) {
1112 bioReceptorGene
&g
= *d
.data
;
1114 // TODO: same issues as c2eOrgan::processReceptor below, probably
1116 if (!d
.locus
) return;
1118 unsigned char f
= chemicals
[g
.chemical
];
1121 r
= f
> g
.threshold
? g
.gain
: 0;
1123 // TODO: int promotion correct to makke this work out?
1124 r
= (((int)f
- g
.threshold
) * g
.gain
) / 255;
1126 if (g
.inverted
) r
= g
.nominal
- r
;
1127 else r
+= g
.nominal
;
1129 // clip the result of the calculation to unsigned char, and reassign it
1130 if (r
< 0) r
= 0; else if (r
> 255) r
= 255;
1133 if (f
== 0 && g
.organ
== 1 && g
.tissue
== 3 && g
.locus
== 0) // evil check for "Die if non-zero!" locus
1139 void c2eOrgan::processReceptor(c2eReceptor
&d
, bool checkchem
) {
1140 bioReceptorGene
&g
= *d
.data
;
1143 * TODO: This code has issues..
1145 * eg, if you have two receptors pointing at a non-local locus,
1146 * we just stomp over it in order, so the last receptor always get it
1147 * while c2e seems to alternate between them (possibly organ clockrate stuff)
1153 d
.lastvalue
= parent
->getChemical(g
.chemical
);
1156 if (!d
.processed
) return;
1157 if (!d
.locus
) return;
1161 f
= d
.lastvalue
> d
.threshold
? d
.gain
: 0.0f
;
1163 f
= (d
.lastvalue
- d
.threshold
) * d
.gain
;
1164 if (g
.inverted
) f
*= -1.0f
;
1167 if (f
< 0.0f
) f
= 0.0f
; else if (f
> 1.0f
) f
= 1.0f
; // TODO: correct?
1169 if (f
== 0.0f
&& g
.organ
== 1 && g
.tissue
== 3 && g
.locus
== 0) // evil check for "Die if non-zero!" locus
1171 else if (d
.receptors
) {
1172 if (*d
.receptors
== 0) *d
.locus
= 0.0f
;
1179 float *c2eOrgan::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
, unsigned int**receptors
) {
1180 if (receptors
) *receptors
= 0;
1186 case 0: // clock rate
1187 if (receptors
) *receptors
= &clockratereceptors
;
1189 case 1: // repair rate
1190 if (receptors
) *receptors
= &repairratereceptors
;
1192 case 2: // injury to apply
1193 if (receptors
) *receptors
= &injuryreceptors
;
1194 return &injurytoapply
;
1198 if (t
== 0 && l
== 0) { // reaction rate
1199 shared_ptr
<c2eReaction
> r
= reactions
.back();
1201 std::cout
<< "c2eOrgan::getLocusPointer failed to find a reaction" << std::endl
;
1204 if (receptors
) *receptors
= &r
->receptors
;
1210 return parent
->getLocusPointer(receptor
, o
, t
, l
);
1213 void c1Reaction::init(bioReactionGene
*g
) {
1217 void c2eReaction::init(bioReactionGene
*g
) {
1220 // rate is stored in genome as 0 fastest, 255 slowest
1221 // reversed in game, i think .. TODO: check this
1222 rate
= 1.0 - (g
->rate
/ 255.0);
1225 void c1Receptor::init(bioReceptorGene
*g
, c1Creature
*parent
) {
1227 locus
= parent
->getLocusPointer(true, g
->organ
, g
->tissue
, g
->locus
);
1230 void c2eReceptor::init(bioReceptorGene
*g
, c2eOrgan
*parent
, shared_ptr
<c2eReaction
> r
) {
1233 nominal
= g
->nominal
/ 255.0f
;
1234 threshold
= g
->threshold
/ 255.0f
;
1235 gain
= g
->gain
/ 255.0f
;
1236 locus
= parent
->getLocusPointer(true, g
->organ
, g
->tissue
, g
->locus
, &receptors
);
1239 void c1Emitter::init(bioEmitterGene
*g
, c1Creature
*parent
) {
1241 locus
= parent
->getLocusPointer(false, g
->organ
, g
->tissue
, g
->locus
);
1244 void c2eEmitter::init(bioEmitterGene
*g
, c2eOrgan
*parent
) {
1247 threshold
= g
->threshold
/ 255.0f
;
1248 gain
= g
->gain
/ 255.0f
;
1249 locus
= parent
->getLocusPointer(false, g
->organ
, g
->tissue
, g
->locus
, 0);
1252 #include "AgentHelpers.h"
1254 bool Creature::agentInSight(AgentRef a
) {
1255 #ifndef _CREATURE_STANDALONE
1256 if (a
->invisible()) return false;
1258 // TODO: specify x/y location for eyes
1259 // TODO: check open cabin?
1260 return agentIsVisible(parent
, a
);
1266 void Creature::chooseAgents() {
1267 #ifndef _CREATURE_STANDALONE
1268 // zot any chosen agents which went out of range, went invisible or changed category
1269 for (unsigned int i
= 0; i
< chosenagents
.size(); i
++) {
1270 AgentRef a
= chosenagents
[i
];
1272 if (a
->category
!= (int)i
|| !agentInSight(a
))
1273 chosenagents
[i
].clear();
1277 std::vector
<std::vector
<AgentRef
> > possibles(chosenagents
.size());
1279 for (std::list
<boost::shared_ptr
<Agent
> >::iterator i
= world
.agents
.begin(); i
!= world
.agents
.end(); i
++) {
1280 boost::shared_ptr
<Agent
> a
= *i
;
1283 // if agent category is -1 or outside of our #categories, continue
1284 if (a
->category
< 0) continue;
1285 if (a
->category
>= (int)chosenagents
.size()) continue;
1287 // if we already chose an agent from this category, continue
1288 if (chosenagents
[a
->category
]) continue;
1290 if (!agentInSight(a
)) continue;
1292 possibles
[a
->category
].push_back(a
);
1295 for (unsigned int i
= 0; i
< chosenagents
.size(); i
++) {
1296 if (!chosenagents
[i
])
1297 chosenagents
[i
] = selectRepresentativeAgent(i
, possibles
[i
]);
1302 AgentRef
c2eCreature::selectRepresentativeAgent(int type
, std::vector
<AgentRef
> possibles
) {
1303 // TODO: proper selection method
1305 if (possibles
.size() > 0)
1306 return possibles
[rand() % possibles
.size()];
1311 int c2eCreature::reverseMapVerbToNeuron(unsigned int verb
) {
1312 // TODO: reverse-mapping like this seems utterly horrible, is it correct?
1313 int actualverb
= -1;
1314 for (unsigned int i
= 0; i
< mappinginfo
.size(); i
++) {
1315 if (mappinginfo
[i
] == verb
)
1316 actualverb
= (int)i
;
1321 void c2eCreature::handleStimulus(c2eStim
&stim
) {
1322 // TODO: handle out-of-range verb_amount/noun_amount
1324 if (stim
.verb_id
>= 0) {
1325 c2eLobe
*verblobe
= brain
->getLobeById("verb");
1327 if ((unsigned int)stim
.verb_id
< verblobe
->getNoNeurons())
1328 verblobe
->setNeuronInput(stim
.verb_id
, stim
.verb_amount
);
1332 if (stim
.noun_id
>= 0) {
1333 c2eLobe
*nounlobe
= brain
->getLobeById("noun");
1335 if ((unsigned int)stim
.noun_id
< nounlobe
->getNoNeurons())
1336 nounlobe
->setNeuronInput(stim
.noun_id
, stim
.noun_amount
);
1340 for (unsigned int i
= 0; i
< 4; i
++) {
1341 if (stim
.drive_id
[i
] >= 0) {
1342 unsigned char chemno
= stim
.drive_id
[i
] + 148;
1343 adjustChemical(chemno
, stim
.drive_amount
[i
]);
1344 if (!stim
.drive_silent
[i
]) {
1345 c2eLobe
*resplobe
= brain
->getLobeById("resp");
1347 if ((unsigned int)stim
.drive_id
[i
] < resplobe
->getNoNeurons())
1348 resplobe
->setNeuronInput(stim
.drive_id
[i
], stim
.drive_amount
[i
]);
1355 // TODO: this needs to be passed noun details, it seems, judging by documentation
1356 void c2eCreature::handleStimulus(unsigned int id
, float strength
) {
1357 // note that g->addoffset does not seem to exist in c2e
1360 creatureStimulusGene
*g
= 0;
1362 // TODO: generate the damn c2eStims in addGene, thus zapping a whole bunch of bugs
1363 for (vector
<gene
*>::iterator i
= genome
->genes
.begin(); i
!= genome
->genes
.end(); i
++) {
1364 if (typeid(*(*i
)) == typeid(creatureStimulusGene
)) {
1365 creatureStimulusGene
*x
= (creatureStimulusGene
*)(*i
);
1366 if (x
->stim
== id
) {
1374 // if we're asleep and the stimulus isn't to be processed when asleep, return
1375 if (!g
->whenasleep
&& isAsleep()) return;
1377 // TODO: g->modulate
1379 // TODO: is multipler usage below okay?
1380 float multiplier
= (strength
== 0.0f
? 1.0f
: strength
);
1383 * TODO: what the heck does g->intensity do? it seems to almost entirely be 0
1384 * in the standard genomes (apart from a 255?) and it doesn't seem to change
1387 // TODO: grmph, g->sensoryneuron and g->significance make no sense to me right now
1388 // either, so commenting the verb_id setting out until someone works it out - fuzzie
1389 /*if (stim.verb_id != 0) // TODO: this is a guess to stop stuff from resting seemingly forever
1390 stim.verb_id = reverseMapVerbToNeuron(g->sensoryneuron); */
1391 // TODO: huh? gene kit has it in 255-ish steps
1392 stim
.verb_amount
= g
->significance
* (1.0f
/ 124.0f
); /* multiply by 0.5? */
1393 for (unsigned int i
= 0; i
< 4; i
++) {
1394 // TODO: ack, amount should be bound to range
1395 // TODO: fuzzie is suspicious about multiply/dividing on g->amounts here
1396 if (g
->drives
[i
] != 255)
1397 stim
.setupDriveStim(i
, g
->drives
[i
], ((g
->amounts
[i
] * (1.0f
/ 124.0f
)) - 1.0f
) * multiplier
, g
->silent
[i
]);
1399 if (strength
== 0.0f
)
1400 stim
.drive_silent
[i
] = true;
1403 handleStimulus(stim
);
1406 /* vim: set noet: */