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