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 c2Creature::processGenes() {
91 oldCreature::processGenes();
93 for (std::vector
<shared_ptr
<c2Organ
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
98 void c2eCreature::processGenes() {
99 // brain must be processed first (to create loci etc)
100 // organs should be processed last, because new ones will be created by normal processGenes()
102 brain
->processGenes();
103 Creature::processGenes();
104 for (std::vector
<shared_ptr
<c2eOrgan
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
105 (*x
)->processGenes();
109 void Creature::addGene(gene
*g
) {
110 if (typeid(*g
) == typeid(creatureInstinctGene
)) {
111 unprocessedinstincts
.push_back((creatureInstinctGene
*)g
);
112 } else if (typeid(*g
) == typeid(creatureGenusGene
)) {
113 // TODO: mmh, genus changes after setup shouldn't be valid
114 genus
= ((creatureGenusGene
*)g
)->genus
;
115 parent
->genus
= genus
+ 1;
116 } else if (typeid(*g
) == typeid(creaturePigmentGene
)) {
117 creaturePigmentGene
&p
= *((creaturePigmentGene
*)g
);
118 // TODO: we don't sanity-check
119 tintinfo
[p
.color
] = p
.amount
;
120 } else if (typeid(*g
) == typeid(creaturePigmentGene
)) {
121 creaturePigmentBleedGene
&p
= *((creaturePigmentBleedGene
*)g
);
122 tintinfo
[3] = p
.rotation
;
123 tintinfo
[4] = p
.swap
;
127 void Creature::ageCreature() {
128 if (stage
>= senile
) return; // TODO
130 stage
= (lifestage
)((int)stage
+ 1);
134 parent
->creatureAged();
135 #ifndef _CREATURE_STANDALONE
136 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(4, "", ""); // aged event
140 void Creature::setAsleep(bool a
) {
141 // TODO: skeletalcreature might need to close eyes? or should that just be done during the skeletal update?
147 void Creature::setDreaming(bool d
) {
153 void Creature::born() {
154 parent
->creatureBorn();
157 #ifndef _CREATURE_STANDALONE
158 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).wasBorn();
159 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(3, "", ""); // born event, parents..
165 void Creature::die() {
166 parent
->creatureDied();
169 #ifndef _CREATURE_STANDALONE
170 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).hasDied();
171 world
.history
.getMoniker(world
.history
.findMoniker(genome
)).addEvent(7, "", ""); // died event
173 // TODO: disable brain/biochemistry updates
175 // TODO: TODO: TODO: this is c2e-specific
176 parent
->stopScript();
177 parent
->queueScript(72);
178 // skeletalcreature eyes, also? see setAsleep comment
182 void Creature::tick() {
191 * oldCreature contains the shared elements of C1 of C2 (creatures are mostly identical in both games)
193 oldCreature::oldCreature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : Creature(g
, is_female
, _variant
, a
) {
197 for (unsigned int i
= 0; i
< 8; i
++) floatingloci
[i
] = 0;
198 for (unsigned int i
= 0; i
< 7; i
++) lifestageloci
[i
] = 0;
199 for (unsigned int i
= 0; i
< 8; i
++) involaction
[i
] = 0;
200 for (unsigned int i
= 0; i
< 256; i
++) chemicals
[i
] = 0;
203 fertile
= pregnant
= receptive
= 0;
206 brain
= 0; // just in case
209 c1Creature::c1Creature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : oldCreature(g
, is_female
, _variant
, a
) {
210 assert(g
->getVersion() == 1);
212 for (unsigned int i
= 0; i
< 6; i
++) senses
[i
] = 0;
213 for (unsigned int i
= 0; i
< 8; i
++) gaitloci
[i
] = 0;
214 for (unsigned int i
= 0; i
< 16; i
++) drives
[i
] = 0;
216 // TODO: chosenagents size
218 brain
= new oldBrain(this);
223 c2Creature::c2Creature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : oldCreature(g
, is_female
, _variant
, a
) {
224 assert(g
->getVersion() == 2);
226 for (unsigned int i
= 0; i
< 14; i
++) senses
[i
] = 0;
227 for (unsigned int i
= 0; i
< 16; i
++) gaitloci
[i
] = 0;
228 for (unsigned int i
= 0; i
< 17; i
++) drives
[i
] = 0;
230 mutationchance
= 0; mutationdegree
= 0;
232 // TODO: chosenagents size
234 brain
= new oldBrain(this);
239 c2eCreature::c2eCreature(shared_ptr
<genomeFile
> g
, bool is_female
, unsigned char _variant
, CreatureAgent
*a
) : Creature(g
, is_female
, _variant
, a
) {
240 assert(g
->getVersion() == 3);
242 for (unsigned int i
= 0; i
< 256; i
++) chemicals
[i
] = 0.0f
;
245 for (unsigned int i
= 0; i
< 7; i
++) lifestageloci
[i
] = 0.0f
;
247 for (unsigned int i
= 0; i
< 32; i
++) floatingloci
[i
] = 0.0f
;
248 fertile
= pregnant
= ovulate
= receptive
= chanceofmutation
= degreeofmutation
= 0.0f
;
250 for (unsigned int i
= 0; i
< 8; i
++) involaction
[i
] = 0.0f
;
251 for (unsigned int i
= 0; i
< 16; i
++) gaitloci
[i
] = 0.0f
;
252 for (unsigned int i
= 0; i
< 14; i
++) senses
[i
] = 0.0f
;
253 for (unsigned int i
= 0; i
< 20; i
++) drives
[i
] = 0.0f
;
255 for (unsigned int i
= 0; i
< 8; i
++) involactionlatency
[i
] = 0;
259 if (!catalogue
.hasTag("Action Script To Neuron Mappings"))
260 throw creaturesException("c2eCreature was unable to read the 'Action Script To Neuron Mappings' catalogue tag");
261 const std::vector
<std::string
> &mappinginfotag
= catalogue
.getTag("Action Script To Neuron Mappings");
262 for (std::vector
<std::string
>::const_iterator i
= mappinginfotag
.begin(); i
!= mappinginfotag
.end(); i
++)
263 mappinginfo
.push_back(atoi(i
->c_str()));
265 // TODO: should we really hard-code this?
266 chosenagents
.resize(40);
268 brain
= new c2eBrain(this);
273 unsigned int c1Creature::getGait() {
274 unsigned int gait
= 0;
276 for (unsigned int i
= 1; i
< 8; i
++)
277 if (gaitloci
[i
] > gaitloci
[gait
])
283 unsigned int c2Creature::getGait() {
284 unsigned int gait
= 0;
286 for (unsigned int i
= 1; i
< 16; i
++)
287 if (gaitloci
[i
] > gaitloci
[gait
])
293 unsigned int c2eCreature::getGait() {
294 unsigned int gait
= 0;
296 for (unsigned int i
= 1; i
< 16; i
++)
297 if (gaitloci
[i
] > gaitloci
[gait
])
303 void c1Creature::tick() {
304 // TODO: should we tick some things even if dead?
307 senses
[0] = 255; // always-on
308 senses
[1] = (asleep
? 255 : 0); // asleep
314 for (unsigned int i
= 0; i
< 7; i
++) {
315 if ((lifestageloci
[i
] != 0) && (stage
== (lifestage
)i
))
319 if (dead
!= 0) die();
324 void c2Creature::tick() {
325 // TODO: should we tick some things even if dead?
328 senses
[0] = 255; // always-on
329 senses
[1] = (asleep
? 255 : 0); // asleep
335 for (unsigned int i
= 0; i
< 7; i
++) {
336 if ((lifestageloci
[i
] != 0) && (stage
== (lifestage
)i
))
340 if (dead
!= 0) die();
345 void oldCreature::tickBrain() {
353 void c2eCreature::tick() {
354 // TODO: should we tick some things even if dead?
357 // TODO: update muscleenergy
359 senses
[0] = 1.0f
; // always-on
360 senses
[1] = (asleep
? 1.0f
: 0.0f
); // asleep
361 // space for old C2 senses: hotness, coldness, light level
362 senses
[5] = 0.0f
; // crowedness (TODO)
363 // space for old C2 senses: radiation, time of day, season
364 senses
[9] = 1.0f
; // air quality (TODO)
365 senses
[10] = 0.0f
; // steepness of upcoming slope (up) (TODO)
366 senses
[11] = 0.0f
; // steepness of upcoming slope (down) (TODO)
367 // space for old C2 senses: oncoming wind, wind from behind
373 for (unsigned int i
= 0; i
< 7; i
++) {
374 if ((lifestageloci
[i
] != 0.0f
) && (stage
== (lifestage
)i
))
378 if (dead
!= 0.0f
) die();
383 void c2eCreature::tickBrain() {
387 attention
.clear(); // TODO: doesn't belong here
388 if (!dreaming
) return; // TODO
391 // TODO: correct timing?
392 if ((ticks
% 4) != 0)
396 // 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?
397 // .. if not, make it a void ;p
402 c2eLobe
*drivlobe
= brain
->getLobeById("driv");
404 for (unsigned int i
= 0; i
< 20 && i
< drivlobe
->getNoNeurons(); i
++) {
405 drivlobe
->setNeuronInput(i
, drives
[i
]);
409 /*c2eLobe *verblobe = brain->getLobeById("verb");
411 for (unsigned int i = 0; i < verblobe->getNoNeurons(); i++) {
412 verblobe->setNeuronInput(i, 0.0f); // TODO
416 c2eLobe *nounlobe = brain->getLobeById("noun");
418 for (unsigned int i = 0; i < nounlobe->getNoNeurons(); i++) {
419 nounlobe->setNeuronInput(i, 0.0f); // TODO
423 #ifndef _CREATURE_STANDALONE
428 c2eLobe
*visnlobe
= brain
->getLobeById("visn");
430 for (unsigned int i
= 0; i
< visnlobe
->getNoNeurons() && i
< chosenagents
.size(); i
++) {
431 AgentRef a
= chosenagents
[i
];
434 // TODO: use eye position? see Creature::agentInSight
435 float ourxpos
= parent
->x
+ (parent
->getWidth() / 2.0f
);
436 float theirxpos
= a
->x
+ (a
->getWidth() / 2.0f
);
437 float distance
= theirxpos
- ourxpos
;
439 // TODO: squash result into appropriate range?
440 visnlobe
->setNeuronInput(i
, distance
/ parent
->range
.getFloat());
444 c2eLobe
*smellobe
= brain
->getLobeById("smel");
452 #ifndef _CREATURE_STANDALONE
453 AgentRef oldattn
= attention
;
456 c2eLobe
*attnlobe
= brain
->getLobeById("attn");
458 attn
= attnlobe
->getSpareNeuron();
461 c2eLobe
*decnlobe
= brain
->getLobeById("decn");
463 // TODO: check bounds of mappinginfo
464 decn
= mappinginfo
[decnlobe
->getSpareNeuron()];
467 // TODO: doesn't belong here
468 if (attn
>= 0 && attn
< (int)chosenagents
.size())
469 attention
= chosenagents
[attn
];
471 if (zombie
) return; // TODO: docs say zombies "don't process decision scripts", correct?
473 // fire scripts as needed
474 // TODO: doesn't belong here
475 // TODO: deal with decisions which don't have agents attached
476 // TODO: deal with moving between ATTNs which don't have a choseagent right now (eg, nothing in sight)
477 if (parent
->vmStopped() || oldattn
!= attention
|| olddecn
!= decn
) {
478 if (attention
&& dynamic_cast<CreatureAgent
*>(attention
.get())) {
479 parent
->queueScript(decn
+ 32); // 'on creatures'
481 parent
->queueScript(decn
+ 16); // 'on agents'
485 // involuntary actions
486 for (unsigned int i
= 0; i
< 8; i
++) {
487 if (involactionlatency
[i
] > 0) {
488 involactionlatency
[i
]--;
492 if (involaction
[i
] > 0.0f
) {
493 parent
->queueScript(i
+ 64);
499 bool c2eCreature::processInstinct() {
500 if (unprocessedinstincts
.empty()) return false;
502 creatureInstinctGene
*g
= unprocessedinstincts
.front();
503 unprocessedinstincts
.pop_front();
505 // *** work out which verb neuron to fire by reverse-mapping from the mapping table
506 int actualverb
= reverseMapVerbToNeuron(g
->action
);
507 // we have no idea which verb neuron to use, so no instinct processing
508 if (actualverb
== -1) return false;
512 /*std::cout << "*** processing instinct for verb #" << actualverb << std::endl;
513 std::cout << "reinforce using drive #" << (int)g->drive << " at level " << ((int)g->level - 128) / 128.0f << std::endl;
514 for (unsigned int i = 0; i < 3; i++) {
515 if (g->lobes[i] != 255) {
516 std::cout << "input: lobe tissue #" << (int)(g->lobes[i] - 1) << ", neuron #" << (int)g->neurons[i] << std::endl;
521 * instinct processing! a production by fuzzie in conjunction with coffee
523 * this is mostly guesswork because instincts seem to take place in a single tick in the engine,
524 * making them pretty difficult to observe
526 * we reset the brain by setting pre-REM chemical to full and ticking it once, then we set REM to full
527 * and perform two ticks: one with just the inputs set, and once with a response in the 'resp' lobe
530 // *** sanity checks/setup
532 c2eLobe
*resplobe
= brain
->getLobeById("resp");
533 c2eLobe
*verblobe
= brain
->getLobeById("verb");
534 // no response/verb lobe? no instincts for you, then..
535 if (!resplobe
|| !verblobe
) return false;
537 // if action/drive are beyond the size of the relevant lobe, can't process instinct
538 if ((unsigned int)actualverb
>= verblobe
->getNoNeurons()) return false;
539 if (g
->drive
>= resplobe
->getNoNeurons()) return false;
541 c2eLobe
*inputlobe
[3] = { 0, 0, 0 };
543 for (unsigned int i
= 0; i
< 3; i
++) {
544 // TODO: what about unused?
545 uint8 lobetissueid
= g
->lobes
[i
];
546 if (lobetissueid
== 255) continue;
547 /* fuzzie would like to take this opportunity to quote from the pygenes source:
548 * 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. */
550 inputlobe
[i
] = brain
->getLobeByTissue(lobetissueid
);
551 // TODO: should we really barf out if this happens?
552 if (!inputlobe
[i
]) return false;
553 if (g
->neurons
[i
] >= inputlobe
[i
]->getNoNeurons()) return false;
558 // TODO: is this a sensible place to wipe the lobes?
559 for (std::map
<std::string
, c2eLobe
*>::iterator i
= brain
->lobes
.begin(); i
!= brain
->lobes
.end(); i
++)
562 // TODO: non-hardcode 212/213? they seem to be in "Brain Parameters" catalogue tag
563 // TODO: won't learning be sort of ruined by the repeated application of pre-REM?
564 chemicals
[212] = 1.0f
; // pre-REM to full
565 chemicals
[213] = 0.0f
; // REM to null
567 chemicals
[212] = 0.0f
; // pre-REM to null
568 chemicals
[213] = 1.0f
; // REM to full
570 // *** set inputs and tick
572 for (unsigned int i
= 0; i
< 3; i
++) {
573 // TODO: eeeevil hack - it looks like this is required, but is there no better way?
574 if (g
->lobes
[i
] == 3) {
576 * the visn lobe subtracts input from 1.0 to get distance of object, so 1.0 is no good
577 * we use 0.1, like c2e seems to feed it (the joys of hacked genetics and brain-in-a-vat!)
579 // TODO: shouldn't we check lobe size?
580 c2eLobe
*visnlobe
= brain
->getLobeById("visn");
582 visnlobe
->setNeuronInput(g
->neurons
[i
], 0.1f
);
586 inputlobe
[i
]->setNeuronInput(g
->neurons
[i
], 1.0f
);
588 verblobe
->setNeuronInput(actualverb
, 1.0f
);
591 // *** set response and tick
593 // TODO: shouldn't we make sure that decn/attn achieved the desired result?
594 // TODO: should we set the input neurons again here? (it seems to work without - fuzzie)
596 // TODO: TODO: TODO: check division of g->level!!
597 // g->drive seems to be a direct mapping
598 resplobe
->setNeuronInput(g
->drive
, ((int)g
->level
- 128) / 128.0f
);
601 // *** finish off and return
603 // TODO: shouldn't REM be present throughout sleep?
604 chemicals
[213] = 0.0f
; // REM to null
606 // wipe the lobes again, to stop any issues with neurons being set which shouldn't be at the end of an instinct run
607 // TODO: is wiping the lobes here truly what we should do?
608 for (std::map
<std::string
, c2eLobe
*>::iterator i
= brain
->lobes
.begin(); i
!= brain
->lobes
.end(); i
++)
611 //std::cout << "*** instinct done" << std::endl;
612 //std::cout << std::endl;
617 void oldCreature::addGene(gene
*g
) {
618 Creature::addGene(g
);
619 if (typeid(*g
) == typeid(bioInitialConcentrationGene
)) {
620 // initialise chemical levels
621 bioInitialConcentrationGene
*b
= (bioInitialConcentrationGene
*)(g
);
622 chemicals
[b
->chemical
] = b
->quantity
;
623 } else if (typeid(*g
) == typeid(bioHalfLivesGene
)) {
624 bioHalfLivesGene
*d
= dynamic_cast<bioHalfLivesGene
*>(g
);
630 void c1Creature::addGene(gene
*g
) {
631 oldCreature::addGene(g
);
633 if (typeid(*g
) == typeid(bioReactionGene
)) {
634 reactions
.push_back(shared_ptr
<c1Reaction
>(new c1Reaction()));
635 reactions
.back()->init((bioReactionGene
*)(g
));
636 } else if (typeid(*g
) == typeid(bioEmitterGene
)) {
637 emitters
.push_back(c1Emitter());
638 emitters
.back().init((bioEmitterGene
*)(g
), this);
639 } else if (typeid(*g
) == typeid(bioReceptorGene
)) {
640 receptors
.push_back(c1Receptor());
641 receptors
.back().init((bioReceptorGene
*)(g
), this);
645 void c2Creature::addGene(gene
*g
) {
646 Creature::addGene(g
);
648 if (typeid(*g
) == typeid(organGene
)) {
650 organGene
*o
= dynamic_cast<organGene
*>(g
);
652 if (!o
->isBrain()) { // TODO: handle brain organ
653 organs
.push_back(shared_ptr
<c2Organ
>(new c2Organ(this, o
)));
658 void c2eCreature::addGene(gene
*g
) {
659 Creature::addGene(g
);
661 if (typeid(*g
) == typeid(bioInitialConcentrationGene
)) {
662 // initialise chemical levels
663 bioInitialConcentrationGene
*b
= (bioInitialConcentrationGene
*)(g
);
664 chemicals
[b
->chemical
] = b
->quantity
/ 255.0f
; // TODO: correctness unchecked
665 } else if (typeid(*g
) == typeid(organGene
)) {
667 organGene
*o
= dynamic_cast<organGene
*>(g
);
669 if (!o
->isBrain()) { // TODO: handle brain organ
670 organs
.push_back(shared_ptr
<c2eOrgan
>(new c2eOrgan(this, o
)));
672 } else if (typeid(*g
) == typeid(bioHalfLivesGene
)) {
673 bioHalfLivesGene
*d
= dynamic_cast<bioHalfLivesGene
*>(g
);
679 void oldCreature::addChemical(unsigned char id
, unsigned char val
) {
683 if ((int)chemicals
[id
] + val
> 255) chemicals
[id
] = 255;
684 else chemicals
[id
] += val
;
687 void oldCreature::subChemical(unsigned char id
, unsigned char val
) {
691 if ((int)chemicals
[id
] - val
< 0) chemicals
[id
] = 0;
692 else chemicals
[id
] -= val
;
695 void c2eCreature::adjustChemical(unsigned char id
, float value
) {
698 chemicals
[id
] += value
;
700 if (chemicals
[id
] < 0.0f
) chemicals
[id
] = 0.0f
;
701 else if (chemicals
[id
] > 1.0f
) chemicals
[id
] = 1.0f
;
704 void c2eCreature::adjustDrive(unsigned int id
, float value
) {
708 if (drives
[id
] < 0.0f
) drives
[id
] = 0.0f
;
709 else if (drives
[id
] > 1.0f
) drives
[id
] = 1.0f
;
712 // lookup table, snaffled from real creatures
713 // TODO: work out if these are meaningful values :)
714 unsigned int c1rates
[32] = {
715 0, 0x32A5, 0x71DD, 0xAABB, 0xD110, 0xE758, 0xF35C,
716 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
717 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
718 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999, 0xF999,
722 inline unsigned int oldCreature::calculateMultiplier(unsigned char rate
) {
723 return c1rates
[rate
];
726 inline unsigned int oldCreature::calculateTickMask(unsigned char rate
) {
727 if (rate
< 7) return 0;
728 else return (1 << ((unsigned int)rate
- 7)) - 1;
731 void c1Creature::tickBiochemistry() {
734 if ((ticks
% 5) != 0) return;
737 for (std::vector
<c1Emitter
>::iterator i
= emitters
.begin(); i
!= emitters
.end(); i
++) {
742 for (std::vector
<c1Receptor
>::iterator i
= receptors
.begin(); i
!= receptors
.end(); i
++) {
747 for (std::vector
<shared_ptr
<c1Reaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) {
748 processReaction(**i
);
751 oldCreature::tickBiochemistry();
754 void c2Creature::tickBiochemistry() {
757 if ((ticks
% 5) != 0) return;
760 for (std::vector
<shared_ptr
<c2Organ
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
764 oldCreature::tickBiochemistry();
767 void oldCreature::tickBiochemistry() {
768 // process half-lives
769 if (!halflives
) return; // TODO: correct?
770 for (unsigned int i
= 0; i
< 256; i
++) {
771 // TODO: this code hasn't been tested thoroughly, but seems to agree with basic testing
773 // work out which rate we're dealing with
774 unsigned char rate
= halflives
->halflives
[i
] / 8;
776 // if the tickmask doesn't want us to change things this tick, don't!
777 if ((biochemticks
& calculateTickMask(rate
)) != 0) continue;
779 // do the actual adjustment
780 chemicals
[i
] = (chemicals
[i
] * calculateMultiplier(rate
)) / 65536;
786 void c2eCreature::tickBiochemistry() {
787 // only process biochem every 4 ticks
788 // TODO: correct? should probably apply to brain too, at least
789 if ((ticks
% 4) != 0) return;
792 for (std::vector
<shared_ptr
<c2eOrgan
> >::iterator x
= organs
.begin(); x
!= organs
.end(); x
++) {
796 // process half-lives for chemicals
797 if (!halflives
) return; // TODO: correct?
798 for (unsigned int x
= 0; x
< 256; x
++) {
799 if (halflives
->halflives
[x
] == 0) {
800 // 0 is a special case for half-lives
803 // reaction rate = 1.0 - 0.5**(1.0 / 2.2**(rate * 32.0 / 255.0))
804 float rate
= 1.0 - powf(0.5, 1.0 / powf(2.2, (halflives
->halflives
[x
] * 32.0) / 255.0));
806 chemicals
[x
] -= chemicals
[x
] * rate
;
811 unsigned char *c1Creature::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
) {
821 return &lifestageloci
[l
];
822 } else if (l
== 0) return &muscleenergy
;
825 case 1: // circulatory
827 return &floatingloci
[l
];
829 case 2: // reproductive
831 if (l
== 0) return &fertile
;
832 else if (l
== 1) return &receptive
;
834 if (l
== 0) return &fertile
;
835 else if (l
== 1) return &pregnant
;
840 if (l
== 0) return &dead
;
843 case 4: // sensorimotor
845 if (l
< 8) return &involaction
[l
];
846 else if (l
< 16) return &gaitloci
[l
- 8];
848 if (l
< 6) return &senses
[l
];
850 break; // TODO: should this break be here? added it, but can't check, no internet
852 case 5: // drive levels
853 if (l
< 16) return &drives
[l
];
857 std::cout
<< "c1Creature::getLocusPointer failed to interpret locus (" << (int)o
<< ", "
858 << (int)t
<< ", " << (int)l
<< ") of " << (receptor
? "receptor" : "emitter")
864 unsigned char *c2Creature::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
) {
867 std::cout
<< "c2Creature::getLocusPointer failed to interpret locus (" << (int)o
<< ", "
868 << (int)t
<< ", " << (int)l
<< ") of " << (receptor
? "receptor" : "emitter")
874 float *c2eCreature::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
) {
878 c2eLobe
*lobe
= brain
->getLobeByTissue(t
);
881 unsigned int neuronid
= o
/3, stateno
= o
%3;
882 if (neuronid
>= lobe
->getNoNeurons()) break;
883 return &lobe
->getNeuron(neuronid
)->variables
[stateno
];
891 return &lifestageloci
[l
];
892 } else if (l
== 0) return &muscleenergy
;
895 case 1: // circulatory
897 return &floatingloci
[l
];
899 case 2: // reproductive
902 if (!receptor
) { // emitter
903 if (l
== 0) return &fertile
;
904 else if (l
== 1) return &pregnant
;
909 case 0: return &ovulate
;
910 case 1: return &receptive
;
911 case 2: return &chanceofmutation
;
912 case 3: return °reeofmutation
;
917 if (l
== 0) return &dead
;
920 case 4: // sensorimotor
923 if (!receptor
) { // emitter
924 if (val
< 14) return &senses
[val
];
927 if (val
< 8) return &involaction
[val
];
929 if (val
< 16) return &gaitloci
[val
];
934 if (l
< 20) return &drives
[l
];
940 std::cout
<< "c2eCreature::getLocusPointer failed to interpret locus (" << (int)o
<< ", "
941 << (int)t
<< ", " << (int)l
<< ") of " << (receptor
? "receptor" : "emitter")
946 /*****************************************************************************/
948 c2Organ::c2Organ(c2Creature
*p
, organGene
*g
) {
949 parent
= p
; assert(parent
);
950 ourGene
= g
; assert(ourGene
);
951 lifeforce
= ourGene
->lifeforce
* (1000000.0f
/ 255.0f
);
952 longtermlifeforce
= shorttermlifeforce
= lifeforce
;
954 repairrate
= 0; // TODO
955 clockrate
= ourGene
->clockrate
;
957 damagerate
= ourGene
->damagerate
; // TODO
959 atpdamagecoefficient
= ourGene
->atpdamagecoefficient
* (lifeforce
/ (255.0f
* 255.0f
));
961 // TODO: is genes.size() always the size we want?
962 energycost
= 2 + (ourGene
->genes
.size() / 10);
965 c2eOrgan::c2eOrgan(c2eCreature
*p
, organGene
*g
) {
966 parent
= p
; assert(parent
);
967 ourGene
= g
; assert(ourGene
);
968 lifeforce
= ourGene
->lifeforce
* (1000000.0f
/ 255.0f
);
969 longtermlifeforce
= shorttermlifeforce
= lifeforce
;
972 clockrate
= ourGene
->clockrate
/ 255.0f
;
973 injurytoapply
= 0.0f
;
974 damagerate
= ourGene
->damagerate
/ 255.0f
;
975 biotick
= ourGene
->biotickstart
/ 255.0f
;
976 atpdamagecoefficient
= ourGene
->atpdamagecoefficient
* (lifeforce
/ (255.0f
* 255.0f
));
978 // TODO: is genes.size() always the size we want?
979 energycost
= (1.0f
/ 128.0f
) + ourGene
->genes
.size() * (0.1f
/ 255.0f
);
982 void c2Organ::processGenes() {
983 for (vector
<gene
*>::iterator i
= ourGene
->genes
.begin(); i
!= ourGene
->genes
.end(); i
++) {
984 if (!parent
->shouldProcessGene(*i
)) continue;
990 void c2eOrgan::processGenes() {
991 shared_ptr
<c2eReaction
> r
; // we need to store the previous reaction for possible receptor use
992 // TODO: should this cope with receptors created at other lifestages? i doubt it.. - fuzzie
994 for (vector
<gene
*>::iterator i
= ourGene
->genes
.begin(); i
!= ourGene
->genes
.end(); i
++) {
995 if (!parent
->shouldProcessGene(*i
)) continue;
997 if (typeid(*(*i
)) == typeid(bioReactionGene
)) {
998 reactions
.push_back(shared_ptr
<c2eReaction
>(new c2eReaction()));
999 r
= reactions
.back();
1000 reactions
.back()->init((bioReactionGene
*)(*i
));
1001 } else if (typeid(*(*i
)) == typeid(bioEmitterGene
)) {
1002 emitters
.push_back(c2eEmitter());
1003 emitters
.back().init((bioEmitterGene
*)(*i
), this);
1004 } else if (typeid(*(*i
)) == typeid(bioReceptorGene
)) {
1005 receptors
.push_back(c2eReceptor());
1006 receptors
.back().init((bioReceptorGene
*)(*i
), this, r
);
1011 void c2Organ::tick() {
1012 if (longtermlifeforce
<= 0.5f
) return; // We're dead!
1014 biotick
+= clockrate
;
1016 bool ticked
= false;
1018 if (biotick
>= 255) {
1027 // *** decay life force
1028 shorttermlifeforce
-= shorttermlifeforce
* (1.0f
/ 1000000.0f
);
1029 longtermlifeforce
-= longtermlifeforce
* (1.0f
/ 1000000.0f
);
1032 void c2eOrgan::tick() {
1033 if (longtermlifeforce
<= 0.5f
) return; // We're dead!
1035 biotick
+= clockrate
;
1037 bool ticked
= false;
1039 // if it's our turn to tick..
1040 if (biotick
>= 1.0f
) {
1042 // .. push the biotick back down
1045 // *** energy consumption
1046 // chem 35 = ATP, chem 36 = ADP (TODO: fix hardcoding)
1047 float atplevel
= parent
->getChemical(35);
1048 bool hadenergy
= false;
1049 if (atplevel
>= energycost
) {
1051 parent
->adjustChemical(35, -energycost
);
1052 parent
->adjustChemical(36, energycost
);
1054 // *** tick emitters
1055 for (vector
<c2eEmitter
>::iterator i
= emitters
.begin(); i
!= emitters
.end(); i
++)
1058 // *** tick reactions
1059 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++)
1060 processReaction(**i
);
1062 // *** out of energy damage
1063 applyInjury(atpdamagecoefficient
);
1066 // *** long-term damage
1067 float diff
= longtermlifeforce
- shorttermlifeforce
;
1068 longtermlifeforce
= longtermlifeforce
- (diff
* damagerate
); // damagerate always <= 1.0
1070 // *** repair injuries
1071 float repair
= diff
* repairrate
; // repairrate always <= 1.00
1072 shorttermlifeforce
+= repair
;
1073 // adjust Injury chemical (TODO: de-hardcode)
1074 parent
->adjustChemical(127, -repair
/ lifeforce
);
1077 applyInjury(injurytoapply
);
1080 // *** tick receptors
1081 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) (*i
)->receptors
= 0;
1082 clockratereceptors
= 0; repairratereceptors
= 0; injuryreceptors
= 0;
1084 for (vector
<c2eReceptor
>::iterator i
= receptors
.begin(); i
!= receptors
.end(); i
++)
1085 processReceptor(*i
, ticked
);
1087 for (vector
<shared_ptr
<c2eReaction
> >::iterator i
= reactions
.begin(); i
!= reactions
.end(); i
++) if ((*i
)->receptors
> 0) (*i
)->rate
/= (*i
)->receptors
;
1088 if (clockratereceptors
> 0) clockrate
/= clockratereceptors
;
1089 if (repairratereceptors
> 0) repairrate
/= repairratereceptors
;
1090 if (injuryreceptors
> 0) injurytoapply
/= injuryreceptors
;
1092 // *** decay life force
1093 shorttermlifeforce
-= shorttermlifeforce
* (1.0f
/ 1000000.0f
);
1094 longtermlifeforce
-= longtermlifeforce
* (1.0f
/ 1000000.0f
);
1097 void c2eOrgan::applyInjury(float value
) {
1098 shorttermlifeforce
-= value
;
1099 if (shorttermlifeforce
< 0.0f
)
1100 shorttermlifeforce
= 0.0f
;
1101 // adjust Injury chemical (TODO: de-hardcode)
1102 parent
->adjustChemical(127, value
/ lifeforce
);
1105 void c1Creature::processReaction(c1Reaction
&d
) {
1108 bioReactionGene
&g
= *d
.data
;
1110 // TODO: this might not all be correct
1112 // work out which rate we're dealing with
1113 unsigned char rate
= g
.rate
/ 8;
1115 // if the tickmask doesn't want us to change things this tick, don't!
1116 if ((biochemticks
& calculateTickMask(rate
)) != 0) return;
1118 unsigned char ratio
= 255, ratio2
= 255;
1119 if (g
.reactant
[0] != 0) {
1120 assert(g
.quantity
[0] != 0); // TODO
1121 ratio
= getChemical(g
.reactant
[0]) / g
.quantity
[0];
1123 if (g
.reactant
[1] != 0) {
1124 assert(g
.quantity
[1] != 0); // TODO
1125 ratio2
= getChemical(g
.reactant
[1]) / g
.quantity
[1];
1128 // pick lowest ratio, if zero then return
1129 if (ratio2
< ratio
) ratio
= ratio2
;
1130 if (ratio
== 0) return;
1132 // calculate the actual adjustment (can't go out of bounds)
1133 ratio
= ratio
- ((ratio
* calculateMultiplier(rate
)) / 65536);
1135 // change chemical levels
1136 subChemical(g
.reactant
[0], ratio
* g
.quantity
[0]);
1137 subChemical(g
.reactant
[1], ratio
* g
.quantity
[1]);
1138 addChemical(g
.reactant
[2], ratio
* g
.quantity
[2]);
1139 addChemical(g
.reactant
[3], ratio
* g
.quantity
[3]);
1142 void c2eOrgan::processReaction(c2eReaction
&d
) {
1143 bioReactionGene
&g
= *d
.data
;
1145 // TODO: this might not all be correct
1147 float ratio
= 1.0f
, ratio2
= 1.0f
;
1148 if (g
.reactant
[0] != 0) {
1149 assert(g
.quantity
[0] != 0); // TODO
1150 ratio
= parent
->getChemical(g
.reactant
[0]) / (float)g
.quantity
[0];
1152 if (g
.reactant
[1] != 0) {
1153 assert(g
.quantity
[1] != 0); // TODO
1154 ratio2
= parent
->getChemical(g
.reactant
[1]) / (float)g
.quantity
[1];
1157 // pick lowest ratio, if zero then return
1158 if (ratio2
< ratio
) ratio
= ratio2
;
1159 if (ratio
== 0.0f
) return;
1161 // calculate the actual adjustment
1162 float rate
= 1.0 - powf(0.5, 1.0 / powf(2.2, (1.0 - d
.rate
) * 32.0));
1163 ratio
= ratio
* rate
;
1165 // change chemical levels
1166 parent
->adjustChemical(g
.reactant
[0], -(ratio
* (float)g
.quantity
[0]));
1167 parent
->adjustChemical(g
.reactant
[1], -(ratio
* (float)g
.quantity
[1]));
1168 parent
->adjustChemical(g
.reactant
[2], ratio
* (float)g
.quantity
[2]);
1169 parent
->adjustChemical(g
.reactant
[3], ratio
* (float)g
.quantity
[3]);
1172 void c1Creature::processEmitter(c1Emitter
&d
) {
1175 bioEmitterGene
&g
= *d
.data
;
1177 if ((biochemticks
% g
.rate
) != 0) return;
1179 if (!d
.locus
) return;
1180 unsigned char f
= *d
.locus
;
1181 if (g
.clear
) *d
.locus
= 0;
1182 if (g
.invert
) f
= 255 - f
;
1185 if (f
< g
.threshold
) return;
1186 addChemical(g
.chemical
, g
.gain
);
1188 int r
= (((int)f
- g
.threshold
) * g
.gain
) / 255;
1190 // clip the result of the calculation to unsigned char, and reassign it
1191 if (r
< 0) r
= 0; else if (r
> 255) r
= 255;
1194 addChemical(g
.chemical
, f
);
1198 void c2eOrgan::processEmitter(c2eEmitter
&d
) {
1199 bioEmitterGene
&g
= *d
.data
;
1201 if (d
.sampletick
!= g
.rate
) {
1202 assert(d
.sampletick
< g
.rate
);
1209 if (!d
.locus
) return;
1211 if (g
.clear
) *d
.locus
= 0.0f
;
1212 if (g
.invert
) f
= 1.0f
- f
;
1215 if (f
< d
.threshold
) return;
1216 parent
->adjustChemical(g
.chemical
, d
.gain
);
1218 f
= (f
- d
.threshold
) * d
.gain
;
1219 if (f
> 0.0f
) // TODO: correct check?
1220 parent
->adjustChemical(g
.chemical
, f
);
1224 void c1Creature::processReceptor(c1Receptor
&d
) {
1227 bioReceptorGene
&g
= *d
.data
;
1229 // TODO: same issues as c2eOrgan::processReceptor below, probably
1231 if (!d
.locus
) return;
1233 unsigned char f
= chemicals
[g
.chemical
];
1236 r
= f
> g
.threshold
? g
.gain
: 0;
1238 // TODO: int promotion correct to makke this work out?
1239 r
= (((int)f
- g
.threshold
) * g
.gain
) / 255;
1241 if (g
.inverted
) r
= g
.nominal
- r
;
1242 else r
+= g
.nominal
;
1244 // clip the result of the calculation to unsigned char, and reassign it
1245 if (r
< 0) r
= 0; else if (r
> 255) r
= 255;
1248 if (f
== 0 && g
.organ
== 1 && g
.tissue
== 3 && g
.locus
== 0) // evil check for "Die if non-zero!" locus
1254 void c2eOrgan::processReceptor(c2eReceptor
&d
, bool checkchem
) {
1255 bioReceptorGene
&g
= *d
.data
;
1258 * TODO: This code has issues..
1260 * eg, if you have two receptors pointing at a non-local locus,
1261 * we just stomp over it in order, so the last receptor always get it
1262 * while c2e seems to alternate between them (possibly organ clockrate stuff)
1268 d
.lastvalue
= parent
->getChemical(g
.chemical
);
1271 if (!d
.processed
) return;
1272 if (!d
.locus
) return;
1276 f
= d
.lastvalue
> d
.threshold
? d
.gain
: 0.0f
;
1278 f
= (d
.lastvalue
- d
.threshold
) * d
.gain
;
1279 if (g
.inverted
) f
*= -1.0f
;
1282 if (f
< 0.0f
) f
= 0.0f
; else if (f
> 1.0f
) f
= 1.0f
; // TODO: correct?
1284 if (f
== 0.0f
&& g
.organ
== 1 && g
.tissue
== 3 && g
.locus
== 0) // evil check for "Die if non-zero!" locus
1286 else if (d
.receptors
) {
1287 if (*d
.receptors
== 0) *d
.locus
= 0.0f
;
1294 float *c2eOrgan::getLocusPointer(bool receptor
, unsigned char o
, unsigned char t
, unsigned char l
, unsigned int**receptors
) {
1295 if (receptors
) *receptors
= 0;
1301 case 0: // clock rate
1302 if (receptors
) *receptors
= &clockratereceptors
;
1304 case 1: // repair rate
1305 if (receptors
) *receptors
= &repairratereceptors
;
1307 case 2: // injury to apply
1308 if (receptors
) *receptors
= &injuryreceptors
;
1309 return &injurytoapply
;
1313 if (t
== 0 && l
== 0) { // reaction rate
1314 shared_ptr
<c2eReaction
> r
= reactions
.back();
1316 std::cout
<< "c2eOrgan::getLocusPointer failed to find a reaction" << std::endl
;
1319 if (receptors
) *receptors
= &r
->receptors
;
1325 return parent
->getLocusPointer(receptor
, o
, t
, l
);
1328 void c1Reaction::init(bioReactionGene
*g
) {
1332 void c2eReaction::init(bioReactionGene
*g
) {
1335 // rate is stored in genome as 0 fastest, 255 slowest
1336 // reversed in game, i think .. TODO: check this
1337 rate
= 1.0 - (g
->rate
/ 255.0);
1340 void c1Receptor::init(bioReceptorGene
*g
, c1Creature
*parent
) {
1342 locus
= parent
->getLocusPointer(true, g
->organ
, g
->tissue
, g
->locus
);
1345 void c2eReceptor::init(bioReceptorGene
*g
, c2eOrgan
*parent
, shared_ptr
<c2eReaction
> r
) {
1348 nominal
= g
->nominal
/ 255.0f
;
1349 threshold
= g
->threshold
/ 255.0f
;
1350 gain
= g
->gain
/ 255.0f
;
1351 locus
= parent
->getLocusPointer(true, g
->organ
, g
->tissue
, g
->locus
, &receptors
);
1354 void c1Emitter::init(bioEmitterGene
*g
, c1Creature
*parent
) {
1356 locus
= parent
->getLocusPointer(false, g
->organ
, g
->tissue
, g
->locus
);
1359 void c2eEmitter::init(bioEmitterGene
*g
, c2eOrgan
*parent
) {
1362 threshold
= g
->threshold
/ 255.0f
;
1363 gain
= g
->gain
/ 255.0f
;
1364 locus
= parent
->getLocusPointer(false, g
->organ
, g
->tissue
, g
->locus
, 0);
1367 #include "AgentHelpers.h"
1369 bool Creature::agentInSight(AgentRef a
) {
1370 #ifndef _CREATURE_STANDALONE
1371 if (a
->invisible()) return false;
1373 // TODO: specify x/y location for eyes
1374 // TODO: check open cabin?
1375 return agentIsVisible(parent
, a
);
1381 void Creature::chooseAgents() {
1382 #ifndef _CREATURE_STANDALONE
1383 // zot any chosen agents which went out of range, went invisible or changed category
1384 for (unsigned int i
= 0; i
< chosenagents
.size(); i
++) {
1385 AgentRef a
= chosenagents
[i
];
1387 if (a
->category
!= (int)i
|| !agentInSight(a
))
1388 chosenagents
[i
].clear();
1392 std::vector
<std::vector
<AgentRef
> > possibles(chosenagents
.size());
1394 for (std::list
<boost::shared_ptr
<Agent
> >::iterator i
= world
.agents
.begin(); i
!= world
.agents
.end(); i
++) {
1395 boost::shared_ptr
<Agent
> a
= *i
;
1398 // if agent category is -1 or outside of our #categories, continue
1399 if (a
->category
< 0) continue;
1400 if (a
->category
>= (int)chosenagents
.size()) continue;
1402 // if we already chose an agent from this category, continue
1403 if (chosenagents
[a
->category
]) continue;
1405 if (!agentInSight(a
)) continue;
1407 possibles
[a
->category
].push_back(a
);
1410 for (unsigned int i
= 0; i
< chosenagents
.size(); i
++) {
1411 if (!chosenagents
[i
])
1412 chosenagents
[i
] = selectRepresentativeAgent(i
, possibles
[i
]);
1417 AgentRef
c2eCreature::selectRepresentativeAgent(int type
, std::vector
<AgentRef
> possibles
) {
1418 // TODO: proper selection method
1420 if (possibles
.size() > 0)
1421 return possibles
[rand() % possibles
.size()];
1426 int c2eCreature::reverseMapVerbToNeuron(unsigned int verb
) {
1427 // TODO: reverse-mapping like this seems utterly horrible, is it correct?
1428 int actualverb
= -1;
1429 for (unsigned int i
= 0; i
< mappinginfo
.size(); i
++) {
1430 if (mappinginfo
[i
] == verb
)
1431 actualverb
= (int)i
;
1436 void c2eCreature::handleStimulus(c2eStim
&stim
) {
1437 // TODO: handle out-of-range verb_amount/noun_amount
1439 if (stim
.verb_id
>= 0) {
1440 c2eLobe
*verblobe
= brain
->getLobeById("verb");
1442 if ((unsigned int)stim
.verb_id
< verblobe
->getNoNeurons())
1443 verblobe
->setNeuronInput(stim
.verb_id
, stim
.verb_amount
);
1447 if (stim
.noun_id
>= 0) {
1448 c2eLobe
*nounlobe
= brain
->getLobeById("noun");
1450 if ((unsigned int)stim
.noun_id
< nounlobe
->getNoNeurons())
1451 nounlobe
->setNeuronInput(stim
.noun_id
, stim
.noun_amount
);
1455 for (unsigned int i
= 0; i
< 4; i
++) {
1456 if (stim
.drive_id
[i
] >= 0) {
1457 unsigned char chemno
= stim
.drive_id
[i
] + 148;
1458 adjustChemical(chemno
, stim
.drive_amount
[i
]);
1459 if (!stim
.drive_silent
[i
]) {
1460 c2eLobe
*resplobe
= brain
->getLobeById("resp");
1462 if ((unsigned int)stim
.drive_id
[i
] < resplobe
->getNoNeurons())
1463 resplobe
->setNeuronInput(stim
.drive_id
[i
], stim
.drive_amount
[i
]);
1470 // TODO: this needs to be passed noun details, it seems, judging by documentation
1471 void c2eCreature::handleStimulus(unsigned int id
, float strength
) {
1472 // note that g->addoffset does not seem to exist in c2e
1475 creatureStimulusGene
*g
= 0;
1477 // TODO: generate the damn c2eStims in addGene, thus zapping a whole bunch of bugs
1478 for (vector
<gene
*>::iterator i
= genome
->genes
.begin(); i
!= genome
->genes
.end(); i
++) {
1479 if (typeid(*(*i
)) == typeid(creatureStimulusGene
)) {
1480 creatureStimulusGene
*x
= (creatureStimulusGene
*)(*i
);
1481 if (x
->stim
== id
) {
1489 // if we're asleep and the stimulus isn't to be processed when asleep, return
1490 if (!g
->whenasleep
&& isAsleep()) return;
1492 // TODO: g->modulate
1494 // TODO: is multipler usage below okay?
1495 float multiplier
= (strength
== 0.0f
? 1.0f
: strength
);
1498 * TODO: what the heck does g->intensity do? it seems to almost entirely be 0
1499 * in the standard genomes (apart from a 255?) and it doesn't seem to change
1502 // TODO: grmph, g->sensoryneuron and g->significance make no sense to me right now
1503 // either, so commenting the verb_id setting out until someone works it out - fuzzie
1504 /*if (stim.verb_id != 0) // TODO: this is a guess to stop stuff from resting seemingly forever
1505 stim.verb_id = reverseMapVerbToNeuron(g->sensoryneuron); */
1506 // TODO: huh? gene kit has it in 255-ish steps
1507 stim
.verb_amount
= g
->significance
* (1.0f
/ 124.0f
); /* multiply by 0.5? */
1508 for (unsigned int i
= 0; i
< 4; i
++) {
1509 // TODO: ack, amount should be bound to range
1510 // TODO: fuzzie is suspicious about multiply/dividing on g->amounts here
1511 if (g
->drives
[i
] != 255)
1512 stim
.setupDriveStim(i
, g
->drives
[i
], ((g
->amounts
[i
] * (1.0f
/ 124.0f
)) - 1.0f
) * multiplier
, g
->silent
[i
]);
1514 if (strength
== 0.0f
)
1515 stim
.drive_silent
[i
] = true;
1518 handleStimulus(stim
);
1521 /* vim: set noet: */