3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
12 /* Compiled through itemset.cpp */
14 cchar
*ToHitValueDescription
[] = {
15 "unbelievably inaccurate",
16 "extremely inaccurate",
22 "unbelievably accurate"
25 cchar
*StrengthValueDescription
[] = {
36 itemprototype::itemprototype (const itemprototype
*Base
, itemspawner Spawner
, itemcloner Cloner
, cchar
*ClassID
) :
42 Index
= protocontainer
<item
>::Add(this);
46 truth
itemdatabase::AllowRandomInstantiation () const { return !(Config
& S_LOCK_ID
); }
60 truth
item::IsOnGround () const { return Slot
[0]->IsOnGround(); }
61 truth
item::IsSimiliarTo (item
*Item
) const { return Item
->GetType() == GetType() && Item
->GetConfig() == GetConfig(); }
62 double item::GetBaseDamage () const { return sqrt(5e-5*GetWeaponStrength())+GetDamageBonus(); }
63 int item::GetBaseMinDamage () const { return int(GetBaseDamage()*0.75); }
64 int item::GetBaseMaxDamage () const { return int(GetBaseDamage()*1.25)+1; }
65 int item::GetBaseToHitValue () const { return int(10000.0/(1000+GetWeight())+GetTHVBonus()); }
66 int item::GetBaseBlockValue () const { return int((10000.0/(1000+GetWeight())+GetTHVBonus())*GetBlockModifier()/10000.0); }
67 truth
item::IsInCorrectSlot (int I
) const { return I
== RIGHT_WIELDED_INDEX
|| I
== LEFT_WIELDED_INDEX
; }
68 truth
item::IsInCorrectSlot () const { return IsInCorrectSlot(static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex()); }
69 int item::GetEquipmentIndex () const { return static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex(); }
70 int item::GetGraphicsContainerIndex () const { return GR_ITEM
; }
71 truth
item::IsBroken () const { return GetConfig () & BROKEN
; }
72 truth
item::IsFood() const { return DataBase
->Category
& FOOD
; }
73 cchar
*item::GetBreakVerb () const { return "breaks"; }
74 square
*item::GetSquareUnderEntity (int I
) const { return GetSquareUnder(I
); }
75 square
*item::GetSquareUnder (int I
) const { return Slot
[I
] ? Slot
[I
]->GetSquareUnder () : 0; }
76 lsquare
*item::GetLSquareUnder (int I
) const { return static_cast<lsquare
*>(Slot
[I
]->GetSquareUnder ()); }
77 void item::SignalStackAdd (stackslot
*StackSlot
, void (stack::*)(item
*, truth
)) { Slot
[0] = StackSlot
; }
78 truth
item::IsAnimated () const { return GraphicData
.AnimationFrames
> 1 || (Fluid
&& ShowFluids ()); }
79 truth
item::IsRusted () const { return MainMaterial
->GetRustLevel () != NOT_RUSTED
; }
80 truth
item::IsEatable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsSolid
) && IsConsumable (); }
81 truth
item::IsDrinkable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsLiquid
) && IsConsumable (); }
82 pixelpredicate
item::GetFluidPixelAllowedPredicate () const { return &rawbitmap::IsTransparent
; }
83 void item::Cannibalize () { Flags
|= CANNIBALIZED
; }
84 void item::SetMainMaterial (material
*NewMaterial
, int SpecialFlags
) { SetMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
85 void item::ChangeMainMaterial (material
*NewMaterial
, int SpecialFlags
) { ChangeMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
86 void item::InitMaterials (const materialscript
*M
, const materialscript
*, truth CUP
) { InitMaterials(M
->Instantiate (), CUP
); }
87 int item::GetMainMaterialRustLevel () const { return MainMaterial
->GetRustLevel(); }
90 item::item (citem
&Item
) :
94 DataBase(Item
.DataBase
),
99 SquaresUnder(Item
.SquaresUnder
),
100 LifeExpectancy(Item
.LifeExpectancy
),
101 ItemFlags(Item
.ItemFlags
)
103 Flags
&= ENTITY_FLAGS
|SQUARE_POSITION_BITS
;
104 ID
= game::CreateNewItemID(this);
105 CloneMotherID
= new idholder(Item
.ID
);
106 idholder
* TI
= CloneMotherID
;
108 for (idholder
* II
= Item
.CloneMotherID
; II
; II
= II
->Next
) TI
= TI
->Next
= new idholder(II
->ID
);
110 Slot
= new slot
*[SquaresUnder
];
111 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
117 game::RemoveItemID(ID
);
120 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
121 for (fluid
* F
= FP
[c
]; F
;) {
133 void item::Fly (character
*Thrower
, int Direction
, int Force
) {
134 int Range
= Force
*25/Max(sLong(sqrt(GetWeight())), 1);
135 lsquare
*LSquareUnder
= GetLSquareUnder();
137 LSquareUnder
->GetStack()->AddItem(this, false);
138 if (!Range
|| GetSquaresUnder() != 1) {
139 if (GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
142 if (Direction
== RANDOM_DIR
) Direction
= RAND()&7;
143 v2 StartingPos
= GetPos();
144 v2 Pos
= StartingPos
;
145 v2 DirVector
= game::GetMoveVector(Direction
);
146 truth Breaks
= false;
147 double BaseDamage
, BaseToHitValue
;
150 int Bonus
= Thrower
->IsHumanoid() ? Thrower
->GetCWeaponSkill(GetWeaponCategory())->GetBonus() : 1000;
151 BaseDamage
= sqrt(5e-12 * GetWeaponStrength() * Force
/ Range
) * Bonus
;
152 BaseToHitValue
= 10 * Bonus
* Thrower
->GetMoveEase() / (500 + GetWeight()) * Thrower
->GetAttribute(DEXTERITY
) * sqrt(2.5e-8 * Thrower
->GetAttribute(PERCEPTION
)) / Range
;
154 BaseDamage
= sqrt(5e-6 * GetWeaponStrength() * Force
/ Range
);
155 BaseToHitValue
= 10 * 100 / (500 + GetWeight()) / Range
;
158 for (RangeLeft
= Range
; RangeLeft
; --RangeLeft
) {
159 if (!GetLevel()->IsValidPos(Pos
+DirVector
)) break;
160 lsquare
*JustHit
= GetNearLSquare(Pos
+DirVector
);
161 if (!JustHit
->IsFlyable()) {
163 JustHit
->GetOLTerrain()->HasBeenHitByItem(Thrower
, this, int(BaseDamage
*sqrt(RangeLeft
)));
166 clock_t StartTime
= clock();
169 JustHit
->GetStack()->AddItem(this, false);
170 truth Draw
= game::OnScreen(JustHit
->GetPos()) && JustHit
->CanBeSeenByPlayer();
171 if (Draw
) game::DrawEverything();
172 if (JustHit
->GetCharacter()) {
173 int Damage
= int(BaseDamage
* sqrt(RangeLeft
));
174 double ToHitValue
= BaseToHitValue
*RangeLeft
;
175 int Returned
= HitCharacter(Thrower
, JustHit
->GetCharacter(), Damage
, ToHitValue
, Direction
);
176 if (Returned
== HIT
) Breaks
= true;
177 if (Returned
!= MISSED
) break;
179 if (Draw
) { while (clock()-StartTime
< 0.03 * CLOCKS_PER_SEC
); } //FIXME
182 if (Breaks
) ReceiveDamage(Thrower
, int(sqrt(GetWeight()*RangeLeft
) / 10), THROW
|PHYSICAL_DAMAGE
, Direction
);
183 if (Exists() && GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
187 int item::HitCharacter (character
*Thrower
, character
*Dude
, int Damage
, double ToHitValue
, int Direction
) {
188 if (Dude
->Catches(this)) return CATCHED
;
189 if (Thrower
&& !EffectIsGood()) Thrower
->Hostility(Dude
);
190 if (Dude
->DodgesFlyingItem(this, ToHitValue
)) {
191 if (Dude
->IsPlayer()) ADD_MESSAGE("%s misses you.", CHAR_NAME(DEFINITE
));
192 else if (Dude
->CanBeSeenByPlayer()) ADD_MESSAGE("%s misses %s.", CHAR_NAME(DEFINITE
), Dude
->CHAR_NAME(DEFINITE
));
195 Dude
->HasBeenHitByItem(Thrower
, this, Damage
, ToHitValue
, Direction
);
200 double item::GetWeaponStrength () const {
201 return GetFormModifier() * GetMainMaterial()->GetStrengthValue() * sqrt(GetMainMaterial()->GetWeight());
205 int item::GetStrengthRequirement () const {
206 double WeightTimesSize
= GetWeight() * GetSize();
207 return int(1.25e-10 * WeightTimesSize
* WeightTimesSize
);
211 truth
item::Apply (character
*Applier
) {
212 if (Applier
->IsPlayer()) ADD_MESSAGE("You can't apply this!");
217 /* Returns truth that tells whether the Polymorph really happened */
218 truth
item::Polymorph (character
*Polymorpher
, stack
*CurrentStack
) {
219 if (!IsPolymorphable()) return false;
220 if (Polymorpher
&& IsOnGround()) {
221 room
*Room
= GetRoom();
222 if (Room
) Room
->HostileAction(Polymorpher
);
224 if (GetSquarePosition() != CENTER
) {
225 stack
*Stack
= CurrentStack
->GetLSquareUnder()->GetStackOfAdjacentSquare(GetSquarePosition());
226 if (Stack
) CurrentStack
= Stack
;
228 CurrentStack
->AddItem(protosystem::BalancedCreateItem(0, 0, MAX_PRICE
, ANY_CATEGORY
, 0, 0, 0, true));
235 /* Returns whether the Eater must stop eating the item */
236 truth
item::Consume (character
*Eater
, sLong Amount
) {
237 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
238 if (!ConsumeMaterial
) return true;
239 if (Eater
->IsPlayer() && !(Flags
& CANNIBALIZED
) && Eater
->CheckCannibalism(ConsumeMaterial
)) {
240 game::DoEvilDeed(25);
241 ADD_MESSAGE("You feel that this was an evil deed.");
244 feuLong ID
= GetID();
245 material
*Garbage
= ConsumeMaterial
->EatEffect(Eater
, Amount
);
246 item
*NewConsuming
= GetID() ? this : game::SearchItem(ID
);
247 material
*NewConsumeMaterial
= NewConsuming
->GetConsumeMaterial(Eater
);
248 if (!NewConsuming
->Exists() || !NewConsumeMaterial
|| !NewConsumeMaterial
->IsSameAs(ConsumeMaterial
))
249 ConsumeMaterial
->FinishConsuming(Eater
);
251 return !NewConsuming
->Exists() || !NewConsumeMaterial
;
255 truth
item::CanBeEatenByAI (ccharacter
*Eater
) const {
256 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
257 return (!Eater
->IsPet()
258 || !(Eater
->GetCommandFlags() & DONT_CONSUME_ANYTHING_VALUABLE
)
261 && ConsumeMaterial
&& ConsumeMaterial
->CanBeEatenByAI(Eater
);
265 void item::Save (outputfile
&SaveFile
) const {
266 SaveFile
<< (uShort
)GetType();
267 object::Save(SaveFile
);
268 SaveFile
<< (uShort
)0;
269 SaveFile
<< mIsStepedOn
;
270 SaveFile
<< (uShort
)GetConfig();
271 SaveFile
<< (uShort
)Flags
;
272 SaveFile
<< Size
<< ID
<< LifeExpectancy
<< ItemFlags
;
273 SaveLinkedList(SaveFile
, CloneMotherID
);
276 SaveFile
<< FluidCount
;
277 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) SaveLinkedList(SaveFile
, Fluid
[c
]);
284 void item::Load (inputfile
&SaveFile
) {
285 object::Load(SaveFile
);
286 int ver
= ReadType(uShort
, SaveFile
);
287 if (ver
!= 0) ABORT("invalid item version in savefile: %d", ver
);
288 SaveFile
>> mIsStepedOn
;
289 databasecreator
<item
>::InstallDataBase(this, ReadType(uShort
, SaveFile
));
290 Flags
|= ReadType(uShort
, SaveFile
) & ~ENTITY_FLAGS
;
291 SaveFile
>> Size
>> ID
>> LifeExpectancy
>> ItemFlags
;
292 LoadLinkedList(SaveFile
, CloneMotherID
);
293 if (LifeExpectancy
) Enable();
294 game::AddItemID(this, ID
);
295 if (SaveFile
.Get()) {
296 SaveFile
>> FluidCount
;
297 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
298 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
299 LoadLinkedList(SaveFile
, Fluid
[c
]);
300 for (fluid
*F
= Fluid
[c
]; F
; F
= F
->Next
) F
->SetMotherItem(this);
303 if (Fluid
) Fluid
= 0; //FIXME: MEMORY LEAK
307 const fearray<festring> < = GetLevelTags();
309 fprintf(stderr, "====\n");
310 for (uInt f = 0; f < lt.Size; ++f) fprintf(stderr, " %u: [%s]\n", f, lt[f].CStr());
316 void item::TeleportRandomly () {
317 if (GetSquaresUnder() == 1) {
319 lsquare
*Square
= GetNearLSquare(GetLevel()->GetRandomSquare());
320 MoveTo(Square
->GetStack());
321 if (Square
->CanBeSeenByPlayer()) ADD_MESSAGE("Suddenly %s appears!", CHAR_NAME(INDEFINITE
));
326 int item::GetStrengthValue () const {
327 return sLong(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
331 void item::RemoveFromSlot () {
332 for (int c
= 0; c
< SquaresUnder
; ++c
) {
336 } catch (quitrequest
) {
346 void item::MoveTo (stack
*Stack
) {
348 Stack
->AddItem(this);
352 cchar
*item::GetItemCategoryName (sLong Category
) {
355 case HELMET
: return "Helmets";
356 case AMULET
: return "Amulets";
357 case CLOAK
: return "Cloaks";
358 case BODY_ARMOR
: return "Body armors";
359 case WEAPON
: return "Weapons";
360 case SHIELD
: return "Shields";
361 case RING
: return "Rings";
362 case GAUNTLET
: return "Gauntlets";
363 case BELT
: return "Belts";
364 case BOOT
: return "Boots";
365 case FOOD
: return "Food";
366 case POTION
: return "Potions";
367 case SCROLL
: return "Scrolls";
368 case BOOK
: return "Books";
369 case WAND
: return "Wands";
370 case TOOL
: return "Tools";
371 case VALUABLE
: return "Valuables";
372 case MISC
: return "Miscellaneous items";
378 int item::GetResistance (int Type
) const {
379 switch (Type
&0xFFF) {
380 case PHYSICAL_DAMAGE
: return GetStrengthValue();
384 case MUSTARD_GAS_DAMAGE
:
386 case FIRE
: return GetFireResistance();
387 case POISON
: return GetPoisonResistance();
388 case ELECTRICITY
: return GetElectricityResistance();
389 case ACID
: return GetAcidResistance();
391 ABORT("Resistance lack detected!");
396 truth
item::Open (character
*Char
) {
397 if (Char
->IsPlayer()) ADD_MESSAGE("You can't open %s.", CHAR_NAME(DEFINITE
));
402 item
*itemprototype::SpawnAndLoad (inputfile
&SaveFile
) const {
403 item
*Item
= Spawner(0, LOAD
);
404 Item
->Load(SaveFile
);
405 Item
->CalculateAll();
410 void item::LoadDataBaseStats () {
411 SetSize(GetDefaultSize());
415 void item::Initialize (int NewConfig
, int SpecialFlags
) {
416 CalculateSquaresUnder();
417 Slot
= new slot
*[SquaresUnder
];
418 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
419 if (!(SpecialFlags
& LOAD
)) {
420 ID
= game::CreateNewItemID(this);
421 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
423 RandomizeVisualEffects();
424 Flags
|= CENTER
<< SQUARE_POSITION_SHIFT
;
425 if (!(SpecialFlags
& NO_MATERIALS
)) GenerateMaterials();
427 if (!(SpecialFlags
& LOAD
)) PostConstruct();
428 if (!(SpecialFlags
& (LOAD
|NO_MATERIALS
))) {
430 if (!(SpecialFlags
& NO_PIC_UPDATE
)) UpdatePictures();
435 truth
item::ShowMaterial () const {
436 if (GetMainMaterialConfig().Size
== 1) return GetMainMaterial()->GetConfig() != GetMainMaterialConfig()[0];
437 //FIXME: gum solution
439 // never show the material for 'bone bone'
440 if (GetMainMaterial()->GetConfig() == BONE
) return false;
446 sLong
item::GetBlockModifier() const
449 return GetSize() * GetRoundness() << 1;
451 return GetSize() * GetRoundness() << 2;
454 truth
item::CanBeSeenByPlayer() const
456 return CanBeSeenBy(PLAYER
);
459 truth
item::CanBeSeenBy(ccharacter
* Who
) const
461 for(int c
= 0; c
< SquaresUnder
; ++c
)
462 if(Slot
[c
] && Slot
[c
]->CanBeSeenBy(Who
))
465 return Who
->IsPlayer() && game::GetSeeWholeMapCheatMode();
468 festring
item::GetDescription(int Case
) const
470 if(CanBeSeenByPlayer())
471 return GetName(Case
);
473 return CONST_S("something");
476 void item::SignalVolumeAndWeightChange()
478 CalculateVolumeAndWeight();
480 for(int c
= 0; c
< SquaresUnder
; ++c
)
482 Slot
[c
]->SignalVolumeAndWeightChange();
485 void item::CalculateVolumeAndWeight()
489 for(int c
= 0; c
< GetMaterials(); ++c
)
491 cmaterial
* Material
= GetMaterial(c
);
495 Volume
+= Material
->GetVolume();
496 Weight
+= Material
->GetWeight();
501 void item::SignalEmitationIncrease(col24 EmitationUpdate
)
503 if(game::CompareLights(EmitationUpdate
, Emitation
) > 0)
505 game::CombineLights(Emitation
, EmitationUpdate
);
507 for(int c
= 0; c
< SquaresUnder
; ++c
)
509 Slot
[c
]->SignalEmitationIncrease(EmitationUpdate
);
513 void item::SignalEmitationDecrease(col24 EmitationUpdate
)
515 if(game::CompareLights(EmitationUpdate
, Emitation
) >= 0 && Emitation
)
517 col24 Backup
= Emitation
;
518 CalculateEmitation();
520 if(Backup
!= Emitation
)
521 for(int c
= 0; c
< SquaresUnder
; ++c
)
523 Slot
[c
]->SignalEmitationDecrease(EmitationUpdate
);
527 void item::CalculateAll()
529 CalculateVolumeAndWeight();
530 CalculateEmitation();
533 /* Temporary and buggy. */
535 void item::WeaponSkillHit(int Hits
)
537 if(Slot
[0] && Slot
[0]->IsGearSlot())
538 static_cast<arm
*>(static_cast<gearslot
*>(*Slot
)->GetBodyPart())->WieldedSkillHit(Hits
);
541 /* Returns 0 if item cannot be cloned */
543 item
* item::Duplicate(feuLong Flags
)
545 if(!(Flags
& IGNORE_PROHIBITIONS
)
546 && ((!(Flags
& MIRROR_IMAGE
) && !CanBeCloned())
547 || (Flags
& MIRROR_IMAGE
&& (!CanBeMirrored()
549 && !(MainMaterial
->GetCommonFlags() & CAN_BE_MIRRORED
))
550 || (GetSecondaryMaterial()
551 && !(GetSecondaryMaterial()->GetCommonFlags() & CAN_BE_MIRRORED
))))))
554 item
* Clone
= GetProtoType()->Clone(this);
556 if(Flags
& MIRROR_IMAGE
)
557 Clone
->SetLifeExpectancy(Flags
>> LE_BASE_SHIFT
& LE_BASE_RANGE
,
558 Flags
>> LE_RAND_SHIFT
& LE_RAND_RANGE
);
560 idholder
* I
= new idholder(ID
);
561 I
->Next
= CloneMotherID
;
563 game::RemoveItemID(ID
);
564 ID
= game::CreateNewItemID(this);
565 Clone
->UpdatePictures();
569 void item::AddInventoryEntry(ccharacter
*, festring
& Entry
, int Amount
, truth ShowSpecialInfo
) const
572 AddName(Entry
, INDEFINITE
);
575 Entry
<< Amount
<< ' ';
576 AddName(Entry
, PLURAL
);
580 Entry
<< " [" << GetWeight() * Amount
<< "g]";
583 const itemdatabase
* itemprototype::ChooseBaseForConfig(itemdatabase
** TempConfig
, int Configs
, int ConfigNumber
)
585 if(!(ConfigNumber
& BROKEN
))
589 ConfigNumber
^= BROKEN
;
591 for(int c
= 0; c
< Configs
; ++c
)
592 if(TempConfig
[c
]->Config
== ConfigNumber
)
593 return TempConfig
[c
];
599 truth
item::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int Dir
)
601 if(CanBeBroken() && !IsBroken() && Type
& (PHYSICAL_DAMAGE
|SOUND
|ENERGY
|ACID
))
603 int StrengthValue
= GetStrengthValue();
608 if(Damage
> StrengthValue
<< 2 && RAND() & 3 && RAND() % (25 * Damage
/ StrengthValue
) >= 100)
615 if(Type
& ACID
&& IsBroken() && IsDestroyable(Damager
))
617 int StrengthValue
= GetStrengthValue();
622 if(Damage
> StrengthValue
<< 4 && !(RAND() & 3) && RAND() % (100 * Damage
/ StrengthValue
) >= 100)
624 Destroy(Damager
, Dir
);
632 void itemdatabase::InitDefaults(const itemprototype
* NewProtoType
, int NewConfig
)
635 ProtoType
= NewProtoType
;
638 if(NewConfig
& BROKEN
)
640 if(Adjective
.GetSize())
641 Adjective
.Insert(0, "broken ");
643 Adjective
= CONST_S("broken");
647 StrengthModifier
>>= 1;
651 sLong
item::GetNutritionValue() const
655 for(int c
= 0; c
< GetMaterials(); ++c
)
657 NV
+= GetMaterial(c
)->GetTotalNutritionValue();
662 void item::SignalSpoil(material
*)
667 if(CanBeSeenByPlayer())
668 ADD_MESSAGE("%s spoils completely.", GetExtendedDescription().CStr());
670 truth Equipped
= PLAYER
->Equips(this);
674 game::AskForEscPress(CONST_S("Equipment destroyed!"));
677 item
* item::DuplicateToStack(stack
* CurrentStack
, feuLong Flags
)
679 item
* Duplicated
= Duplicate(Flags
);
684 CurrentStack
->AddItem(Duplicated
);
688 truth
item::CanBePiledWith(citem
* Item
, ccharacter
* Viewer
) const
690 return (GetType() == Item
->GetType()
691 && GetConfig() == Item
->GetConfig()
692 && ItemFlags
== Item
->ItemFlags
693 && (WeightIsIrrelevant() || Weight
== Item
->Weight
)
694 && MainMaterial
->IsSameAs(Item
->MainMaterial
)
695 && MainMaterial
->GetSpoilLevel() == Item
->MainMaterial
->GetSpoilLevel()
696 && MainMaterial
->GetRustLevel() == Item
->MainMaterial
->GetRustLevel()
697 && Viewer
->GetCWeaponSkillLevel(this) == Viewer
->GetCWeaponSkillLevel(Item
)
698 && Viewer
->GetSWeaponSkillLevel(this) == Viewer
->GetSWeaponSkillLevel(Item
)
699 && !Fluid
&& !Item
->Fluid
700 && !LifeExpectancy
== !Item
->LifeExpectancy
);
703 void item::Break(character
* Breaker
, int)
705 if(CanBeSeenByPlayer())
706 ADD_MESSAGE("%s %s.", GetExtendedDescription().CStr(), GetBreakVerb());
708 if(Breaker
&& IsOnGround())
710 room
* Room
= GetRoom();
713 Room
->HostileAction(Breaker
);
716 item
* Broken
= GetProtoType()->Clone(this);
717 Broken
->SetConfig(GetConfig() | BROKEN
);
718 Broken
->SetSize(Broken
->GetSize() >> 1);
719 DonateFluidsTo(Broken
);
721 DonateSlotTo(Broken
);
724 if(PLAYER
->Equips(Broken
))
725 game::AskForEscPress(CONST_S("Equipment broken!"));
730 MainMaterial
->Be(ItemFlags
);
732 if (Exists() && LifeExpectancy
) {
733 if (LifeExpectancy
== 1) {
734 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", GetExtendedDescription().CStr());
735 truth Equipped
= PLAYER
->Equips(this);
737 if (Equipped
) game::AskForEscPress(CONST_S("Equipment destroyed!"));
744 int item::GetOfferValue(int Receiver
) const
748 int OfferValue
= int(sqrt(GetTruePrice()));
750 if(Receiver
== GetAttachedGod())
758 void item::SignalEnchantmentChange()
760 for(int c
= 0; c
< SquaresUnder
; ++c
)
762 Slot
[c
]->SignalEnchantmentChange();
765 sLong
item::GetEnchantedPrice(int Enchantment
) const
767 return !PriceIsProportionalToEnchantment() ? item::GetPrice() : Max
<int>(item::GetPrice() * Enchantment
* Enchantment
, 0);
776 Fixed
= GetProtoType()->Clone(this);
777 Fixed
->SetConfig(GetConfig() ^ BROKEN
);
778 Fixed
->SetSize(Fixed
->GetSize() << 1);
779 DonateFluidsTo(Fixed
);
788 void item::DonateSlotTo(item
* Item
)
792 Slot
[0]->DonateTo(Item
);
795 for(int c
= 1; c
< SquaresUnder
; ++c
)
804 int item::GetSpoilLevel() const
806 return MainMaterial
->GetSpoilLevel();
809 void item::SignalSpoilLevelChange(material
*)
811 if(!IsAnimated() && GetSpoilLevel() && Slot
[0] && Slot
[0]->IsVisible())
812 for(int c
= 0; c
< SquaresUnder
; ++c
)
813 GetSquareUnder(c
)->IncStaticAnimatedEntities();
815 SignalVolumeAndWeightChange(); // gum
819 truth
item::AllowSpoil() const
823 lsquare
* Square
= GetLSquareUnder();
824 int RoomNumber
= Square
->GetRoomIndex();
825 return !RoomNumber
|| Square
->GetLevel()->GetRoom(RoomNumber
)->AllowSpoil(this);
831 void item::ResetSpoiling()
833 for(int c
= 0; c
< GetMaterials(); ++c
)
835 GetMaterial(c
)->ResetSpoiling();
838 cchar
* item::GetBaseToHitValueDescription() const
840 if(GetBaseToHitValue() < 10)
841 return ToHitValueDescription
[Min(GetBaseToHitValue(), 6)];
843 return ToHitValueDescription
[7];
846 cchar
* item::GetBaseBlockValueDescription() const
848 if(GetBaseBlockValue() < 20)
849 return ToHitValueDescription
[Min(GetBaseBlockValue() >> 1, 6)];
851 return ToHitValueDescription
[7];
854 cchar
* item::GetStrengthValueDescription() const
856 int SV
= GetStrengthValue();
859 return StrengthValueDescription
[0];
861 return StrengthValueDescription
[1];
863 return StrengthValueDescription
[2];
865 return StrengthValueDescription
[3];
867 return StrengthValueDescription
[4];
869 return StrengthValueDescription
[5];
871 return StrengthValueDescription
[6];
874 void item::SpecialGenerationHandler()
877 Slot
[0]->AddFriendItem(Duplicate());
880 void item::SortAllItems(const sortdata
& SortData
) const
882 if(SortData
.Sorter
== 0 || (this->*SortData
.Sorter
)(SortData
.Character
))
883 SortData
.AllItems
.push_back(const_cast<item
*>(this));
886 int item::GetAttachedGod() const
888 return DataBase
->AttachedGod
? DataBase
->AttachedGod
: MainMaterial
->GetAttachedGod();
891 sLong
item::GetMaterialPrice() const
893 return MainMaterial
->GetRawPrice();
896 sLong
item::GetTruePrice() const
901 sLong Price
= Max(GetPrice(), GetMaterialPrice());
904 Price
= Price
* (100 - GetMaxSpoilPercentage()) / 500;
911 void item::AddAttackInfo(felist
& List
) const
913 festring
Entry(40, ' ');
914 Entry
<< int(GetWeight());
916 Entry
<< int(GetSize());
918 Entry
<< int(GetStrengthRequirement());
920 Entry
<< GetBaseMinDamage() << '-' << GetBaseMaxDamage();
921 List
.AddEntry(Entry
, LIGHT_GRAY
);
924 void item::AddMiscellaneousInfo(felist
& List
) const
926 festring
Entry(40, ' ');
927 Entry
<< int(GetTruePrice());
929 Entry
<< GetOfferValue(0);
931 Entry
<< int(GetNutritionValue());
932 List
.AddEntry(Entry
, LIGHT_GRAY
);
938 void item::PreProcessForBone () {
943 game::RemoveItemID(ID
);
945 game::AddItemID(this, ID
);
951 void item::PostProcessForBone () {
952 boneidmap::iterator BI
= game::GetBoneItemIDMap().find(-ID
);
953 game::RemoveItemID(ID
);
955 if (BI
== game::GetBoneItemIDMap().end()) {
956 feuLong NewID
= game::CreateNewItemID(this);
957 game::GetBoneItemIDMap().insert(std::make_pair(-ID
, NewID
));
960 if (game::SearchItem(BI
->second
)) {
962 game::AddItemID(this, ID
);
965 for (idholder
* I
= CloneMotherID
; I
; I
= I
->Next
) {
966 BI
= game::GetBoneItemIDMap().find(I
->ID
);
967 if (BI
== game::GetBoneItemIDMap().end()) {
968 feuLong NewCloneMotherID
= game::CreateNewItemID(0);
969 game::GetBoneItemIDMap().insert(std::make_pair(I
->ID
, NewCloneMotherID
));
970 I
->ID
= NewCloneMotherID
;
978 void item::SetConfig(int NewConfig
, int SpecialFlags
)
980 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
983 if(!(SpecialFlags
& NO_PIC_UPDATE
))
987 god
* item::GetMasterGod() const
989 return game::GetGod(GetConfig());
992 int itemprototype::CreateSpecialConfigurations(itemdatabase
** TempConfig
, int Configs
, int Level
)
997 if(TempConfig
[0]->CreateDivineConfigurations
)
998 Configs
= databasecreator
<item
>::CreateDivineConfigurations(this, TempConfig
, Configs
);
1002 if(TempConfig
[0]->CreateLockConfigurations
)
1004 const item::database
*const* KeyConfigData
= key::ProtoType
.GetConfigData();
1005 int KeyConfigSize
= key::ProtoType
.GetConfigSize();
1006 int OldConfigs
= Configs
;
1008 for(int c1
= 0; c1
< OldConfigs
; ++c1
)
1009 if(!TempConfig
[c1
]->IsAbstract
)
1011 int BaseConfig
= TempConfig
[c1
]->Config
;
1012 int NewConfig
= BaseConfig
| BROKEN_LOCK
;
1013 itemdatabase
* ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1014 ConfigDataBase
->InitDefaults(this, NewConfig
);
1015 ConfigDataBase
->PostFix
<< "with a broken lock";
1016 ConfigDataBase
->Possibility
= 0;
1017 TempConfig
[Configs
++] = ConfigDataBase
;
1019 for(int c2
= 0; c2
< KeyConfigSize
; ++c2
)
1021 NewConfig
= BaseConfig
| KeyConfigData
[c2
]->Config
;
1022 ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1023 ConfigDataBase
->InitDefaults(this, NewConfig
);
1024 ConfigDataBase
->PostFix
<< "with ";
1026 if(KeyConfigData
[c2
]->UsesLongAdjectiveArticle
)
1027 ConfigDataBase
->PostFix
<< "an ";
1029 ConfigDataBase
->PostFix
<< "a ";
1031 ConfigDataBase
->PostFix
<< KeyConfigData
[c2
]->Adjective
<< " lock";
1032 ConfigDataBase
->Possibility
= 0;
1033 TempConfig
[Configs
++] = ConfigDataBase
;
1041 void item::Draw(blitdata
& BlitData
) const
1043 cint AF
= GraphicData
.AnimationFrames
;
1044 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) || AF
== 1 ? 0 : GET_TICK() & (AF
- 1);
1045 cbitmap
* P
= GraphicData
.Picture
[F
];
1047 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1048 P
->AlphaLuminanceBlit(BlitData
);
1050 P
->LuminanceMaskedBlit(BlitData
);
1052 if(Fluid
&& ShowFluids())
1053 DrawFluids(BlitData
);
1056 v2
item::GetLargeBitmapPos(v2 BasePos
, int I
) const
1058 cint SquareIndex
= I
? I
/ (GraphicData
.AnimationFrames
>> 2) : 0;
1059 return v2(SquareIndex
& 1 ? BasePos
.X
+ 16 : BasePos
.X
, SquareIndex
& 2 ? BasePos
.Y
+ 16 : BasePos
.Y
);
1062 void item::LargeDraw(blitdata
& BlitData
) const
1064 cint TrueAF
= GraphicData
.AnimationFrames
>> 2;
1065 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1066 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) ? SquareIndex
* TrueAF
: SquareIndex
* TrueAF
+ (GET_TICK() & (TrueAF
- 1));
1067 cbitmap
* P
= GraphicData
.Picture
[F
];
1069 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1070 P
->AlphaLuminanceBlit(BlitData
);
1072 P
->LuminanceMaskedBlit(BlitData
);
1075 void item::DonateIDTo(item
* Item
)
1077 game::RemoveItemID(Item
->ID
);
1078 game::UpdateItemID(Item
, ID
);
1083 void item::SignalRustLevelChange()
1085 SignalVolumeAndWeightChange();
1087 SendNewDrawAndMemorizedUpdateRequest();
1090 const rawbitmap
* item::GetRawPicture() const
1092 return igraph::GetRawGraphic(GetGraphicsContainerIndex());
1095 void item::RemoveFluid(fluid
*ToBeRemoved
) {
1096 truth WasAnimated
= IsAnimated();
1097 truth HasFluids
= false;
1099 if (Fluid
&& ToBeRemoved
) {
1100 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
1101 fluid
*F
= Fluid
[c
];
1103 if (F
== ToBeRemoved
) {
1108 for (F
= F
->Next
; F
; LF
= F
, F
= F
->Next
) if (F
== ToBeRemoved
) { LF
->Next
= F
->Next
; break; }
1110 if (Fluid
[c
]) HasFluids
= true;
1114 if (!HasFluids
&& Fluid
) {
1117 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) GetSquareUnder()->DecStaticAnimatedEntities();
1119 if (ToBeRemoved
) SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
1120 SignalVolumeAndWeightChange();
1124 void item::RemoveAllFluids () {
1126 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ) {
1127 //fprintf(stderr, "c: %d; SquaresUnder: %d\n", c, SquaresUnder);
1128 fluid
*F
= Fluid
[c
];
1141 void item::AddFluid (liquid
*ToBeAdded
, festring LocationName
, int SquareIndex
, truth IsInside
) {
1142 truth WasAnimated
= IsAnimated();
1144 if (SquareIndex
< 0) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1147 fluid
*F
= Fluid
[SquareIndex
];
1149 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1151 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1156 if (ToBeAdded
->IsSameAs(F
->GetLiquid())) {
1157 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
1164 LF
->Next
= new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1167 FluidCount
= SquaresUnder
;
1168 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
1169 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1170 memset(Fluid
, 0, SquaresUnder
*sizeof(fluid
*));
1171 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1175 SignalVolumeAndWeightChange();
1176 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
1179 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) {
1180 GetSquareUnder()->IncStaticAnimatedEntities();
1182 SendNewDrawAndMemorizedUpdateRequest();
1186 void item::SendNewDrawAndMemorizedUpdateRequest() const
1188 if(!game::IsInWilderness())
1189 for(int c
= 0; c
< SquaresUnder
; ++c
)
1192 lsquare
*Square
= GetLSquareUnder(c
);
1194 Square
->SendNewDrawRequest();
1195 Square
->SendMemorizedUpdateRequest();
1200 void item::CalculateEmitation()
1202 object::CalculateEmitation();
1205 for(int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
)
1206 for(const fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1207 game::CombineLights(Emitation
, F
->GetEmitation());
1210 void item::FillFluidVector (fluidvector
&Vector
, int SquareIndex
) const {
1212 if (SquareIndex
< 0 || SquareIndex
>= FluidCount
) ABORT("item::FillFluidVector(): invalid SquareIndex: %d\n", SquareIndex
);
1213 for (fluid
*F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
) Vector
.push_back(F
);
1217 void item::SpillFluid(character
*, liquid
* Liquid
, int SquareIndex
)
1219 if(AllowFluids() && Liquid
->GetVolume())
1220 AddFluid(Liquid
, "", SquareIndex
, false);
1225 void item::TryToRust (sLong LiquidModifier
) {
1226 if (MainMaterial
->TryToRust(LiquidModifier
)) {
1227 if (CanBeSeenByPlayer()) {
1228 if (MainMaterial
->GetRustLevel() == NOT_RUSTED
) ADD_MESSAGE("%s rusts.", CHAR_NAME(DEFINITE
));
1229 else ADD_MESSAGE("%s rusts more.", CHAR_NAME(DEFINITE
));
1231 MainMaterial
->SetRustLevel(MainMaterial
->GetRustLevel() + 1);
1235 void item::CheckFluidGearPictures(v2 ShadowPos
, int SpecialFlags
, truth BodyArmor
)
1238 for(fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1239 F
->CheckGearPicture(ShadowPos
, SpecialFlags
, BodyArmor
);
1242 void item::DrawFluidGearPictures(blitdata
& BlitData
, int SpecialFlags
) const
1245 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1246 F
->DrawGearPicture(BlitData
, SpecialFlags
);
1249 void item::DrawFluidBodyArmorPictures(blitdata
& BlitData
, int SpecialFlags
) const
1252 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1253 F
->DrawBodyArmorPicture(BlitData
, SpecialFlags
);
1256 void item::DrawFluids(blitdata
& BlitData
) const
1258 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1260 for(const fluid
* F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
)
1264 void item::ReceiveAcid(material
*, cfestring
&, sLong Modifier
)
1266 if(GetMainMaterial()->GetInteractionFlags() & CAN_DISSOLVE
)
1268 int Damage
= Modifier
/ 1000;
1272 Damage
+= RAND() % Damage
;
1273 ReceiveDamage(0, Damage
, ACID
);
1278 void item::DonateFluidsTo(item
* Item
)
1281 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1282 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1284 liquid
* Liquid
= F
->GetLiquid();
1285 Item
->AddFluid(Liquid
->SpawnMoreLiquid(Liquid
->GetVolume()), F
->GetLocationName(), c
, F
->IsInside());
1289 void item::Destroy(character
* Destroyer
, int)
1291 if(CanBeSeenByPlayer())
1292 ADD_MESSAGE("%s is destroyed.", GetExtendedDescription().CStr());
1294 if(Destroyer
&& IsOnGround())
1296 room
* Room
= GetRoom();
1299 Room
->HostileAction(Destroyer
);
1302 truth Equipped
= PLAYER
->Equips(this);
1307 game::AskForEscPress(CONST_S("Equipment destroyed!"));
1310 void item::RemoveRust()
1312 for(int c
= 0; c
< GetMaterials(); ++c
)
1314 GetMaterial(c
)->SetRustLevel(NOT_RUSTED
);
1317 void item::SetSpoilPercentage(int Value
)
1319 for(int c
= 0; c
< GetMaterials(); ++c
)
1321 material
* Material
= GetMaterial(c
);
1323 if(Material
&& Material
->CanSpoil())
1324 Material
->SetSpoilCounter(Material
->GetSpoilModifier() * Value
/ 100);
1328 void item::RedistributeFluids()
1331 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1332 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1336 material
* item::GetConsumeMaterial(ccharacter
* Consumer
, materialpredicate Predicate
) const
1338 return (MainMaterial
->*Predicate
)() && Consumer
->CanConsume(MainMaterial
) ? MainMaterial
: 0;
1341 /* The parameter can only be MainMaterial */
1343 material
* item::RemoveMaterial(material
*)
1350 void item::InitMaterials(material
* FirstMaterial
, truth CallUpdatePictures
)
1352 InitMaterial(MainMaterial
, FirstMaterial
, GetDefaultMainVolume());
1353 SignalVolumeAndWeightChange();
1355 if(CallUpdatePictures
)
1359 void item::GenerateMaterials()
1361 int Chosen
= RandomizeMaterialConfiguration();
1362 const fearray
<sLong
>& MMC
= GetMainMaterialConfig();
1363 InitMaterial(MainMaterial
,
1364 MAKE_MATERIAL(MMC
.Data
[MMC
.Size
== 1 ? 0 : Chosen
]),
1365 GetDefaultMainVolume());
1368 void item::SignalSquarePositionChange(int Position
)
1370 Flags
&= ~SQUARE_POSITION_BITS
;
1371 Flags
|= Position
<< SQUARE_POSITION_SHIFT
;
1374 truth
item::Read(character
* Reader
)
1376 Reader
->StartReading(this, GetReadDifficulty());
1380 truth
item::CanBeHardened(ccharacter
*) const
1382 return MainMaterial
->GetHardenedMaterial(this) != NONE
;
1385 void item::SetLifeExpectancy(int Base
, int RandPlus
)
1387 LifeExpectancy
= RandPlus
> 1 ? Base
+ RAND_N(RandPlus
) : Base
;
1391 truth
item::IsVeryCloseToSpoiling() const
1393 for(int c
= 0; c
< GetMaterials(); ++c
)
1394 if(GetMaterial(c
) && !GetMaterial(c
)->IsVeryCloseToSpoiling())
1400 truth
item::IsValuable() const
1402 if(DataBase
->IsValuable
)
1405 for(int c
= 0; c
< GetMaterials(); ++c
)
1407 material
* M
= GetMaterial(c
);
1409 if(M
&& M
->GetCommonFlags() & IS_VALUABLE
)
1416 int item::GetHinderVisibilityBonus(ccharacter
* Char
) const
1420 if(GetGearStates() & INFRA_VISION
1421 && !Char
->TemporaryStateIsActivated(INFRA_VISION
))
1424 if(GetGearStates() & ESP
1425 && !Char
->TemporaryStateIsActivated(ESP
))
1428 if(!game::IsDark(GetEmitation()))
1434 sLong
item::GetFixPrice() const
1436 item
* Clone
= GetProtoType()->Clone(this);
1437 Clone
= Clone
->Fix();
1438 Clone
->RemoveRust();
1439 sLong FixPrice
= Clone
->GetTruePrice();
1440 Clone
->SendToHell();
1441 return Max(sLong(3.5 * sqrt(FixPrice
)), 10);
1444 void item::AddTrapName(festring
& String
, int Amount
) const
1447 AddName(String
, DEFINITE
);
1450 String
<< Amount
<< ' ';
1451 AddName(String
, PLURAL
);
1455 truth
item::Spoils() const
1457 for(int c
= 0; c
< GetMaterials(); ++c
)
1459 cmaterial
* Material
= GetMaterial(c
);
1461 if(Material
&& Material
->Spoils())
1468 int item::GetMaxSpoilPercentage() const
1470 int MaxPercentage
= 0;
1472 for(int c
= 0; c
< GetMaterials(); ++c
)
1474 cmaterial
* Material
= GetMaterial(c
);
1477 MaxPercentage
= Max(MaxPercentage
, Material
->GetSpoilPercentage());
1480 return MaxPercentage
;
1483 truth
item::HasPrice() const
1485 return GetPrice() || GetMaterialPrice();
1488 void item::Disappear()
1494 outputfile
& operator<<(outputfile
& SaveFile
, const idholder
* IdHolder
)
1496 SaveFile
<< IdHolder
->ID
;
1500 inputfile
& operator>>(inputfile
& SaveFile
, idholder
*& IdHolder
)
1502 IdHolder
= new idholder(ReadType(feuLong
, SaveFile
));
1506 festring
item::GetExtendedDescription() const
1508 if(!CanBeSeenByPlayer())
1509 return CONST_S("something");
1512 ccharacter
* Carrier
= FindCarrier();
1516 if(Carrier
->IsPlayer())
1519 AddName(Desc
, UNARTICLED
);
1522 else if(Carrier
->CanBeSeenByPlayer())
1524 Carrier
->AddName(Desc
, DEFINITE
);
1526 AddName(Desc
, UNARTICLED
);
1531 AddName(Desc
, DEFINITE
);
1534 GetLSquareUnder()->AddLocationDescription(Desc
);
1539 ccharacter
* item::FindCarrier() const
1541 return Slot
[0]->FindCarrier();
1544 /* returns 0 if not worn or wielded else the wearer */
1546 const character
* item::GetWearer() const
1548 if(!GetSlot()->IsGearSlot())
1551 return FindCarrier();
1554 void itemlock::PostConstruct()
1556 /* Terrible gum solution! */
1558 if(!(GetVirtualConfig() & LOCK_BITS
))
1560 int NormalLockTypes
= 0;
1561 const itemdatabase
*const* ConfigData
= GetVirtualProtoType()->GetConfigData();
1562 int c
, ConfigSize
= GetVirtualProtoType()->GetConfigSize();
1564 for(c
= 0; c
< ConfigSize
; ++c
)
1565 if(ConfigData
[c
]->Config
& LOCK_BITS
1566 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1567 && !(ConfigData
[c
]->Config
& S_LOCK_ID
))
1570 int ChosenLock
= RAND() % NormalLockTypes
;
1572 for(c
= 0; c
< ConfigSize
; ++c
)
1573 if(ConfigData
[c
]->Config
& LOCK_BITS
1574 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1575 && !(ConfigData
[c
]->Config
& S_LOCK_ID
)
1578 SetVirtualConfig(ConfigData
[c
]->Config
, NO_PIC_UPDATE
);
1584 truth
itemlock::TryKey(item
* Key
, character
* Applier
)
1586 if(GetVirtualConfig() & BROKEN_LOCK
)
1588 ADD_MESSAGE("The lock is broken.");
1592 if(Key
->CanOpenLockType(GetVirtualConfig()&LOCK_BITS
))
1596 if(Applier
->IsPlayer())
1597 ADD_MESSAGE("You unlock %s.", GetVirtualDescription(DEFINITE
).CStr());
1598 else if(Applier
->CanBeSeenByPlayer())
1599 ADD_MESSAGE("%s unlocks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1603 if(Applier
->IsPlayer())
1604 ADD_MESSAGE("You lock %s.", GetVirtualDescription(DEFINITE
).CStr());
1605 else if(Applier
->CanBeSeenByPlayer())
1606 ADD_MESSAGE("%s locks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1613 if(Applier
->IsPlayer())
1614 ADD_MESSAGE("%s doesn't fit in the lock.", Key
->CHAR_NAME(DEFINITE
));
1615 else if(Applier
->CanBeSeenByPlayer())
1616 ADD_MESSAGE("%s tries to fit %s in the lock, but fails.", Applier
->CHAR_NAME(DEFINITE
), Key
->CHAR_NAME(DEFINITE
));
1622 void itemlock::Save(outputfile
& SaveFile
) const
1627 void itemlock::Load(inputfile
& SaveFile
)
1632 truth
item::IsBeverage(ccharacter
*) const
1634 for(int c
= 0; c
< GetMaterials(); ++c
)
1636 cmaterial
* Material
= GetMaterial(c
);
1638 if(Material
&& (Material
->GetCategoryFlags() & IS_BEVERAGE
))
1649 SendMemorizedUpdateRequest();
1655 ItemFlags
&= ~HASTE
;
1656 SendMemorizedUpdateRequest();
1659 void item::SendMemorizedUpdateRequest() const
1661 if(!game::IsInWilderness())
1662 for(int c
= 0; c
< SquaresUnder
; ++c
)
1665 lsquare
* Square
= GetLSquareUnder(c
);
1666 Square
->SendMemorizedUpdateRequest();
1670 truth
item::AddStateDescription(festring
& Name
, truth Articled
) const
1675 if((ItemFlags
& (HASTE
|SLOW
)) && Articled
)
1678 if(ItemFlags
& HASTE
)
1681 if(ItemFlags
& SLOW
)
1688 truth
item::Burn (character
*who
, v2 where
, int dir
) {
1689 //who->EditExperience(PERCEPTION, 150, 1 << 10);
1690 where
+= game::GetMoveVector(dir
);
1691 area
*ca
= who
->GetSquareUnder()->GetArea();
1692 if (where
.X
< 0 || where
.Y
< 0 || where
.X
>= ca
->GetXSize() || where
.Y
>= ca
->GetYSize()) return false;
1693 lsquare
*sq
= static_cast<lsquare
*>(ca
->GetSquare(where
.X
, where
.Y
));
1695 sq
->ReceiveTrapDamage(who
, 50, FIRE
, dir
);