# ai_list.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "../../stdafx.h"
    00013 #include "ai_list.hpp"
    00014 #include "../../debug.h"
    00015 #include "../../script/squirrel.hpp"
    00016
    00020 class AIListSorter {
    00021 protected:
    00022   AIList *list;
    00023   bool has_no_more_items;
    00024   int32 item_next;
    00025
    00026 public:
    00030   virtual ~AIListSorter() { }
    00031
    00035   virtual int32 Begin() = 0;
    00036
    00040   virtual void End() = 0;
    00041
    00045   virtual int32 Next() = 0;
    00046
    00050   bool IsEnd()
    00051   {
    00052     return this->list->buckets.empty() || this->has_no_more_items;
    00053   }
    00054
    00058   virtual void Remove(int item) = 0;
    00059 };
    00060
    00064 class AIListSorterValueAscending : public AIListSorter {
    00065 private:
    00066   AIList::AIListBucket::iterator bucket_iter;
    00067   AIList::AIItemList *bucket_list;
    00068   AIList::AIItemList::iterator bucket_list_iter;
    00069
    00070 public:
    00075   AIListSorterValueAscending(AIList *list)
    00076   {
    00077     this->list = list;
    00078     this->End();
    00079   }
    00080
    00081   int32 Begin()
    00082   {
    00083     if (this->list->buckets.empty()) return 0;
    00084     this->has_no_more_items = false;
    00085
    00086     this->bucket_iter = this->list->buckets.begin();
    00087     this->bucket_list = &(*this->bucket_iter).second;
    00088     this->bucket_list_iter = this->bucket_list->begin();
    00089     this->item_next = *this->bucket_list_iter;
    00090
    00091     int32 item_current = this->item_next;
    00092     FindNext();
    00093     return item_current;
    00094   }
    00095
    00096   void End()
    00097   {
    00098     this->bucket_list = NULL;
    00099     this->has_no_more_items = true;
    00100     this->item_next = 0;
    00101   }
    00102
    00106   void FindNext()
    00107   {
    00108     if (this->bucket_list == NULL) {
    00109       this->has_no_more_items = true;
    00110       return;
    00111     }
    00112
    00113     this->bucket_list_iter++;
    00114     if (this->bucket_list_iter == this->bucket_list->end()) {
    00115       this->bucket_iter++;
    00116       if (this->bucket_iter == this->list->buckets.end()) {
    00117         this->bucket_list = NULL;
    00118         return;
    00119       }
    00120       this->bucket_list = &(*this->bucket_iter).second;
    00121       this->bucket_list_iter = this->bucket_list->begin();
    00122     }
    00123     this->item_next = *this->bucket_list_iter;
    00124   }
    00125
    00126   int32 Next()
    00127   {
    00128     if (this->IsEnd()) return 0;
    00129
    00130     int32 item_current = this->item_next;
    00131     FindNext();
    00132     return item_current;
    00133   }
    00134
    00135   void Remove(int item)
    00136   {
    00137     if (this->IsEnd()) return;
    00138
    00139     /* If we remove the 'next' item, skip to the next */
    00140     if (item == this->item_next) {
    00141       FindNext();
    00142       return;
    00143     }
    00144   }
    00145 };
    00146
    00150 class AIListSorterValueDescending : public AIListSorter {
    00151 private:
    00152   AIList::AIListBucket::iterator bucket_iter;
    00153   AIList::AIItemList *bucket_list;
    00154   AIList::AIItemList::iterator bucket_list_iter;
    00155
    00156 public:
    00161   AIListSorterValueDescending(AIList *list)
    00162   {
    00163     this->list = list;
    00164     this->End();
    00165   }
    00166
    00167   int32 Begin()
    00168   {
    00169     if (this->list->buckets.empty()) return 0;
    00170     this->has_no_more_items = false;
    00171
    00172     /* Go to the end of the bucket-list */
    00173     this->bucket_iter = this->list->buckets.begin();
    00174     for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
    00175     this->bucket_list = &(*this->bucket_iter).second;
    00176
    00177     /* Go to the end of the items in the bucket */
    00178     this->bucket_list_iter = this->bucket_list->begin();
    00179     for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
    00180     this->item_next = *this->bucket_list_iter;
    00181
    00182     int32 item_current = this->item_next;
    00183     FindNext();
    00184     return item_current;
    00185   }
    00186
    00187   void End()
    00188   {
    00189     this->bucket_list = NULL;
    00190     this->has_no_more_items = true;
    00191     this->item_next = 0;
    00192   }
    00193
    00197   void FindNext()
    00198   {
    00199     if (this->bucket_list == NULL) {
    00200       this->has_no_more_items = true;
    00201       return;
    00202     }
    00203
    00204     if (this->bucket_list_iter == this->bucket_list->begin()) {
    00205       if (this->bucket_iter == this->list->buckets.begin()) {
    00206         this->bucket_list = NULL;
    00207         return;
    00208       }
    00209       this->bucket_iter--;
    00210       this->bucket_list = &(*this->bucket_iter).second;
    00211       /* Go to the end of the items in the bucket */
    00212       this->bucket_list_iter = this->bucket_list->begin();
    00213       for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
    00214     } else {
    00215       this->bucket_list_iter--;
    00216     }
    00217     this->item_next = *this->bucket_list_iter;
    00218   }
    00219
    00220   int32 Next()
    00221   {
    00222     if (this->IsEnd()) return 0;
    00223
    00224     int32 item_current = this->item_next;
    00225     FindNext();
    00226     return item_current;
    00227   }
    00228
    00229   void Remove(int item)
    00230   {
    00231     if (this->IsEnd()) return;
    00232
    00233     /* If we remove the 'next' item, skip to the next */
    00234     if (item == this->item_next) {
    00235       FindNext();
    00236       return;
    00237     }
    00238   }
    00239 };
    00240
    00244 class AIListSorterItemAscending : public AIListSorter {
    00245 private:
    00246   AIList::AIListMap::iterator item_iter;
    00247
    00248 public:
    00253   AIListSorterItemAscending(AIList *list)
    00254   {
    00255     this->list = list;
    00256     this->End();
    00257   }
    00258
    00259   int32 Begin()
    00260   {
    00261     if (this->list->items.empty()) return 0;
    00262     this->has_no_more_items = false;
    00263
    00264     this->item_iter = this->list->items.begin();
    00265     this->item_next = (*this->item_iter).first;
    00266
    00267     int32 item_current = this->item_next;
    00268     FindNext();
    00269     return item_current;
    00270   }
    00271
    00272   void End()
    00273   {
    00274     this->has_no_more_items = true;
    00275   }
    00276
    00280   void FindNext()
    00281   {
    00282     if (this->item_iter == this->list->items.end()) {
    00283       this->has_no_more_items = true;
    00284       return;
    00285     }
    00286     this->item_iter++;
    00287     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
    00288   }
    00289
    00290   int32 Next()
    00291   {
    00292     if (this->IsEnd()) return 0;
    00293
    00294     int32 item_current = this->item_next;
    00295     FindNext();
    00296     return item_current;
    00297   }
    00298
    00299   void Remove(int item)
    00300   {
    00301     if (this->IsEnd()) return;
    00302
    00303     /* If we remove the 'next' item, skip to the next */
    00304     if (item == this->item_next) {
    00305       FindNext();
    00306       return;
    00307     }
    00308   }
    00309 };
    00310
    00314 class AIListSorterItemDescending : public AIListSorter {
    00315 private:
    00316   AIList::AIListMap::iterator item_iter;
    00317
    00318 public:
    00323   AIListSorterItemDescending(AIList *list)
    00324   {
    00325     this->list = list;
    00326     this->End();
    00327   }
    00328
    00329   int32 Begin()
    00330   {
    00331     if (this->list->items.empty()) return 0;
    00332     this->has_no_more_items = false;
    00333
    00334     this->item_iter = this->list->items.begin();
    00335     for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
    00336     this->item_next = (*this->item_iter).first;
    00337
    00338     int32 item_current = this->item_next;
    00339     FindNext();
    00340     return item_current;
    00341   }
    00342
    00343   void End()
    00344   {
    00345     this->has_no_more_items = true;
    00346   }
    00347
    00351   void FindNext()
    00352   {
    00353     if (this->item_iter == this->list->items.end()) {
    00354       this->has_no_more_items = true;
    00355       return;
    00356     }
    00357     this->item_iter--;
    00358     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
    00359   }
    00360
    00361   int32 Next()
    00362   {
    00363     if (this->IsEnd()) return 0;
    00364
    00365     int32 item_current = this->item_next;
    00366     FindNext();
    00367     return item_current;
    00368   }
    00369
    00370   void Remove(int item)
    00371   {
    00372     if (this->IsEnd()) return;
    00373
    00374     /* If we remove the 'next' item, skip to the next */
    00375     if (item == this->item_next) {
    00376       FindNext();
    00377       return;
    00378     }
    00379   }
    00380 };
    00381
    00382
    00383
    00384 AIList::AIList()
    00385 {
    00386   /* Default sorter */
    00387   this->sorter         = new AIListSorterValueDescending(this);
    00388   this->sorter_type    = SORT_BY_VALUE;
    00389   this->sort_ascending = false;
    00390   this->initialized    = false;
    00391   this->modifications  = 0;
    00392 }
    00393
    00394 AIList::~AIList()
    00395 {
    00396   delete this->sorter;
    00397 }
    00398
    00399 bool AIList::HasItem(int32 item)
    00400 {
    00401   return this->items.count(item) == 1;
    00402 }
    00403
    00404 void AIList::Clear()
    00405 {
    00406   this->modifications++;
    00407
    00408   this->items.clear();
    00409   this->buckets.clear();
    00410   this->sorter->End();
    00411 }
    00412
    00413 void AIList::AddItem(int32 item, int32 value)
    00414 {
    00415   this->modifications++;
    00416
    00417   if (this->HasItem(item)) return;
    00418
    00419   this->items[item] = 0;
    00420   this->buckets[0].insert(item);
    00421
    00422   this->SetValue(item, value);
    00423 }
    00424
    00425 void AIList::RemoveItem(int32 item)
    00426 {
    00427   this->modifications++;
    00428
    00429   if (!this->HasItem(item)) return;
    00430
    00431   int32 value = this->GetValue(item);
    00432
    00433   this->sorter->Remove(item);
    00434   this->buckets[value].erase(item);
    00435   if (this->buckets[value].empty()) this->buckets.erase(value);
    00436   this->items.erase(item);
    00437 }
    00438
    00439 int32 AIList::Begin()
    00440 {
    00441   this->initialized = true;
    00442   return this->sorter->Begin();
    00443 }
    00444
    00445 int32 AIList::Next()
    00446 {
    00447   if (this->initialized == false) {
    00448     DEBUG(ai, 0, "Next() is invalid as Begin() is never called");
    00449     return 0;
    00450   }
    00451   return this->sorter->Next();
    00452 }
    00453
    00454 bool AIList::IsEmpty()
    00455 {
    00456   return this->items.empty();
    00457 }
    00458
    00459 bool AIList::IsEnd()
    00460 {
    00461   if (this->initialized == false) {
    00462     DEBUG(ai, 0, "IsEnd() is invalid as Begin() is never called");
    00463     return true;
    00464   }
    00465   return this->sorter->IsEnd();
    00466 }
    00467
    00468 int32 AIList::Count()
    00469 {
    00470   return (int32)this->items.size();
    00471 }
    00472
    00473 int32 AIList::GetValue(int32 item)
    00474 {
    00475   if (!this->HasItem(item)) return 0;
    00476
    00477   return this->items[item];
    00478 }
    00479
    00480 bool AIList::SetValue(int32 item, int32 value)
    00481 {
    00482   this->modifications++;
    00483
    00484   if (!this->HasItem(item)) return false;
    00485
    00486   int32 value_old = this->GetValue(item);
    00487   if (value_old == value) return true;
    00488
    00489   this->sorter->Remove(item);
    00490   this->buckets[value_old].erase(item);
    00491   if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
    00492   this->items[item] = value;
    00493   this->buckets[value].insert(item);
    00494
    00495   return true;
    00496 }
    00497
    00498 void AIList::Sort(SorterType sorter, bool ascending)
    00499 {
    00500   this->modifications++;
    00501
    00502   if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
    00503   if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
    00504
    00505   delete this->sorter;
    00506   switch (sorter) {
    00507     case SORT_BY_ITEM:
    00508       if (ascending) {
    00509         this->sorter = new AIListSorterItemAscending(this);
    00510       } else {
    00511         this->sorter = new AIListSorterItemDescending(this);
    00512       }
    00513       break;
    00514
    00515     case SORT_BY_VALUE:
    00516       if (ascending) {
    00517         this->sorter = new AIListSorterValueAscending(this);
    00518       } else {
    00519         this->sorter = new AIListSorterValueDescending(this);
    00520       }
    00521       break;
    00522
    00523     default:
    00524       this->Sort(SORT_BY_ITEM, false);
    00525       return;
    00526   }
    00527   this->sorter_type    = sorter;
    00528   this->sort_ascending = ascending;
    00529   this->initialized    = false;
    00530 }
    00531
    00532 void AIList::AddList(AIList *list)
    00533 {
    00534   AIListMap *list_items = &list->items;
    00535   for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
    00536     this->AddItem((*iter).first);
    00537     this->SetValue((*iter).first, (*iter).second);
    00538   }
    00539 }
    00540
    00541 void AIList::RemoveAboveValue(int32 value)
    00542 {
    00543   this->modifications++;
    00544
    00545   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00546     next_iter = iter; next_iter++;
    00547     if ((*iter).second > value) this->RemoveItem((*iter).first);
    00548   }
    00549 }
    00550
    00551 void AIList::RemoveBelowValue(int32 value)
    00552 {
    00553   this->modifications++;
    00554
    00555   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00556     next_iter = iter; next_iter++;
    00557     if ((*iter).second < value) this->RemoveItem((*iter).first);
    00558   }
    00559 }
    00560
    00561 void AIList::RemoveBetweenValue(int32 start, int32 end)
    00562 {
    00563   this->modifications++;
    00564
    00565   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00566     next_iter = iter; next_iter++;
    00567     if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first);
    00568   }
    00569 }
    00570
    00571 void AIList::RemoveValue(int32 value)
    00572 {
    00573   this->modifications++;
    00574
    00575   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00576     next_iter = iter; next_iter++;
    00577     if ((*iter).second == value) this->RemoveItem((*iter).first);
    00578   }
    00579 }
    00580
    00581 void AIList::RemoveTop(int32 count)
    00582 {
    00583   this->modifications++;
    00584
    00585   if (!this->sort_ascending) {
    00586     this->Sort(this->sorter_type, !this->sort_ascending);
    00587     this->RemoveBottom(count);
    00588     this->Sort(this->sorter_type, !this->sort_ascending);
    00589     return;
    00590   }
    00591
    00592   switch (this->sorter_type) {
    00593     default: NOT_REACHED();
    00594     case SORT_BY_VALUE:
    00595       for (AIListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
    00596         AIItemList *items = &(*iter).second;
    00597         size_t size = items->size();
    00598         for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
    00599           if (--count < 0) return;
    00600           this->RemoveItem(*iter);
    00601           /* When the last item is removed from the bucket, the bucket itself is removed.
    00602            * This means that the iterators can be invalid after a call to RemoveItem.
    00603            */
    00604           if (--size == 0) break;
    00605         }
    00606       }
    00607       break;
    00608
    00609     case SORT_BY_ITEM:
    00610       for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
    00611         if (--count < 0) return;
    00612         this->RemoveItem((*iter).first);
    00613       }
    00614       break;
    00615   }
    00616 }
    00617
    00618 void AIList::RemoveBottom(int32 count)
    00619 {
    00620   this->modifications++;
    00621
    00622   if (!this->sort_ascending) {
    00623     this->Sort(this->sorter_type, !this->sort_ascending);
    00624     this->RemoveTop(count);
    00625     this->Sort(this->sorter_type, !this->sort_ascending);
    00626     return;
    00627   }
    00628
    00629   switch (this->sorter_type) {
    00630     default: NOT_REACHED();
    00631     case SORT_BY_VALUE:
    00632       for (AIListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
    00633         AIItemList *items = &(*iter).second;
    00634         size_t size = items->size();
    00635         for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
    00636           if (--count < 0) return;
    00637           this->RemoveItem(*iter);
    00638           /* When the last item is removed from the bucket, the bucket itself is removed.
    00639            * This means that the iterators can be invalid after a call to RemoveItem.
    00640            */
    00641           if (--size == 0) break;
    00642         }
    00643       }
    00644
    00645     case SORT_BY_ITEM:
    00646       for (AIListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
    00647         if (--count < 0) return;
    00648         this->RemoveItem((*iter).first);
    00649       }
    00650       break;
    00651   }
    00652 }
    00653
    00654 void AIList::RemoveList(AIList *list)
    00655 {
    00656   this->modifications++;
    00657
    00658   AIListMap *list_items = &list->items;
    00659   for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
    00660     this->RemoveItem((*iter).first);
    00661   }
    00662 }
    00663
    00664 void AIList::KeepAboveValue(int32 value)
    00665 {
    00666   this->modifications++;
    00667
    00668   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00669     next_iter = iter; next_iter++;
    00670     if ((*iter).second <= value) this->RemoveItem((*iter).first);
    00671   }
    00672 }
    00673
    00674 void AIList::KeepBelowValue(int32 value)
    00675 {
    00676   this->modifications++;
    00677
    00678   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00679     next_iter = iter; next_iter++;
    00680     if ((*iter).second >= value) this->RemoveItem((*iter).first);
    00681   }
    00682 }
    00683
    00684 void AIList::KeepBetweenValue(int32 start, int32 end)
    00685 {
    00686   this->modifications++;
    00687
    00688   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00689     next_iter = iter; next_iter++;
    00690     if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first);
    00691   }
    00692 }
    00693
    00694 void AIList::KeepValue(int32 value)
    00695 {
    00696   this->modifications++;
    00697
    00698   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
    00699     next_iter = iter; next_iter++;
    00700     if ((*iter).second != value) this->RemoveItem((*iter).first);
    00701   }
    00702 }
    00703
    00704 void AIList::KeepTop(int32 count)
    00705 {
    00706   this->modifications++;
    00707
    00708   this->RemoveBottom(this->Count() - count);
    00709 }
    00710
    00711 void AIList::KeepBottom(int32 count)
    00712 {
    00713   this->modifications++;
    00714
    00715   this->RemoveTop(this->Count() - count);
    00716 }
    00717
    00718 void AIList::KeepList(AIList *list)
    00719 {
    00720   this->modifications++;
    00721
    00722   AIList tmp;
    00723   for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
    00724     tmp.AddItem((*iter).first);
    00725     tmp.SetValue((*iter).first, (*iter).second);
    00726   }
    00727
    00728   tmp.RemoveList(list);
    00729   this->RemoveList(&tmp);
    00730 }
    00731
    00732 SQInteger AIList::_get(HSQUIRRELVM vm)
    00733 {
    00734   if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
    00735
    00736   SQInteger idx;
    00737   sq_getinteger(vm, 2, &idx);
    00738
    00739   if (!this->HasItem(idx)) return SQ_ERROR;
    00740
    00741   sq_pushinteger(vm, this->GetValue(idx));
    00742   return 1;
    00743 }
    00744
    00745 SQInteger AIList::_set(HSQUIRRELVM vm)
    00746 {
    00747   if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
    00748   if (sq_gettype(vm, 3) != OT_INTEGER || sq_gettype(vm, 3) == OT_NULL) {
    00749     return sq_throwerror(vm, _SC("you can only assign integers to this list"));
    00750   }
    00751
    00752   SQInteger idx, val;
    00753   sq_getinteger(vm, 2, &idx);
    00754   if (sq_gettype(vm, 3) == OT_NULL) {
    00755     this->RemoveItem(idx);
    00756     return 0;
    00757   }
    00758
    00759   sq_getinteger(vm, 3, &val);
    00760   if (!this->HasItem(idx)) {
    00761     this->AddItem(idx, val);
    00762     return 0;
    00763   }
    00764
    00765   this->SetValue(idx, val);
    00766   return 0;
    00767 }
    00768
    00769 SQInteger AIList::_nexti(HSQUIRRELVM vm)
    00770 {
    00771   if (sq_gettype(vm, 2) == OT_NULL) {
    00772     if (this->IsEmpty()) {
    00773       sq_pushnull(vm);
    00774       return 1;
    00775     }
    00776     sq_pushinteger(vm, this->Begin());
    00777     return 1;
    00778   }
    00779
    00780   SQInteger idx;
    00781   sq_getinteger(vm, 2, &idx);
    00782
    00783   int val = this->Next();
    00784   if (this->IsEnd()) {
    00785     sq_pushnull(vm);
    00786     return 1;
    00787   }
    00788
    00789   sq_pushinteger(vm, val);
    00790   return 1;
    00791 }
    00792
    00793 SQInteger AIList::Valuate(HSQUIRRELVM vm)
    00794 {
    00795   this->modifications++;
    00796
    00797   /* The first parameter is the instance of AIList. */
    00798   int nparam = sq_gettop(vm) - 1;
    00799
    00800   if (nparam < 1) {
    00801     return sq_throwerror(vm, _SC("You need to give a least a Valuator as parameter to AIList::Valuate"));
    00802   }
    00803
    00804   /* Make sure the valuator function is really a function, and not any
    00805    * other type. It's parameter 2 for us, but for the user it's the
    00806    * first parameter they give. */
    00807   SQObjectType valuator_type = sq_gettype(vm, 2);
    00808   if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
    00809     return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected function)"));
    00810   }
    00811
    00812   /* Don't allow docommand from a Valuator, as we can't resume in
    00813    * mid C++-code. */
    00814   bool backup_allow = AIObject::GetAllowDoCommand();
    00815   AIObject::SetAllowDoCommand(false);
    00816
    00817   /* Push the function to call */
    00818   sq_push(vm, 2);
    00819
    00820   for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
    00821     /* Check for changing of items. */
    00822     int previous_modification_count = this->modifications;
    00823
    00824     /* Push the root table as instance object, this is what squirrel does for meta-functions. */
    00825     sq_pushroottable(vm);
    00826     /* Push all arguments for the valuator function. */
    00827     sq_pushinteger(vm, (*iter).first);
    00828     for (int i = 0; i < nparam - 1; i++) {
    00829       sq_push(vm, i + 3);
    00830     }
    00831
    00832     /* Call the function. Squirrel pops all parameters and pushes the return value. */
    00833     if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
    00834       AIObject::SetAllowDoCommand(backup_allow);
    00835       return SQ_ERROR;
    00836     }
    00837
    00838     /* Retreive the return value */
    00839     SQInteger value;
    00840     switch (sq_gettype(vm, -1)) {
    00841       case OT_INTEGER: {
    00842         sq_getinteger(vm, -1, &value);
    00843         break;
    00844       }
    00845
    00846       case OT_BOOL: {
    00847         SQBool v;
    00848         sq_getbool(vm, -1, &v);
    00849         value = v ? 1 : 0;
    00850         break;
    00851       }
    00852
    00853       default: {
    00854         /* See below for explanation. The extra pop is the return value. */
    00855         sq_pop(vm, nparam + 4);
    00856
    00857         AIObject::SetAllowDoCommand(backup_allow);
    00858         return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
    00859       }
    00860     }
    00861
    00862     /* Was something changed? */
    00863     if (previous_modification_count != this->modifications) {
    00864       /* See below for explanation. The extra pop is the return value. */
    00865       sq_pop(vm, nparam + 4);
    00866
    00867       AIObject::SetAllowDoCommand(backup_allow);
    00868       return sq_throwerror(vm, _SC("modifying valuated list outside of valuator function"));
    00869     }
    00870
    00871     this->SetValue((*iter).first, value);
    00872
    00873     /* Pop the return value. */
    00874     sq_poptop(vm);
    00875
    00876     Squirrel::DecreaseOps(vm, 5);
    00877   }
    00878   /* Pop from the squirrel stack:
    00879    * 1. The root stable (as instance object).
    00880    * 2. The valuator function.
    00881    * 3. The parameters given to this function.
    00882    * 4. The AIList instance object. */
    00883   sq_pop(vm, nparam + 3);
    00884
    00885   AIObject::SetAllowDoCommand(backup_allow);
    00886   return 0;
    00887 }