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 }

Generated on Wed Apr 13 00:47:45 2011 for OpenTTD by  doxygen 1.6.1